Fix wrong creation of inner join

This commit is contained in:
Andrea Boriero 2021-07-07 14:39:48 +02:00
parent bf22f098d1
commit 94a258c8d7
21 changed files with 73 additions and 28 deletions

View File

@ -50,7 +50,7 @@ public class InformixSqmToSqlAstConverter<T extends Statement> extends BaseSqmTo
if ( this.needsDummyTableGroup ) {
querySpec.getFromClause().addRoot(
new StandardTableGroup(
false,
true,
null,
null,
null,

View File

@ -50,7 +50,7 @@ public class IngresSqmToSqlAstConverter<T extends Statement> extends BaseSqmToSq
if ( this.needsDummyTableGroup ) {
querySpec.getFromClause().addRoot(
new StandardTableGroup(
false,
true,
null,
null,
null,

View File

@ -147,7 +147,6 @@ class DatabaseSnapshotExecutor {
if ( contributorMapping instanceof EntityAssociationMapping ) {
domainResults.add(
( (EntityAssociationMapping) contributorMapping ).createDelayedDomainResult(
true,
navigablePath,
rootTableGroup,
null,

View File

@ -41,7 +41,6 @@ public interface EntityAssociationMapping extends ModelPart, Association, TableG
* Create a delayed DomainResult for a specific reference to this ModelPart.
*/
default <T> DomainResult<T> createDelayedDomainResult(
boolean canUseInnerJoins,
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,

View File

@ -84,6 +84,11 @@ public class EntityCollectionPart
}
@Override
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
return SqlAstJoinType.INNER;
}
@Override
public Nature getNature() {
return nature;

View File

@ -556,6 +556,11 @@ public class PluralAttributeMappingImpl
return sqlAliasStem;
}
@Override
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
return SqlAstJoinType.LEFT;
}
@Override
public TableGroupJoin createTableGroupJoin(
NavigablePath navigablePath,
@ -608,7 +613,7 @@ public class PluralAttributeMappingImpl
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableGroup tableGroup = createOneToManyTableGroup(
lhs.canUseInnerJoins(),
lhs.canUseInnerJoins() && sqlAstJoinType == SqlAstJoinType.INNER,
navigablePath,
fetched,
explicitSourceAlias,
@ -777,7 +782,7 @@ public class PluralAttributeMappingImpl
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableGroup tableGroup = createCollectionTableGroup(
lhs.canUseInnerJoins(),
lhs.canUseInnerJoins() && sqlAstJoinType == SqlAstJoinType.INNER,
navigablePath,
fetched,
explicitSourceAlias,

View File

@ -750,7 +750,6 @@ public class ToOneAttributeMapping
@Override
public <T> DomainResult<T> createDelayedDomainResult(
boolean canUseInnerJoins,
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
@ -762,7 +761,7 @@ public class ToOneAttributeMapping
navigablePath,
tableGroup,
null,
SqlAstJoinType.LEFT,
getDefaultSqlAstJoinType( tableGroup ),
true,
creationState.getSqlAstCreationState()
);
@ -807,7 +806,7 @@ public class ToOneAttributeMapping
);
}
private SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
if ( isNullable ) {
return SqlAstJoinType.LEFT;
}
@ -857,7 +856,7 @@ public class ToOneAttributeMapping
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( sqlAliasStem );
boolean canUseInnerJoin = lhs.canUseInnerJoins() && sqlAstJoinType == SqlAstJoinType.INNER;
boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins() && !isNullable;
final LazyTableGroup lazyTableGroup = new LazyTableGroup(
canUseInnerJoin,
navigablePath,

View File

@ -414,8 +414,8 @@ public class DomainResultCreationStateImpl
}
}
fetchableContainer.visitKeyFetchables( fetchableConsumer, null );
fetchableContainer.visitFetchables( fetchableConsumer, null );
return fetches;
}

View File

@ -79,6 +79,7 @@ public class CompleteResultBuilderEntityJpa implements CompleteResultBuilderEnti
impl.getFromClauseAccess().resolveTableGroup(
navigablePath,
np -> entityDescriptor.createRootTableGroup(
// since this is only used for result set mappings, the canUseInnerJoins value is irrelevant.
true,
navigablePath,
null,

View File

@ -71,6 +71,7 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
impl.getFromClauseAccess().resolveTableGroup(
navigablePath,
np -> entityDescriptor.createRootTableGroup(
// since this is only used for result set mappings, the canUseInnerJoins value is irrelevant.
true,
navigablePath,
null,

View File

@ -57,6 +57,7 @@ public class ImplicitModelPartResultBuilderEntity
}
return modelPart.getEntityMappingType().createRootTableGroup(
// since this is only used for result set mappings, the canUseInnerJoins value is irrelevant.
true,
navigablePath,
null,

View File

@ -11,7 +11,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

View File

@ -1835,7 +1835,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
// If we have just inner joins against a correlated root, we can render the joins as references
final SqlAliasBase sqlAliasBase = sqlAliasBaseManager.createSqlAliasBase( parentTableGroup.getGroupAlias() );
tableGroup = new CorrelatedTableGroup(
parentTableGroup.canUseInnerJoins(),
parentTableGroup,
sqlAliasBase,
currentQuerySpec(),
@ -2101,8 +2100,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private void consumeEntityJoin(SqmEntityJoin sqmJoin, TableGroup lhsTableGroup) {
final EntityPersister entityDescriptor = resolveEntityPersister( sqmJoin.getReferencedPathSource() );
final SqlAstJoinType correspondingSqlJoinType = sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType();
final TableGroup tableGroup = entityDescriptor.createRootTableGroup(
true,
correspondingSqlJoinType == SqlAstJoinType.INNER || correspondingSqlJoinType == SqlAstJoinType.CROSS ,
sqmJoin.getNavigablePath(),
sqmJoin.getExplicitAlias(),
() -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(
@ -2116,7 +2116,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
sqmJoin.getNavigablePath(),
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
correspondingSqlJoinType,
tableGroup,
null
);
@ -2125,7 +2125,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
consumeReusablePaths( sqmJoin, tableGroupJoin.getJoinedGroup() );
// add any additional join restrictions
// add any additional join restrictionsHbmResultSetMappingDescriptor.java
if ( sqmJoin.getJoinPredicate() != null ) {
tableGroupJoin.applyPredicate(
(Predicate) sqmJoin.getJoinPredicate().accept( this )
@ -2169,11 +2169,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( subPart instanceof TableGroupJoinProducer ) {
implicitJoinChecker.accept( joinedPath );
final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart;
final SqlAstJoinType defaultSqlAstJoinType = joinProducer.getDefaultSqlAstJoinType(
parentTableGroup );
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
joinedPath.getNavigablePath(),
parentTableGroup,
null,
SqlAstJoinType.LEFT,
defaultSqlAstJoinType,
false,
this
);
@ -4281,7 +4283,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final TableGroup parentTableGroup = parentFromClauseAccess.getTableGroup( parentNavPath );
final SqlAliasBase sqlAliasBase = sqlAliasBaseManager.createSqlAliasBase( parentTableGroup.getGroupAlias() );
final TableGroup tableGroup = new CorrelatedTableGroup(
parentTableGroup.canUseInnerJoins(),
parentTableGroup,
sqlAliasBase,
subQuerySpec,
@ -4676,6 +4677,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
if ( joined && fetchable instanceof TableGroupJoinProducer ) {
TableGroupJoinProducer tableGroupJoinProducer = (TableGroupJoinProducer) fetchable;
fromClauseIndex.resolveTableGroup(
fetchablePath,
np -> {
@ -4685,7 +4687,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
fetchablePath,
lhs,
alias,
SqlAstJoinType.LEFT,
tableGroupJoinProducer.getDefaultSqlAstJoinType( lhs ),
true,
this
);

View File

@ -20,13 +20,13 @@ import org.hibernate.sql.ast.spi.SqlAliasBase;
* @author Steve Ebersole
*/
public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifier implements TableGroup {
private final boolean canUseInnerJoins;
private final NavigablePath navigablePath;
private final TableGroupProducer producer;
private final String sourceAlias;
private final SqlAliasBase sqlAliasBase;
private List<TableGroupJoin> tableGroupJoins;
private boolean canUseInnerJoins;
private final SessionFactoryImplementor sessionFactory;

View File

@ -13,7 +13,6 @@ import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlAstJoinType;
/**
* @author Steve Ebersole
@ -25,13 +24,11 @@ public class CompositeTableGroup implements VirtualTableGroup {
private final TableGroup underlyingTableGroup;
private List<TableGroupJoin> tableGroupJoins;
private final boolean canUseInnerJoins;
public CompositeTableGroup(
NavigablePath navigablePath,
EmbeddableValuedModelPart compositionMapping,
TableGroup underlyingTableGroup) {
this.canUseInnerJoins = underlyingTableGroup.canUseInnerJoins();
this.navigablePath = navigablePath;
this.compositionMapping = compositionMapping;
this.underlyingTableGroup = underlyingTableGroup;
@ -70,7 +67,7 @@ public class CompositeTableGroup implements VirtualTableGroup {
@Override
public boolean canUseInnerJoins() {
return canUseInnerJoins;
return underlyingTableGroup.canUseInnerJoins();
}
@Override

View File

@ -29,14 +29,13 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
private final Consumer<Predicate> joinPredicateConsumer;
public CorrelatedTableGroup(
boolean canUseInnerJoins,
TableGroup correlatedTableGroup,
SqlAliasBase sqlAliasBase,
QuerySpec querySpec,
Consumer<Predicate> joinPredicateConsumer,
SessionFactoryImplementor sessionFactory) {
super(
canUseInnerJoins,
true,
correlatedTableGroup.getNavigablePath(),
(TableGroupProducer) correlatedTableGroup.getExpressionType(),
null,

View File

@ -22,7 +22,7 @@ import org.hibernate.sql.ast.spi.SqlAliasBase;
*/
public class LazyTableGroup extends AbstractColumnReferenceQualifier implements TableGroup {
private boolean canUseInnerJoins;
private final boolean canUseInnerJoins;
private final NavigablePath navigablePath;
private final TableGroupProducer producer;
private final String sourceAlias;

View File

@ -18,6 +18,9 @@ import org.hibernate.sql.ast.spi.SqlExpressionResolver;
* @author Steve Ebersole
*/
public interface TableGroupJoinProducer extends TableGroupProducer {
SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup);
/**
* Create a TableGroupJoin as defined for this producer
*/

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.sql.results.graph.embeddable;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
@ -13,4 +15,8 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
* @author Steve Ebersole
*/
public interface EmbeddableValuedFetchable extends EmbeddableValuedModelPart, Fetchable {
@Override
default SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
return SqlAstJoinType.LEFT;
}
}

View File

@ -18,12 +18,14 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.hibernate.Hibernate;
import org.hibernate.query.NativeQuery;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* @author Max Rydahl Andersen
@ -126,6 +128,7 @@ public class WhereTest extends BaseCoreFunctionalTestCase {
File parent = (File) query.list().get( 0 );
// @Where should not be applied
assertTrue( Hibernate.isInitialized( parent.getChildren() ) );
assertEquals( 2, parent.getChildren().size() );
}
);

View File

@ -18,6 +18,7 @@ import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@ -245,7 +246,32 @@ public class ExtraLazyTest {
session.clear();
List results = session.getNamedQuery( "userSessionData" ).setParameter( "uname", "%in" ).list();
assertThat( results.size(), is( 2 ) );
gavin = (User) ( (Object[]) results.get( 0 ) )[0];
gavin = (User) results.get( 0 ) ;
assertThat( gavin.getName(), is( "gavin" ) );
Assert.assertTrue( Hibernate.isInitialized( gavin.getSession()) );
assertThat( gavin.getSession().size(), is( 2 ) );
session.createQuery( "delete SessionAttribute" ).executeUpdate();
session.createQuery( "delete User" ).executeUpdate();
}
);
}
@Test
@RequiresDialectFeature(feature = DialectFeatureChecks.DoubleQuoteQuoting.class)
public void testSQLQuery2(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
User gavin = new User( "gavin", "secret" );
User turin = new User( "turin", "tiger" );
gavin.getSession().put( "foo", new SessionAttribute( "foo", "foo bar baz" ) );
gavin.getSession().put( "bar", new SessionAttribute( "bar", "foo bar baz 2" ) );
session.persist( gavin );
session.persist( turin );
session.flush();
session.clear();
List results = session.getNamedQuery( "userData" ).setParameter( "uname", "%in" ).list();
assertThat( results.size(), is( 2 ) );
gavin = (User) results.get( 0 );
assertThat( gavin.getName(), is( "gavin" ) );
assertThat( gavin.getSession().size(), is( 2 ) );
session.createQuery( "delete SessionAttribute" ).executeUpdate();