From 5a27b2a4da3470fd37e6d91a7ee0222e07d9c37d Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Mon, 11 Dec 2023 11:06:58 +0100 Subject: [PATCH] HHH-17483 Fix applyDiscriminator treat for nested inheritance subtypes Also small fix to joined-inheritance pruning. --- .../entity/AbstractEntityPersister.java | 22 +++++++++++-- .../entity/JoinedSubclassEntityPersister.java | 16 ++++++---- .../entity/SingleTableEntityPersister.java | 2 +- .../entity/UnionSubclassEntityPersister.java | 2 +- .../sqm/sql/BaseSqmToSqlAstConverter.java | 32 +++++++++++++------ 5 files changed, 53 insertions(+), 21 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 40ff18a7d4..598fad93bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -3037,7 +3037,7 @@ protected void logStaticSQL() { public abstract Map getSubclassByDiscriminatorValue(); - protected abstract boolean needsDiscriminator(); + public abstract boolean needsDiscriminator(); protected boolean isDiscriminatorFormula() { return false; @@ -3130,7 +3130,25 @@ public void applyDiscriminator( TableGroup tableGroup, SqlAstCreationState creationState) { if ( needsDiscriminator() ) { - pruneForSubclasses( tableGroup, Collections.singletonMap( getEntityName(), EntityNameUse.TREAT ) ); + assert !creationState.supportsEntityNameUsage() : "Entity name usage should have been used instead"; + final Map entityNameUseMap; + final Collection subMappingTypes = getSubMappingTypes(); + if ( subMappingTypes.isEmpty() ) { + entityNameUseMap = Collections.singletonMap( getEntityName(), EntityNameUse.TREAT ); + } + else { + entityNameUseMap = new HashMap<>( 1 + subMappingTypes.size() ); + entityNameUseMap.put( getEntityName(), EntityNameUse.TREAT ); + // We need to register TREAT uses for all subtypes when pruning + for ( EntityMappingType subMappingType : subMappingTypes ) { + entityNameUseMap.put( subMappingType.getEntityName(), EntityNameUse.TREAT ); + } + if ( isInherited() ) { + // Make sure the table group includes the root table when needed for TREAT + tableGroup.resolveTableReference( getRootTableName() ); + } + } + pruneForSubclasses( tableGroup, entityNameUseMap ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 689b40f384..4d4e918f8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -744,7 +744,7 @@ private void associateSubclassNamesToSubclassTableIndex( } @Override - protected boolean needsDiscriminator() { + public boolean needsDiscriminator() { return forceDiscriminator; } @@ -1325,15 +1325,17 @@ public void pruneForSubclasses(TableGroup tableGroup, Map final String[] subclassTableNames = persister.getSubclassTableNames(); // Build the intersection of all tables names that are of the class or super class // These are the tables that can be safely inner joined - if ( tablesToInnerJoin.isEmpty() ) { - for ( int i = 0; i < subclassTableNames.length; i++ ) { - if ( persister.isClassOrSuperclassTable[i] ) { - tablesToInnerJoin.add( subclassTableNames[i] ); - } + final Set classOrSuperclassTables = new HashSet<>( subclassTableNames.length ); + for ( int i = 0; i < subclassTableNames.length; i++ ) { + if ( persister.isClassOrSuperclassTable[i] ) { + classOrSuperclassTables.add( subclassTableNames[i] ); } } + if ( tablesToInnerJoin.isEmpty() ) { + tablesToInnerJoin.addAll( classOrSuperclassTables ); + } else { - tablesToInnerJoin.retainAll( Arrays.asList( subclassTableNames ) ); + tablesToInnerJoin.retainAll( classOrSuperclassTables ); } if ( useKind == EntityNameUse.UseKind.FILTER && explicitDiscriminatorColumnName == null ) { // If there is no discriminator column, diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index c046aa64a0..6cff99cb99 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -548,7 +548,7 @@ public String fromTableFragment(String name) { } @Override - protected boolean needsDiscriminator() { + public boolean needsDiscriminator() { return forceDiscriminator || isInherited(); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index d98449cdf4..9880922620 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -286,7 +286,7 @@ public TableGroup createRootTableGroup( } @Override - protected boolean needsDiscriminator() { + public boolean needsDiscriminator() { return false; } 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 6bf4fdedba..b6ba343088 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 @@ -3102,20 +3102,30 @@ private void registerEntityNameUsage( ); } } - if ( useKind == EntityNameUse.UseKind.TREAT || useKind == EntityNameUse.UseKind.PROJECTION ) { - // If we encounter a treat use, we also want register the use for all subtypes. - // We do this here to not have to expand entity name uses during pruning later on + // If we encounter a treat or projection use, we also want register the use for all subtypes. + // We do this here to not have to expand entity name uses during pruning later on + if ( useKind == EntityNameUse.UseKind.TREAT ) { for ( EntityMappingType subType : persister.getSubMappingTypes() ) { entityNameUses.compute( subType.getEntityName(), (s, existingUse) -> finalEntityNameUse.stronger( existingUse ) ); - if ( useKind == EntityNameUse.UseKind.PROJECTION ) { - actualTableGroup.resolveTableReference( - null, - subType.getEntityPersister().getMappedTableDetails().getTableName() - ); - } + } + if ( persister.isInherited() && persister.needsDiscriminator() ) { + // Make sure the table group includes the root table when needed for TREAT + actualTableGroup.resolveTableReference( persister.getRootTableName() ); + } + } + else if ( useKind == EntityNameUse.UseKind.PROJECTION ) { + for ( EntityMappingType subType : persister.getSubMappingTypes() ) { + entityNameUses.compute( + subType.getEntityName(), + (s, existingUse) -> finalEntityNameUse.stronger( existingUse ) + ); + actualTableGroup.resolveTableReference( + null, + subType.getEntityPersister().getMappedTableDetails().getTableName() + ); } } } @@ -8217,7 +8227,9 @@ else if ( getLoadQueryInfluencers().hasEnabledFetchProfiles() ) { if ( entityMappingType.getSuperMappingType() != null ) { // A joined table group was created by an enabled entity graph or fetch profile, // and it's of an inheritance subtype, so we should apply the discriminator - entityMappingType.applyDiscriminator( null, null, actualTableGroup, this ); + getCurrentClauseStack().push( Clause.FROM ); + registerEntityNameUsage( actualTableGroup, EntityNameUse.TREAT, entityMappingType.getEntityName() ); + getCurrentClauseStack().pop(); } } }