Fix join predicate rendering and fix support for implicit joins in the ON clause

This commit is contained in:
Christian Beikov 2021-10-21 14:46:58 +02:00
parent 8fc0e05930
commit fa3101c29e
18 changed files with 902 additions and 958 deletions

View File

@ -42,6 +42,7 @@
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
@ -173,19 +174,38 @@ public TableGroupJoin createTableGroupJoin(
SqlAliasBaseGenerator aliasBaseGenerator, SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
final CompositeTableGroup compositeTableGroup = new CompositeTableGroup( final TableGroup tableGroup = createRootTableGroupJoin(
navigablePath, navigablePath,
this,
lhs, lhs,
fetched explicitSourceAlias,
sqlAstJoinType,
fetched,
null,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
); );
final TableGroupJoin join = new TableGroupJoin( navigablePath, SqlAstJoinType.LEFT, compositeTableGroup, null ); final TableGroupJoin join = new TableGroupJoin( navigablePath, SqlAstJoinType.LEFT, tableGroup, null );
lhs.addTableGroupJoin( join ); lhs.addTableGroupJoin( join );
return join; return join;
} }
@Override
public TableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
Consumer<Predicate> predicateConsumer,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
return new CompositeTableGroup( navigablePath, this, lhs, fetched );
}
@Override @Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) { public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
return embeddableDescriptor.findSubPart( name, treatTargetType ); return embeddableDescriptor.findSubPart( name, treatTargetType );

View File

@ -44,6 +44,7 @@
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
@ -286,21 +287,45 @@ public TableGroupJoin createTableGroupJoin(
SqlAliasBaseGenerator aliasBaseGenerator, SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
final CompositeTableGroup compositeTableGroup = new CompositeTableGroup( final TableGroup tableGroup = createRootTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
null,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
tableGroup
);
lhs.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin;
}
@Override
public TableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
Consumer<Predicate> predicateConsumer,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
return new CompositeTableGroup(
navigablePath, navigablePath,
this, this,
lhs, lhs,
fetched fetched
); );
TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
compositeTableGroup
);
lhs.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin;
} }
@Override @Override

View File

@ -40,6 +40,7 @@
import org.hibernate.sql.ast.tree.from.CompositeTableGroup; import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
@ -204,9 +205,17 @@ public TableGroupJoin createTableGroupJoin(
SqlAliasBaseGenerator aliasBaseGenerator, SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
assert lhs.getModelPart() instanceof PluralAttributeMapping; final TableGroup tableGroup = createRootTableGroupJoin(
navigablePath,
final TableGroup tableGroup = new CompositeTableGroup( navigablePath, this, lhs, fetched ); lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
null,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
final TableGroupJoin tableGroupJoin = new TableGroupJoin( final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath, navigablePath,
@ -218,6 +227,22 @@ public TableGroupJoin createTableGroupJoin(
return tableGroupJoin; return tableGroupJoin;
} }
@Override
public TableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
Consumer<Predicate> predicateConsumer,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
assert lhs.getModelPart() instanceof PluralAttributeMapping;
return new CompositeTableGroup( navigablePath, this, lhs, fetched );
}
@Override @Override
public String getSqlAliasStem() { public String getSqlAliasStem() {
return sqlAliasStem; return sqlAliasStem;

View File

@ -335,31 +335,16 @@ private <T> DomainResult<T> createDomainResult(
@Override @Override
public Predicate generateJoinPredicate( public Predicate generateJoinPredicate(
TableGroup lhs, TableGroup targetSideTableGroup,
TableGroup tableGroup, TableGroup keySideTableGroup,
SqlAstJoinType sqlAstJoinType, SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
TableReference lhsTableReference; final TableReference lhsTableReference = targetSideTableGroup.getTableReference(
TableReference rhsTableKeyReference; targetSideTableGroup.getNavigablePath(),
if ( targetTable.equals( keyTable ) ) {
lhsTableReference = getTableReferenceWhenTargetEqualsKey( lhs, tableGroup, keyTable );
rhsTableKeyReference = getTableReference(
lhs,
tableGroup,
targetTable targetTable
); );
} final TableReference rhsTableKeyReference = keySideTableGroup.getTableReference( keyTable );
else {
lhsTableReference = getTableReference( lhs, tableGroup, keyTable );
rhsTableKeyReference = getTableReference(
lhs,
tableGroup,
targetTable
);
}
return generateJoinPredicate( return generateJoinPredicate(
lhsTableReference, lhsTableReference,
@ -372,21 +357,12 @@ public Predicate generateJoinPredicate(
@Override @Override
public Predicate generateJoinPredicate( public Predicate generateJoinPredicate(
TableReference lhs, TableReference targetSideReference,
TableReference rhs, TableReference keySideReference,
SqlAstJoinType sqlAstJoinType, SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
final String rhsTableExpression = rhs.getTableExpression(); return getPredicate( targetSideReference, keySideReference, creationContext, targetSelectableMappings, keySelectableMappings );
final String lhsTableExpression = lhs.getTableExpression();
if ( lhsTableExpression.equals( keyTable ) ) {
assert rhsTableExpression.equals( targetTable );
return getPredicate( lhs, rhs, creationContext, keySelectableMappings, targetSelectableMappings );
}
else {
assert rhsTableExpression.equals( keyTable );
return getPredicate( lhs, rhs, creationContext, targetSelectableMappings, keySelectableMappings );
}
} }
private Predicate getPredicate( private Predicate getPredicate(
@ -417,23 +393,6 @@ private Predicate getPredicate(
return predicate; return predicate;
} }
protected TableReference getTableReferenceWhenTargetEqualsKey(TableGroup lhs, TableGroup tableGroup, String table) {
if ( tableGroup.getPrimaryTableReference().getTableExpression().equals( table ) ) {
return tableGroup.getPrimaryTableReference();
}
if ( lhs.getPrimaryTableReference().getTableExpression().equals( table ) ) {
return lhs.getPrimaryTableReference();
}
for ( TableReferenceJoin tableJoin : lhs.getTableReferenceJoins() ) {
if ( tableJoin.getJoinedTableReference().getTableExpression().equals( table ) ) {
return tableJoin.getJoinedTableReference();
}
}
throw new IllegalStateException( "Could not resolve binding for table `" + table + "`" );
}
protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) { protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) {
if ( lhs.getPrimaryTableReference().getTableExpression().equals( table ) ) { if ( lhs.getPrimaryTableReference().getTableExpression().equals( table ) ) {
return lhs.getPrimaryTableReference(); return lhs.getPrimaryTableReference();

View File

@ -7,6 +7,7 @@
package org.hibernate.metamodel.mapping.internal; package org.hibernate.metamodel.mapping.internal;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
@ -32,6 +33,7 @@
import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.FetchOptions; import org.hibernate.sql.results.graph.FetchOptions;
@ -286,6 +288,30 @@ public TableGroupJoin createTableGroupJoin(
); );
} }
@Override
public TableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
Consumer<Predicate> predicateConsumer,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
return collectionDescriptor.getAttributeMapping().createRootTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
predicateConsumer,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
}
@Override @Override
public String getSqlAliasStem() { public String getSqlAliasStem() {
return collectionDescriptor.getAttributeMapping().getSqlAliasStem(); return collectionDescriptor.getAttributeMapping().getSqlAliasStem();

View File

@ -627,57 +627,17 @@ public TableGroupJoin createTableGroupJoin(
SqlAliasBaseGenerator aliasBaseGenerator, SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
final CollectionPersister collectionDescriptor = getCollectionDescriptor(); final TableGroup tableGroup = createRootTableGroupJoin(
if ( collectionDescriptor.isOneToMany() ) {
return createOneToManyTableGroupJoin(
navigablePath, navigablePath,
lhs, lhs,
explicitSourceAlias, explicitSourceAlias,
sqlAstJoinType, sqlAstJoinType,
fetched, fetched,
null,
aliasBaseGenerator, aliasBaseGenerator,
sqlExpressionResolver, sqlExpressionResolver,
creationContext creationContext
); );
}
else {
return createCollectionTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
}
}
public void setForeignKeyDescriptor(ForeignKeyDescriptor fkDescriptor) {
this.fkDescriptor = fkDescriptor;
}
@SuppressWarnings("unused")
private TableGroupJoin createOneToManyTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableGroup tableGroup = createOneToManyTableGroup(
lhs.canUseInnerJoins() && sqlAstJoinType == SqlAstJoinType.INNER,
navigablePath,
fetched,
explicitSourceAlias,
aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() ),
sqlExpressionResolver,
creationContext
);
final TableGroupJoin tableGroupJoin = new TableGroupJoin( final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath, navigablePath,
sqlAstJoinType, sqlAstJoinType,
@ -696,6 +656,60 @@ private TableGroupJoin createOneToManyTableGroupJoin(
return tableGroupJoin; return tableGroupJoin;
} }
@Override
public TableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
Consumer<Predicate> predicateConsumer,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final CollectionPersister collectionDescriptor = getCollectionDescriptor();
final TableGroup tableGroup;
if ( collectionDescriptor.isOneToMany() ) {
tableGroup = createOneToManyTableGroup(
lhs.canUseInnerJoins() && sqlAstJoinType == SqlAstJoinType.INNER,
navigablePath,
fetched,
explicitSourceAlias,
aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() ),
sqlExpressionResolver,
creationContext
);
}
else {
tableGroup = createCollectionTableGroup(
lhs.canUseInnerJoins() && sqlAstJoinType == SqlAstJoinType.INNER,
navigablePath,
fetched,
explicitSourceAlias,
aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() ),
sqlExpressionResolver,
creationContext
);
}
if ( predicateConsumer != null ) {
predicateConsumer.accept(
getKeyDescriptor().generateJoinPredicate(
lhs,
tableGroup,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
);
}
return tableGroup;
}
public void setForeignKeyDescriptor(ForeignKeyDescriptor fkDescriptor) {
this.fkDescriptor = fkDescriptor;
}
private TableGroup createOneToManyTableGroup( private TableGroup createOneToManyTableGroup(
boolean canUseInnerJoins, boolean canUseInnerJoins,
NavigablePath navigablePath, NavigablePath navigablePath,
@ -825,44 +839,6 @@ else if ( indexDescriptorEntityMappingType.containsTableReference( tableExpressi
); );
} }
@SuppressWarnings("unused")
private TableGroupJoin createCollectionTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final TableGroup tableGroup = createCollectionTableGroup(
lhs.canUseInnerJoins() && sqlAstJoinType == SqlAstJoinType.INNER,
navigablePath,
fetched,
explicitSourceAlias,
aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() ),
sqlExpressionResolver,
creationContext
);
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
tableGroup,
getKeyDescriptor().generateJoinPredicate(
lhs,
tableGroup,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
);
lhs.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin;
}
private TableGroup createCollectionTableGroup( private TableGroup createCollectionTableGroup(
boolean canUseInnerJoins, boolean canUseInnerJoins,
NavigablePath navigablePath, NavigablePath navigablePath,
@ -1054,8 +1030,8 @@ private Function<TableGroup, TableReferenceJoin> createTableGroupFinalizer(
joinType, joinType,
elementAssociatedPrimaryTable, elementAssociatedPrimaryTable,
elementFkDescriptor.generateJoinPredicate( elementFkDescriptor.generateJoinPredicate(
collectionTableReference,
elementAssociatedPrimaryTable, elementAssociatedPrimaryTable,
collectionTableReference,
joinType, joinType,
sqlExpressionResolver, sqlExpressionResolver,
creationContext creationContext

View File

@ -242,70 +242,40 @@ private <T> DomainResult<T> createDomainResult(
@Override @Override
public Predicate generateJoinPredicate( public Predicate generateJoinPredicate(
TableReference lhs, TableReference targetSideReference,
TableReference rhs, TableReference keySideReference,
SqlAstJoinType sqlAstJoinType, SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
if ( lhs.getTableReference( keySide.getModelPart().getContainingTableExpression() ) != null ) {
return new ComparisonPredicate( return new ComparisonPredicate(
new ColumnReference( new ColumnReference(
lhs, targetSideReference,
keySide.getModelPart(),
creationContext.getSessionFactory()
),
ComparisonOperator.EQUAL,
new ColumnReference(
rhs,
targetSide.getModelPart(),
creationContext.getSessionFactory()
)
);
}
else {
return new ComparisonPredicate(
new ColumnReference(
lhs,
targetSide.getModelPart(), targetSide.getModelPart(),
creationContext.getSessionFactory() creationContext.getSessionFactory()
), ),
ComparisonOperator.EQUAL, ComparisonOperator.EQUAL,
new ColumnReference( new ColumnReference(
rhs, keySideReference,
keySide.getModelPart(), keySide.getModelPart(),
creationContext.getSessionFactory() creationContext.getSessionFactory()
) )
); );
} }
}
@Override @Override
public Predicate generateJoinPredicate( public Predicate generateJoinPredicate(
TableGroup lhs, TableGroup targetSideTableGroup,
TableGroup tableGroup, TableGroup keySideTableGroup,
SqlAstJoinType sqlAstJoinType, SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
TableReference lhsTableReference; final TableReference lhsTableReference = targetSideTableGroup.getTableReference(
TableReference rhsTableKeyReference; targetSideTableGroup.getNavigablePath(),
if ( targetSide.getModelPart().getContainingTableExpression().equals( keySide.getModelPart().getContainingTableExpression() ) ) {
lhsTableReference = getTableReferenceWhenTargetEqualsKey( lhs, tableGroup, keySide.getModelPart().getContainingTableExpression() );
rhsTableKeyReference = getTableReference(
lhs,
tableGroup,
targetSide.getModelPart().getContainingTableExpression() targetSide.getModelPart().getContainingTableExpression()
); );
} final TableReference rhsTableKeyReference = keySideTableGroup.getTableReference(
else { keySide.getModelPart().getContainingTableExpression()
lhsTableReference = getTableReference( lhs, tableGroup, keySide.getModelPart().getContainingTableExpression() );
rhsTableKeyReference = getTableReference(
lhs,
tableGroup,
targetSide.getModelPart().getContainingTableExpression()
); );
}
return generateJoinPredicate( return generateJoinPredicate(
lhsTableReference, lhsTableReference,
@ -316,23 +286,6 @@ public Predicate generateJoinPredicate(
); );
} }
protected TableReference getTableReferenceWhenTargetEqualsKey(TableGroup lhs, TableGroup tableGroup, String table) {
if ( tableGroup.getPrimaryTableReference().getTableExpression().equals( table ) ) {
return tableGroup.getPrimaryTableReference();
}
if ( lhs.getPrimaryTableReference().getTableExpression().equals( table ) ) {
return lhs.getPrimaryTableReference();
}
for ( TableReferenceJoin tableJoin : lhs.getTableReferenceJoins() ) {
if ( tableJoin.getJoinedTableReference().getTableExpression().equals( table ) ) {
return tableJoin.getJoinedTableReference();
}
}
throw new IllegalStateException( "Could not resolve binding for table `" + table + "`" );
}
protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) { protected TableReference getTableReference(TableGroup lhs, TableGroup tableGroup, String table) {
final NavigablePath navigablePath = lhs.getNavigablePath().append( getNavigableRole().getNavigableName() ); final NavigablePath navigablePath = lhs.getNavigablePath().append( getNavigableRole().getNavigableName() );
if ( lhs.getPrimaryTableReference().getTableReference( navigablePath, table ) != null ) { if ( lhs.getPrimaryTableReference().getTableReference( navigablePath, table ) != null ) {

View File

@ -10,6 +10,7 @@
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchStyle;
@ -56,6 +57,7 @@
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer; import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.from.TableGroupProducer; import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetch;
@ -421,6 +423,10 @@ public String getTargetKeyPropertyName() {
return targetKeyPropertyName; return targetKeyPropertyName;
} }
public boolean isTargetKeyPropertyPath(String path) {
return targetKeyPropertyNames.contains( path );
}
public Cardinality getCardinality() { public Cardinality getCardinality() {
return cardinality; return cardinality;
} }
@ -924,6 +930,59 @@ public TableGroupJoin createTableGroupJoin(
SqlAliasBaseGenerator aliasBaseGenerator, SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) { SqlAstCreationContext creationContext) {
final LazyTableGroup lazyTableGroup = createRootTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
null,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
lazyTableGroup,
null
);
final TableReference lhsTableReference = lhs.resolveTableReference( navigablePath, identifyingColumnsTableExpression );
lazyTableGroup.setTableGroupInitializerCallback(
tableGroup -> tableGroupJoin.applyPredicate(
foreignKeyDescriptor.generateJoinPredicate(
sideNature == ForeignKeyDescriptor.Nature.TARGET ? lhsTableReference : tableGroup.getPrimaryTableReference(),
sideNature == ForeignKeyDescriptor.Nature.TARGET ? tableGroup.getPrimaryTableReference() : lhsTableReference,
sqlAstJoinType,
sqlExpressionResolver,
creationContext
)
)
);
lhs.addTableGroupJoin( tableGroupJoin );
if ( sqlAstJoinType == SqlAstJoinType.INNER && isNullable ) {
// Force initialization of the underlying table group join to retain cardinality
lazyTableGroup.getPrimaryTableReference();
}
return tableGroupJoin;
}
@Override
public LazyTableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
Consumer<Predicate> predicateConsumer,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( sqlAliasStem ); final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( sqlAliasStem );
final boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins() && !isNullable; final boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins() && !isNullable;
final LazyTableGroup lazyTableGroup = new LazyTableGroup( final LazyTableGroup lazyTableGroup = new LazyTableGroup(
@ -967,34 +1026,31 @@ public TableGroupJoin createTableGroupJoin(
lhs lhs
); );
final TableGroupJoin tableGroupJoin = new TableGroupJoin( if ( predicateConsumer != null ) {
final TableReference lhsTableReference = lhs.resolveTableReference(
navigablePath, navigablePath,
sqlAstJoinType, identifyingColumnsTableExpression
lazyTableGroup,
null
); );
final TableReference lhsTableReference = lhs.resolveTableReference( navigablePath, identifyingColumnsTableExpression );
lazyTableGroup.setTableGroupInitializerCallback( lazyTableGroup.setTableGroupInitializerCallback(
tableGroup -> tableGroupJoin.applyPredicate( tableGroup -> predicateConsumer.accept(
foreignKeyDescriptor.generateJoinPredicate( foreignKeyDescriptor.generateJoinPredicate(
lhsTableReference, sideNature == ForeignKeyDescriptor.Nature.TARGET ? lhsTableReference : tableGroup.getPrimaryTableReference(),
tableGroup.getPrimaryTableReference(), sideNature == ForeignKeyDescriptor.Nature.TARGET ? tableGroup.getPrimaryTableReference() : lhsTableReference,
sqlAstJoinType, sqlAstJoinType,
sqlExpressionResolver, sqlExpressionResolver,
creationContext creationContext
) )
) )
); );
lhs.addTableGroupJoin( tableGroupJoin );
if ( sqlAstJoinType == SqlAstJoinType.INNER && isNullable ) { if ( sqlAstJoinType == SqlAstJoinType.INNER && isNullable ) {
// Force initialization of the underlying table group join to retain cardinality // Force initialization of the underlying table group join to retain cardinality
lazyTableGroup.getPrimaryTableReference(); lazyTableGroup.getPrimaryTableReference();
} }
}
return tableGroupJoin; return lazyTableGroup;
} }
private SqlAstJoinType getJoinType(NavigablePath navigablePath, TableGroup tableGroup) { private SqlAstJoinType getJoinType(NavigablePath navigablePath, TableGroup tableGroup) {

View File

@ -21,10 +21,10 @@
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class QualifiedJoinPredicatePathConsumer extends BasicDotIdentifierConsumer { public class QualifiedJoinPredicatePathConsumer extends BasicDotIdentifierConsumer {
private final SqmQualifiedJoin sqmJoin; private final SqmQualifiedJoin<?, ?> sqmJoin;
public QualifiedJoinPredicatePathConsumer( public QualifiedJoinPredicatePathConsumer(
SqmQualifiedJoin sqmJoin, SqmQualifiedJoin<?, ?> sqmJoin,
SqmCreationState creationState) { SqmCreationState creationState) {
super( creationState ); super( creationState );
this.sqmJoin = sqmJoin; this.sqmJoin = sqmJoin;

View File

@ -1683,6 +1683,7 @@ protected void consumeQualifiedJoin(HqlParser.QualifiedJoinContext parserJoin, S
// not consumed by the identifierConsumer // not consumed by the identifierConsumer
join.setExplicitAlias( alias ); join.setExplicitAlias( alias );
final HqlParser.QualifiedJoinPredicateContext qualifiedJoinPredicateContext = parserJoin.qualifiedJoinPredicate();
if ( join instanceof SqmEntityJoin ) { if ( join instanceof SqmEntityJoin ) {
//noinspection unchecked //noinspection unchecked
sqmRoot.addSqmJoin( join ); sqmRoot.addSqmJoin( join );
@ -1690,8 +1691,7 @@ protected void consumeQualifiedJoin(HqlParser.QualifiedJoinContext parserJoin, S
else { else {
if ( getCreationOptions().useStrictJpaCompliance() ) { if ( getCreationOptions().useStrictJpaCompliance() ) {
if ( join.getExplicitAlias() != null ) { if ( join.getExplicitAlias() != null ) {
//noinspection rawtypes if ( ( (SqmAttributeJoin<?, ?>) join ).isFetched() ) {
if ( ( (SqmAttributeJoin) join ).isFetched() ) {
throw new StrictJpaComplianceViolation( throw new StrictJpaComplianceViolation(
"Encountered aliased fetch join, but strict JPQL compliance was requested", "Encountered aliased fetch join, but strict JPQL compliance was requested",
StrictJpaComplianceViolation.Type.ALIASED_FETCH_JOIN StrictJpaComplianceViolation.Type.ALIASED_FETCH_JOIN
@ -1699,9 +1699,11 @@ protected void consumeQualifiedJoin(HqlParser.QualifiedJoinContext parserJoin, S
} }
} }
} }
if ( qualifiedJoinPredicateContext != null && ( (SqmAttributeJoin<?, ?>) join ).isFetched() ) {
throw new SemanticException( "with-clause not allowed on fetched associations; use filters" );
}
} }
final HqlParser.QualifiedJoinPredicateContext qualifiedJoinPredicateContext = parserJoin.qualifiedJoinPredicate();
if ( qualifiedJoinPredicateContext != null ) { if ( qualifiedJoinPredicateContext != null ) {
dotIdentifierConsumerStack.push( new QualifiedJoinPredicatePathConsumer( join, this ) ); dotIdentifierConsumerStack.push( new QualifiedJoinPredicatePathConsumer( join, this ) );
try { try {

View File

@ -43,6 +43,11 @@ public TableGroup findByAlias(String alias) {
return null; return null;
} }
@Override
public TableGroup findTableGroupOnLeaf(NavigablePath navigablePath) {
return findTableGroup( navigablePath );
}
@Override @Override
public TableGroup findTableGroup(NavigablePath navigablePath) { public TableGroup findTableGroup(NavigablePath navigablePath) {
if ( tableGroupByPath != null ) { if ( tableGroupByPath != null ) {

View File

@ -19,6 +19,9 @@
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface FromClauseAccess { public interface FromClauseAccess {
TableGroup findTableGroupOnLeaf(NavigablePath navigablePath);
/** /**
* Find a TableGroup by the NavigablePath it is registered under. Returns * Find a TableGroup by the NavigablePath it is registered under. Returns
* {@code null} if no TableGroup is registered under that NavigablePath * {@code null} if no TableGroup is registered under that NavigablePath

View File

@ -31,6 +31,11 @@ public SimpleFromClauseAccessImpl(FromClauseAccess parent) {
this.parent = parent; this.parent = parent;
} }
@Override
public TableGroup findTableGroupOnLeaf(NavigablePath navigablePath) {
return tableGroupMap.get( navigablePath );
}
@Override @Override
public TableGroup findTableGroup(NavigablePath navigablePath) { public TableGroup findTableGroup(NavigablePath navigablePath) {
final TableGroup tableGroup = tableGroupMap.get( navigablePath ); final TableGroup tableGroup = tableGroupMap.get( navigablePath );

View File

@ -59,6 +59,10 @@ public LazyTableGroup(
} }
public boolean isInitialized() {
return tableGroup != null;
}
public TableGroup getUnderlyingTableGroup() { public TableGroup getUnderlyingTableGroup() {
return tableGroup; return tableGroup;
} }

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.sql.ast.tree.from; package org.hibernate.sql.ast.tree.from;
import java.util.function.Consumer;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlAstJoinType; import org.hibernate.sql.ast.SqlAstJoinType;
@ -13,6 +15,7 @@
import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.predicate.Predicate;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -55,4 +58,42 @@ TableGroupJoin createTableGroupJoin(
SqlAliasBaseGenerator aliasBaseGenerator, SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver, SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext); SqlAstCreationContext creationContext);
/**
* Create a TableGroup as defined for this producer
*/
default TableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
Consumer<Predicate> predicateConsumer,
SqlAstCreationState creationState) {
return createRootTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
predicateConsumer,
creationState.getSqlAliasBaseGenerator(),
creationState.getSqlExpressionResolver(),
creationState.getCreationContext()
);
}
/**
* Create a TableGroupJoin as defined for this producer
*/
TableGroup createRootTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
boolean fetched,
Consumer<Predicate> predicateConsumer,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext);
} }

View File

@ -10,7 +10,10 @@
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.QueryException;
import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.TiDBDialect;
import org.hibernate.query.Query; import org.hibernate.query.Query;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
@ -25,9 +28,11 @@
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
/** /**
* Implementation of WithClauseTest. * Implementation of WithClauseTest.
@ -54,6 +59,26 @@ public void dropTestData(SessionFactoryScope scope) {
data.cleanup( scope ); data.cleanup( scope );
} }
@Test
public void testWithClauseFailsWithFetch(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> {
try {
session.createQuery( "from Animal a inner join fetch a.offspring as o with o.bodyWeight = :someLimit" )
.setParameter( "someLimit", 1 )
.list();
fail( "ad-hoc on clause allowed with fetched association" );
}
catch (IllegalArgumentException e) {
assertTyping( QueryException.class, e.getCause() );
}
catch ( HibernateException e ) {
// the expected response...
}
}
);
}
@Test @Test
public void testWithClause(SessionFactoryScope scope) { public void testWithClause(SessionFactoryScope scope) {
scope.inTransaction( scope.inTransaction(
@ -85,7 +110,16 @@ public void testWithClause(SessionFactoryScope scope) {
.list(); .list();
assertTrue( list.isEmpty(), "ad-hoc on did not take effect" ); assertTrue( list.isEmpty(), "ad-hoc on did not take effect" );
list = session.createQuery( "from Human h inner join h.offspring o with o.mother.father = :cousin" ) }
);
}
@Test
@SkipForDialect(dialectClass = TiDBDialect.class, reason = "TiDB db does not support subqueries for ON condition")
public void testWithClauseWithImplicitJoin(SessionFactoryScope scope) {
scope.inTransaction(
(session) -> {
List list = session.createQuery( "from Human h inner join h.offspring o with o.mother.father = :cousin" )
.setParameter( "cousin", session.load( Human.class, Long.valueOf( "123" ) ) ) .setParameter( "cousin", session.load( Human.class, Long.valueOf( "123" ) ) )
.list(); .list();
assertTrue( list.isEmpty(), "ad-hoc did take effect" ); assertTrue( list.isEmpty(), "ad-hoc did take effect" );

View File

@ -187,7 +187,7 @@ public void testCriteriaParameters() throws Exception {
1, 1,
sqlStatementInterceptor.getSqlQueries().size() sqlStatementInterceptor.getSqlQueries().size()
); );
sqlStatementInterceptor.assertExecuted( "select a1_0.name from Book b1_0 join Author a1_0 on a1_0.book_id=b1_0.id where b1_0.name=? and a1_0.index_id=?" ); sqlStatementInterceptor.assertExecuted( "select a1_0.name from Book b1_0 join Author a1_0 on b1_0.id=a1_0.book_id where b1_0.name=? and a1_0.index_id=?" );
} ); } );
} }