HHH-17001 Visit nested joins and predicates only once through special consume methods in BaseSemanticQueryWalker
This commit is contained in:
parent
861774fd8e
commit
b3ec2cd943
|
@ -10,6 +10,7 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
|
||||
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPath;
|
||||
import org.hibernate.query.sqm.InterpretationException;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.tree.SqmVisitableNode;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteContainer;
|
||||
|
@ -74,7 +75,9 @@ import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
|
|||
import org.hibernate.query.sqm.tree.from.SqmCteJoin;
|
||||
import org.hibernate.query.sqm.tree.from.SqmDerivedJoin;
|
||||
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
|
||||
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
||||
import org.hibernate.query.sqm.tree.from.SqmFromClause;
|
||||
import org.hibernate.query.sqm.tree.from.SqmJoin;
|
||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
|
||||
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
|
||||
|
@ -110,6 +113,8 @@ import org.hibernate.query.sqm.tree.select.SqmSubQuery;
|
|||
import org.hibernate.query.sqm.tree.update.SqmAssignment;
|
||||
import org.hibernate.query.sqm.tree.update.SqmSetClause;
|
||||
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
|
||||
import org.hibernate.sql.ast.spi.SqlAstQueryPartProcessingState;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
|
@ -247,84 +252,166 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
|
||||
@Override
|
||||
public Object visitFromClause(SqmFromClause fromClause) {
|
||||
fromClause.visitRoots( root -> root.accept( this ) );
|
||||
fromClause.visitRoots( this::consumeFromClauseRoot );
|
||||
return fromClause;
|
||||
}
|
||||
|
||||
protected void consumeFromClauseRoot(SqmRoot<?> sqmRoot) {
|
||||
if ( sqmRoot instanceof SqmDerivedRoot<?> ) {
|
||||
( (SqmDerivedRoot<?>) sqmRoot ).getQueryPart().accept( this );
|
||||
}
|
||||
consumeJoins( sqmRoot );
|
||||
}
|
||||
|
||||
private void consumeJoins(SqmRoot<?> sqmRoot) {
|
||||
if ( sqmRoot.getOrderedJoins() == null ) {
|
||||
consumeExplicitJoins( sqmRoot );
|
||||
}
|
||||
else {
|
||||
for ( SqmJoin<?, ?> join : sqmRoot.getOrderedJoins() ) {
|
||||
consumeExplicitJoin( join, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumeExplicitJoins(SqmFrom<?, ?> sqmFrom) {
|
||||
sqmFrom.visitSqmJoins(
|
||||
sqmJoin -> {
|
||||
consumeExplicitJoin( sqmJoin, true );
|
||||
}
|
||||
);
|
||||
final List<SqmFrom<?, ?>> sqmTreats = sqmFrom.getSqmTreats();
|
||||
if ( !sqmTreats.isEmpty() ) {
|
||||
for ( SqmFrom<?, ?> sqmTreat : sqmTreats ) {
|
||||
consumeTreat( sqmTreat );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumeTreat(SqmFrom<?, ?> sqmTreat) {
|
||||
consumeExplicitJoins( sqmTreat );
|
||||
}
|
||||
|
||||
protected void consumeExplicitJoin(
|
||||
SqmJoin<?, ?> sqmJoin,
|
||||
boolean transitive) {
|
||||
if ( sqmJoin instanceof SqmAttributeJoin<?, ?> ) {
|
||||
consumeAttributeJoin( ( (SqmAttributeJoin<?, ?>) sqmJoin ), transitive );
|
||||
}
|
||||
else if ( sqmJoin instanceof SqmCrossJoin<?> ) {
|
||||
consumeCrossJoin( ( (SqmCrossJoin<?>) sqmJoin ), transitive );
|
||||
}
|
||||
else if ( sqmJoin instanceof SqmEntityJoin<?> ) {
|
||||
consumeEntityJoin( ( (SqmEntityJoin<?>) sqmJoin ), transitive );
|
||||
}
|
||||
else if ( sqmJoin instanceof SqmDerivedJoin<?> ) {
|
||||
consumeDerivedJoin( ( (SqmDerivedJoin<?>) sqmJoin ), transitive );
|
||||
}
|
||||
else if ( sqmJoin instanceof SqmCteJoin<?> ) {
|
||||
consumeCteJoin( ( (SqmCteJoin<?>) sqmJoin ), transitive );
|
||||
}
|
||||
else if ( sqmJoin instanceof SqmPluralPartJoin<?, ?> ) {
|
||||
consumePluralPartJoin( ( (SqmPluralPartJoin<?, ?>) sqmJoin ), transitive );
|
||||
}
|
||||
else {
|
||||
throw new InterpretationException( "Could not visit SqmJoin [" + sqmJoin.getNavigablePath() + "] of type [" + sqmJoin.getClass().getName() + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumeAttributeJoin(SqmAttributeJoin<?, ?> sqmJoin, boolean transitive) {
|
||||
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||
sqmJoin.getJoinPredicate().accept( this );
|
||||
}
|
||||
if ( transitive ) {
|
||||
consumeExplicitJoins( sqmJoin );
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumeCrossJoin(SqmCrossJoin<?> sqmJoin, boolean transitive) {
|
||||
if ( transitive ) {
|
||||
consumeExplicitJoins( sqmJoin );
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumeEntityJoin(SqmEntityJoin<?> sqmJoin, boolean transitive) {
|
||||
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||
sqmJoin.getJoinPredicate().accept( this );
|
||||
}
|
||||
if ( transitive ) {
|
||||
consumeExplicitJoins( sqmJoin );
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumeDerivedJoin(SqmDerivedJoin<?> sqmJoin, boolean transitive) {
|
||||
sqmJoin.getQueryPart().accept( this );
|
||||
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||
sqmJoin.getJoinPredicate().accept( this );
|
||||
}
|
||||
if ( transitive ) {
|
||||
consumeExplicitJoins( sqmJoin );
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumeCteJoin(SqmCteJoin<?> sqmJoin, boolean transitive) {
|
||||
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||
sqmJoin.getJoinPredicate().accept( this );
|
||||
}
|
||||
if ( transitive ) {
|
||||
consumeExplicitJoins( sqmJoin );
|
||||
}
|
||||
}
|
||||
|
||||
protected void consumePluralPartJoin(SqmPluralPartJoin<?, ?> sqmJoin, boolean transitive) {
|
||||
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||
sqmJoin.getJoinPredicate().accept( this );
|
||||
}
|
||||
if ( transitive ) {
|
||||
consumeExplicitJoins( sqmJoin );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitRootPath(SqmRoot<?> sqmRoot) {
|
||||
sqmRoot.visitReusablePaths( path -> path.accept( this ) );
|
||||
sqmRoot.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
return sqmRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitRootDerived(SqmDerivedRoot<?> sqmRoot) {
|
||||
sqmRoot.getQueryPart().accept( this );
|
||||
sqmRoot.visitReusablePaths( path -> path.accept( this ) );
|
||||
sqmRoot.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
return sqmRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitRootCte(SqmCteRoot<?> sqmRoot) {
|
||||
sqmRoot.visitReusablePaths( path -> path.accept( this ) );
|
||||
sqmRoot.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
return sqmRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitCrossJoin(SqmCrossJoin<?> joinedFromElement) {
|
||||
joinedFromElement.visitReusablePaths( path -> path.accept( this ) );
|
||||
joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
return joinedFromElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitPluralPartJoin(SqmPluralPartJoin<?, ?> joinedFromElement) {
|
||||
joinedFromElement.visitReusablePaths( path -> path.accept( this ) );
|
||||
joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
return joinedFromElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitQualifiedEntityJoin(SqmEntityJoin<?> joinedFromElement) {
|
||||
joinedFromElement.visitReusablePaths( path -> path.accept( this ) );
|
||||
joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
if ( joinedFromElement.getJoinPredicate() != null ) {
|
||||
joinedFromElement.getJoinPredicate().accept( this );
|
||||
}
|
||||
return joinedFromElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitQualifiedAttributeJoin(SqmAttributeJoin<?,?> joinedFromElement) {
|
||||
joinedFromElement.visitReusablePaths( path -> path.accept( this ) );
|
||||
joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
if ( joinedFromElement.getJoinPredicate() != null ) {
|
||||
joinedFromElement.getJoinPredicate().accept( this );
|
||||
}
|
||||
return joinedFromElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitQualifiedDerivedJoin(SqmDerivedJoin<?> joinedFromElement) {
|
||||
joinedFromElement.getQueryPart().accept( this );
|
||||
joinedFromElement.visitReusablePaths( path -> path.accept( this ) );
|
||||
joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
if ( joinedFromElement.getJoinPredicate() != null ) {
|
||||
joinedFromElement.getJoinPredicate().accept( this );
|
||||
}
|
||||
return joinedFromElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitQualifiedCteJoin(SqmCteJoin<?> joinedFromElement) {
|
||||
joinedFromElement.visitReusablePaths( path -> path.accept( this ) );
|
||||
joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
if ( joinedFromElement.getJoinPredicate() != null ) {
|
||||
joinedFromElement.getJoinPredicate().accept( this );
|
||||
}
|
||||
return joinedFromElement;
|
||||
}
|
||||
|
||||
|
@ -385,8 +472,6 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
|
||||
@Override
|
||||
public Object visitCorrelation(SqmCorrelation<?, ?> correlation) {
|
||||
correlation.visitReusablePaths( path -> path.accept( this ) );
|
||||
correlation.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) );
|
||||
return correlation;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.hibernate.query.sqm.SqmExpressible;
|
|||
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.tree.SqmExpressibleAccessor;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.SqmVisitableNode;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath;
|
||||
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
||||
|
@ -98,7 +99,7 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
|
||||
@Override
|
||||
public Object visitFunction(SqmFunction<?> sqmFunction) {
|
||||
SqmExpressibleAccessor<?> current = inferenceBasis;
|
||||
final SqmExpressibleAccessor<?> current = inferenceBasis;
|
||||
inferenceBasis = null;
|
||||
super.visitFunction( sqmFunction );
|
||||
inferenceBasis = current;
|
||||
|
@ -140,11 +141,11 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
|
||||
private SqmExpressibleAccessor<?> inferenceBasis;
|
||||
|
||||
private void withTypeInference(SqmExpressibleAccessor<?> inferenceBasis, Runnable action) {
|
||||
private void withTypeInference(SqmExpressibleAccessor<?> inferenceBasis, SqmVisitableNode sqmVisitableNode) {
|
||||
SqmExpressibleAccessor<?> original = this.inferenceBasis;
|
||||
this.inferenceBasis = inferenceBasis;
|
||||
try {
|
||||
action.run();
|
||||
sqmVisitableNode.accept( this );
|
||||
}
|
||||
finally {
|
||||
this.inferenceBasis = original;
|
||||
|
@ -164,17 +165,17 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
}
|
||||
return null;
|
||||
},
|
||||
() -> expression.getFixture().accept( this )
|
||||
expression.getFixture()
|
||||
);
|
||||
SqmExpressibleAccessor<?> resolved = determineCurrentExpressible( expression );
|
||||
for ( SqmCaseSimple.WhenFragment<?, ?> whenFragment : expression.getWhenFragments() ) {
|
||||
withTypeInference(
|
||||
expression.getFixture(),
|
||||
() -> whenFragment.getCheckValue().accept( this )
|
||||
whenFragment.getCheckValue()
|
||||
);
|
||||
withTypeInference(
|
||||
resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved,
|
||||
() -> whenFragment.getResult().accept( this )
|
||||
whenFragment.getResult()
|
||||
);
|
||||
resolved = highestPrecedence( resolved, whenFragment.getResult() );
|
||||
}
|
||||
|
@ -182,7 +183,7 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
if ( expression.getOtherwise() != null ) {
|
||||
withTypeInference(
|
||||
resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved,
|
||||
() -> expression.getOtherwise().accept( this )
|
||||
expression.getOtherwise()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -197,11 +198,11 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
for ( SqmCaseSearched.WhenFragment<?> whenFragment : expression.getWhenFragments() ) {
|
||||
withTypeInference(
|
||||
null,
|
||||
() -> whenFragment.getPredicate().accept( this )
|
||||
whenFragment.getPredicate()
|
||||
);
|
||||
withTypeInference(
|
||||
resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved,
|
||||
() -> whenFragment.getResult().accept( this )
|
||||
whenFragment.getResult()
|
||||
);
|
||||
resolved = highestPrecedence( resolved, whenFragment.getResult() );
|
||||
}
|
||||
|
@ -209,7 +210,7 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
if ( expression.getOtherwise() != null ) {
|
||||
withTypeInference(
|
||||
resolved == null && inferenceSupplier != null ? inferenceSupplier : resolved,
|
||||
() -> expression.getOtherwise().accept( this )
|
||||
expression.getOtherwise()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -245,60 +246,56 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
@Override
|
||||
public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath<?> path) {
|
||||
path.getLhs().accept( this );
|
||||
withTypeInference( path.getPluralAttribute().getIndexPathSource(), () -> path.getSelectorExpression().accept( this ) );
|
||||
withTypeInference( path.getPluralAttribute().getIndexPathSource(), path.getSelectorExpression() );
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitIsEmptyPredicate(SqmEmptinessPredicate predicate) {
|
||||
withTypeInference( null, () -> super.visitIsEmptyPredicate( predicate ) );
|
||||
final SqmExpressibleAccessor<?> original = this.inferenceBasis;
|
||||
this.inferenceBasis = null;
|
||||
super.visitIsEmptyPredicate( predicate );
|
||||
this.inferenceBasis = original;
|
||||
return predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitIsNullPredicate(SqmNullnessPredicate predicate) {
|
||||
withTypeInference( null, () -> super.visitIsNullPredicate( predicate ) );
|
||||
final SqmExpressibleAccessor<?> original = this.inferenceBasis;
|
||||
this.inferenceBasis = null;
|
||||
super.visitIsNullPredicate( predicate );
|
||||
this.inferenceBasis = original;
|
||||
return predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitComparisonPredicate(SqmComparisonPredicate predicate) {
|
||||
withTypeInference( predicate.getRightHandExpression(), () -> predicate.getLeftHandExpression().accept( this ) );
|
||||
withTypeInference( predicate.getLeftHandExpression(), () -> predicate.getRightHandExpression().accept( this ) );
|
||||
withTypeInference( predicate.getRightHandExpression(), predicate.getLeftHandExpression() );
|
||||
withTypeInference( predicate.getLeftHandExpression(), predicate.getRightHandExpression() );
|
||||
return predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitBetweenPredicate(SqmBetweenPredicate predicate) {
|
||||
withTypeInference( predicate.getLowerBound(), () -> predicate.getExpression().accept( this ) );
|
||||
withTypeInference(
|
||||
predicate.getExpression(),
|
||||
() -> {
|
||||
predicate.getLowerBound().accept( this );
|
||||
predicate.getUpperBound().accept( this );
|
||||
}
|
||||
);
|
||||
withTypeInference( predicate.getLowerBound(), predicate.getExpression() );
|
||||
withTypeInference( predicate.getExpression(), predicate.getLowerBound() );
|
||||
withTypeInference( predicate.getExpression(), predicate.getUpperBound() );
|
||||
return predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitLikePredicate(SqmLikePredicate predicate) {
|
||||
withTypeInference( predicate.getPattern(), () -> predicate.getMatchExpression().accept( this ) );
|
||||
withTypeInference(
|
||||
predicate.getMatchExpression(),
|
||||
() -> {
|
||||
predicate.getPattern().accept( this );
|
||||
withTypeInference( predicate.getPattern(), predicate.getMatchExpression() );
|
||||
withTypeInference( predicate.getMatchExpression(), predicate.getPattern() );
|
||||
if ( predicate.getEscapeCharacter() != null ) {
|
||||
predicate.getEscapeCharacter().accept( this );
|
||||
withTypeInference( predicate.getMatchExpression(), predicate.getEscapeCharacter() );
|
||||
}
|
||||
}
|
||||
);
|
||||
return predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMemberOfPredicate(SqmMemberOfPredicate predicate) {
|
||||
withTypeInference( predicate.getPluralPath(), () -> predicate.getLeftHandExpression().accept( this ) );
|
||||
withTypeInference( predicate.getPluralPath(), predicate.getLeftHandExpression() );
|
||||
predicate.getPluralPath().accept( this );
|
||||
return predicate;
|
||||
}
|
||||
|
@ -308,22 +305,17 @@ public class ParameterCollector extends BaseSemanticQueryWalker {
|
|||
final SqmExpression<?> firstListElement = predicate.getListExpressions().isEmpty()
|
||||
? null
|
||||
: predicate.getListExpressions().get( 0 );
|
||||
withTypeInference( firstListElement, () -> predicate.getTestExpression().accept( this ) );
|
||||
withTypeInference(
|
||||
predicate.getTestExpression(),
|
||||
() -> {
|
||||
withTypeInference( firstListElement, predicate.getTestExpression() );
|
||||
for ( SqmExpression<?> expression : predicate.getListExpressions() ) {
|
||||
expression.accept( this );
|
||||
withTypeInference( predicate.getTestExpression(), expression );
|
||||
}
|
||||
}
|
||||
);
|
||||
return predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitInSubQueryPredicate(SqmInSubQueryPredicate<?> predicate) {
|
||||
withTypeInference( predicate.getSubQueryExpression(), () -> predicate.getTestExpression().accept( this ) );
|
||||
withTypeInference( predicate.getTestExpression(), () -> predicate.getSubQueryExpression().accept( this ) );
|
||||
withTypeInference( predicate.getSubQueryExpression(), predicate.getTestExpression() );
|
||||
withTypeInference( predicate.getTestExpression(), predicate.getSubQueryExpression() );
|
||||
return predicate;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue