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.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
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.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -173,19 +174,38 @@ public abstract class AbstractCompositeIdentifierMapping
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final CompositeTableGroup compositeTableGroup = new CompositeTableGroup(
final TableGroup tableGroup = createRootTableGroupJoin(
navigablePath,
this,
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 );
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
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
return embeddableDescriptor.findSubPart( name, treatTargetType );

View File

@ -44,6 +44,7 @@ import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
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.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -286,21 +287,45 @@ public class EmbeddedAttributeMapping
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
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,
this,
lhs,
fetched
);
TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
sqlAstJoinType,
compositeTableGroup
);
lhs.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin;
}
@Override

View File

@ -40,6 +40,7 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
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.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -204,9 +205,17 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
assert lhs.getModelPart() instanceof PluralAttributeMapping;
final TableGroup tableGroup = new CompositeTableGroup( navigablePath, this, lhs, fetched );
final TableGroup tableGroup = createRootTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
null,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
navigablePath,
@ -218,6 +227,22 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
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
public String getSqlAliasStem() {
return sqlAliasStem;

View File

@ -335,31 +335,16 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
@Override
public Predicate generateJoinPredicate(
TableGroup lhs,
TableGroup tableGroup,
TableGroup targetSideTableGroup,
TableGroup keySideTableGroup,
SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
TableReference lhsTableReference;
TableReference rhsTableKeyReference;
if ( targetTable.equals( keyTable ) ) {
lhsTableReference = getTableReferenceWhenTargetEqualsKey( lhs, tableGroup, keyTable );
rhsTableKeyReference = getTableReference(
lhs,
tableGroup,
final TableReference lhsTableReference = targetSideTableGroup.getTableReference(
targetSideTableGroup.getNavigablePath(),
targetTable
);
}
else {
lhsTableReference = getTableReference( lhs, tableGroup, keyTable );
rhsTableKeyReference = getTableReference(
lhs,
tableGroup,
targetTable
);
}
final TableReference rhsTableKeyReference = keySideTableGroup.getTableReference( keyTable );
return generateJoinPredicate(
lhsTableReference,
@ -372,21 +357,12 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
@Override
public Predicate generateJoinPredicate(
TableReference lhs,
TableReference rhs,
TableReference targetSideReference,
TableReference keySideReference,
SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final String rhsTableExpression = rhs.getTableExpression();
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 );
}
return getPredicate( targetSideReference, keySideReference, creationContext, targetSelectableMappings, keySelectableMappings );
}
private Predicate getPredicate(
@ -417,23 +393,6 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
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) {
if ( lhs.getPrimaryTableReference().getTableExpression().equals( table ) ) {
return lhs.getPrimaryTableReference();

View File

@ -7,6 +7,7 @@
package org.hibernate.metamodel.mapping.internal;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
@ -32,6 +33,7 @@ import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
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.DomainResultCreationState;
import org.hibernate.sql.results.graph.FetchOptions;
@ -286,6 +288,30 @@ public class EntityCollectionPart
);
}
@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
public String getSqlAliasStem() {
return collectionDescriptor.getAttributeMapping().getSqlAliasStem();

View File

@ -627,57 +627,17 @@ public class PluralAttributeMappingImpl
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final CollectionPersister collectionDescriptor = getCollectionDescriptor();
if ( collectionDescriptor.isOneToMany() ) {
return createOneToManyTableGroupJoin(
final TableGroup tableGroup = createRootTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
fetched,
null,
aliasBaseGenerator,
sqlExpressionResolver,
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(
navigablePath,
sqlAstJoinType,
@ -696,6 +656,60 @@ public class PluralAttributeMappingImpl
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(
boolean canUseInnerJoins,
NavigablePath navigablePath,
@ -825,44 +839,6 @@ public class PluralAttributeMappingImpl
);
}
@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(
boolean canUseInnerJoins,
NavigablePath navigablePath,
@ -1054,8 +1030,8 @@ public class PluralAttributeMappingImpl
joinType,
elementAssociatedPrimaryTable,
elementFkDescriptor.generateJoinPredicate(
collectionTableReference,
elementAssociatedPrimaryTable,
collectionTableReference,
joinType,
sqlExpressionResolver,
creationContext

View File

@ -242,70 +242,40 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
@Override
public Predicate generateJoinPredicate(
TableReference lhs,
TableReference rhs,
TableReference targetSideReference,
TableReference keySideReference,
SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
if ( lhs.getTableReference( keySide.getModelPart().getContainingTableExpression() ) != null ) {
return new ComparisonPredicate(
new ColumnReference(
lhs,
keySide.getModelPart(),
creationContext.getSessionFactory()
),
ComparisonOperator.EQUAL,
new ColumnReference(
rhs,
targetSide.getModelPart(),
creationContext.getSessionFactory()
)
);
}
else {
return new ComparisonPredicate(
new ColumnReference(
lhs,
targetSideReference,
targetSide.getModelPart(),
creationContext.getSessionFactory()
),
ComparisonOperator.EQUAL,
new ColumnReference(
rhs,
keySideReference,
keySide.getModelPart(),
creationContext.getSessionFactory()
)
);
}
}
@Override
public Predicate generateJoinPredicate(
TableGroup lhs,
TableGroup tableGroup,
TableGroup targetSideTableGroup,
TableGroup keySideTableGroup,
SqlAstJoinType sqlAstJoinType,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
TableReference lhsTableReference;
TableReference rhsTableKeyReference;
if ( targetSide.getModelPart().getContainingTableExpression().equals( keySide.getModelPart().getContainingTableExpression() ) ) {
lhsTableReference = getTableReferenceWhenTargetEqualsKey( lhs, tableGroup, keySide.getModelPart().getContainingTableExpression() );
rhsTableKeyReference = getTableReference(
lhs,
tableGroup,
final TableReference lhsTableReference = targetSideTableGroup.getTableReference(
targetSideTableGroup.getNavigablePath(),
targetSide.getModelPart().getContainingTableExpression()
);
}
else {
lhsTableReference = getTableReference( lhs, tableGroup, keySide.getModelPart().getContainingTableExpression() );
rhsTableKeyReference = getTableReference(
lhs,
tableGroup,
targetSide.getModelPart().getContainingTableExpression()
final TableReference rhsTableKeyReference = keySideTableGroup.getTableReference(
keySide.getModelPart().getContainingTableExpression()
);
}
return generateJoinPredicate(
lhsTableReference,
@ -316,23 +286,6 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
);
}
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) {
final NavigablePath navigablePath = lhs.getNavigablePath().append( getNavigableRole().getNavigableName() );
if ( lhs.getPrimaryTableReference().getTableReference( navigablePath, table ) != null ) {

View File

@ -10,6 +10,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStyle;
@ -56,6 +57,7 @@ import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
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.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -421,6 +423,10 @@ public class ToOneAttributeMapping
return targetKeyPropertyName;
}
public boolean isTargetKeyPropertyPath(String path) {
return targetKeyPropertyNames.contains( path );
}
public Cardinality getCardinality() {
return cardinality;
}
@ -924,6 +930,59 @@ public class ToOneAttributeMapping
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
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 boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins() && !isNullable;
final LazyTableGroup lazyTableGroup = new LazyTableGroup(
@ -967,34 +1026,31 @@ public class ToOneAttributeMapping
lhs
);
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
if ( predicateConsumer != null ) {
final TableReference lhsTableReference = lhs.resolveTableReference(
navigablePath,
sqlAstJoinType,
lazyTableGroup,
null
identifyingColumnsTableExpression
);
final TableReference lhsTableReference = lhs.resolveTableReference( navigablePath, identifyingColumnsTableExpression );
lazyTableGroup.setTableGroupInitializerCallback(
tableGroup -> tableGroupJoin.applyPredicate(
tableGroup -> predicateConsumer.accept(
foreignKeyDescriptor.generateJoinPredicate(
lhsTableReference,
tableGroup.getPrimaryTableReference(),
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;
return lazyTableGroup;
}
private SqlAstJoinType getJoinType(NavigablePath navigablePath, TableGroup tableGroup) {

View File

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

View File

@ -1683,6 +1683,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
// not consumed by the identifierConsumer
join.setExplicitAlias( alias );
final HqlParser.QualifiedJoinPredicateContext qualifiedJoinPredicateContext = parserJoin.qualifiedJoinPredicate();
if ( join instanceof SqmEntityJoin ) {
//noinspection unchecked
sqmRoot.addSqmJoin( join );
@ -1690,8 +1691,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
else {
if ( getCreationOptions().useStrictJpaCompliance() ) {
if ( join.getExplicitAlias() != null ) {
//noinspection rawtypes
if ( ( (SqmAttributeJoin) join ).isFetched() ) {
if ( ( (SqmAttributeJoin<?, ?>) join ).isFetched() ) {
throw new StrictJpaComplianceViolation(
"Encountered aliased fetch join, but strict JPQL compliance was requested",
StrictJpaComplianceViolation.Type.ALIASED_FETCH_JOIN
@ -1699,9 +1699,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
}
}
}
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 ) {
dotIdentifierConsumerStack.push( new QualifiedJoinPredicatePathConsumer( join, this ) );
try {

View File

@ -43,6 +43,11 @@ public class FromClauseAccessImpl implements FromClauseAccess {
return null;
}
@Override
public TableGroup findTableGroupOnLeaf(NavigablePath navigablePath) {
return findTableGroup( navigablePath );
}
@Override
public TableGroup findTableGroup(NavigablePath navigablePath) {
if ( tableGroupByPath != null ) {

View File

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

View File

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

View File

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

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.sql.ast.tree.from;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlAstJoinType;
@ -13,6 +15,7 @@ import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.predicate.Predicate;
/**
* @author Steve Ebersole
@ -55,4 +58,42 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.QueryException;
import org.hibernate.dialect.DerbyDialect;
import org.hibernate.dialect.TiDBDialect;
import org.hibernate.query.Query;
import org.hibernate.testing.TestForIssue;
@ -25,9 +28,11 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
/**
* Implementation of WithClauseTest.
@ -54,6 +59,26 @@ public class WithClauseTest {
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
public void testWithClause(SessionFactoryScope scope) {
scope.inTransaction(
@ -85,7 +110,16 @@ public class WithClauseTest {
.list();
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" ) ) )
.list();
assertTrue( list.isEmpty(), "ad-hoc did take effect" );

View File

@ -187,7 +187,7 @@ public class CriteriaLiteralsTest extends BaseEntityManagerFunctionalTestCase {
1,
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=?" );
} );
}