HHH-16657 Propagate PROJECTION entity name use from subquery to outer table group

This commit is contained in:
Christian Beikov 2023-05-21 14:19:10 +02:00
parent 7f5ebc207e
commit 4795b94f68
3 changed files with 88 additions and 3 deletions

View File

@ -2973,14 +2973,20 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return;
}
final TableGroup actualTableGroup;
final EntityNameUse finalEntityNameUse;
if ( tableGroup instanceof PluralTableGroup ) {
actualTableGroup = ( (PluralTableGroup) tableGroup ).getElementTableGroup();
finalEntityNameUse = entityNameUse;
}
else if ( tableGroup instanceof CorrelatedTableGroup ) {
actualTableGroup = ( (CorrelatedTableGroup) tableGroup ).getCorrelatedTableGroup();
// For correlated table groups we can't apply filters,
// as the context is in which the use happens may only affect the result of the subquery
finalEntityNameUse = entityNameUse == EntityNameUse.EXPRESSION ? entityNameUse : EntityNameUse.PROJECTION;
}
else {
actualTableGroup = tableGroup;
finalEntityNameUse = entityNameUse;
}
final Map<String, EntityNameUse> entityNameUses = tableGroupEntityNameUses.computeIfAbsent(
actualTableGroup,
@ -2988,13 +2994,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
entityNameUses.compute(
hibernateEntityName,
(s, existingUse) -> entityNameUse.stronger( existingUse )
(s, existingUse) -> finalEntityNameUse.stronger( existingUse )
);
// Resolve the table reference for all types which we register an entity name use for
actualTableGroup.resolveTableReference( null, persister.getTableName() );
if ( entityNameUse == EntityNameUse.PROJECTION ) {
if ( finalEntityNameUse == EntityNameUse.PROJECTION ) {
// For projections also register uses of all super and subtypes,
// as well as resolve the respective table references
EntityMappingType superMappingType = persister;
@ -3014,7 +3020,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
actualTableGroup.resolveTableReference( null, persister.getSubclassTableName( i ) );
}
}
else if ( entityNameUse == EntityNameUse.TREAT ) {
else if ( finalEntityNameUse == EntityNameUse.TREAT ) {
// 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
for ( EntityMappingType subType : persister.getSubMappingTypes() ) {

View File

@ -15,19 +15,27 @@ import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import jakarta.persistence.metamodel.EntityType;
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
import org.hibernate.orm.test.jpa.metamodel.Thing;
import org.hibernate.orm.test.jpa.metamodel.ThingWithQuantity;
import org.hibernate.orm.test.jpa.metamodel.ThingWithQuantity_;
import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntity;
import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntitySubSubclass;
import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntitySubSubclass2;
import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntitySubclass;
import org.hibernate.orm.test.jpa.ql.TreatKeywordTest.JoinedEntitySubclass2;
import org.hibernate.testing.TestForIssue;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* @author Steve Ebersole
@ -37,6 +45,8 @@ public class TreatKeywordTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] {
JoinedEntity.class, JoinedEntitySubclass.class, JoinedEntitySubSubclass.class,
JoinedEntitySubclass2.class, JoinedEntitySubSubclass2.class,
Animal.class, Elephant.class, Human.class, Thing.class, ThingWithQuantity.class,
TreatAnimal.class, Dog.class, Dachshund.class, Greyhound.class
};
@ -254,6 +264,46 @@ public class TreatKeywordTest extends BaseEntityManagerFunctionalTestCase {
em.close();
}
@Test
@TestForIssue(jiraKey = "HHH-16657")
public void testTypeFilterInSubquery() {
EntityManager em = getOrCreateEntityManager();
EntityTransaction entityTransaction = em.getTransaction();
entityTransaction.begin();
JoinedEntitySubclass2 child1 = new JoinedEntitySubclass2( 3, "child1");
JoinedEntitySubSubclass2 child2 = new JoinedEntitySubSubclass2( 4, "child2");
JoinedEntitySubclass root1 = new JoinedEntitySubclass( 1, "root1", child1);
JoinedEntitySubSubclass root2 = new JoinedEntitySubSubclass( 2, "root2", child2);
em.persist( child1 );
em.persist( child2 );
em.persist( root1 );
em.persist( root2 );
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<String> query = cb.createQuery( String.class );
Root<JoinedEntitySubclass> root = query.from( JoinedEntitySubclass.class );
query.orderBy( cb.asc( root.get( "id" ) ) );
Subquery<String> subquery = query.subquery( String.class );
Root<JoinedEntitySubclass> subqueryRoot = subquery.correlate( root );
Join<Object, Object> other = subqueryRoot.join( "other" );
subquery.select( other.get( "name" ) );
subquery.where( cb.equal( root.type(), cb.literal( JoinedEntitySubclass.class ) ) );
query.select( subquery );
List<String> results = em.createQuery(
"select (select o.name from j.other o where type(j) = JoinedEntitySubSubclass) from JoinedEntitySubclass j order by j.id",
String.class
).getResultList();
assertEquals( 2, results.size() );
assertNull( results.get( 0 ) );
assertEquals( "child2", results.get( 1 ) );
entityTransaction.commit();
em.close();
}
@Entity(name = "TreatAnimal")
public static abstract class TreatAnimal {
@Id

View File

@ -30,6 +30,7 @@ import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
@ -208,6 +209,34 @@ public class TreatKeywordTest extends BaseCoreFunctionalTestCase {
s.close();
}
@Test
@TestForIssue(jiraKey = "HHH-16657")
public void testTypeFilterInSubquery() {
Session s = openSession();
Transaction tx = s.beginTransaction();
JoinedEntitySubclass2 child1 = new JoinedEntitySubclass2(3, "child1");
JoinedEntitySubSubclass2 child2 = new JoinedEntitySubSubclass2(4, "child2");
JoinedEntitySubclass root1 = new JoinedEntitySubclass(1, "root1", child1);
JoinedEntitySubSubclass root2 = new JoinedEntitySubSubclass(2, "root2", child2);
s.persist( child1 );
s.persist( child2 );
s.persist( root1 );
s.persist( root2 );
List<String> results = s.createSelectionQuery(
"select (select o.name from j.other o where type(j) = JoinedEntitySubSubclass) from JoinedEntitySubclass j order by j.id",
String.class
).list();
assertEquals( 2, results.size() );
assertNull( results.get( 0 ) );
assertEquals( "child2", results.get( 1 ) );
tx.commit();
s.close();
}
@Entity( name = "JoinedEntity" )
@Table( name = "JoinedEntity" )
@Inheritance( strategy = InheritanceType.JOINED )