Skip to content

Commit

Permalink
HHH-16382 Make sure joins are adapted to inner if non-FK parts of a p…
Browse files Browse the repository at this point in the history
…ath are de-referenced
  • Loading branch information
beikov committed Apr 25, 2023
1 parent 991ea65 commit eb82b2f
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 10 deletions.
Expand Up @@ -3406,23 +3406,30 @@ else if ( parentPath instanceof SqmFrom<?, ?> ) {
registerTreatUsage( (SqmFrom<?, ?>) parentPath, tableGroup );
}

if ( getCurrentClauseStack().getCurrent() != Clause.SELECT
if ( parentPath instanceof SqmSimplePath<?>
&& CollectionPart.Nature.fromName( parentPath.getNavigablePath().getLocalName() ) == null
&& getCurrentClauseStack().getCurrent() != Clause.SELECT
&& parentPath.getParentPath() != null
&& tableGroup.getModelPart() instanceof ToOneAttributeMapping ) {
// we need to handle the case of an implicit path involving a to-one
// association with not-found mapping where that path has been previously
// joined using left. typically, this indicates that the to-one is being
// association that path has been previously joined using left.
// typically, this indicates that the to-one is being
// fetched - the fetch would use a left-join. however, since the path is
// used outside the select-clause also, we need to force the join to be inner
final ToOneAttributeMapping toOneMapping = (ToOneAttributeMapping) tableGroup.getModelPart();
if ( toOneMapping.hasNotFoundAction() ) {
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) tableGroup.getModelPart();
final String partName = sqmPath.getResolvedModel().getPathName();
final ModelPart pathPart;
if ( !toOneAttributeMapping.isFkOptimizationAllowed()
|| !( ( pathPart = toOneAttributeMapping.findSubPart( partName ) ) instanceof ValuedModelPart )
|| !toOneAttributeMapping.getForeignKeyDescriptor().isKeyPart( (ValuedModelPart) pathPart ) ) {
final NavigablePath parentParentPath = parentPath.getParentPath().getNavigablePath();
final TableGroup parentParentTableGroup = fromClauseIndex.findTableGroup( parentParentPath );
parentParentTableGroup.visitTableGroupJoins( (join) -> {
if ( join.getNavigablePath().equals( parentPath.getNavigablePath() ) && join.isImplicit() ) {
join.setJoinType( SqlAstJoinType.INNER );
}
} );
final TableGroupJoin tableGroupJoin = parentParentTableGroup.findTableGroupJoin( tableGroup );
// We might get null here if the parentParentTableGroup is correlated and tableGroup is from the outer query
// In this case, we don't want to override the join type, though it is debatable if it's ok to reuse a join in this case
if ( tableGroupJoin != null ) {
tableGroupJoin.setJoinType( SqlAstJoinType.INNER );
}
}
}

Expand Down
Expand Up @@ -7,6 +7,7 @@
package org.hibernate.orm.test.annotations.onetoone;

import java.util.Iterator;
import java.util.List;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
Expand All @@ -27,6 +28,10 @@
import org.hibernate.orm.test.annotations.Discount;
import org.hibernate.orm.test.annotations.Passport;
import org.hibernate.orm.test.annotations.Ticket;
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
import org.hibernate.query.criteria.JpaCriteriaQuery;
import org.hibernate.query.criteria.JpaRoot;

import org.junit.Test;

import static org.hamcrest.CoreMatchers.is;
Expand Down Expand Up @@ -416,6 +421,36 @@ public void testHqlQuery() {
assertThat( p, is( notNullValue() ) );
} );
}

@Test
public void testDereferenceOneToOne() {
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
Client c1 = new Client();
c1.setName( "C1" );
Client c2 = new Client();
c2.setName( "C2" );
Client c3 = new Client();
c3.setName( "C3" );
Address a = new Address();
a.setCity( "Vienna" );
c1.setAddress( a );
c3.setAddress( new Address() );
session.persist( c1 );
session.persist( c2 );
session.persist( c3 );
} );

TransactionUtil.doInHibernate( this::sessionFactory, session -> {
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
JpaCriteriaQuery<Client> query = cb.createQuery( Client.class );
JpaRoot<Client> root = query.from( Client.class );
query.where( root.get( "address" ).get( "city" ).isNull() );
List<Client> resultList = session.createQuery( query ).getResultList();

assertEquals( 1, resultList.size() );
assertEquals( "C3", resultList.get( 0 ).getName() );
} );
}

@Override
protected Class[] getAnnotatedClasses() {
Expand Down

0 comments on commit eb82b2f

Please sign in to comment.