Add support for from-space wide explicit join ordering and thus support entity/cross joins on all JpaFrom elements
This commit is contained in:
parent
1456a2dd7f
commit
6745f71f88
|
@ -421,9 +421,9 @@ public class LoaderSelectBuilder {
|
||||||
null,
|
null,
|
||||||
SqlAstJoinType.LEFT,
|
SqlAstJoinType.LEFT,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
sqlAstCreationState
|
sqlAstCreationState
|
||||||
);
|
);
|
||||||
|
rootTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
tableGroup = tableGroupJoin.getJoinedGroup();
|
tableGroup = tableGroupJoin.getJoinedGroup();
|
||||||
sqlAstCreationState.getFromClauseAccess().registerTableGroup( navigablePath, tableGroup );
|
sqlAstCreationState.getFromClauseAccess().registerTableGroup( navigablePath, tableGroup );
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,6 @@ public abstract class AbstractCompositeIdentifierMapping
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
boolean nested,
|
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
|
@ -187,15 +186,7 @@ public abstract class AbstractCompositeIdentifierMapping
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
final TableGroupJoin join = new TableGroupJoin( navigablePath, SqlAstJoinType.LEFT, tableGroup, null );
|
return new TableGroupJoin( navigablePath, SqlAstJoinType.LEFT, tableGroup, null );
|
||||||
if ( nested ) {
|
|
||||||
lhs.addNestedTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lhs.addTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
|
|
||||||
return join;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -284,7 +284,6 @@ public class EmbeddedAttributeMapping
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
boolean nested,
|
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
|
@ -300,19 +299,7 @@ public class EmbeddedAttributeMapping
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
final TableGroupJoin join = new TableGroupJoin(
|
return new TableGroupJoin( navigablePath, sqlAstJoinType, tableGroup );
|
||||||
navigablePath,
|
|
||||||
sqlAstJoinType,
|
|
||||||
tableGroup
|
|
||||||
);
|
|
||||||
if ( nested ) {
|
|
||||||
lhs.addNestedTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lhs.addTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
|
|
||||||
return join;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -202,7 +202,6 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
boolean nested,
|
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
|
@ -218,19 +217,7 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
final TableGroupJoin join = new TableGroupJoin(
|
return new TableGroupJoin( navigablePath, sqlAstJoinType, tableGroup, null );
|
||||||
navigablePath,
|
|
||||||
sqlAstJoinType,
|
|
||||||
tableGroup,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
if ( nested ) {
|
|
||||||
lhs.addNestedTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lhs.addTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
return join;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -305,9 +305,9 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
null,
|
null,
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
creationState.getSqlAstCreationState()
|
creationState.getSqlAstCreationState()
|
||||||
);
|
);
|
||||||
|
tableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -273,7 +273,6 @@ public class EntityCollectionPart
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
boolean nested,
|
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
|
@ -283,7 +282,6 @@ public class EntityCollectionPart
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
sqlAstJoinType,
|
sqlAstJoinType,
|
||||||
fetched,
|
fetched,
|
||||||
nested,
|
|
||||||
aliasBaseGenerator,
|
aliasBaseGenerator,
|
||||||
sqlExpressionResolver,
|
sqlExpressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
|
|
|
@ -572,9 +572,9 @@ public class PluralAttributeMappingImpl
|
||||||
null,
|
null,
|
||||||
SqlAstJoinType.LEFT,
|
SqlAstJoinType.LEFT,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
creationState.getSqlAstCreationState()
|
creationState.getSqlAstCreationState()
|
||||||
);
|
);
|
||||||
|
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -625,7 +625,6 @@ public class PluralAttributeMappingImpl
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
boolean nested,
|
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
|
@ -640,7 +639,7 @@ public class PluralAttributeMappingImpl
|
||||||
sqlExpressionResolver,
|
sqlExpressionResolver,
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
final TableGroupJoin join = new TableGroupJoin(
|
return new TableGroupJoin(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
sqlAstJoinType,
|
sqlAstJoinType,
|
||||||
tableGroup,
|
tableGroup,
|
||||||
|
@ -652,15 +651,6 @@ public class PluralAttributeMappingImpl
|
||||||
creationContext
|
creationContext
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( nested ) {
|
|
||||||
lhs.addNestedTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lhs.addTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
|
|
||||||
return join;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -716,27 +716,33 @@ public class ToOneAttributeMapping
|
||||||
final TableGroup tableGroup;
|
final TableGroup tableGroup;
|
||||||
if ( fetchParent instanceof EntityResultJoinedSubclassImpl &&
|
if ( fetchParent instanceof EntityResultJoinedSubclassImpl &&
|
||||||
( (EntityPersister) fetchParent.getReferencedModePart() ).findDeclaredAttributeMapping( getPartName() ) == null ) {
|
( (EntityPersister) fetchParent.getReferencedModePart() ).findDeclaredAttributeMapping( getPartName() ) == null ) {
|
||||||
tableGroup = createTableGroupJoin(
|
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
true,
|
parentTableGroup,
|
||||||
getJoinType( fetchablePath, parentTableGroup ),
|
|
||||||
resultVariable,
|
resultVariable,
|
||||||
creationState,
|
getJoinType( fetchablePath, parentTableGroup ),
|
||||||
parentTableGroup
|
true,
|
||||||
|
creationState.getSqlAstCreationState()
|
||||||
);
|
);
|
||||||
|
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
tableGroup = tableGroupJoin.getJoinedGroup();
|
||||||
fromClauseAccess.registerTableGroup( fetchablePath, tableGroup );
|
fromClauseAccess.registerTableGroup( fetchablePath, tableGroup );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tableGroup = fromClauseAccess.resolveTableGroup(
|
tableGroup = fromClauseAccess.resolveTableGroup(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
np ->
|
np -> {
|
||||||
createTableGroupJoin(
|
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
true,
|
parentTableGroup,
|
||||||
resultVariable,
|
resultVariable,
|
||||||
creationState,
|
getDefaultSqlAstJoinType( parentTableGroup ),
|
||||||
parentTableGroup
|
true,
|
||||||
)
|
creationState.getSqlAstCreationState()
|
||||||
|
);
|
||||||
|
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
return tableGroupJoin.getJoinedGroup();
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -839,9 +845,9 @@ public class ToOneAttributeMapping
|
||||||
null,
|
null,
|
||||||
getDefaultSqlAstJoinType( tableGroup ),
|
getDefaultSqlAstJoinType( tableGroup ),
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
creationState.getSqlAstCreationState()
|
creationState.getSqlAstCreationState()
|
||||||
);
|
);
|
||||||
|
tableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
|
||||||
creationState.getSqlAstCreationState().getFromClauseAccess().registerTableGroup(
|
creationState.getSqlAstCreationState().getFromClauseAccess().registerTableGroup(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
|
@ -867,22 +873,6 @@ public class ToOneAttributeMapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TableGroup createTableGroupJoin(
|
|
||||||
NavigablePath fetchablePath,
|
|
||||||
boolean fetched,
|
|
||||||
String sourceAlias,
|
|
||||||
DomainResultCreationState creationState,
|
|
||||||
TableGroup parentTableGroup) {
|
|
||||||
return createTableGroupJoin(
|
|
||||||
fetchablePath,
|
|
||||||
fetched,
|
|
||||||
getDefaultSqlAstJoinType( parentTableGroup ),
|
|
||||||
sourceAlias,
|
|
||||||
creationState,
|
|
||||||
parentTableGroup
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
|
public SqlAstJoinType getDefaultSqlAstJoinType(TableGroup parentTableGroup) {
|
||||||
if ( isNullable ) {
|
if ( isNullable ) {
|
||||||
|
@ -912,7 +902,6 @@ public class ToOneAttributeMapping
|
||||||
sourceAlias,
|
sourceAlias,
|
||||||
sqlAstJoinType,
|
sqlAstJoinType,
|
||||||
fetched,
|
fetched,
|
||||||
false,
|
|
||||||
creationState.getSqlAstCreationState()
|
creationState.getSqlAstCreationState()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -931,7 +920,6 @@ public class ToOneAttributeMapping
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
boolean nested,
|
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
|
@ -967,12 +955,6 @@ public class ToOneAttributeMapping
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if ( nested ) {
|
|
||||||
lhs.addNestedTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lhs.addTableGroupJoin( join );
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.criteria;
|
package org.hibernate.query.criteria;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
|
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.From;
|
import jakarta.persistence.criteria.From;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,4 +19,12 @@ import jakarta.persistence.criteria.From;
|
||||||
public interface JpaFrom<O,T> extends JpaPath<T>, JpaFetchParent<O,T>, From<O,T> {
|
public interface JpaFrom<O,T> extends JpaPath<T>, JpaFetchParent<O,T>, From<O,T> {
|
||||||
@Override
|
@Override
|
||||||
JpaFrom<O,T> getCorrelationParent();
|
JpaFrom<O,T> getCorrelationParent();
|
||||||
|
|
||||||
|
<X> JpaEntityJoin<X> join(Class<X> entityJavaType);
|
||||||
|
|
||||||
|
<X> JpaEntityJoin<X> join(EntityDomainType<X> entity);
|
||||||
|
|
||||||
|
<X> JpaEntityJoin<X> join(Class<X> entityJavaType, SqmJoinType joinType);
|
||||||
|
|
||||||
|
<X> JpaEntityJoin<X> join(EntityDomainType<X> entity, SqmJoinType joinType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.query.criteria;
|
||||||
import jakarta.persistence.criteria.Root;
|
import jakarta.persistence.criteria.Root;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -19,12 +18,4 @@ public interface JpaRoot<T> extends JpaFrom<T,T>, Root<T> {
|
||||||
EntityDomainType<T> getModel();
|
EntityDomainType<T> getModel();
|
||||||
|
|
||||||
EntityDomainType<T> getManagedType();
|
EntityDomainType<T> getManagedType();
|
||||||
|
|
||||||
<X> JpaEntityJoin<X> join(Class<X> entityJavaType);
|
|
||||||
|
|
||||||
<X> JpaEntityJoin<X> join(EntityDomainType<X> entity);
|
|
||||||
|
|
||||||
<X> JpaEntityJoin<X> join(Class<X> entityJavaType, SqmJoinType joinType);
|
|
||||||
|
|
||||||
<X> JpaEntityJoin<X> join(EntityDomainType<X> entity, SqmJoinType joinType);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1628,7 +1628,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
protected void consumeQualifiedJoin(HqlParser.QualifiedJoinContext parserJoin, SqmRoot<?> sqmRoot) {
|
protected <X> void consumeQualifiedJoin(HqlParser.QualifiedJoinContext parserJoin, SqmRoot<X> sqmRoot) {
|
||||||
final SqmJoinType joinType;
|
final SqmJoinType joinType;
|
||||||
final int firstJoinTypeSymbolType;
|
final int firstJoinTypeSymbolType;
|
||||||
if ( parserJoin.getChild( 0 ) instanceof HqlParser.JoinTypeQualifierContext
|
if ( parserJoin.getChild( 0 ) instanceof HqlParser.JoinTypeQualifierContext
|
||||||
|
@ -1676,22 +1676,22 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//noinspection rawtypes
|
//noinspection unchecked
|
||||||
final SqmQualifiedJoin join = (SqmQualifiedJoin) qualifiedJoinRhsContext.getChild( 0 ).accept( this );
|
final SqmQualifiedJoin<X, ?> join = (SqmQualifiedJoin<X, ?>) qualifiedJoinRhsContext.getChild( 0 ).accept( this );
|
||||||
|
|
||||||
// we need to set the alias here because the path could be treated - the treat operator is
|
// we need to set the alias here because the path could be treated - the treat operator is
|
||||||
// not consumed by the identifierConsumer
|
// not consumed by the identifierConsumer
|
||||||
join.setExplicitAlias( alias );
|
join.setExplicitAlias( alias );
|
||||||
|
|
||||||
final HqlParser.QualifiedJoinPredicateContext qualifiedJoinPredicateContext = parserJoin.qualifiedJoinPredicate();
|
final HqlParser.QualifiedJoinPredicateContext qualifiedJoinPredicateContext = parserJoin.qualifiedJoinPredicate();
|
||||||
if ( join instanceof SqmEntityJoin ) {
|
if ( join instanceof SqmEntityJoin<?> ) {
|
||||||
//noinspection unchecked
|
|
||||||
sqmRoot.addSqmJoin( join );
|
sqmRoot.addSqmJoin( join );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
final SqmAttributeJoin<?, ?> attributeJoin = (SqmAttributeJoin<?, ?>) join;
|
||||||
if ( getCreationOptions().useStrictJpaCompliance() ) {
|
if ( getCreationOptions().useStrictJpaCompliance() ) {
|
||||||
if ( join.getExplicitAlias() != null ) {
|
if ( join.getExplicitAlias() != null ) {
|
||||||
if ( ( (SqmAttributeJoin<?, ?>) join ).isFetched() ) {
|
if ( attributeJoin.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,7 +1699,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( qualifiedJoinPredicateContext != null && ( (SqmAttributeJoin<?, ?>) join ).isFetched() ) {
|
if ( qualifiedJoinPredicateContext != null && attributeJoin.isFetched() ) {
|
||||||
throw new SemanticException( "with-clause not allowed on fetched associations; use filters" );
|
throw new SemanticException( "with-clause not allowed on fetched associations; use filters" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,10 +91,9 @@ public class TableGroupImpl implements TableGroup {
|
||||||
if ( tableGroupJoins == null ) {
|
if ( tableGroupJoins == null ) {
|
||||||
tableGroupJoins = new ArrayList<>();
|
tableGroupJoins = new ArrayList<>();
|
||||||
}
|
}
|
||||||
if ( !tableGroupJoins.contains( join ) ) {
|
assert !tableGroupJoins.contains( join );
|
||||||
tableGroupJoins.add( join );
|
tableGroupJoins.add( join );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||||
|
|
|
@ -118,11 +118,11 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue
|
||||||
tableAlias,
|
tableAlias,
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
s -> sqlAliasBase,
|
s -> sqlAliasBase,
|
||||||
creationState.getSqlExpressionResolver(),
|
creationState.getSqlExpressionResolver(),
|
||||||
creationState.getCreationContext()
|
creationState.getCreationContext()
|
||||||
);
|
);
|
||||||
|
ownerTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
creationState.getFromClauseAccess().registerTableGroup( fetchPath, tableGroup = tableGroupJoin.getJoinedGroup() );
|
creationState.getFromClauseAccess().registerTableGroup( fetchPath, tableGroup = tableGroupJoin.getJoinedGroup() );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -89,9 +89,9 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
|
||||||
null,
|
null,
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
creationStateImpl
|
creationStateImpl
|
||||||
);
|
);
|
||||||
|
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -70,7 +70,6 @@ public class ImplicitModelPartResultBuilderEmbeddable
|
||||||
null,
|
null,
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
creationStateImpl
|
creationStateImpl
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,9 @@ import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource;
|
||||||
import org.hibernate.query.criteria.JpaPath;
|
import org.hibernate.query.criteria.JpaPath;
|
||||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||||
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
|
||||||
|
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||||
|
import org.hibernate.query.sqm.tree.domain.SqmCorrelatedRootJoin;
|
||||||
|
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
||||||
import org.hibernate.sql.exec.internal.VersionTypeSeedParameterSpecification;
|
import org.hibernate.sql.exec.internal.VersionTypeSeedParameterSpecification;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -1926,12 +1929,24 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
final TableGroup tableGroup;
|
final TableGroup tableGroup;
|
||||||
if ( sqmRoot.isCorrelated() ) {
|
if ( sqmRoot.isCorrelated() ) {
|
||||||
final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory();
|
final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory();
|
||||||
final TableGroup parentTableGroup = fromClauseIndex.findTableGroup(
|
|
||||||
sqmRoot.getCorrelationParent().getNavigablePath()
|
|
||||||
);
|
|
||||||
final EntityPersister entityDescriptor = resolveEntityPersister( sqmRoot.getReferencedPathSource() );
|
final EntityPersister entityDescriptor = resolveEntityPersister( sqmRoot.getReferencedPathSource() );
|
||||||
if ( sqmRoot.containsOnlyInnerJoins() ) {
|
if ( sqmRoot.containsOnlyInnerJoins() ) {
|
||||||
// If we have just inner joins against a correlated root, we can render the joins as references
|
// If we have just inner joins against a correlated root, we can render the joins as references
|
||||||
|
final SqmFrom<?, ?> from;
|
||||||
|
// If we correlate a join, we have to create a special SqmRoot shell called SqmCorrelatedRootJoin.
|
||||||
|
// The only purpose of that is to serve as SqmRoot, which is needed for the FROM clause.
|
||||||
|
// It will always contain just a single correlated join though, which is what is actually correlated
|
||||||
|
if ( sqmRoot instanceof SqmCorrelatedRootJoin<?> ) {
|
||||||
|
assert sqmRoot.getSqmJoins().size() == 1;
|
||||||
|
assert sqmRoot.getSqmJoins().get( 0 ).isCorrelated();
|
||||||
|
from = sqmRoot.getSqmJoins().get( 0 );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
from = sqmRoot;
|
||||||
|
}
|
||||||
|
final TableGroup parentTableGroup = fromClauseIndex.findTableGroup(
|
||||||
|
from.getCorrelationParent().getNavigablePath()
|
||||||
|
);
|
||||||
final SqlAliasBase sqlAliasBase = sqlAliasBaseManager.createSqlAliasBase( parentTableGroup.getGroupAlias() );
|
final SqlAliasBase sqlAliasBase = sqlAliasBaseManager.createSqlAliasBase( parentTableGroup.getGroupAlias() );
|
||||||
tableGroup = new CorrelatedTableGroup(
|
tableGroup = new CorrelatedTableGroup(
|
||||||
parentTableGroup,
|
parentTableGroup,
|
||||||
|
@ -1945,11 +1960,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
);
|
);
|
||||||
|
|
||||||
log.tracef( "Resolved SqmRoot [%s] to correlated TableGroup [%s]", sqmRoot, tableGroup );
|
log.tracef( "Resolved SqmRoot [%s] to correlated TableGroup [%s]", sqmRoot, tableGroup );
|
||||||
|
consumeExplicitJoins( from, tableGroup );
|
||||||
consumeExplicitJoins( sqmRoot, tableGroup );
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
final TableGroup parentTableGroup = fromClauseIndex.findTableGroup(
|
||||||
|
sqmRoot.getCorrelationParent().getNavigablePath()
|
||||||
|
);
|
||||||
// If we have non-inner joins against a correlated root, we must render the root with a correlation predicate
|
// If we have non-inner joins against a correlated root, we must render the root with a correlation predicate
|
||||||
tableGroup = entityDescriptor.createRootTableGroup(
|
tableGroup = entityDescriptor.createRootTableGroup(
|
||||||
true,
|
true,
|
||||||
|
@ -2042,8 +2059,34 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
fromClauseIndex.register( sqmRoot, tableGroup );
|
fromClauseIndex.register( sqmRoot, tableGroup );
|
||||||
currentQuerySpec.getFromClause().addRoot( tableGroup );
|
currentQuerySpec.getFromClause().addRoot( tableGroup );
|
||||||
|
|
||||||
|
if ( sqmRoot.getOrderedJoins() == null ) {
|
||||||
consumeExplicitJoins( sqmRoot, tableGroup );
|
consumeExplicitJoins( sqmRoot, tableGroup );
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if ( log.isTraceEnabled() ) {
|
||||||
|
log.tracef( "Visiting explicit joins for `%s`", sqmRoot.getNavigablePath() );
|
||||||
|
}
|
||||||
|
TableGroup lastTableGroup = tableGroup;
|
||||||
|
for ( SqmJoin<?, ?> join : sqmRoot.getOrderedJoins() ) {
|
||||||
|
final TableGroup ownerTableGroup;
|
||||||
|
if ( join.getLhs() == null ) {
|
||||||
|
ownerTableGroup = tableGroup;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ( join.getLhs() instanceof SqmCorrelation<?, ?> ) {
|
||||||
|
ownerTableGroup = fromClauseIndex.findTableGroup(
|
||||||
|
( (SqmCorrelation<?, ?>) join.getLhs() ).getCorrelatedRoot().getNavigablePath()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ownerTableGroup = fromClauseIndex.findTableGroup( join.getLhs().getNavigablePath() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert ownerTableGroup != null;
|
||||||
|
lastTableGroup = consumeExplicitJoin( join, lastTableGroup, ownerTableGroup, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private EntityPersister resolveEntityPersister(EntityDomainType<?> entityDomainType) {
|
private EntityPersister resolveEntityPersister(EntityDomainType<?> entityDomainType) {
|
||||||
return creationContext.getDomainModel().getEntityDescriptor( entityDomainType.getHibernateEntityName() );
|
return creationContext.getDomainModel().getEntityDescriptor( entityDomainType.getHibernateEntityName() );
|
||||||
|
@ -2054,29 +2097,38 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
log.tracef( "Visiting explicit joins for `%s`", sqmFrom.getNavigablePath() );
|
log.tracef( "Visiting explicit joins for `%s`", sqmFrom.getNavigablePath() );
|
||||||
}
|
}
|
||||||
sqmFrom.visitSqmJoins(
|
sqmFrom.visitSqmJoins(
|
||||||
sqmJoin -> consumeExplicitJoin( sqmJoin, lhsTableGroup )
|
sqmJoin -> consumeExplicitJoin( sqmJoin, lhsTableGroup, lhsTableGroup, true )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
protected void consumeExplicitJoin(SqmJoin<?, ?> sqmJoin, TableGroup lhsTableGroup) {
|
protected TableGroup consumeExplicitJoin(
|
||||||
|
SqmJoin<?, ?> sqmJoin,
|
||||||
|
TableGroup lhsTableGroup,
|
||||||
|
TableGroup ownerTableGroup,
|
||||||
|
boolean transitive) {
|
||||||
if ( sqmJoin instanceof SqmAttributeJoin<?, ?> ) {
|
if ( sqmJoin instanceof SqmAttributeJoin<?, ?> ) {
|
||||||
consumeAttributeJoin( ( (SqmAttributeJoin<?, ?>) sqmJoin ), lhsTableGroup );
|
return consumeAttributeJoin( ( (SqmAttributeJoin<?, ?>) sqmJoin ), lhsTableGroup, ownerTableGroup, transitive );
|
||||||
}
|
}
|
||||||
else if ( sqmJoin instanceof SqmCrossJoin<?> ) {
|
else if ( sqmJoin instanceof SqmCrossJoin<?> ) {
|
||||||
consumeCrossJoin( ( (SqmCrossJoin<?>) sqmJoin ), lhsTableGroup );
|
return consumeCrossJoin( ( (SqmCrossJoin<?>) sqmJoin ), lhsTableGroup, transitive );
|
||||||
}
|
}
|
||||||
else if ( sqmJoin instanceof SqmEntityJoin<?> ) {
|
else if ( sqmJoin instanceof SqmEntityJoin<?> ) {
|
||||||
consumeEntityJoin( ( (SqmEntityJoin<?>) sqmJoin ), lhsTableGroup );
|
return consumeEntityJoin( ( (SqmEntityJoin<?>) sqmJoin ), lhsTableGroup, transitive );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new InterpretationException( "Could not resolve SqmJoin [" + sqmJoin.getNavigablePath() + "] to TableGroupJoin" );
|
throw new InterpretationException( "Could not resolve SqmJoin [" + sqmJoin.getNavigablePath() + "] to TableGroupJoin" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void consumeAttributeJoin(SqmAttributeJoin<?, ?> sqmJoin, TableGroup lhsTableGroup) {
|
private TableGroup consumeAttributeJoin(
|
||||||
|
SqmAttributeJoin<?, ?> sqmJoin,
|
||||||
|
TableGroup lhsTableGroup,
|
||||||
|
TableGroup ownerTableGroup,
|
||||||
|
boolean transitive) {
|
||||||
|
|
||||||
final SqmPathSource<?> pathSource = sqmJoin.getReferencedPathSource();
|
final SqmPathSource<?> pathSource = sqmJoin.getReferencedPathSource();
|
||||||
|
final SqmJoinType sqmJoinType = sqmJoin.getSqmJoinType();
|
||||||
|
|
||||||
final TableGroupJoin joinedTableGroupJoin;
|
final TableGroupJoin joinedTableGroupJoin;
|
||||||
final TableGroup joinedTableGroup;
|
final TableGroup joinedTableGroup;
|
||||||
|
@ -2084,7 +2136,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
final NavigablePath sqmJoinNavigablePath = sqmJoin.getNavigablePath();
|
final NavigablePath sqmJoinNavigablePath = sqmJoin.getNavigablePath();
|
||||||
final NavigablePath parentNavigablePath = sqmJoinNavigablePath.getParent();
|
final NavigablePath parentNavigablePath = sqmJoinNavigablePath.getParent();
|
||||||
|
|
||||||
final ModelPart modelPart = lhsTableGroup.getModelPart().findSubPart(
|
final ModelPart modelPart = ownerTableGroup.getModelPart().findSubPart(
|
||||||
pathSource.getPathName(),
|
pathSource.getPathName(),
|
||||||
SqmMappingModelHelper.resolveExplicitTreatTarget( sqmJoin, this )
|
SqmMappingModelHelper.resolveExplicitTreatTarget( sqmJoin, this )
|
||||||
);
|
);
|
||||||
|
@ -2108,11 +2160,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
|
|
||||||
joinedTableGroupJoin = pluralAttributeMapping.createTableGroupJoin(
|
joinedTableGroupJoin = pluralAttributeMapping.createTableGroupJoin(
|
||||||
joinPath,
|
joinPath,
|
||||||
lhsTableGroup,
|
ownerTableGroup,
|
||||||
sqmJoin.getExplicitAlias(),
|
sqmJoin.getExplicitAlias(),
|
||||||
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
|
sqmJoinType.getCorrespondingSqlJoinType(),
|
||||||
sqmJoin.isFetched(),
|
sqmJoin.isFetched(),
|
||||||
false,
|
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2123,13 +2174,19 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
|
|
||||||
joinedTableGroupJoin = ( (TableGroupJoinProducer) modelPart ).createTableGroupJoin(
|
joinedTableGroupJoin = ( (TableGroupJoinProducer) modelPart ).createTableGroupJoin(
|
||||||
joinPath,
|
joinPath,
|
||||||
lhsTableGroup,
|
ownerTableGroup,
|
||||||
sqmJoin.getExplicitAlias(),
|
sqmJoin.getExplicitAlias(),
|
||||||
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
|
sqmJoinType.getCorrespondingSqlJoinType(),
|
||||||
sqmJoin.isFetched(),
|
sqmJoin.isFetched(),
|
||||||
false,
|
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Since this is an explicit join, we force the initialization of a possible lazy table group
|
||||||
|
// to retain the cardinality, but only if this is a non-trivial attribute join.
|
||||||
|
// Left or inner singular attribute joins without a predicate can be safely optimized away
|
||||||
|
if ( sqmJoin.getJoinPredicate() != null || sqmJoinType != SqmJoinType.INNER && sqmJoinType != SqmJoinType.LEFT ) {
|
||||||
|
joinedTableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
joinedTableGroup = joinedTableGroupJoin.getJoinedGroup();
|
joinedTableGroup = joinedTableGroupJoin.getJoinedGroup();
|
||||||
|
@ -2153,8 +2210,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
currentlyProcessingJoin = oldJoin;
|
currentlyProcessingJoin = oldJoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( transitive ) {
|
||||||
consumeExplicitJoins( sqmJoin, joinedTableGroup );
|
consumeExplicitJoins( sqmJoin, joinedTableGroup );
|
||||||
}
|
}
|
||||||
|
return joinedTableGroup;
|
||||||
|
}
|
||||||
|
|
||||||
private NavigablePath getJoinNavigablePath(
|
private NavigablePath getJoinNavigablePath(
|
||||||
NavigablePath sqmJoinNavigablePath,
|
NavigablePath sqmJoinNavigablePath,
|
||||||
|
@ -2173,7 +2233,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void consumeCrossJoin(SqmCrossJoin sqmJoin, TableGroup lhsTableGroup) {
|
private TableGroup consumeCrossJoin(SqmCrossJoin<?> sqmJoin, TableGroup lhsTableGroup, boolean transitive) {
|
||||||
final EntityPersister entityDescriptor = resolveEntityPersister( sqmJoin.getReferencedPathSource() );
|
final EntityPersister entityDescriptor = resolveEntityPersister( sqmJoin.getReferencedPathSource() );
|
||||||
|
|
||||||
final TableGroup tableGroup = entityDescriptor.createRootTableGroup(
|
final TableGroup tableGroup = entityDescriptor.createRootTableGroup(
|
||||||
|
@ -2198,10 +2258,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
|
|
||||||
getFromClauseIndex().register( sqmJoin, tableGroup );
|
getFromClauseIndex().register( sqmJoin, tableGroup );
|
||||||
|
|
||||||
|
if ( transitive ) {
|
||||||
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||||
}
|
}
|
||||||
|
return tableGroup;
|
||||||
|
}
|
||||||
|
|
||||||
private void consumeEntityJoin(SqmEntityJoin sqmJoin, TableGroup lhsTableGroup) {
|
private TableGroup consumeEntityJoin(SqmEntityJoin<?> sqmJoin, TableGroup lhsTableGroup, boolean transitive) {
|
||||||
final EntityPersister entityDescriptor = resolveEntityPersister( sqmJoin.getReferencedPathSource() );
|
final EntityPersister entityDescriptor = resolveEntityPersister( sqmJoin.getReferencedPathSource() );
|
||||||
|
|
||||||
final SqlAstJoinType correspondingSqlJoinType = sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType();
|
final SqlAstJoinType correspondingSqlJoinType = sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType();
|
||||||
|
@ -2236,9 +2299,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
// Note that we add the entity join after processing the predicate because implicit joins needed in there
|
// 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
|
// can be just ordered right before the entity join without changing the semantics
|
||||||
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
if ( transitive ) {
|
||||||
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||||
}
|
}
|
||||||
|
return tableGroup;
|
||||||
|
}
|
||||||
|
|
||||||
private <X> X prepareReusablePath(SqmPath<?> sqmPath, Supplier<X> supplier) {
|
private <X> X prepareReusablePath(SqmPath<?> sqmPath, Supplier<X> supplier) {
|
||||||
final Consumer<TableGroup> implicitJoinChecker;
|
final Consumer<TableGroup> implicitJoinChecker;
|
||||||
|
@ -2354,13 +2419,20 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
null,
|
null,
|
||||||
defaultSqlAstJoinType,
|
defaultSqlAstJoinType,
|
||||||
false,
|
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
|
this
|
||||||
);
|
);
|
||||||
|
// Implicit joins in the ON clause of attribute joins need to be added as nested table group joins
|
||||||
|
// We don't have to do that for entity joins etc. as these do not have an inherent dependency on the lhs.
|
||||||
|
// We can just add the implicit join before the currently processing join
|
||||||
|
// See consumeEntityJoin for details
|
||||||
|
final boolean nested = currentClauseStack.getCurrent() == Clause.FROM
|
||||||
|
&& currentlyProcessingJoin instanceof SqmAttributeJoin<?, ?>;
|
||||||
|
if ( nested ) {
|
||||||
|
parentTableGroup.addNestedTableGroupJoin( tableGroupJoin );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
}
|
||||||
tableGroup = tableGroupJoin.getJoinedGroup();
|
tableGroup = tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2822,12 +2894,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
null,
|
null,
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
false,
|
false,
|
||||||
false,
|
|
||||||
sqlAliasBaseManager,
|
sqlAliasBaseManager,
|
||||||
getSqlExpressionResolver(),
|
getSqlExpressionResolver(),
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
|
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -4657,16 +4729,17 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
).getExpressionType();
|
).getExpressionType();
|
||||||
// The creation of the table group join against the correlated table group
|
// The creation of the table group join against the correlated table group
|
||||||
// has the side effect that the from and where clause of the sub-query are set
|
// has the side effect that the from and where clause of the sub-query are set
|
||||||
|
tableGroup.addTableGroupJoin(
|
||||||
pluralAttributeMapping.createTableGroupJoin(
|
pluralAttributeMapping.createTableGroupJoin(
|
||||||
pluralPathNavPath,
|
pluralPathNavPath,
|
||||||
tableGroup,
|
tableGroup,
|
||||||
sqmPluralPath.getExplicitAlias(),
|
sqmPluralPath.getExplicitAlias(),
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
false,
|
false,
|
||||||
false,
|
|
||||||
sqlAliasBaseManager,
|
sqlAliasBaseManager,
|
||||||
subQueryState,
|
subQueryState,
|
||||||
creationContext
|
creationContext
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
final ForeignKeyDescriptor collectionKeyDescriptor = pluralAttributeMapping.getKeyDescriptor();
|
final ForeignKeyDescriptor collectionKeyDescriptor = pluralAttributeMapping.getKeyDescriptor();
|
||||||
|
@ -5072,9 +5145,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
alias,
|
alias,
|
||||||
tableGroupJoinProducer.getDefaultSqlAstJoinType( lhs ),
|
tableGroupJoinProducer.getDefaultSqlAstJoinType( lhs ),
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
|
lhs.addTableGroupJoin( tableGroupJoin );
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -311,10 +311,9 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
||||||
null,
|
null,
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
false,
|
false,
|
||||||
false,
|
|
||||||
sqlAstCreationState
|
sqlAstCreationState
|
||||||
);
|
);
|
||||||
|
parentTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||||
import org.hibernate.metamodel.model.domain.SetPersistentAttribute;
|
import org.hibernate.metamodel.model.domain.SetPersistentAttribute;
|
||||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.query.criteria.JpaEntityJoin;
|
||||||
import org.hibernate.query.criteria.JpaPath;
|
import org.hibernate.query.criteria.JpaPath;
|
||||||
import org.hibernate.query.criteria.JpaSelection;
|
import org.hibernate.query.criteria.JpaSelection;
|
||||||
import org.hibernate.query.sqm.NodeBuilder;
|
import org.hibernate.query.sqm.NodeBuilder;
|
||||||
|
@ -43,6 +44,7 @@ import org.hibernate.query.hql.spi.SqmCreationState;
|
||||||
import org.hibernate.query.sqm.spi.SqmCreationHelper;
|
import org.hibernate.query.sqm.spi.SqmCreationHelper;
|
||||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
|
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
|
||||||
|
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmJoin;
|
import org.hibernate.query.sqm.tree.from.SqmJoin;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||||
|
@ -142,7 +144,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasJoins() {
|
public boolean hasJoins() {
|
||||||
return ! (joins == null || joins.isEmpty() );
|
return !( joins == null || joins.isEmpty() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -156,6 +158,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
||||||
joins = new ArrayList<>();
|
joins = new ArrayList<>();
|
||||||
}
|
}
|
||||||
joins.add( join );
|
joins.add( join );
|
||||||
|
findRoot().addOrderedJoin( join );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -408,6 +411,29 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> JpaEntityJoin<X> join(Class<X> entityJavaType) {
|
||||||
|
return join( nodeBuilder().getDomainModel().entity( entityJavaType ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> JpaEntityJoin<X> join(EntityDomainType<X> entity) {
|
||||||
|
return join( entity, SqmJoinType.INNER );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> JpaEntityJoin<X> join(Class<X> entityJavaType, SqmJoinType joinType) {
|
||||||
|
return join( nodeBuilder().getDomainModel().entity( entityJavaType ), joinType );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> JpaEntityJoin<X> join(EntityDomainType<X> entity, SqmJoinType joinType) {
|
||||||
|
final SqmEntityJoin<X> join = new SqmEntityJoin<>( entity, null, joinType, findRoot() );
|
||||||
|
//noinspection unchecked
|
||||||
|
addSqmJoin( (SqmJoin<T, ?>) join );
|
||||||
|
return join;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Fetch<T, ?>> getFetches() {
|
public Set<Fetch<T, ?>> getFetches() {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.query.sqm.tree.from;
|
package org.hibernate.query.sqm.tree.from;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
@ -31,6 +34,7 @@ import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
public class SqmRoot<E> extends AbstractSqmFrom<E,E> implements JpaRoot<E>, DomainResultProducer<E> {
|
public class SqmRoot<E> extends AbstractSqmFrom<E,E> implements JpaRoot<E>, DomainResultProducer<E> {
|
||||||
|
|
||||||
private final boolean allowJoins;
|
private final boolean allowJoins;
|
||||||
|
private List<SqmJoin<?, ?>> orderedJoins;
|
||||||
|
|
||||||
public SqmRoot(
|
public SqmRoot(
|
||||||
EntityDomainType<E> entityType,
|
EntityDomainType<E> entityType,
|
||||||
|
@ -68,6 +72,28 @@ public class SqmRoot<E> extends AbstractSqmFrom<E,E> implements JpaRoot<E>, Doma
|
||||||
return allowJoins;
|
return allowJoins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<SqmJoin<?, ?>> getOrderedJoins() {
|
||||||
|
return orderedJoins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addOrderedJoin(SqmJoin<?, ?> join) {
|
||||||
|
if ( orderedJoins == null ) {
|
||||||
|
// If we encounter anything but an attribute join, we need to order joins strictly
|
||||||
|
if ( !( join instanceof SqmAttributeJoin<?, ?> ) ) {
|
||||||
|
orderedJoins = new ArrayList<>();
|
||||||
|
visitSqmJoins( this::addOrderedJoinTransitive );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
orderedJoins.add( join );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addOrderedJoinTransitive(SqmJoin<?, ?> join) {
|
||||||
|
orderedJoins.add( join );
|
||||||
|
join.visitSqmJoins( this::addOrderedJoinTransitive );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addSqmJoin(SqmJoin<E, ?> join) {
|
public void addSqmJoin(SqmJoin<E, ?> join) {
|
||||||
if ( !allowJoins ) {
|
if ( !allowJoins ) {
|
||||||
|
@ -127,29 +153,6 @@ public class SqmRoot<E> extends AbstractSqmFrom<E,E> implements JpaRoot<E>, Doma
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public <X> JpaEntityJoin<X> join(Class<X> entityJavaType) {
|
|
||||||
return join( nodeBuilder().getDomainModel().entity( entityJavaType ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <X> JpaEntityJoin<X> join(EntityDomainType<X> entity) {
|
|
||||||
return join( entity, SqmJoinType.INNER );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <X> JpaEntityJoin<X> join(Class<X> entityJavaType, SqmJoinType joinType) {
|
|
||||||
return join( nodeBuilder().getDomainModel().entity( entityJavaType ), joinType );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <X> JpaEntityJoin<X> join(EntityDomainType<X> entity, SqmJoinType joinType) {
|
|
||||||
final SqmEntityJoin<X> join = new SqmEntityJoin<>( entity, null, joinType, this );
|
|
||||||
//noinspection unchecked
|
|
||||||
addSqmJoin( (SqmJoin<E, ?>) join );
|
|
||||||
return join;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityDomainType<E> getModel() {
|
public EntityDomainType<E> getModel() {
|
||||||
return getReferencedPathSource();
|
return getReferencedPathSource();
|
||||||
|
|
|
@ -107,20 +107,18 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie
|
||||||
if ( tableGroupJoins == null ) {
|
if ( tableGroupJoins == null ) {
|
||||||
tableGroupJoins = new ArrayList<>();
|
tableGroupJoins = new ArrayList<>();
|
||||||
}
|
}
|
||||||
if ( !tableGroupJoins.contains( join ) ) {
|
assert !tableGroupJoins.contains( join );
|
||||||
tableGroupJoins.add( join );
|
tableGroupJoins.add( join );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||||
if ( nestedTableGroupJoins == null ) {
|
if ( nestedTableGroupJoins == null ) {
|
||||||
nestedTableGroupJoins = new ArrayList<>();
|
nestedTableGroupJoins = new ArrayList<>();
|
||||||
}
|
}
|
||||||
if ( !nestedTableGroupJoins.contains( join ) ) {
|
assert !nestedTableGroupJoins.contains( join );
|
||||||
nestedTableGroupJoins.add( join );
|
nestedTableGroupJoins.add( join );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||||
|
|
|
@ -94,20 +94,18 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
||||||
if ( tableGroupJoins == null ) {
|
if ( tableGroupJoins == null ) {
|
||||||
tableGroupJoins = new ArrayList<>();
|
tableGroupJoins = new ArrayList<>();
|
||||||
}
|
}
|
||||||
if ( !tableGroupJoins.contains( join ) ) {
|
assert !tableGroupJoins.contains( join );
|
||||||
tableGroupJoins.add( join );
|
tableGroupJoins.add( join );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||||
if ( nestedTableGroupJoins == null ) {
|
if ( nestedTableGroupJoins == null ) {
|
||||||
nestedTableGroupJoins = new ArrayList<>();
|
nestedTableGroupJoins = new ArrayList<>();
|
||||||
}
|
}
|
||||||
if ( !nestedTableGroupJoins.contains( join ) ) {
|
assert !nestedTableGroupJoins.contains( join );
|
||||||
nestedTableGroupJoins.add( join );
|
nestedTableGroupJoins.add( join );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||||
|
|
|
@ -49,9 +49,7 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTableGroupJoin(TableGroupJoin join) {
|
public void addTableGroupJoin(TableGroupJoin join) {
|
||||||
if ( getTableGroupJoins().contains( join ) ) {
|
assert !getTableGroupJoins().contains( join );
|
||||||
return;
|
|
||||||
}
|
|
||||||
assert join.getJoinType() == SqlAstJoinType.INNER;
|
assert join.getJoinType() == SqlAstJoinType.INNER;
|
||||||
querySpec.getFromClause().addRoot( join.getJoinedGroup() );
|
querySpec.getFromClause().addRoot( join.getJoinedGroup() );
|
||||||
joinPredicateConsumer.accept( join.getPredicate() );
|
joinPredicateConsumer.accept( join.getPredicate() );
|
||||||
|
|
|
@ -32,7 +32,6 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
boolean nested,
|
|
||||||
SqlAstCreationState creationState) {
|
SqlAstCreationState creationState) {
|
||||||
return createTableGroupJoin(
|
return createTableGroupJoin(
|
||||||
navigablePath,
|
navigablePath,
|
||||||
|
@ -40,7 +39,6 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
|
||||||
explicitSourceAlias,
|
explicitSourceAlias,
|
||||||
sqlAstJoinType,
|
sqlAstJoinType,
|
||||||
fetched,
|
fetched,
|
||||||
nested,
|
|
||||||
creationState.getSqlAliasBaseGenerator(),
|
creationState.getSqlAliasBaseGenerator(),
|
||||||
creationState.getSqlExpressionResolver(),
|
creationState.getSqlExpressionResolver(),
|
||||||
creationState.getCreationContext()
|
creationState.getCreationContext()
|
||||||
|
@ -56,7 +54,6 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
|
||||||
String explicitSourceAlias,
|
String explicitSourceAlias,
|
||||||
SqlAstJoinType sqlAstJoinType,
|
SqlAstJoinType sqlAstJoinType,
|
||||||
boolean fetched,
|
boolean fetched,
|
||||||
boolean nested,
|
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext);
|
SqlAstCreationContext creationContext);
|
||||||
|
|
|
@ -92,20 +92,18 @@ public class UnionTableGroup implements VirtualTableGroup {
|
||||||
if ( tableGroupJoins == null ) {
|
if ( tableGroupJoins == null ) {
|
||||||
tableGroupJoins = new ArrayList<>();
|
tableGroupJoins = new ArrayList<>();
|
||||||
}
|
}
|
||||||
if ( !tableGroupJoins.contains( join ) ) {
|
assert !tableGroupJoins.contains( join );
|
||||||
tableGroupJoins.add( join );
|
tableGroupJoins.add( join );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
public void addNestedTableGroupJoin(TableGroupJoin join) {
|
||||||
if ( nestedTableGroupJoins == null ) {
|
if ( nestedTableGroupJoins == null ) {
|
||||||
nestedTableGroupJoins = new ArrayList<>();
|
nestedTableGroupJoins = new ArrayList<>();
|
||||||
}
|
}
|
||||||
if ( !nestedTableGroupJoins.contains( join ) ) {
|
assert !nestedTableGroupJoins.contains( join );
|
||||||
nestedTableGroupJoins.add( join );
|
nestedTableGroupJoins.add( join );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||||
|
|
|
@ -68,9 +68,9 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
|
||||||
null,
|
null,
|
||||||
nullable ? SqlAstJoinType.LEFT : SqlAstJoinType.INNER,
|
nullable ? SqlAstJoinType.LEFT : SqlAstJoinType.INNER,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
creationState.getSqlAstCreationState()
|
creationState.getSqlAstCreationState()
|
||||||
);
|
);
|
||||||
|
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,10 +54,9 @@ public class EmbeddableResultImpl<T> extends AbstractFetchParent implements Embe
|
||||||
resultVariable,
|
resultVariable,
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
creationState.getSqlAstCreationState()
|
creationState.getSqlAstCreationState()
|
||||||
);
|
);
|
||||||
|
tableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -128,6 +128,28 @@ public class OuterJoinTest {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinOrderAttributeJoinDependsOnEntityJoin(EntityManagerFactoryScope scope) {
|
||||||
|
scope.inTransaction( em -> {
|
||||||
|
List<Tuple> resultList = em.createQuery(
|
||||||
|
"SELECT a.value, b.value, c.value " +
|
||||||
|
"FROM A a " +
|
||||||
|
"INNER JOIN a.cAssociationByKey c " +
|
||||||
|
"INNER JOIN B b ON a.key = b.key " +
|
||||||
|
"INNER JOIN c.association ca ON ca.key = b.key " +
|
||||||
|
"ORDER BY a.key, b.key, c.key",
|
||||||
|
Tuple.class
|
||||||
|
)
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
assertEquals( 1, resultList.size() );
|
||||||
|
|
||||||
|
assertEquals( "a", resultList.get( 0 ).get( 0 ) );
|
||||||
|
assertEquals( "d", resultList.get( 0 ).get( 1 ) );
|
||||||
|
assertEquals( "g", resultList.get( 0 ).get( 2 ) );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJoinOrderWithRightNormalJoin(EntityManagerFactoryScope scope) {
|
public void testJoinOrderWithRightNormalJoin(EntityManagerFactoryScope scope) {
|
||||||
scope.inTransaction( em -> {
|
scope.inTransaction( em -> {
|
||||||
|
|
Loading…
Reference in New Issue