Render implicit joins as nested table group joins instead of sub queries
This commit is contained in:
parent
756afb8788
commit
1456a2dd7f
|
@ -421,6 +421,7 @@ public class LoaderSelectBuilder {
|
|||
null,
|
||||
SqlAstJoinType.LEFT,
|
||||
true,
|
||||
false,
|
||||
sqlAstCreationState
|
||||
);
|
||||
tableGroup = tableGroupJoin.getJoinedGroup();
|
||||
|
|
|
@ -171,6 +171,7 @@ public abstract class AbstractCompositeIdentifierMapping
|
|||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean nested,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
|
@ -187,7 +188,12 @@ public abstract class AbstractCompositeIdentifierMapping
|
|||
);
|
||||
|
||||
final TableGroupJoin join = new TableGroupJoin( navigablePath, SqlAstJoinType.LEFT, tableGroup, null );
|
||||
lhs.addTableGroupJoin( join );
|
||||
if ( nested ) {
|
||||
lhs.addNestedTableGroupJoin( join );
|
||||
}
|
||||
else {
|
||||
lhs.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
return join;
|
||||
}
|
||||
|
|
|
@ -284,6 +284,7 @@ public class EmbeddedAttributeMapping
|
|||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean nested,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
|
@ -299,14 +300,19 @@ public class EmbeddedAttributeMapping
|
|||
creationContext
|
||||
);
|
||||
|
||||
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
|
||||
final TableGroupJoin join = new TableGroupJoin(
|
||||
navigablePath,
|
||||
sqlAstJoinType,
|
||||
tableGroup
|
||||
);
|
||||
lhs.addTableGroupJoin( tableGroupJoin );
|
||||
if ( nested ) {
|
||||
lhs.addNestedTableGroupJoin( join );
|
||||
}
|
||||
else {
|
||||
lhs.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
return tableGroupJoin;
|
||||
return join;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -202,6 +202,7 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
|||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean nested,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
|
@ -217,14 +218,19 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
|||
creationContext
|
||||
);
|
||||
|
||||
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
|
||||
final TableGroupJoin join = new TableGroupJoin(
|
||||
navigablePath,
|
||||
sqlAstJoinType,
|
||||
tableGroup,
|
||||
null
|
||||
);
|
||||
lhs.addTableGroupJoin( tableGroupJoin );
|
||||
return tableGroupJoin;
|
||||
if ( nested ) {
|
||||
lhs.addNestedTableGroupJoin( join );
|
||||
}
|
||||
else {
|
||||
lhs.addTableGroupJoin( join );
|
||||
}
|
||||
return join;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
|||
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.from.TableReferenceJoin;
|
||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.Junction;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
|
@ -306,6 +305,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
null,
|
||||
SqlAstJoinType.INNER,
|
||||
true,
|
||||
false,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
|
|
|
@ -273,6 +273,7 @@ public class EntityCollectionPart
|
|||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean nested,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
|
@ -282,6 +283,7 @@ public class EntityCollectionPart
|
|||
explicitSourceAlias,
|
||||
sqlAstJoinType,
|
||||
fetched,
|
||||
nested,
|
||||
aliasBaseGenerator,
|
||||
sqlExpressionResolver,
|
||||
creationContext
|
||||
|
|
|
@ -572,6 +572,7 @@ public class PluralAttributeMappingImpl
|
|||
null,
|
||||
SqlAstJoinType.LEFT,
|
||||
true,
|
||||
false,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
|
@ -624,6 +625,7 @@ public class PluralAttributeMappingImpl
|
|||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean nested,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
|
@ -638,7 +640,7 @@ public class PluralAttributeMappingImpl
|
|||
sqlExpressionResolver,
|
||||
creationContext
|
||||
);
|
||||
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
|
||||
final TableGroupJoin join = new TableGroupJoin(
|
||||
navigablePath,
|
||||
sqlAstJoinType,
|
||||
tableGroup,
|
||||
|
@ -651,9 +653,14 @@ public class PluralAttributeMappingImpl
|
|||
)
|
||||
);
|
||||
|
||||
lhs.addTableGroupJoin( tableGroupJoin );
|
||||
if ( nested ) {
|
||||
lhs.addNestedTableGroupJoin( join );
|
||||
}
|
||||
else {
|
||||
lhs.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
return tableGroupJoin;
|
||||
return join;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -839,6 +839,7 @@ public class ToOneAttributeMapping
|
|||
null,
|
||||
getDefaultSqlAstJoinType( tableGroup ),
|
||||
true,
|
||||
false,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
|
||||
|
@ -911,6 +912,7 @@ public class ToOneAttributeMapping
|
|||
sourceAlias,
|
||||
sqlAstJoinType,
|
||||
fetched,
|
||||
false,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
|
||||
|
@ -929,6 +931,7 @@ public class ToOneAttributeMapping
|
|||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean nested,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
|
@ -944,7 +947,7 @@ public class ToOneAttributeMapping
|
|||
sqlExpressionResolver,
|
||||
creationContext
|
||||
);
|
||||
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
|
||||
final TableGroupJoin join = new TableGroupJoin(
|
||||
navigablePath,
|
||||
sqlAstJoinType,
|
||||
lazyTableGroup,
|
||||
|
@ -954,7 +957,7 @@ public class ToOneAttributeMapping
|
|||
final TableReference lhsTableReference = lhs.resolveTableReference( navigablePath, identifyingColumnsTableExpression );
|
||||
|
||||
lazyTableGroup.setTableGroupInitializerCallback(
|
||||
tableGroup -> tableGroupJoin.applyPredicate(
|
||||
tableGroup -> join.applyPredicate(
|
||||
foreignKeyDescriptor.generateJoinPredicate(
|
||||
sideNature == ForeignKeyDescriptor.Nature.TARGET ? lhsTableReference : tableGroup.getPrimaryTableReference(),
|
||||
sideNature == ForeignKeyDescriptor.Nature.TARGET ? tableGroup.getPrimaryTableReference() : lhsTableReference,
|
||||
|
@ -964,14 +967,19 @@ public class ToOneAttributeMapping
|
|||
)
|
||||
)
|
||||
);
|
||||
lhs.addTableGroupJoin( tableGroupJoin );
|
||||
if ( nested ) {
|
||||
lhs.addNestedTableGroupJoin( join );
|
||||
}
|
||||
else {
|
||||
lhs.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
if ( sqlAstJoinType == SqlAstJoinType.INNER && isNullable ) {
|
||||
// Force initialization of the underlying table group join to retain cardinality
|
||||
lazyTableGroup.getPrimaryTableReference();
|
||||
}
|
||||
|
||||
return tableGroupJoin;
|
||||
return join;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -991,7 +999,7 @@ public class ToOneAttributeMapping
|
|||
canUseInnerJoin,
|
||||
navigablePath,
|
||||
fetched,
|
||||
() -> createTableGroupJoinInternal(
|
||||
() -> createTableGroupInternal(
|
||||
canUseInnerJoin,
|
||||
navigablePath,
|
||||
fetched,
|
||||
|
@ -1064,7 +1072,7 @@ public class ToOneAttributeMapping
|
|||
return getDefaultSqlAstJoinType( tableGroup );
|
||||
}
|
||||
|
||||
public TableGroup createTableGroupJoinInternal(
|
||||
public TableGroup createTableGroupInternal(
|
||||
boolean canUseInnerJoins,
|
||||
NavigablePath navigablePath,
|
||||
boolean fetched,
|
||||
|
|
|
@ -77,13 +77,13 @@ public class TableGroupImpl implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return false;
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return tableGroupJoins != null && !tableGroupJoins.isEmpty();
|
||||
public boolean canUseInnerJoins() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,6 +96,11 @@ public class TableGroupImpl implements TableGroup {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroupJoins != null ) {
|
||||
|
@ -103,6 +108,10 @@ public class TableGroupImpl implements TableGroup {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
|
|||
tableAlias,
|
||||
SqlAstJoinType.INNER,
|
||||
true,
|
||||
false,
|
||||
s -> sqlAliasBase,
|
||||
creationState.getSqlExpressionResolver(),
|
||||
creationState.getCreationContext()
|
||||
|
|
|
@ -89,6 +89,7 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
|
|||
null,
|
||||
SqlAstJoinType.INNER,
|
||||
true,
|
||||
false,
|
||||
creationStateImpl
|
||||
);
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
|
|
|
@ -70,6 +70,7 @@ public class ImplicitModelPartResultBuilderEmbeddable
|
|||
null,
|
||||
SqlAstJoinType.INNER,
|
||||
true,
|
||||
false,
|
||||
creationStateImpl
|
||||
);
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.util.function.Consumer;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import jakarta.persistence.TemporalType;
|
||||
import jakarta.persistence.metamodel.EmbeddableType;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Internal;
|
||||
|
@ -373,8 +372,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
private final Stack<FromClauseIndex> fromClauseIndexStack = new StandardStack<>();
|
||||
private SqlAstProcessingState lastPoppedProcessingState;
|
||||
private FromClauseIndex lastPoppedFromClauseIndex;
|
||||
private SqlAstQueryPartProcessingStateImpl joinPredicateWrapper;
|
||||
private SqmJoin<?, ?> currentJoin;
|
||||
private SqmJoin<?, ?> currentlyProcessingJoin;
|
||||
|
||||
private final Stack<Clause> currentClauseStack = new StandardStack<>();
|
||||
|
||||
|
@ -2114,6 +2112,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
sqmJoin.getExplicitAlias(),
|
||||
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
|
||||
sqmJoin.isFetched(),
|
||||
false,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -2128,6 +2127,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
sqmJoin.getExplicitAlias(),
|
||||
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
|
||||
sqmJoin.isFetched(),
|
||||
false,
|
||||
this
|
||||
);
|
||||
}
|
||||
|
@ -2147,22 +2147,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
final SqmJoin<?, ?> oldJoin = currentJoin;
|
||||
currentJoin = sqmJoin;
|
||||
final Predicate predicate = (Predicate) sqmJoin.getJoinPredicate().accept( this );
|
||||
if ( joinPredicateWrapper == null ) {
|
||||
joinedTableGroupJoin.applyPredicate( predicate );
|
||||
}
|
||||
else {
|
||||
// See #prepareReusablePath for an explanation why this is necessary
|
||||
popProcessingStateStack();
|
||||
|
||||
final QuerySpec querySpec = joinPredicateWrapper.getInflightQueryPart().getFirstQuerySpec();
|
||||
querySpec.applyPredicate( predicate );
|
||||
joinedTableGroupJoin.applyPredicate( new ExistsPredicate( querySpec, getBooleanType() ) );
|
||||
joinPredicateWrapper = null;
|
||||
}
|
||||
currentJoin = oldJoin;
|
||||
final SqmJoin<?, ?> oldJoin = currentlyProcessingJoin;
|
||||
currentlyProcessingJoin = sqmJoin;
|
||||
joinedTableGroupJoin.applyPredicate( (Predicate) sqmJoin.getJoinPredicate().accept( this ) );
|
||||
currentlyProcessingJoin = oldJoin;
|
||||
}
|
||||
|
||||
consumeExplicitJoins( sqmJoin, joinedTableGroup );
|
||||
|
@ -2236,29 +2224,20 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
tableGroup,
|
||||
null
|
||||
);
|
||||
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||
|
||||
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||
|
||||
// add any additional join restrictions
|
||||
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||
final SqmJoin<?, ?> oldJoin = currentJoin;
|
||||
currentJoin = sqmJoin;
|
||||
final Predicate predicate = (Predicate) sqmJoin.getJoinPredicate().accept( this );
|
||||
if ( joinPredicateWrapper == null ) {
|
||||
tableGroupJoin.applyPredicate( predicate );
|
||||
}
|
||||
else {
|
||||
// See #prepareReusablePath for an explanation why this is necessary
|
||||
popProcessingStateStack();
|
||||
|
||||
final QuerySpec querySpec = joinPredicateWrapper.getInflightQueryPart().getFirstQuerySpec();
|
||||
querySpec.applyPredicate( predicate );
|
||||
tableGroupJoin.applyPredicate( new ExistsPredicate( querySpec, getBooleanType() ) );
|
||||
joinPredicateWrapper = null;
|
||||
}
|
||||
currentJoin = oldJoin;
|
||||
final SqmJoin<?, ?> oldJoin = currentlyProcessingJoin;
|
||||
currentlyProcessingJoin = sqmJoin;
|
||||
tableGroupJoin.applyPredicate( (Predicate) sqmJoin.getJoinPredicate().accept( this ) );
|
||||
currentlyProcessingJoin = oldJoin;
|
||||
}
|
||||
|
||||
// Note that we add the entity join after processing the predicate because implicit joins needed in there
|
||||
// can be just ordered right before the entity join without changing the semantics
|
||||
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||
|
||||
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||
}
|
||||
|
||||
private <X> X prepareReusablePath(SqmPath<?> sqmPath, Supplier<X> supplier) {
|
||||
|
@ -2271,41 +2250,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
final FromClauseIndex fromClauseIndex = fromClauseIndexStack.getCurrent();
|
||||
final boolean useInnerJoin = currentClauseStack.getCurrent() == Clause.SELECT;
|
||||
if ( currentClauseStack.getCurrent() == Clause.FROM && currentJoin instanceof SqmAttributeJoin<?, ?>
|
||||
&& joinPredicateWrapper == null && needsJoinForPath( fromClauseIndex, sqmPath ) ) {
|
||||
// If we encounter a reusable path that requires a join in the ON clause of an attribute join
|
||||
// we have to transform the predicate into `.. on exists (select 1 from ... where ..)`
|
||||
// Note that we don't need this for e.g. entity joins because the implicit joins needed in such ON clauses
|
||||
// can be just ordered right before the entity join without changing the semantics
|
||||
final QuerySpec querySpec = new QuerySpec( false );
|
||||
final JdbcLiteral<Integer> jdbcLiteral = new JdbcLiteral<>( 1, basicType( Integer.class ) );
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl( 1, 0, jdbcLiteral )
|
||||
);
|
||||
joinPredicateWrapper = new SqlAstQueryPartProcessingStateImpl(
|
||||
querySpec,
|
||||
getCurrentProcessingState(),
|
||||
this,
|
||||
currentClauseStack::getCurrent
|
||||
);
|
||||
pushProcessingState( joinPredicateWrapper );
|
||||
// Note that the pop must happen where the join predicate is applied
|
||||
// This is necessary as we want to retain the FromClauseIndex of this newly created sub query
|
||||
// while we are still processing expressions of the predicate
|
||||
currentClauseStack.push( Clause.WHERE );
|
||||
prepareReusablePath( fromClauseIndex, sqmPath, useInnerJoin, implicitJoinChecker );
|
||||
currentClauseStack.pop();
|
||||
}
|
||||
else {
|
||||
prepareReusablePath( fromClauseIndex, sqmPath, useInnerJoin, implicitJoinChecker );
|
||||
}
|
||||
prepareReusablePath( fromClauseIndex, sqmPath, useInnerJoin, implicitJoinChecker );
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
private TableGroup prepareReusablePath(
|
||||
FromClauseIndex fromClauseIndex,
|
||||
JpaPath<?> sqmPath,
|
||||
boolean useInnerJoin, Consumer<TableGroup> implicitJoinChecker) {
|
||||
boolean useInnerJoin,
|
||||
Consumer<TableGroup> implicitJoinChecker) {
|
||||
final JpaPath<?> parentPath = sqmPath.getParentPath();
|
||||
final TableGroup tableGroup = fromClauseIndex.findTableGroup( parentPath.getNavigablePath() );
|
||||
if ( tableGroup == null ) {
|
||||
|
@ -2354,105 +2307,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
}
|
||||
|
||||
private boolean needsJoinForPath(FromClauseIndex fromClauseIndex, SqmPath<?> sqmPath) {
|
||||
final JpaPath<?> parentPath = sqmPath.getParentPath();
|
||||
final TableGroup parentTableGroup = fromClauseIndex.findTableGroup( parentPath.getNavigablePath() );
|
||||
// First, check if we can find the table group for the direct parent
|
||||
if ( parentTableGroup != null ) {
|
||||
return needsJoinForPath( fromClauseIndex, parentTableGroup, sqmPath.getReferencedPathSource().getPathName() );
|
||||
}
|
||||
JpaPath<?> realParentPath = parentPath;
|
||||
int realParentDistance = 0;
|
||||
// Next, check if we can find the table group for the parent, after traversing up embeddable paths
|
||||
if ( realParentPath.getModel() instanceof EmbeddableType<?> ) {
|
||||
do {
|
||||
realParentPath = realParentPath.getParentPath();
|
||||
realParentDistance++;
|
||||
} while ( realParentPath.getModel() instanceof EmbeddableType<?> );
|
||||
final TableGroup assumedToOneTableGroup = fromClauseIndex.findTableGroup( realParentPath.getNavigablePath() );
|
||||
if ( assumedToOneTableGroup != null ) {
|
||||
if ( assumedToOneTableGroup.getModelPart() instanceof ToOneAttributeMapping ) {
|
||||
realParentPath = parentPath.getParentPath();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( sqmPath.getReferencedPathSource().getPathName() );
|
||||
for ( int i = realParentDistance - 1; i >= 0; i-- ) {
|
||||
sb.insert( 0, realParentPath.getNavigablePath().getUnaliasedLocalName() + '.' );
|
||||
realParentPath = realParentPath.getParentPath();
|
||||
}
|
||||
return needsJoinForPath( fromClauseIndex, assumedToOneTableGroup, sb.toString() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Finally, check if we can find the grandparent table group
|
||||
final TableGroup grandparentTableGroup = fromClauseIndex.findTableGroup( realParentPath.getParentPath().getNavigablePath() );
|
||||
if ( grandparentTableGroup == null ) {
|
||||
// without a grandparent, we always need a join
|
||||
return true;
|
||||
}
|
||||
|
||||
// With the grandparent available, we can determine if the model part is a to-one mapping
|
||||
final ModelPart realParentModelPart = grandparentTableGroup.getModelPart().findSubPart(
|
||||
realParentPath.getNavigablePath().getUnaliasedLocalName(),
|
||||
null
|
||||
);
|
||||
// This must be a to-one otherwise we assume to always need a join
|
||||
if ( !( realParentModelPart instanceof ToOneAttributeMapping ) ) {
|
||||
return true;
|
||||
}
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) realParentModelPart;
|
||||
final String path;
|
||||
if ( realParentDistance == 0 ) {
|
||||
path = sqmPath.getReferencedPathSource().getPathName();
|
||||
}
|
||||
else {
|
||||
realParentPath = parentPath.getParentPath();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append( sqmPath.getReferencedPathSource().getPathName() );
|
||||
for ( int i = realParentDistance - 1; i >= 0; i-- ) {
|
||||
sb.insert( 0, realParentPath.getNavigablePath().getUnaliasedLocalName() + '.' );
|
||||
realParentPath = realParentPath.getParentPath();
|
||||
}
|
||||
path = sb.toString();
|
||||
}
|
||||
|
||||
return !toOneAttributeMapping.isTargetKeyPropertyPath( path );
|
||||
}
|
||||
|
||||
private boolean needsJoinForPath(
|
||||
FromClauseIndex fromClauseIndex,
|
||||
TableGroup tableGroup,
|
||||
String pathName) {
|
||||
TableGroup parentTableGroup = tableGroup;
|
||||
ToOneAttributeMapping toOneAttributeMapping;
|
||||
ModelPartContainer modelPart = tableGroup.getModelPart();
|
||||
String path;
|
||||
if ( modelPart instanceof ToOneAttributeMapping ) {
|
||||
toOneAttributeMapping = (ToOneAttributeMapping) modelPart;
|
||||
path = pathName;
|
||||
}
|
||||
else {
|
||||
if ( !( modelPart instanceof EmbeddableValuedModelPart ) ) {
|
||||
return false;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append( pathName );
|
||||
do {
|
||||
sb.insert( 0, modelPart.getPartName() + '.' );
|
||||
parentTableGroup = fromClauseIndex.findTableGroup( parentTableGroup.getNavigablePath().getParent() );
|
||||
modelPart = parentTableGroup.getModelPart();
|
||||
} while ( modelPart instanceof EmbeddableValuedModelPart );
|
||||
if ( !( modelPart instanceof ToOneAttributeMapping ) ) {
|
||||
return false;
|
||||
}
|
||||
toOneAttributeMapping = (ToOneAttributeMapping) modelPart;
|
||||
path = sb.toString();
|
||||
}
|
||||
final LazyTableGroup lazyTableGroup = (LazyTableGroup) parentTableGroup;
|
||||
// Unless the lazy table group is not initialized and the requested sub part is not the FK
|
||||
return !lazyTableGroup.isInitialized() && !toOneAttributeMapping.isTargetKeyPropertyPath( path );
|
||||
}
|
||||
|
||||
private TableGroup createTableGroup(TableGroup parentTableGroup, SqmPath<?> joinedPath, boolean useInnerJoin) {
|
||||
final SqmPath<?> lhsPath = joinedPath.getLhs();
|
||||
final FromClauseIndex fromClauseIndex = getFromClauseIndex();
|
||||
|
@ -2500,6 +2354,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
null,
|
||||
defaultSqlAstJoinType,
|
||||
false,
|
||||
// Implicit joins in the ON clause need to be added as nested table group joins
|
||||
currentClauseStack.getCurrent() == Clause.FROM
|
||||
// Except for entity joins, as we can order the implicit joins before the entity join
|
||||
// See consumeEntityJoin for details
|
||||
&& !( currentlyProcessingJoin instanceof SqmEntityJoin<?> ),
|
||||
this
|
||||
);
|
||||
tableGroup = tableGroupJoin.getJoinedGroup();
|
||||
|
@ -2963,6 +2822,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
null,
|
||||
SqlAstJoinType.INNER,
|
||||
false,
|
||||
false,
|
||||
sqlAliasBaseManager,
|
||||
getSqlExpressionResolver(),
|
||||
creationContext
|
||||
|
@ -4340,17 +4200,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
|
||||
@Override
|
||||
public QueryPart visitSubQueryExpression(SqmSubQuery<?> sqmSubQuery) {
|
||||
return visitQueryPart( sqmSubQuery.getQueryPart() );
|
||||
//
|
||||
// final ExpressableType<?> expressableType = determineExpressableType( sqmSubQuery );
|
||||
//
|
||||
// return new SubQuery(
|
||||
// subQuerySpec,
|
||||
// expressableType instanceof BasicValuedExpressableType<?>
|
||||
// ? ( (BasicValuedExpressableType) expressableType ).getSqlExpressableType( getTypeConfiguration() )
|
||||
// : null,
|
||||
// expressableType
|
||||
// );
|
||||
// The only purpose for tracking the current join is to
|
||||
// Reset the current join for sub queries because in there, we won't add nested joins
|
||||
final SqmJoin<?, ?> oldJoin = currentlyProcessingJoin;
|
||||
currentlyProcessingJoin = null;
|
||||
final QueryPart queryPart = visitQueryPart( sqmSubQuery.getQueryPart() );
|
||||
currentlyProcessingJoin = oldJoin;
|
||||
return queryPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4807,6 +4663,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
sqmPluralPath.getExplicitAlias(),
|
||||
SqlAstJoinType.INNER,
|
||||
false,
|
||||
false,
|
||||
sqlAliasBaseManager,
|
||||
subQueryState,
|
||||
creationContext
|
||||
|
@ -5215,6 +5072,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
alias,
|
||||
tableGroupJoinProducer.getDefaultSqlAstJoinType( lhs ),
|
||||
true,
|
||||
false,
|
||||
this
|
||||
);
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
|
|
|
@ -311,6 +311,7 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
null,
|
||||
SqlAstJoinType.INNER,
|
||||
false,
|
||||
false,
|
||||
sqlAstCreationState
|
||||
);
|
||||
|
||||
|
|
|
@ -3403,9 +3403,10 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
|
||||
protected void renderTableGroup(TableGroup tableGroup, Predicate predicate) {
|
||||
// Without reference joins, even a real table group does not need parenthesis
|
||||
// Without reference joins or nested join groups, even a real table group does not need parenthesis
|
||||
final boolean realTableGroup = tableGroup.isRealTableGroup()
|
||||
&& CollectionHelper.isNotEmpty( tableGroup.getTableReferenceJoins() );
|
||||
&& ( CollectionHelper.isNotEmpty( tableGroup.getTableReferenceJoins() )
|
||||
|| hasTableGroupsToRender( tableGroup.getNestedTableGroupJoins() ) );
|
||||
if ( realTableGroup ) {
|
||||
appendSql( OPEN_PARENTHESIS );
|
||||
}
|
||||
|
@ -3415,6 +3416,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
|
||||
if ( realTableGroup ) {
|
||||
renderTableReferenceJoins( tableGroup );
|
||||
processNestedTableGroupJoins( tableGroup );
|
||||
appendSql( CLOSE_PARENTHESIS );
|
||||
}
|
||||
|
||||
|
@ -3444,6 +3446,17 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
}
|
||||
}
|
||||
|
||||
private boolean hasTableGroupsToRender(List<TableGroupJoin> nestedTableGroupJoins) {
|
||||
for ( TableGroupJoin nestedTableGroupJoin : nestedTableGroupJoins ) {
|
||||
final TableGroup joinedGroup = nestedTableGroupJoin.getJoinedGroup();
|
||||
if ( !( joinedGroup instanceof LazyTableGroup ) || ( (LazyTableGroup) joinedGroup ).isInitialized() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) {
|
||||
appendSql( tableReference.getTableExpression() );
|
||||
|
@ -3503,6 +3516,11 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
source.visitTableGroupJoins( this::processTableGroupJoin );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void processNestedTableGroupJoins(TableGroup source) {
|
||||
source.visitNestedTableGroupJoins( this::processTableGroupJoin );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected void processTableGroupJoin(TableGroupJoin tableGroupJoin) {
|
||||
final TableGroup joinedGroup = tableGroupJoin.getJoinedGroup();
|
||||
|
@ -3513,6 +3531,12 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
else if ( !( joinedGroup instanceof LazyTableGroup ) || ( (LazyTableGroup) joinedGroup ).getUnderlyingTableGroup() != null ) {
|
||||
appendSql( WHITESPACE );
|
||||
SqlAstJoinType joinType = tableGroupJoin.getJoinType();
|
||||
// todo (6.0): no exactly sure why this is necessary and IMO this should ideally go away.
|
||||
// I realized that inverse one-to-one associations with join tables are considered "non-nullable" in the boot model.
|
||||
// Due to that, we use an inner join for the table group join of that association which the following "works around"
|
||||
// IMO such an association should be considered nullable. It's also odd that the association
|
||||
// has the FK Side KEY, although it is clearly TARGET
|
||||
// See org.hibernate.orm.test.annotations.manytoone.ManyToOneJoinTest.testOneToOneJoinTable2
|
||||
if ( !joinedGroup.isRealTableGroup() && joinType == SqlAstJoinType.INNER && !joinedGroup.getTableReferenceJoins().isEmpty() ) {
|
||||
joinType = SqlAstJoinType.LEFT;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,11 @@ public class CteTableGroup implements TableGroup {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return false;
|
||||
|
@ -87,18 +92,22 @@ public class CteTableGroup implements TableGroup {
|
|||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return false;
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
throw new UnsupportedOperationException( );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
throw new UnsupportedOperationException( );
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
|||
private final SqlAliasBase sqlAliasBase;
|
||||
|
||||
private List<TableGroupJoin> tableGroupJoins;
|
||||
private List<TableGroupJoin> nestedTableGroupJoins;
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
|
@ -87,13 +88,18 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return canUseInnerJoins;
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return nestedTableGroupJoins == null ? Collections.emptyList() : Collections.unmodifiableList( nestedTableGroupJoins );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return tableGroupJoins != null && !tableGroupJoins.isEmpty();
|
||||
public boolean isRealTableGroup() {
|
||||
return nestedTableGroupJoins != null && !nestedTableGroupJoins.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return canUseInnerJoins;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -106,6 +112,16 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
if ( nestedTableGroupJoins == null ) {
|
||||
nestedTableGroupJoins = new ArrayList<>();
|
||||
}
|
||||
if ( !nestedTableGroupJoins.contains( join ) ) {
|
||||
nestedTableGroupJoins.add( join );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroupJoins != null ) {
|
||||
|
@ -113,6 +129,13 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( nestedTableGroupJoins != null ) {
|
||||
nestedTableGroupJoins.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + '(' + getNavigablePath() + ')';
|
||||
|
|
|
@ -25,6 +25,7 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
|||
private final boolean fetched;
|
||||
|
||||
private List<TableGroupJoin> tableGroupJoins;
|
||||
private List<TableGroupJoin> nestedTableGroupJoins;
|
||||
|
||||
public CompositeTableGroup(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -74,13 +75,18 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return underlyingTableGroup.canUseInnerJoins();
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return nestedTableGroupJoins == null ? Collections.emptyList() : Collections.unmodifiableList( nestedTableGroupJoins );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return tableGroupJoins != null && !tableGroupJoins.isEmpty();
|
||||
public boolean isRealTableGroup() {
|
||||
return nestedTableGroupJoins != null && !nestedTableGroupJoins.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return underlyingTableGroup.canUseInnerJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -93,6 +99,16 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
if ( nestedTableGroupJoins == null ) {
|
||||
nestedTableGroupJoins = new ArrayList<>();
|
||||
}
|
||||
if ( !nestedTableGroupJoins.contains( join ) ) {
|
||||
nestedTableGroupJoins.add( join );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroupJoins != null ) {
|
||||
|
@ -100,6 +116,13 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( nestedTableGroupJoins != null ) {
|
||||
nestedTableGroupJoins.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
underlyingTableGroup.applyAffectedTableNames( nameCollector );
|
||||
|
@ -136,6 +159,14 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
|||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( primaryTableReference != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
|
|
|
@ -71,6 +71,14 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
|
|||
if ( primaryTableReference != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
|
|
|
@ -106,8 +106,8 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return tableGroup != null && tableGroup.hasTableGroupJoins();
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return tableGroup == null ? Collections.emptyList() : tableGroup.getNestedTableGroupJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -115,6 +115,11 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
getTableGroup().addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
getTableGroup().addNestedTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroup != null ) {
|
||||
|
@ -122,6 +127,13 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroup != null ) {
|
||||
tableGroup.visitNestedTableGroupJoins( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return canUseInnerJoins;
|
||||
|
@ -159,7 +171,7 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
|
||||
@Override
|
||||
public boolean isRealTableGroup() {
|
||||
return false;
|
||||
return tableGroup != null && tableGroup.isRealTableGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -93,12 +93,12 @@ public class MutatingTableReferenceGroupWrapper implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return false;
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
public boolean canUseInnerJoins() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -107,10 +107,19 @@ public class MutatingTableReferenceGroupWrapper implements VirtualTableGroup {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return Collections.emptyList();
|
||||
|
|
|
@ -115,7 +115,7 @@ public class StandardTableGroup extends AbstractTableGroup {
|
|||
|
||||
@Override
|
||||
public boolean isRealTableGroup() {
|
||||
return realTableGroup;
|
||||
return realTableGroup || super.isRealTableGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -159,6 +159,12 @@ public class StandardTableGroup extends AbstractTableGroup {
|
|||
return potentiallyCreateTableReference( tableExpression );
|
||||
}
|
||||
|
||||
for ( TableGroupJoin tableGroupJoin : getNestedTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization ) != null ) {
|
||||
|
|
|
@ -41,15 +41,19 @@ public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, SqmPat
|
|||
String getSourceAlias();
|
||||
|
||||
List<TableGroupJoin> getTableGroupJoins();
|
||||
|
||||
List<TableGroupJoin> getNestedTableGroupJoins();
|
||||
|
||||
boolean canUseInnerJoins();
|
||||
|
||||
boolean hasTableGroupJoins();
|
||||
|
||||
void addTableGroupJoin(TableGroupJoin join);
|
||||
|
||||
void addNestedTableGroupJoin(TableGroupJoin join);
|
||||
|
||||
void visitTableGroupJoins(Consumer<TableGroupJoin> consumer);
|
||||
|
||||
void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer);
|
||||
|
||||
void applyAffectedTableNames(Consumer<String> nameCollector);
|
||||
|
||||
TableReference getPrimaryTableReference();
|
||||
|
|
|
@ -8,7 +8,6 @@ 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;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||
|
@ -33,6 +32,7 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
|
|||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean nested,
|
||||
SqlAstCreationState creationState) {
|
||||
return createTableGroupJoin(
|
||||
navigablePath,
|
||||
|
@ -40,6 +40,7 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
|
|||
explicitSourceAlias,
|
||||
sqlAstJoinType,
|
||||
fetched,
|
||||
nested,
|
||||
creationState.getSqlAliasBaseGenerator(),
|
||||
creationState.getSqlExpressionResolver(),
|
||||
creationState.getCreationContext()
|
||||
|
@ -55,6 +56,7 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
|
|||
String explicitSourceAlias,
|
||||
SqlAstJoinType sqlAstJoinType,
|
||||
boolean fetched,
|
||||
boolean nested,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext);
|
||||
|
|
|
@ -23,6 +23,7 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
private final boolean canUseInnerJoins;
|
||||
private final NavigablePath navigablePath;
|
||||
private List<TableGroupJoin> tableGroupJoins;
|
||||
private List<TableGroupJoin> nestedTableGroupJoins;
|
||||
|
||||
private final UnionSubclassEntityPersister modelPart;
|
||||
private final String sourceAlias;
|
||||
|
@ -72,8 +73,13 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return tableGroupJoins != null && !tableGroupJoins.isEmpty();
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return nestedTableGroupJoins == null ? Collections.emptyList() : Collections.unmodifiableList( nestedTableGroupJoins );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRealTableGroup() {
|
||||
return nestedTableGroupJoins != null && !nestedTableGroupJoins.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,6 +97,16 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
if ( nestedTableGroupJoins == null ) {
|
||||
nestedTableGroupJoins = new ArrayList<>();
|
||||
}
|
||||
if ( !nestedTableGroupJoins.contains( join ) ) {
|
||||
nestedTableGroupJoins.add( join );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( tableGroupJoins != null ) {
|
||||
|
@ -98,6 +114,13 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
if ( nestedTableGroupJoins != null ) {
|
||||
nestedTableGroupJoins.forEach( consumer );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
}
|
||||
|
@ -128,6 +151,15 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
if ( tableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization ) != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
if ( nestedTableGroupJoins != null ) {
|
||||
for ( TableGroupJoin tableGroupJoin : nestedTableGroupJoins ) {
|
||||
final TableReference tableReference = tableGroupJoin.getJoinedGroup()
|
||||
.resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( tableGroupJoins != null ) {
|
||||
for ( TableGroupJoin tableGroupJoin : tableGroupJoins ) {
|
||||
final TableReference tableReference = tableGroupJoin.getJoinedGroup()
|
||||
|
|
|
@ -66,13 +66,13 @@ public class EntityCollectionPartTableGroup implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return collectionTableGroup.canUseInnerJoins();
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return collectionTableGroup.getNestedTableGroupJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return collectionTableGroup.hasTableGroupJoins();
|
||||
public boolean canUseInnerJoins() {
|
||||
return collectionTableGroup.canUseInnerJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,11 +80,21 @@ public class EntityCollectionPartTableGroup implements TableGroup {
|
|||
collectionTableGroup.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
collectionTableGroup.addNestedTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
collectionTableGroup.visitTableGroupJoins( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
collectionTableGroup.visitNestedTableGroupJoins( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
collectionTableGroup.applyAffectedTableNames( nameCollector );
|
||||
|
|
|
@ -68,6 +68,7 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
|
|||
null,
|
||||
nullable ? SqlAstJoinType.LEFT : SqlAstJoinType.INNER,
|
||||
true,
|
||||
false,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
|
|
|
@ -54,6 +54,7 @@ public class EmbeddableResultImpl<T> extends AbstractFetchParent implements Embe
|
|||
resultVariable,
|
||||
SqlAstJoinType.INNER,
|
||||
true,
|
||||
false,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ 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;
|
||||
|
@ -115,7 +114,6 @@ public class WithClauseTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = TiDBDialect.class, reason = "TiDB db does not support subqueries for ON condition")
|
||||
public void testWithClauseWithImplicitJoin(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
(session) -> {
|
||||
|
|
|
@ -100,7 +100,7 @@ public class SmokeTests {
|
|||
|
||||
assertThat( rootTableGroup.getTableReferenceJoins().size(), is( 0 ) );
|
||||
|
||||
assertThat( rootTableGroup.hasTableGroupJoins(), is( false ) );
|
||||
assertThat( rootTableGroup.getTableGroupJoins().isEmpty(), is( true ) );
|
||||
|
||||
|
||||
// `s` is the "alias stem" for `SimpleEntity` and as it is the first entity with that stem in
|
||||
|
@ -159,7 +159,7 @@ public class SmokeTests {
|
|||
|
||||
assertThat( rootTableGroup.getTableReferenceJoins().size(), is( 0 ) );
|
||||
|
||||
assertThat( rootTableGroup.hasTableGroupJoins(), is( false ) );
|
||||
assertThat( rootTableGroup.getTableGroupJoins().isEmpty(), is( true ) );
|
||||
|
||||
|
||||
// `s` is the "alias stem" for `SimpleEntity` and as it is the first entity with that stem in
|
||||
|
|
|
@ -174,13 +174,13 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canUseInnerJoins() {
|
||||
return delegate.canUseInnerJoins();
|
||||
public List<TableGroupJoin> getNestedTableGroupJoins() {
|
||||
return delegate.getNestedTableGroupJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return delegate.hasTableGroupJoins();
|
||||
public boolean canUseInnerJoins() {
|
||||
return delegate.canUseInnerJoins();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -188,11 +188,21 @@ public class OrderByFragmentFunction extends AbstractSqmFunctionDescriptor {
|
|||
delegate.addTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||
delegate.addNestedTableGroupJoin( join );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
delegate.visitTableGroupJoins( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestedTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
delegate.visitNestedTableGroupJoins( consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
delegate.applyAffectedTableNames( nameCollector );
|
||||
|
|
Loading…
Reference in New Issue