HHH-16657 Propagate PROJECTION entity name use from subquery to outer table group
This commit is contained in:
parent
7f5ebc207e
commit
4795b94f68
|
@ -2973,14 +2973,20 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final TableGroup actualTableGroup;
|
final TableGroup actualTableGroup;
|
||||||
|
final EntityNameUse finalEntityNameUse;
|
||||||
if ( tableGroup instanceof PluralTableGroup ) {
|
if ( tableGroup instanceof PluralTableGroup ) {
|
||||||
actualTableGroup = ( (PluralTableGroup) tableGroup ).getElementTableGroup();
|
actualTableGroup = ( (PluralTableGroup) tableGroup ).getElementTableGroup();
|
||||||
|
finalEntityNameUse = entityNameUse;
|
||||||
}
|
}
|
||||||
else if ( tableGroup instanceof CorrelatedTableGroup ) {
|
else if ( tableGroup instanceof CorrelatedTableGroup ) {
|
||||||
actualTableGroup = ( (CorrelatedTableGroup) tableGroup ).getCorrelatedTableGroup();
|
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 {
|
else {
|
||||||
actualTableGroup = tableGroup;
|
actualTableGroup = tableGroup;
|
||||||
|
finalEntityNameUse = entityNameUse;
|
||||||
}
|
}
|
||||||
final Map<String, EntityNameUse> entityNameUses = tableGroupEntityNameUses.computeIfAbsent(
|
final Map<String, EntityNameUse> entityNameUses = tableGroupEntityNameUses.computeIfAbsent(
|
||||||
actualTableGroup,
|
actualTableGroup,
|
||||||
|
@ -2988,13 +2994,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
);
|
);
|
||||||
entityNameUses.compute(
|
entityNameUses.compute(
|
||||||
hibernateEntityName,
|
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
|
// Resolve the table reference for all types which we register an entity name use for
|
||||||
actualTableGroup.resolveTableReference( null, persister.getTableName() );
|
actualTableGroup.resolveTableReference( null, persister.getTableName() );
|
||||||
|
|
||||||
if ( entityNameUse == EntityNameUse.PROJECTION ) {
|
if ( finalEntityNameUse == EntityNameUse.PROJECTION ) {
|
||||||
// For projections also register uses of all super and subtypes,
|
// For projections also register uses of all super and subtypes,
|
||||||
// as well as resolve the respective table references
|
// as well as resolve the respective table references
|
||||||
EntityMappingType superMappingType = persister;
|
EntityMappingType superMappingType = persister;
|
||||||
|
@ -3014,7 +3020,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
actualTableGroup.resolveTableReference( null, persister.getSubclassTableName( i ) );
|
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.
|
// 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
|
// We do this here to not have to expand entity name uses during pruning later on
|
||||||
for ( EntityMappingType subType : persister.getSubMappingTypes() ) {
|
for ( EntityMappingType subType : persister.getSubMappingTypes() ) {
|
||||||
|
|
|
@ -15,19 +15,27 @@ import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
import jakarta.persistence.criteria.Join;
|
||||||
import jakarta.persistence.criteria.Root;
|
import jakarta.persistence.criteria.Root;
|
||||||
|
import jakarta.persistence.criteria.Subquery;
|
||||||
import jakarta.persistence.metamodel.EntityType;
|
import jakarta.persistence.metamodel.EntityType;
|
||||||
|
|
||||||
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
|
||||||
import org.hibernate.orm.test.jpa.metamodel.Thing;
|
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.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.hibernate.testing.TestForIssue;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -37,6 +45,8 @@ public class TreatKeywordTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
@Override
|
@Override
|
||||||
protected Class<?>[] getAnnotatedClasses() {
|
protected Class<?>[] getAnnotatedClasses() {
|
||||||
return new Class[] {
|
return new Class[] {
|
||||||
|
JoinedEntity.class, JoinedEntitySubclass.class, JoinedEntitySubSubclass.class,
|
||||||
|
JoinedEntitySubclass2.class, JoinedEntitySubSubclass2.class,
|
||||||
Animal.class, Elephant.class, Human.class, Thing.class, ThingWithQuantity.class,
|
Animal.class, Elephant.class, Human.class, Thing.class, ThingWithQuantity.class,
|
||||||
TreatAnimal.class, Dog.class, Dachshund.class, Greyhound.class
|
TreatAnimal.class, Dog.class, Dachshund.class, Greyhound.class
|
||||||
};
|
};
|
||||||
|
@ -254,6 +264,46 @@ public class TreatKeywordTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
em.close();
|
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")
|
@Entity(name = "TreatAnimal")
|
||||||
public static abstract class TreatAnimal {
|
public static abstract class TreatAnimal {
|
||||||
@Id
|
@Id
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -208,6 +209,34 @@ public class TreatKeywordTest extends BaseCoreFunctionalTestCase {
|
||||||
s.close();
|
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" )
|
@Entity( name = "JoinedEntity" )
|
||||||
@Table( name = "JoinedEntity" )
|
@Table( name = "JoinedEntity" )
|
||||||
@Inheritance( strategy = InheritanceType.JOINED )
|
@Inheritance( strategy = InheritanceType.JOINED )
|
||||||
|
|
Loading…
Reference in New Issue