Flatten the junctions in the SQM model

This commit is contained in:
Christian Beikov 2022-03-03 17:54:32 +01:00
parent 71e3b5277a
commit 0a73425520
11 changed files with 273 additions and 375 deletions

View File

@ -49,17 +49,16 @@
import org.hibernate.query.sqm.tree.from.SqmFromClause; import org.hibernate.query.sqm.tree.from.SqmFromClause;
import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmJunctionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate; import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate; import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
@ -598,19 +597,14 @@ public SqmGroupedPredicate visitGroupedPredicate(SqmGroupedPredicate predicate)
} }
@Override @Override
public SqmAndPredicate visitAndPredicate(SqmAndPredicate predicate) { public SqmJunctionPredicate visitJunctionPredicate(SqmJunctionPredicate predicate) {
return new SqmAndPredicate( final List<SqmPredicate> predicates = new ArrayList<>( predicate.getPredicates().size() );
(SqmPredicate) predicate.getLeftHandPredicate().accept( this ), for ( SqmPredicate subPredicate : predicate.getPredicates() ) {
(SqmPredicate) predicate.getRightHandPredicate().accept( this ), predicates.add( (SqmPredicate) subPredicate.accept( this ) );
getCreationContext().getNodeBuilder() }
); return new SqmJunctionPredicate(
} predicate.getOperator(),
predicates,
@Override
public SqmOrPredicate visitOrPredicate(SqmOrPredicate predicate) {
return new SqmOrPredicate(
(SqmPredicate) predicate.getLeftHandPredicate().accept( this ),
(SqmPredicate) predicate.getRightHandPredicate().accept( this ),
getCreationContext().getNodeBuilder() getCreationContext().getNodeBuilder()
); );
} }

View File

@ -151,7 +151,6 @@
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.insert.SqmValues;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
@ -160,12 +159,12 @@
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmJunctionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate; import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate; import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatablePredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatablePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.AbstractSqmSelectQuery; import org.hibernate.query.sqm.tree.select.AbstractSqmSelectQuery;
@ -191,6 +190,7 @@
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.metamodel.SingularAttribute; import jakarta.persistence.metamodel.SingularAttribute;
import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
@ -1784,18 +1784,41 @@ public SqmGroupedPredicate visitGroupedPredicate(HqlParser.GroupedPredicateConte
@Override @Override
public SqmPredicate visitAndPredicate(HqlParser.AndPredicateContext ctx) { public SqmPredicate visitAndPredicate(HqlParser.AndPredicateContext ctx) {
return new SqmAndPredicate( return junction(
Predicate.BooleanOperator.AND,
(SqmPredicate) ctx.getChild( 0 ).accept( this ), (SqmPredicate) ctx.getChild( 0 ).accept( this ),
(SqmPredicate) ctx.getChild( 2 ).accept( this ), (SqmPredicate) ctx.getChild( 2 ).accept( this )
creationContext.getNodeBuilder()
); );
} }
@Override @Override
public SqmPredicate visitOrPredicate(HqlParser.OrPredicateContext ctx) { public SqmPredicate visitOrPredicate(HqlParser.OrPredicateContext ctx) {
return new SqmOrPredicate( return junction(
Predicate.BooleanOperator.OR,
(SqmPredicate) ctx.getChild( 0 ).accept( this ), (SqmPredicate) ctx.getChild( 0 ).accept( this ),
(SqmPredicate) ctx.getChild( 2 ).accept( this ), (SqmPredicate) ctx.getChild( 2 ).accept( this )
);
}
private SqmPredicate junction(Predicate.BooleanOperator operator, SqmPredicate lhs, SqmPredicate rhs) {
if ( lhs instanceof SqmJunctionPredicate ) {
final SqmJunctionPredicate junction = (SqmJunctionPredicate) lhs;
if ( junction.getOperator() == operator ) {
junction.getPredicates().add( rhs );
return junction;
}
}
if ( rhs instanceof SqmJunctionPredicate ) {
final SqmJunctionPredicate junction = (SqmJunctionPredicate) rhs;
if ( junction.getOperator() == operator ) {
junction.getPredicates().add( 0, lhs );
return junction;
}
}
return new SqmJunctionPredicate(
operator,
lhs,
rhs,
creationContext.getNodeBuilder() creationContext.getNodeBuilder()
); );
} }

View File

@ -66,7 +66,6 @@
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.insert.SqmValues;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
@ -75,11 +74,11 @@
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmJunctionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate; import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate; import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
@ -256,9 +255,7 @@ public interface SemanticQueryWalker<T> {
T visitGroupedPredicate(SqmGroupedPredicate predicate); T visitGroupedPredicate(SqmGroupedPredicate predicate);
T visitAndPredicate(SqmAndPredicate predicate); T visitJunctionPredicate(SqmJunctionPredicate predicate);
T visitOrPredicate(SqmOrPredicate predicate);
T visitComparisonPredicate(SqmComparisonPredicate predicate); T visitComparisonPredicate(SqmComparisonPredicate predicate);

View File

@ -51,7 +51,6 @@
import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.criteria.JpaCriteriaQuery;
import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.criteria.JpaOrder; import org.hibernate.query.criteria.JpaOrder;
import org.hibernate.query.criteria.JpaParameterExpression;
import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.criteria.ValueHandlingMode; import org.hibernate.query.criteria.ValueHandlingMode;
import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryEngine;
@ -90,7 +89,6 @@
import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation; import org.hibernate.query.sqm.tree.expression.SqmUnaryOperation;
import org.hibernate.query.sqm.tree.from.SqmRoot; import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
@ -99,10 +97,10 @@
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmJunctionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate; import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate; import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationArgument; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationArgument;
@ -337,13 +335,11 @@ public final SqmPredicate wrap(Expression<Boolean>... expressions) {
return wrap( expressions[0] ); return wrap( expressions[0] );
} }
final SqmPredicate lhs = wrap( expressions[0] ); final List<SqmPredicate> predicates = new ArrayList<>( expressions.length );
final SqmPredicate rhs = wrap( expressions[1] ); for ( Expression<Boolean> expression : expressions ) {
SqmPredicate predicate = new SqmAndPredicate( lhs, rhs, this ); predicates.add( wrap( expression ) );
for ( int i = 2; i < expressions.length; i++ ) {
predicate = new SqmAndPredicate( predicate, wrap( expressions[i] ), this );
} }
return predicate; return new SqmJunctionPredicate( Predicate.BooleanOperator.AND, predicates, this );
} }
@Override @Override
@ -1567,7 +1563,8 @@ public <R> SqmCaseSearched<R> selectCase() {
@Override @Override
public SqmPredicate and(Expression<Boolean> x, Expression<Boolean> y) { public SqmPredicate and(Expression<Boolean> x, Expression<Boolean> y) {
return new SqmAndPredicate( return new SqmJunctionPredicate(
Predicate.BooleanOperator.AND,
wrap( x ), wrap( x ),
wrap( y ), wrap( y ),
this this
@ -1580,17 +1577,17 @@ public SqmPredicate and(Predicate... restrictions) {
return conjunction(); return conjunction();
} }
SqmPredicate junction = (SqmPredicate) restrictions[0]; final List<SqmPredicate> predicates = new ArrayList<>( restrictions.length );
for ( int i = 1; i < restrictions.length; i++ ) { for ( Predicate expression : restrictions ) {
junction = new SqmAndPredicate( junction, (SqmPredicate) restrictions[i], this ); predicates.add( (SqmPredicate) expression );
} }
return new SqmJunctionPredicate( Predicate.BooleanOperator.AND, predicates, this );
return junction;
} }
@Override @Override
public SqmPredicate or(Expression<Boolean> x, Expression<Boolean> y) { public SqmPredicate or(Expression<Boolean> x, Expression<Boolean> y) {
return new SqmOrPredicate( return new SqmJunctionPredicate(
Predicate.BooleanOperator.OR,
wrap( x ), wrap( x ),
wrap( y ), wrap( y ),
this this
@ -1603,12 +1600,11 @@ public SqmPredicate or(Predicate... restrictions) {
return disjunction(); return disjunction();
} }
SqmPredicate junction = (SqmPredicate) restrictions[0]; final List<SqmPredicate> predicates = new ArrayList<>( restrictions.length );
for ( int i = 1; i < restrictions.length; i++ ) { for ( Predicate expression : restrictions ) {
junction = new SqmOrPredicate( junction, (SqmPredicate) restrictions[i], this ); predicates.add( (SqmPredicate) expression );
} }
return new SqmJunctionPredicate( Predicate.BooleanOperator.OR, predicates, this );
return junction;
} }
@Override @Override

View File

@ -73,7 +73,6 @@
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.insert.SqmValues;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
@ -82,11 +81,11 @@
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmJunctionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate; import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate; import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
@ -107,6 +106,8 @@
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import jakarta.persistence.criteria.Predicate;
/** /**
* Printer for an SQM tree - for debugging purpose * Printer for an SQM tree - for debugging purpose
* *
@ -800,25 +801,13 @@ public Object visitGroupedPredicate(SqmGroupedPredicate predicate) {
} }
@Override @Override
public Object visitAndPredicate(SqmAndPredicate predicate) { public Object visitJunctionPredicate(SqmJunctionPredicate predicate) {
processStanza( processStanza(
"and", predicate.getOperator() == Predicate.BooleanOperator.AND ? "and" : "or",
() -> { () -> {
predicate.getLeftHandPredicate().accept( this ); for ( SqmPredicate subPredicate : predicate.getPredicates() ) {
predicate.getRightHandPredicate().accept( this ); subPredicate.accept( this );
} }
);
return null;
}
@Override
public Object visitOrPredicate(SqmOrPredicate predicate) {
processStanza(
"or",
() -> {
predicate.getLeftHandPredicate().accept( this );
predicate.getRightHandPredicate().accept( this );
} }
); );

View File

@ -72,7 +72,6 @@
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.insert.SqmValues;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
@ -81,11 +80,11 @@
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmJunctionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate; import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate; import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
@ -393,16 +392,10 @@ public Object visitGroupedPredicate(SqmGroupedPredicate predicate) {
} }
@Override @Override
public Object visitAndPredicate(SqmAndPredicate predicate) { public Object visitJunctionPredicate(SqmJunctionPredicate predicate) {
predicate.getLeftHandPredicate().accept( this ); for ( SqmPredicate subPredicate : predicate.getPredicates() ) {
predicate.getRightHandPredicate().accept( this ); subPredicate.accept( this );
return predicate; }
}
@Override
public Object visitOrPredicate(SqmOrPredicate predicate) {
predicate.getLeftHandPredicate().accept( this );
predicate.getRightHandPredicate().accept( this );
return predicate; return predicate;
} }

View File

@ -218,7 +218,6 @@
import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertStatement;
import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement;
import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.insert.SqmValues;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate; import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
@ -227,11 +226,11 @@
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate; import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmJunctionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate; import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate; import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNegatedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmAliasedNode; import org.hibernate.query.sqm.tree.select.SqmAliasedNode;
@ -5747,77 +5746,86 @@ public GroupedPredicate visitGroupedPredicate(SqmGroupedPredicate predicate) {
} }
@Override @Override
public Junction visitAndPredicate(SqmAndPredicate predicate) { public Junction visitJunctionPredicate(SqmJunctionPredicate predicate) {
final Junction conjunction = new Junction( Junction.Nature.CONJUNCTION, getBooleanType() ); if ( predicate.getOperator() == jakarta.persistence.criteria.Predicate.BooleanOperator.AND ) {
conjunction.add( (Predicate) predicate.getLeftHandPredicate().accept( this ) ); final List<Predicate> predicates = new ArrayList<>( predicate.getPredicates().size() );
conjunction.add( (Predicate) predicate.getRightHandPredicate().accept( this ) ); for ( SqmPredicate subPredicate : predicate.getPredicates() ) {
return conjunction; predicates.add( (Predicate) subPredicate.accept( this ) );
} }
return new Junction( Junction.Nature.CONJUNCTION, predicates, getBooleanType() );
}
final Junction disjunction = new Junction(
Junction.Nature.DISJUNCTION,
new ArrayList<>( predicate.getPredicates().size() ),
getBooleanType()
);
final List<Map<SqmPath<?>, Set<String>>> conjunctTreatUsagesList = new ArrayList<>( predicate.getPredicates().size() );
final Map<SqmPath<?>, Set<String>> conjunctTreatUsagesUnion = new IdentityHashMap<>();
boolean hasAnyTreatUsage = false;
for ( SqmPredicate subPredicate : predicate.getPredicates() ) {
disjunction.add( (Predicate) subPredicate.accept( this ) );
if ( conjunctTreatUsages.isEmpty() ) {
conjunctTreatUsagesList.add( null );
}
else {
hasAnyTreatUsage = true;
for ( Map.Entry<SqmPath<?>, Set<String>> entry : conjunctTreatUsages.entrySet() ) {
conjunctTreatUsagesUnion.computeIfAbsent( entry.getKey(), k -> new HashSet<>() )
.addAll( entry.getValue() );
}
conjunctTreatUsagesList.add( new IdentityHashMap<>( conjunctTreatUsages ) );
conjunctTreatUsages.clear();
}
}
if ( !hasAnyTreatUsage ) {
return disjunction;
}
@Override // Build the intersection of the conjunct treat usages,
public Junction visitOrPredicate(SqmOrPredicate predicate) { // so that we can push that up and infer during pruning, which entity subclasses can be omitted
final Junction disjunction = new Junction( Junction.Nature.DISJUNCTION, getBooleanType() ); conjunctTreatUsages.putAll( conjunctTreatUsagesUnion );
final Predicate predicate1 = (Predicate) predicate.getLeftHandPredicate().accept( this );
final Map<SqmPath<?>, Set<String>> conjunctTreatUsages1; final Iterator<Map.Entry<SqmPath<?>, Set<String>>> iterator = conjunctTreatUsages.entrySet().iterator();
if ( conjunctTreatUsages.isEmpty() ) { while ( iterator.hasNext() ) {
conjunctTreatUsages1 = null; final Map.Entry<SqmPath<?>, Set<String>> entry = iterator.next();
} final Set<String> intersected = new HashSet<>( entry.getValue() );
else { entry.setValue( intersected );
conjunctTreatUsages1 = new IdentityHashMap<>( conjunctTreatUsages ); boolean remove = false;
conjunctTreatUsages.clear(); for ( Map<SqmPath<?>, Set<String>> conjunctTreatUsages : conjunctTreatUsagesList ) {
} final Set<String> entityNames = conjunctTreatUsages.get( entry.getKey() );
final Predicate predicate2 = (Predicate) predicate.getRightHandPredicate().accept( this ); if ( entityNames == null ) {
if ( conjunctTreatUsages.isEmpty() || conjunctTreatUsages1 == null ) { remove = true;
disjunction.add(
SqlAstTreeHelper.combinePredicates(
consumeConjunctTreatTypeRestrictions( conjunctTreatUsages1 ),
predicate1
)
);
disjunction.add( predicate2 );
}
else {
// If both disjunctions have treat type restrictions build the intersection of the two,
// so that we can push that up and infer during pruning, which entity subclasses can be omitted
final Map<SqmPath<?>, Set<String>> conjunctTreatUsages2 = new IdentityHashMap<>( conjunctTreatUsages );
final Iterator<Map.Entry<SqmPath<?>, Set<String>>> iterator = conjunctTreatUsages.entrySet().iterator();
while ( iterator.hasNext() ) {
final Map.Entry<SqmPath<?>, Set<String>> entry = iterator.next();
final Set<String> entityNames1 = conjunctTreatUsages1.get( entry.getKey() );
if ( entityNames1 == null ) {
iterator.remove();
continue; continue;
} }
// Intersect the two sets and transfer the common elements to the intersection // Intersect the two sets and transfer the common elements to the intersection
final Set<String> entityNames2 = entry.getValue(); intersected.retainAll( entityNames );
final Set<String> intersected = new HashSet<>( entityNames1 );
intersected.retainAll( entityNames2 );
if ( intersected.isEmpty() ) { if ( intersected.isEmpty() ) {
iterator.remove(); remove = true;
continue; continue;
} }
entry.setValue( intersected ); entityNames.removeAll( intersected );
entityNames1.removeAll( intersected ); if ( entityNames.isEmpty() ) {
entityNames2.removeAll( intersected ); conjunctTreatUsages.remove( entry.getKey() );
if ( entityNames1.isEmpty() ) {
conjunctTreatUsages1.remove( entry.getKey() );
}
if ( entityNames2.isEmpty() ) {
conjunctTreatUsages2.remove( entry.getKey() );
} }
} }
disjunction.add(
SqlAstTreeHelper.combinePredicates( if ( remove ) {
consumeConjunctTreatTypeRestrictions( conjunctTreatUsages1 ), iterator.remove();
predicate1 }
) }
);
disjunction.add( // Prepend the treat type usages to the respective conjuncts
SqlAstTreeHelper.combinePredicates( for ( int i = 0; i < conjunctTreatUsagesList.size(); i++ ) {
consumeConjunctTreatTypeRestrictions( conjunctTreatUsages2 ), final Map<SqmPath<?>, Set<String>> conjunctTreatUsages = conjunctTreatUsagesList.get( i );
predicate2 if ( conjunctTreatUsages != null ) {
) disjunction.getPredicates().set(
); i,
SqlAstTreeHelper.combinePredicates(
consumeConjunctTreatTypeRestrictions( conjunctTreatUsages ),
disjunction.getPredicates().get( i )
)
);
}
} }
return disjunction; return disjunction;
} }

View File

@ -1,107 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.predicate;
import java.util.Arrays;
import java.util.List;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import jakarta.persistence.criteria.Expression;
/**
* @author Steve Ebersole
*/
public class SqmAndPredicate extends AbstractSqmPredicate implements SqmJunctivePredicate {
private final SqmPredicate leftHandPredicate;
private final SqmPredicate rightHandPredicate;
public SqmAndPredicate(
SqmPredicate leftHandPredicate,
SqmPredicate rightHandPredicate,
NodeBuilder nodeBuilder) {
super( leftHandPredicate.getExpressible(), nodeBuilder );
this.leftHandPredicate = leftHandPredicate;
this.rightHandPredicate = rightHandPredicate;
}
@Override
public SqmAndPredicate copy(SqmCopyContext context) {
final SqmAndPredicate existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmAndPredicate predicate = context.registerCopy(
this,
new SqmAndPredicate(
leftHandPredicate.copy( context ),
rightHandPredicate.copy( context ),
nodeBuilder()
)
);
copyTo( predicate, context );
return predicate;
}
@Override
public SqmPredicate getLeftHandPredicate() {
return leftHandPredicate;
}
@Override
public SqmPredicate getRightHandPredicate() {
return rightHandPredicate;
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitAndPredicate( this );
}
@Override
public BooleanOperator getOperator() {
return BooleanOperator.AND;
}
@Override
public boolean isNegated() {
return false;
}
@Override
public List<Expression<Boolean>> getExpressions() {
return Arrays.asList( leftHandPredicate, rightHandPredicate );
}
@Override
public SqmPredicate not() {
return new SqmNegatedPredicate( this, nodeBuilder() );
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( leftHandPredicate instanceof SqmOrPredicate ) {
sb.append( '(' );
leftHandPredicate.appendHqlString( sb );
sb.append( ')' );
}
else {
leftHandPredicate.appendHqlString( sb );
}
sb.append( " and " );
if ( rightHandPredicate instanceof SqmOrPredicate ) {
sb.append( '(' );
rightHandPredicate.appendHqlString( sb );
sb.append( ')' );
}
else {
rightHandPredicate.appendHqlString( sb );
}
}
}

View File

@ -0,0 +1,130 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.predicate;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.sql.ast.tree.predicate.Junction;
import jakarta.persistence.criteria.Expression;
/**
* @author Steve Ebersole
*/
public class SqmJunctionPredicate extends AbstractSqmPredicate {
private final BooleanOperator booleanOperator;
private final List<SqmPredicate> predicates;
public SqmJunctionPredicate(
BooleanOperator booleanOperator,
SqmPredicate leftHandPredicate,
SqmPredicate rightHandPredicate,
NodeBuilder nodeBuilder) {
super( leftHandPredicate.getExpressible(), nodeBuilder );
this.booleanOperator = booleanOperator;
this.predicates = new ArrayList<>( 2 );
this.predicates.add( leftHandPredicate );
this.predicates.add( rightHandPredicate );
}
public SqmJunctionPredicate(
BooleanOperator booleanOperator,
List<SqmPredicate> predicates,
NodeBuilder nodeBuilder) {
super( predicates.get( 0 ).getNodeType(), nodeBuilder );
this.booleanOperator = booleanOperator;
this.predicates = predicates;
}
@Override
public SqmJunctionPredicate copy(SqmCopyContext context) {
final SqmJunctionPredicate existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final List<SqmPredicate> predicates = new ArrayList<>( this.predicates.size() );
for ( SqmPredicate predicate : this.predicates ) {
predicates.add( predicate.copy( context ) );
}
final SqmJunctionPredicate predicate = context.registerCopy(
this,
new SqmJunctionPredicate(
booleanOperator,
predicates,
nodeBuilder()
)
);
copyTo( predicate, context );
return predicate;
}
public List<SqmPredicate> getPredicates() {
return predicates;
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitJunctionPredicate( this );
}
@Override
public BooleanOperator getOperator() {
return booleanOperator;
}
@Override
public boolean isNegated() {
return false;
}
@Override
public List<Expression<Boolean>> getExpressions() {
//noinspection unchecked
return (List<Expression<Boolean>>) (List<?>) predicates;
}
@Override
public SqmPredicate not() {
return new SqmNegatedPredicate( this, nodeBuilder() );
}
@Override
public void appendHqlString(StringBuilder sb) {
final String separator = booleanOperator == BooleanOperator.AND
? " and "
: " or ";
appendJunctionHqlString( predicates.get( 0 ), sb );
for ( int i = 1; i < predicates.size(); i++ ) {
sb.append( separator );
appendJunctionHqlString( predicates.get( i ), sb );
}
}
private void appendJunctionHqlString(SqmPredicate p, StringBuilder sb) {
if ( p instanceof SqmJunctionPredicate ) {
final SqmJunctionPredicate junction = (SqmJunctionPredicate) p;
// If we have the same nature, or if this is a disjunction and the operand is a conjunction,
// then we don't need parenthesis, because the AND operator binds stronger
if ( booleanOperator == junction.getOperator() || booleanOperator == BooleanOperator.OR ) {
junction.appendHqlString( sb );
}
else {
sb.append( '(' );
junction.appendHqlString( sb );
sb.append( ')' );
}
}
else {
p.appendHqlString( sb );
}
}
}

View File

@ -1,17 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.predicate;
/**
*
* @author Steve Ebersole
*/
public interface SqmJunctivePredicate extends SqmPredicate {
SqmPredicate getLeftHandPredicate();
SqmPredicate getRightHandPredicate();
}

View File

@ -1,108 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.tree.predicate;
import java.util.Arrays;
import java.util.List;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression;
import jakarta.persistence.criteria.Expression;
/**
* @author Steve Ebersole
*/
public class SqmOrPredicate extends AbstractSqmExpression<Boolean> implements SqmJunctivePredicate {
private final SqmPredicate leftHandPredicate;
private final SqmPredicate rightHandPredicate;
public SqmOrPredicate(
SqmPredicate leftHandPredicate,
SqmPredicate rightHandPredicate,
NodeBuilder nodeBuilder) {
super( null, nodeBuilder );
this.leftHandPredicate = leftHandPredicate;
this.rightHandPredicate = rightHandPredicate;
}
@Override
public SqmOrPredicate copy(SqmCopyContext context) {
final SqmOrPredicate existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmOrPredicate predicate = context.registerCopy(
this,
new SqmOrPredicate(
leftHandPredicate.copy( context ),
rightHandPredicate.copy( context ),
nodeBuilder()
)
);
copyTo( predicate, context );
return predicate;
}
@Override
public SqmPredicate getLeftHandPredicate() {
return leftHandPredicate;
}
@Override
public SqmPredicate getRightHandPredicate() {
return rightHandPredicate;
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitOrPredicate( this );
}
@Override
public SqmPredicate not() {
return new SqmNegatedPredicate( this, nodeBuilder() );
}
@Override
public BooleanOperator getOperator() {
return BooleanOperator.OR;
}
@Override
public boolean isNegated() {
return false;
}
@Override
public List<Expression<Boolean>> getExpressions() {
return Arrays.asList( leftHandPredicate, rightHandPredicate );
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( leftHandPredicate instanceof SqmAndPredicate ) {
sb.append( '(' );
leftHandPredicate.appendHqlString( sb );
sb.append( ')' );
}
else {
leftHandPredicate.appendHqlString( sb );
}
sb.append( " or " );
if ( rightHandPredicate instanceof SqmAndPredicate ) {
sb.append( '(' );
rightHandPredicate.appendHqlString( sb );
sb.append( ')' );
}
else {
rightHandPredicate.appendHqlString( sb );
}
}
}