diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/ExprCostModel.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/ExprCostModel.java index 4a8f9ccd0292769..43c98969b9b2a19 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/ExprCostModel.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/ExprCostModel.java @@ -18,7 +18,9 @@ package org.apache.doris.nereids.cost; import org.apache.doris.nereids.trees.expressions.Alias; +import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.expressions.literal.Literal; @@ -70,4 +72,14 @@ public Double visitLiteral(Literal literal, Void context) { return 0.0; } + @Override + public Double visitAnd(And and, Void context) { + return 0.0; + } + + @Override + public Double visitOr(Or or, Void context) { + return 0.0; + } + } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/ExpressionTranslator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/ExpressionTranslator.java index 627a983c123b8d5..166892f48a9db6c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/ExpressionTranslator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/ExpressionTranslator.java @@ -104,7 +104,9 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Deque; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -322,22 +324,85 @@ public Expr visitNullLiteral(NullLiteral nullLiteral, PlanTranslatorContext cont return nullLit; } + private static class Frame { + int low; + int high; + CompoundPredicate.Operator op; + boolean processed; + + Frame(int low, int high, CompoundPredicate.Operator op) { + this.low = low; + this.high = high; + this.op = op; + this.processed = false; + } + } + + private Expr toBalancedTree(int low, int high, List children, + CompoundPredicate.Operator op) { + Deque stack = new ArrayDeque<>(); + Deque results = new ArrayDeque<>(); + + stack.push(new Frame(low, high, op)); + + while (!stack.isEmpty()) { + Frame currentFrame = stack.peek(); + + if (!currentFrame.processed) { + int l = currentFrame.low; + int h = currentFrame.high; + int diff = h - l; + + if (diff == 0) { + results.push(children.get(l)); + stack.pop(); + } else if (diff == 1) { + Expr left = children.get(l); + Expr right = children.get(h); + CompoundPredicate cp = new CompoundPredicate(op, left, right); + results.push(cp); + stack.pop(); + } else { + int mid = l + (h - l) / 2; + + currentFrame.processed = true; + + stack.push(new Frame(mid + 1, h, op)); + stack.push(new Frame(l, mid, op)); + } + } else { + stack.pop(); + if (results.size() >= 2) { + Expr right = results.pop(); + Expr left = results.pop(); + CompoundPredicate cp = new CompoundPredicate(currentFrame.op, left, right); + results.push(cp); + } + } + } + return results.pop(); + } + @Override public Expr visitAnd(And and, PlanTranslatorContext context) { - org.apache.doris.analysis.CompoundPredicate cp = new org.apache.doris.analysis.CompoundPredicate( - org.apache.doris.analysis.CompoundPredicate.Operator.AND, - and.child(0).accept(this, context), - and.child(1).accept(this, context)); + List children = and.children().stream().map( + e -> e.accept(this, context) + ).collect(Collectors.toList()); + CompoundPredicate cp = (CompoundPredicate) toBalancedTree(0, children.size() - 1, + children, CompoundPredicate.Operator.AND); + cp.setNullableFromNereids(and.nullable()); return cp; } @Override public Expr visitOr(Or or, PlanTranslatorContext context) { - org.apache.doris.analysis.CompoundPredicate cp = new org.apache.doris.analysis.CompoundPredicate( - org.apache.doris.analysis.CompoundPredicate.Operator.OR, - or.child(0).accept(this, context), - or.child(1).accept(this, context)); + List children = or.children().stream().map( + e -> e.accept(this, context) + ).collect(Collectors.toList()); + CompoundPredicate cp = (CompoundPredicate) toBalancedTree(0, children.size() - 1, + children, CompoundPredicate.Operator.OR); + cp.setNullableFromNereids(or.nullable()); return cp; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index 2b6716d69b02693..dc910920a1a8ed0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -1807,8 +1807,14 @@ public Expression visitLogicalBinary(LogicalBinaryContext ctx) { // into expressions. Collections.reverse(contexts); List expressions = contexts.stream().map(this::getExpression).collect(Collectors.toList()); - // Create a balanced tree. - return reduceToExpressionTree(0, expressions.size() - 1, expressions, ctx); + if (ctx.operator.getType() == DorisParser.AND) { + return new And(expressions); + } else if (ctx.operator.getType() == DorisParser.OR) { + return new Or(expressions); + } else { + // Create a balanced tree. + return reduceToExpressionTree(0, expressions.size() - 1, expressions, ctx); + } }); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java index 49789aa66e1ff82..adc68ac6ecac1b5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java @@ -39,6 +39,7 @@ import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext; import org.apache.doris.nereids.rules.expression.rules.FoldConstantRuleOnFE; import org.apache.doris.nereids.trees.expressions.Alias; +import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.ArrayItemReference; import org.apache.doris.nereids.trees.expressions.BinaryArithmetic; import org.apache.doris.nereids.trees.expressions.BitNot; @@ -46,7 +47,6 @@ import org.apache.doris.nereids.trees.expressions.CaseWhen; import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.ComparisonPredicate; -import org.apache.doris.nereids.trees.expressions.CompoundPredicate; import org.apache.doris.nereids.trees.expressions.Divide; import org.apache.doris.nereids.trees.expressions.EqualTo; import org.apache.doris.nereids.trees.expressions.Expression; @@ -57,6 +57,7 @@ import org.apache.doris.nereids.trees.expressions.Match; import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.Not; +import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.Placeholder; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.SlotReference; @@ -73,6 +74,7 @@ import org.apache.doris.nereids.trees.expressions.functions.udf.UdfBuilder; import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral; import org.apache.doris.nereids.trees.expressions.literal.Literal; +import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; import org.apache.doris.nereids.trees.expressions.literal.StringLiteral; import org.apache.doris.nereids.trees.expressions.typecoercion.ImplicitCastInputTypes; import org.apache.doris.nereids.trees.plans.Plan; @@ -81,6 +83,7 @@ import org.apache.doris.nereids.types.BigIntType; import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DataType; +import org.apache.doris.nereids.util.ExpressionUtils; import org.apache.doris.nereids.util.TypeCoercionUtils; import org.apache.doris.nereids.util.Utils; import org.apache.doris.qe.ConnectContext; @@ -95,6 +98,7 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.Lists; import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; @@ -498,11 +502,59 @@ public Expression visitBinaryArithmetic(BinaryArithmetic binaryArithmetic, Expre } @Override - public Expression visitCompoundPredicate(CompoundPredicate compoundPredicate, ExpressionRewriteContext context) { - Expression left = compoundPredicate.left().accept(this, context); - Expression right = compoundPredicate.right().accept(this, context); - CompoundPredicate ret = (CompoundPredicate) compoundPredicate.withChildren(left, right); - return TypeCoercionUtils.processCompoundPredicate(ret); + public Expression visitOr(Or or, ExpressionRewriteContext context) { + List children = ExpressionUtils.extractDisjunction(or); + List newChildren = Lists.newArrayListWithCapacity(children.size()); + boolean hasNewChild = false; + for (Expression child : children) { + Expression newChild = child.accept(this, context); + if (newChild == null) { + newChild = child; + } + if (newChild.getDataType().isNullType()) { + newChild = new NullLiteral(BooleanType.INSTANCE); + } else { + newChild = TypeCoercionUtils.castIfNotSameType(newChild, BooleanType.INSTANCE); + } + + if (! child.equals(newChild)) { + hasNewChild = true; + } + newChildren.add(newChild); + } + if (hasNewChild) { + return ExpressionUtils.or(newChildren); + } else { + return or; + } + } + + @Override + public Expression visitAnd(And and, ExpressionRewriteContext context) { + List children = ExpressionUtils.extractConjunction(and); + List newChildren = Lists.newArrayListWithCapacity(children.size()); + boolean hasNewChild = false; + for (Expression child : children) { + Expression newChild = child.accept(this, context); + if (newChild == null) { + newChild = child; + } + if (newChild.getDataType().isNullType()) { + newChild = new NullLiteral(BooleanType.INSTANCE); + } else { + newChild = TypeCoercionUtils.castIfNotSameType(newChild, BooleanType.INSTANCE); + } + + if (! child.equals(newChild)) { + hasNewChild = true; + } + newChildren.add(newChild); + } + if (hasNewChild) { + return ExpressionUtils.and(newChildren); + } else { + return and; + } } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java index 17e7d098cad552f..14700b030d68b74 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubqueryToApply.java @@ -27,7 +27,7 @@ import org.apache.doris.nereids.trees.TreeNode; import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.And; -import org.apache.doris.nereids.trees.expressions.BinaryOperator; +import org.apache.doris.nereids.trees.expressions.CompoundPredicate; import org.apache.doris.nereids.trees.expressions.Exists; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.InSubquery; @@ -589,17 +589,19 @@ public Expression visitScalarSubquery(ScalarSubquery scalar, SubqueryContext con } @Override - public Expression visitBinaryOperator(BinaryOperator binaryOperator, SubqueryContext context) { + public Expression visitCompoundPredicate(CompoundPredicate compound, SubqueryContext context) { // update isMarkJoin flag - isMarkJoin = - isMarkJoin || ((binaryOperator.left().anyMatch(SubqueryExpr.class::isInstance) - || binaryOperator.right().anyMatch(SubqueryExpr.class::isInstance)) - && (binaryOperator instanceof Or)); - - Expression left = replace(binaryOperator.left(), context); - Expression right = replace(binaryOperator.right(), context); - - return binaryOperator.withChildren(left, right); + if (compound instanceof Or) { + for (Expression child : compound.children()) { + if (child.anyMatch(SubqueryExpr.class::isInstance)) { + isMarkJoin = true; + break; + } + } + } + return compound.withChildren( + compound.children().stream().map(c -> replace(c, context)).collect(Collectors.toList()) + ); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/ExtractCommonFactorRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/ExtractCommonFactorRule.java index 4032db4aadf5507..1873066ab458662 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/ExtractCommonFactorRule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/ExtractCommonFactorRule.java @@ -60,9 +60,10 @@ public List> buildRules() { private static Expression extractCommonFactor(CompoundPredicate originExpr) { // fast return - if (!(originExpr.left() instanceof CompoundPredicate || originExpr.left() instanceof BooleanLiteral) - && !(originExpr.right() instanceof CompoundPredicate || originExpr.right() instanceof BooleanLiteral)) { - return originExpr; + for (Expression child : originExpr.children()) { + if (!(child instanceof CompoundPredicate || child instanceof BooleanLiteral)) { + return originExpr; + } } // flatten same type to a list diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/PartitionPruneExpressionExtractor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/PartitionPruneExpressionExtractor.java index 322016fd45c4a93..90375e0c0e6a368 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/PartitionPruneExpressionExtractor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/PartitionPruneExpressionExtractor.java @@ -29,7 +29,9 @@ import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -100,49 +102,55 @@ public Expression visit(Expression originExpr, Context parentContext) { } @Override - public Expression visitAnd(And node, Context parentContext) { - // handle left node - Context leftContext = new Context(); - Expression newLeft = node.left().accept(this, leftContext); - // handle right node - Context rightContext = new Context(); - Expression newRight = node.right().accept(this, rightContext); - - // if anyone of them is FALSE, the whole expression should be FALSE. - if (newLeft == BooleanLiteral.FALSE || newRight == BooleanLiteral.FALSE) { - return BooleanLiteral.FALSE; + public Expression visitAnd(And and, Context parentContext) { + List children = and.children(); + List newChildren = Lists.newArrayListWithCapacity(children.size()); + boolean changed = false; + for (Expression child : children) { + Context childContext = new Context(); + Expression newChild = child.accept(this, childContext); + // if anyone of them is FALSE, the whole expression should be FALSE. + if (newChild == BooleanLiteral.FALSE) { + return BooleanLiteral.FALSE; + } + if (newChild != BooleanLiteral.TRUE && !childContext.containsUnEvaluableExpression) { + newChildren.add(newChild); + changed |= !newChild.equals(child); + } else { + changed = true; + } } - - // If left node contains non-partition slot or is TURE, just discard it. - if (newLeft == BooleanLiteral.TRUE || leftContext.containsUnEvaluableExpression) { - return rightContext.containsUnEvaluableExpression ? BooleanLiteral.TRUE : newRight; + if (newChildren.isEmpty()) { + return BooleanLiteral.TRUE; } - - // If right node contains non-partition slot or is TURE, just discard it. - if (newRight == BooleanLiteral.TRUE || rightContext.containsUnEvaluableExpression) { - return newLeft; + if (newChildren.size() == 1) { + return newChildren.get(0); + } + if (changed) { + if (newChildren.isEmpty()) { + return BooleanLiteral.TRUE; + } else { + return and.withChildren(newChildren); + } + } else { + return and; } - - // both does not contains non-partition slot. - return new And(newLeft, newRight); } @Override - public Expression visitOr(Or node, Context parentContext) { - // handle left node - Context leftContext = new Context(); - Expression newLeft = node.left().accept(this, leftContext); - // handle right node - Context rightContext = new Context(); - Expression newRight = node.right().accept(this, rightContext); - - // if anyone of them is TRUE or contains non-partition slot, just return TRUE. - if (newLeft == BooleanLiteral.TRUE || newRight == BooleanLiteral.TRUE - || leftContext.containsUnEvaluableExpression || rightContext.containsUnEvaluableExpression) { - return BooleanLiteral.TRUE; + public Expression visitOr(Or or, Context parentContext) { + List children = or.children(); + List newChildren = Lists.newArrayListWithCapacity(children.size()); + for (Expression child : children) { + Context childContext = new Context(); + Expression newChild = child.accept(this, childContext); + // if anyone of them is TRUE or contains non-partition slot, just return TRUE. + if (newChild == BooleanLiteral.TRUE || childContext.containsUnEvaluableExpression) { + return BooleanLiteral.TRUE; + } + newChildren.add(newChild); } - - return new Or(newLeft, newRight); + return or.withChildren(newChildren); } /** diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyNotExprRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyNotExprRule.java index 484d68f0d7317dd..92ea5ddfd5c9edf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyNotExprRule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/SimplifyNotExprRule.java @@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableList; import java.util.List; +import java.util.stream.Collectors; /** * Rewrite rule of NOT expression. @@ -76,9 +77,7 @@ public static Expression simplify(Not not) { } } else if (child instanceof CompoundPredicate) { CompoundPredicate cp = (CompoundPredicate) child; - Not left = new Not(cp.left()); - Not right = new Not(cp.right()); - return cp.flip(left, right); + return cp.flip(cp.children().stream().map(c -> new Not(c)).collect(Collectors.toList())); } else if (child instanceof Not) { return child.child(0); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/TrySimplifyPredicateWithMarkJoinSlot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/TrySimplifyPredicateWithMarkJoinSlot.java index d4dc6697d80aaab..323a69516882906 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/TrySimplifyPredicateWithMarkJoinSlot.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/TrySimplifyPredicateWithMarkJoinSlot.java @@ -25,6 +25,10 @@ import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral; +import com.google.common.collect.Lists; + +import java.util.List; + /** * TrySimplifyPredicateWithMarkJoinSlot */ @@ -56,19 +60,15 @@ public Expression visitAnd(And and, ExpressionRewriteContext context) { * we change 'predicate(with mark slot) and predicate(no mark slot)' -> predicate(with mark slot) and true * to evaluate the predicate */ - Expression left = and.left(); - Expression newLeft = left.accept(this, context); - - if (newLeft.getInputSlots().stream().noneMatch(MarkJoinSlotReference.class::isInstance)) { - newLeft = BooleanLiteral.TRUE; + List newChildren = Lists.newArrayListWithCapacity(and.children().size()); + for (Expression child : and.children()) { + Expression newChild = child.accept(this, context); + if (newChild.getInputSlots().stream().noneMatch(MarkJoinSlotReference.class::isInstance)) { + newChild = BooleanLiteral.TRUE; + } + newChildren.add(newChild); } - - Expression right = and.right(); - Expression newRight = right.accept(this, context); - if (newRight.getInputSlots().stream().noneMatch(MarkJoinSlotReference.class::isInstance)) { - newRight = BooleanLiteral.TRUE; - } - Expression expr = new And(newLeft, newRight); + Expression expr = new And(newChildren); return expr; } @@ -94,19 +94,17 @@ public Expression visitOr(Or or, ExpressionRewriteContext context) { * we change 'predicate(with mark slot) or predicate(no mark slot)' -> predicate(with mark slot) or false * to evaluate the predicate */ - Expression left = or.left(); - Expression newLeft = left.accept(this, context); - if (newLeft.getInputSlots().stream().noneMatch(MarkJoinSlotReference.class::isInstance)) { - newLeft = BooleanLiteral.FALSE; + List newChildren = Lists.newArrayListWithCapacity(or.children().size()); + for (Expression child : or.children()) { + Expression newChild = child.accept(this, context); + if (newChild.getInputSlots().stream().noneMatch(MarkJoinSlotReference.class::isInstance)) { + newChild = BooleanLiteral.FALSE; + } + newChildren.add(newChild); } - Expression right = or.right(); - Expression newRight = right.accept(this, context); - if (newRight.getInputSlots().stream().noneMatch(MarkJoinSlotReference.class::isInstance)) { - newRight = BooleanLiteral.FALSE; - } - Expression expr = new Or(newLeft, newRight); + Expression expr = new Or(newChildren); return expr; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplace.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplace.java index d6f4925c7adeb71..4fc9efc1943ba66 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplace.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplace.java @@ -29,7 +29,6 @@ import org.apache.doris.nereids.trees.expressions.InPredicate; import org.apache.doris.nereids.trees.expressions.Like; import org.apache.doris.nereids.trees.expressions.Not; -import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait; import org.apache.doris.nereids.trees.expressions.literal.Literal; @@ -81,11 +80,6 @@ public Void visit(Expression expr, Map> context) { return null; } - @Override - public Void visitOr(Or expr, Map> context) { - return null; - } - @Override public Void visitInPredicate(InPredicate inPredicate, Map> context) { if (!validInPredicate(inPredicate)) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ColumnStatsAdjustVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ColumnStatsAdjustVisitor.java index eaf2ce3734408d4..d91cb5b4a6883b4 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ColumnStatsAdjustVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ColumnStatsAdjustVisitor.java @@ -20,9 +20,8 @@ import org.apache.doris.analysis.LiteralExpr; import org.apache.doris.catalog.Type; import org.apache.doris.nereids.trees.expressions.Cast; -import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.literal.Literal; -import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionVisitor; import org.apache.doris.nereids.types.DataType; import org.apache.doris.nereids.types.coercion.CharacterType; import org.apache.doris.statistics.ColumnStatistic; @@ -57,16 +56,10 @@ * for other expressions(except cast), we also need to adjust their input column stats. * */ -public class ColumnStatsAdjustVisitor extends ExpressionVisitor { +public class ColumnStatsAdjustVisitor extends DefaultExpressionVisitor { private static final Logger LOG = LogManager.getLogger(ColumnStatsAdjustVisitor.class); - @Override - public ColumnStatistic visit(Expression expr, Statistics context) { - expr.children().forEach(child -> child.accept(this, context)); - return null; - } - @Override public ColumnStatistic visitCast(Cast cast, Statistics context) { ColumnStatistic colStats = context.findColumnStatistics(cast); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java index 2307a6dfba35256..7d1b5439bace231 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/ExpressionEstimation.java @@ -24,17 +24,18 @@ import org.apache.doris.nereids.trees.expressions.Add; import org.apache.doris.nereids.trees.expressions.AggregateExpression; import org.apache.doris.nereids.trees.expressions.Alias; +import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.BinaryArithmetic; import org.apache.doris.nereids.trees.expressions.CaseWhen; import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.ComparisonPredicate; -import org.apache.doris.nereids.trees.expressions.CompoundPredicate; import org.apache.doris.nereids.trees.expressions.Divide; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.IntegralDivide; import org.apache.doris.nereids.trees.expressions.MarkJoinSlotReference; import org.apache.doris.nereids.trees.expressions.Mod; import org.apache.doris.nereids.trees.expressions.Multiply; +import org.apache.doris.nereids.trees.expressions.Or; import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.expressions.Subtract; import org.apache.doris.nereids.trees.expressions.TimestampArithmetic; @@ -451,12 +452,26 @@ public ColumnStatistic visitComparisonPredicate(ComparisonPredicate cp, Statisti } @Override - public ColumnStatistic visitCompoundPredicate(CompoundPredicate compoundPredicate, Statistics context) { - List childExprs = compoundPredicate.children(); - ColumnStatistic firstChild = childExprs.get(0).accept(this, context); + public ColumnStatistic visitOr(Or or, Statistics inputStats) { + List children = or.children(); + // TODO: this algorithm is not right, fix it latter + ColumnStatistic firstChild = children.get(0).accept(this, inputStats); double maxNull = StatsMathUtil.maxNonNaN(firstChild.numNulls, 1); - for (int i = 1; i < childExprs.size(); i++) { - ColumnStatistic columnStatistic = childExprs.get(i).accept(this, context); + for (int i = 1; i < children.size(); i++) { + ColumnStatistic columnStatistic = children.get(i).accept(this, inputStats); + maxNull = StatsMathUtil.maxNonNaN(maxNull, columnStatistic.numNulls); + } + return new ColumnStatisticBuilder(firstChild).setNumNulls(maxNull).setNdv(2).build(); + } + + @Override + public ColumnStatistic visitAnd(And and, Statistics inputStats) { + List children = and.children(); + // TODO: this algorithm is not right, fix it latter + ColumnStatistic firstChild = children.get(0).accept(this, inputStats); + double maxNull = StatsMathUtil.maxNonNaN(firstChild.numNulls, 1); + for (int i = 1; i < children.size(); i++) { + ColumnStatistic columnStatistic = children.get(i).accept(this, inputStats); maxNull = StatsMathUtil.maxNonNaN(maxNull, columnStatistic.numNulls); } return new ColumnStatisticBuilder(firstChild).setNumNulls(maxNull).setNdv(2).build(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/FilterEstimation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/FilterEstimation.java index e050ae9fe0feec3..488b27e68cbd129 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/FilterEstimation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/FilterEstimation.java @@ -23,7 +23,6 @@ import org.apache.doris.nereids.stats.FilterEstimation.EstimationContext; import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.ComparisonPredicate; -import org.apache.doris.nereids.trees.expressions.CompoundPredicate; import org.apache.doris.nereids.trees.expressions.EqualPredicate; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.GreaterThan; @@ -113,22 +112,36 @@ public Statistics visit(Expression expr, EstimationContext context) { } @Override - public Statistics visitCompoundPredicate(CompoundPredicate predicate, EstimationContext context) { - Expression leftExpr = predicate.child(0); - Expression rightExpr = predicate.child(1); - Statistics leftStats = leftExpr.accept(this, context); + public Statistics visitAnd(And and, EstimationContext context) { + List children = and.children(); + Statistics inputStats = context.statistics; + Statistics outputStats = inputStats; + Preconditions.checkArgument(children.size() > 1, "and expression abnormal: " + and); + for (Expression child : children) { + outputStats = child.accept(this, new EstimationContext(inputStats)); + outputStats.normalizeColumnStatistics(context.statistics.getRowCount()); + inputStats = outputStats; + } + return outputStats; + } + + @Override + public Statistics visitOr(Or or, EstimationContext context) { + List children = or.children(); + Set leftInputSlots = Sets.newHashSet(children.get(0).getInputSlots()); + Statistics leftStats = children.get(0).accept(this, context); leftStats.normalizeColumnStatistics(context.statistics.getRowCount(), true); - Statistics andStats = rightExpr.accept(this, new EstimationContext(leftStats)); - if (predicate instanceof And) { - andStats.normalizeColumnStatistics(context.statistics.getRowCount(), true); - return andStats; - } else if (predicate instanceof Or) { - Statistics rightStats = rightExpr.accept(this, context); + Statistics outputStats = leftStats; + Preconditions.checkArgument(children.size() > 1, "and expression abnormal: " + or); + for (int i = 1; i < children.size(); i++) { + Expression child = children.get(i); + Statistics andStats = child.accept(this, new EstimationContext(leftStats)); + Statistics rightStats = child.accept(this, context); rightStats.normalizeColumnStatistics(context.statistics.getRowCount(), true); double rowCount = leftStats.getRowCount() + rightStats.getRowCount() - andStats.getRowCount(); Statistics orStats = context.statistics.withRowCount(rowCount); - Set leftInputSlots = leftExpr.getInputSlots(); - Set rightInputSlots = rightExpr.getInputSlots(); + + Set rightInputSlots = child.getInputSlots(); for (Slot slot : context.keyColumns) { if (leftInputSlots.contains(slot) && rightInputSlots.contains(slot)) { ColumnStatistic leftColStats = leftStats.findColumnStatistics(slot); @@ -146,13 +159,11 @@ public Statistics visitCompoundPredicate(CompoundPredicate predicate, Estimation orStats.addColumnStats(slot, colBuilder.build()); } } - return orStats; + leftStats = orStats; + outputStats = orStats; + leftInputSlots.addAll(child.getInputSlots()); } - // should not come here - Preconditions.checkArgument(false, - "unsupported compound operator: %s in %s", - predicate.getClass().getName(), predicate.toSql()); - return context.statistics; + return outputStats; } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/And.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/And.java index 5e76c3afa1a6b30..cc302e76061cfad 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/And.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/And.java @@ -18,9 +18,9 @@ package org.apache.doris.nereids.trees.expressions; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.util.ExpressionUtils; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import java.util.List; @@ -28,7 +28,6 @@ * And predicate expression. */ public class And extends CompoundPredicate { - /** * Desc: Constructor for CompoundPredicate. * @@ -36,16 +35,18 @@ public class And extends CompoundPredicate { * @param right right child of comparison predicate */ public And(Expression left, Expression right) { - super(ImmutableList.of(left, right), "AND"); + super(ExpressionUtils.mergeList( + ExpressionUtils.extractConjunction(left), + ExpressionUtils.extractConjunction(right)), "AND"); } - private And(List children) { + public And(List children) { super(children, "AND"); } @Override public Expression withChildren(List children) { - Preconditions.checkArgument(children.size() == 2); + Preconditions.checkArgument(children.size() >= 2); return new And(children); } @@ -56,16 +57,35 @@ public R accept(ExpressionVisitor visitor, C context) { @Override public CompoundPredicate flip() { - return new Or(left(), right()); + return new Or(children); } @Override - public CompoundPredicate flip(Expression left, Expression right) { - return new Or(left, right); + public CompoundPredicate flip(List children) { + return new Or(children); } @Override public Class flipType() { return Or.class; } + + @Override + protected List extract() { + return ExpressionUtils.extractConjunction(this); + } + + @Override + public List children() { + if (flattenChildren.isEmpty()) { + for (Expression child : children) { + if (child instanceof And) { + flattenChildren.addAll(((And) child).extract()); + } else { + flattenChildren.add(child); + } + } + } + return flattenChildren; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/CompoundPredicate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/CompoundPredicate.java index ccc55122125784d..8e0536824a20978 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/CompoundPredicate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/CompoundPredicate.java @@ -18,25 +18,32 @@ package org.apache.doris.nereids.trees.expressions; import org.apache.doris.nereids.exceptions.UnboundException; +import org.apache.doris.nereids.trees.expressions.functions.ExpressionTrait; +import org.apache.doris.nereids.trees.expressions.typecoercion.ExpectsInputTypes; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.DataType; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * Compound predicate expression. - * Such as &&,||,AND,OR. + * Such as AND,OR. */ -public abstract class CompoundPredicate extends BinaryOperator { +public abstract class CompoundPredicate extends Expression implements ExpectsInputTypes { + protected final List flattenChildren = new ArrayList<>(); + private String symbol; public CompoundPredicate(List children, String symbol) { - super(children, symbol); + super(children); + this.symbol = symbol; } @Override public boolean nullable() throws UnboundException { - return left().nullable() || right().nullable(); + return children.stream().anyMatch(ExpressionTrait::nullable); } @Override @@ -50,8 +57,8 @@ public R accept(ExpressionVisitor visitor, C context) { } @Override - public DataType inputType() { - return BooleanType.INSTANCE; + public List expectedInputTypes() { + return children.stream().map(c -> BooleanType.INSTANCE).collect(Collectors.toList()); } /** @@ -62,8 +69,58 @@ public DataType inputType() { /** * Flip logical `and` and `or` operator with new children. */ - public abstract CompoundPredicate flip(Expression left, Expression right); + public abstract CompoundPredicate flip(List children); public abstract Class flipType(); + protected abstract List extract(); + + @Override + public boolean equals(Object o) { + if (compareWidthAndDepth) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + List thisChildren = this.children(); + List thatChildren = ((CompoundPredicate) o).children(); + if (thisChildren.size() != thatChildren.size()) { + return false; + } + for (int i = 0; i < thisChildren.size(); i++) { + if (!thisChildren.get(i).equals(thatChildren.get(i))) { + return false; + } + } + return true; + } else { + return super.equals(o); + } + } + + @Override + public String toSql() { + StringBuilder sb = new StringBuilder(); + children().forEach(c -> sb.append(c.toSql()).append(",")); + sb.deleteCharAt(sb.length() - 1); + return symbol + "[" + sb + "]"; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + children().forEach(c -> sb.append(c.toString()).append(",")); + sb.deleteCharAt(sb.length() - 1); + return symbol + "[" + sb + "]"; + } + + @Override + public String shapeInfo() { + StringBuilder sb = new StringBuilder(); + children().forEach(c -> sb.append(c.shapeInfo()).append(",")); + sb.deleteCharAt(sb.length() - 1); + return symbol + "[" + sb + "]"; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java index 6063ad2b1cd6d18..e20290e8b59c416 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java @@ -17,7 +17,6 @@ package org.apache.doris.nereids.trees.expressions; -import org.apache.doris.common.Config; import org.apache.doris.nereids.analyzer.Unbound; import org.apache.doris.nereids.analyzer.UnboundVariable; import org.apache.doris.nereids.exceptions.AnalysisException; @@ -60,12 +59,12 @@ public abstract class Expression extends AbstractTreeNode implements public static final String DEFAULT_EXPRESSION_NAME = "expression"; // Mask this expression is generated by rule, should be removed. protected Optional exprName = Optional.empty(); + protected final boolean compareWidthAndDepth; private final int depth; private final int width; // Mark this expression is from predicate infer or something else infer private final boolean inferred; private final boolean hasUnbound; - private final boolean compareWidthAndDepth; private final Supplier> inputSlots = Suppliers.memoize( () -> collect(e -> e instanceof Slot && !(e instanceof ArrayItemSlot))); private final int fastChildrenHashCode; @@ -115,8 +114,6 @@ protected Expression(Expression... children) { this.compareWidthAndDepth = compareWidthAndDepth; this.fastChildrenHashCode = fastChildrenHashCode; } - - checkLimit(); this.inferred = false; this.hasUnbound = hasUnbound || this instanceof Unbound; } @@ -170,23 +167,10 @@ protected Expression(List children, boolean inferred) { this.compareWidthAndDepth = compareWidthAndDepth && supportCompareWidthAndDepth(); this.fastChildrenHashCode = fastChildrenhashCode; } - - checkLimit(); this.inferred = inferred; this.hasUnbound = hasUnbound || this instanceof Unbound; } - private void checkLimit() { - if (depth > Config.expr_depth_limit) { - throw new AnalysisException(String.format("Exceeded the maximum depth of an " - + "expression tree (%s).", Config.expr_depth_limit)); - } - if (width > Config.expr_children_limit) { - throw new AnalysisException(String.format("Exceeded the maximum children of an " - + "expression tree (%s).", Config.expr_children_limit)); - } - } - public Alias alias(String alias) { return new Alias(this, alias); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Or.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Or.java index 61249fb91c48ce1..cf6c46c3ea42154 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Or.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Or.java @@ -18,9 +18,9 @@ package org.apache.doris.nereids.trees.expressions; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.util.ExpressionUtils; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import java.util.List; @@ -36,16 +36,18 @@ public class Or extends CompoundPredicate { * @param right right child of comparison predicate */ public Or(Expression left, Expression right) { - super(ImmutableList.of(left, right), "OR"); + super(ExpressionUtils.mergeList( + ExpressionUtils.extractDisjunction(left), + ExpressionUtils.extractDisjunction(right)), "OR"); } - private Or(List children) { + public Or(List children) { super(children, "OR"); } @Override public Expression withChildren(List children) { - Preconditions.checkArgument(children.size() == 2); + Preconditions.checkArgument(children.size() >= 2); return new Or(children); } @@ -56,16 +58,35 @@ public R accept(ExpressionVisitor visitor, C context) { @Override public CompoundPredicate flip() { - return new And(left(), right()); + return new And(children); } @Override - public CompoundPredicate flip(Expression left, Expression right) { - return new And(left, right); + public CompoundPredicate flip(List children) { + return new And(children); } @Override public Class flipType() { return And.class; } + + @Override + protected List extract() { + return ExpressionUtils.extractDisjunction(this); + } + + @Override + public List children() { + if (flattenChildren.isEmpty()) { + for (Expression child : children) { + if (child instanceof Or) { + flattenChildren.addAll(((Or) child).extract()); + } else { + flattenChildren.add(child); + } + } + } + return flattenChildren; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java index ab367a2bf7398e4..406d0835610a176 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/visitor/ExpressionVisitor.java @@ -334,7 +334,7 @@ public R visitStructLiteral(StructLiteral structLiteral, C context) { } public R visitCompoundPredicate(CompoundPredicate compoundPredicate, C context) { - return visitBinaryOperator(compoundPredicate, context); + return visit(compoundPredicate, context); } public R visitAnd(And and, C context) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DeleteFromCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DeleteFromCommand.java index 34a54ec2651f650..ab2a7d3f7414c10 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DeleteFromCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DeleteFromCommand.java @@ -334,8 +334,8 @@ private void checkInPredicate(InPredicate in) { private void checkPredicate(Expression predicate) { if (predicate instanceof And) { - checkPredicate(((And) predicate).left()); - checkPredicate(((And) predicate).right()); + And and = (And) predicate; + and.children().forEach(child -> checkPredicate(child)); } else if (predicate instanceof ComparisonPredicate) { checkComparisonPredicate((ComparisonPredicate) predicate); } else if (predicate instanceof IsNull) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java index bf4d6e084795f10..e3909b87bd3726f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/ExpressionUtils.java @@ -78,10 +78,12 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -131,18 +133,24 @@ public static List extract(CompoundPredicate expr) { private static List extract(Class type, Expression expr) { List result = Lists.newArrayList(); - extract(type, expr, result); + Deque stack = new ArrayDeque<>(); + stack.push(expr); + while (!stack.isEmpty()) { + Expression current = stack.pop(); + if (type.isInstance(current)) { + for (Expression child : current.children()) { + stack.push(child); + } + } else { + result.add(current); + } + } + result = Lists.reverse(result); return result; } private static void extract(Class type, Expression expr, Collection result) { - if (type.isInstance(expr)) { - CompoundPredicate predicate = (CompoundPredicate) expr; - extract(type, predicate.left(), result); - extract(type, predicate.right(), result); - } else { - result.add(expr); - } + result.addAll(extract(type, expr)); } public static Optional> extractEqualSlot(Expression expr) { @@ -1002,6 +1010,24 @@ public static Literal analyzeAndFoldToLiteral(ConnectContext ctx, Expression exp } } + /** + * mergeList + */ + public static List mergeList(List list1, List list2) { + ImmutableList.Builder builder = ImmutableList.builder(); + for (Expression expression : list1) { + if (expression != null) { + builder.add(expression); + } + } + for (Expression expression : list2) { + if (expression != null) { + builder.add(expression); + } + } + return builder.build(); + } + private static class UnboundSlotRewriter extends DefaultExpressionRewriter { public static final UnboundSlotRewriter INSTANCE = new UnboundSlotRewriter(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java index d7f9fc83baf288a..603a891d2d2a490 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java @@ -32,7 +32,6 @@ import org.apache.doris.nereids.trees.expressions.CaseWhen; import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.ComparisonPredicate; -import org.apache.doris.nereids.trees.expressions.CompoundPredicate; import org.apache.doris.nereids.trees.expressions.Divide; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.InPredicate; @@ -1192,28 +1191,6 @@ public static Expression processCaseWhen(CaseWhen caseWhen) { .orElseThrow(() -> new AnalysisException("Cannot find common type for case when " + caseWhen)); } - /** - * process compound predicate type coercion. - */ - public static Expression processCompoundPredicate(CompoundPredicate compoundPredicate) { - // check - compoundPredicate.checkLegalityBeforeTypeCoercion(); - ImmutableList.Builder newChildren - = ImmutableList.builderWithExpectedSize(compoundPredicate.arity()); - boolean changed = false; - for (Expression child : compoundPredicate.children()) { - Expression newChild; - if (child.getDataType().isNullType()) { - newChild = new NullLiteral(BooleanType.INSTANCE); - } else { - newChild = castIfNotSameType(child, BooleanType.INSTANCE); - } - changed |= child != newChild; - newChildren.add(newChild); - } - return changed ? compoundPredicate.withChildren(newChildren.build()) : compoundPredicate; - } - private static boolean canCompareDate(DataType t1, DataType t2) { DataType dateType = t1; DataType anotherType = t2; diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ArrayContainsToArrayOverlapTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ArrayContainsToArrayOverlapTest.java index 028d85ce097fe67..ed56bd2a13c3bc6 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ArrayContainsToArrayOverlapTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/ArrayContainsToArrayOverlapTest.java @@ -89,8 +89,7 @@ void testAndOverlap() { .rewrite() .getPlan(); Expression expression = plan.child(0).getExpressions().get(0).child(0); - Assertions.assertEquals("(array_contains([1], 0) OR " - + "(array_contains([1], 1) AND arrays_overlap([1], [2, 3, 4])))", + Assertions.assertEquals("OR[array_contains([1], 0),AND[array_contains([1], 1),arrays_overlap([1], [2, 3, 4])]]", expression.toSql()); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/OrToInTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/OrToInTest.java index aaca3edf1019491..774be68643feb2e 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/OrToInTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/OrToInTest.java @@ -38,7 +38,7 @@ void test1() { String expr = "col1 = 1 or col1 = 2 or col1 = 3 and (col2 = 4)"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("(col1 IN (1, 2, 3) AND (col1 IN (1, 2) OR ((col1 = 3) AND (col2 = 4))))", + Assertions.assertEquals("AND[col1 IN (1, 2, 3),OR[col1 IN (1, 2),AND[(col1 = 3),(col2 = 4)]]]", rewritten.toSql()); } @@ -106,7 +106,8 @@ void test7() { String expr = "A = 1 or A = 2 or abs(A)=5 or A in (1, 2, 3) or B = 1 or B = 2 or B in (1, 2, 3) or B+1 in (4, 5, 7)"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("(((A IN (1, 2, 3) OR (abs(A) = 5)) OR B IN (1, 2, 3)) OR (B + 1) IN (4, 5, 7))", rewritten.toSql()); + Assertions.assertEquals("OR[A IN (1, 2, 3),(abs(A) = 5),B IN (1, 2, 3),(B + 1) IN (4, 5, 7)]", + rewritten.toSql()); } @Test @@ -114,7 +115,7 @@ void test8() { String expr = "col = 1 or (col = 2 and (col = 3 or col = '4' or col = 5.0))"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("((col = 1) OR ((col = 2) AND col IN ('4', 3, 5.0)))", + Assertions.assertEquals("OR[(col = 1),AND[(col = 2),col IN ('4', 3, 5.0)]]", rewritten.toSql()); } @@ -124,7 +125,7 @@ void testEnsureOrder() { String expr = "col1 IN (1, 2) OR col2 IN (1, 2)"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("(col1 IN (1, 2) OR col2 IN (1, 2))", + Assertions.assertEquals("OR[col1 IN (1, 2),col2 IN (1, 2)]", rewritten.toSql()); } @@ -133,7 +134,7 @@ void test9() { String expr = "col1=1 and (col2=1 or col2=2)"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("((col1 = 1) AND col2 IN (1, 2))", + Assertions.assertEquals("AND[(col1 = 1),col2 IN (1, 2)]", rewritten.toSql()); } @@ -143,7 +144,7 @@ void test10() { String expr = "col1=1 or (col2 = 2 and (col3=4 or col3=5))"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("((col1 = 1) OR ((col2 = 2) AND col3 IN (4, 5)))", + Assertions.assertEquals("OR[(col1 = 1),AND[(col2 = 2),col3 IN (4, 5)]]", rewritten.toSql()); } @@ -153,7 +154,7 @@ void test11() { String expr = "(a=1 and b=2 and c=3) or (a=2 and b=2 and c=4)"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("((b = 2) AND ((a IN (1, 2) AND c IN (3, 4)) AND (((a = 1) AND (c = 3)) OR ((a = 2) AND (c = 4)))))", + Assertions.assertEquals("AND[(b = 2),a IN (1, 2),c IN (3, 4),OR[AND[(a = 1),(c = 3)],AND[(a = 2),(c = 4)]]]", rewritten.toSql()); } @@ -183,7 +184,7 @@ void test14() { String expr = "(a=1 and f(a)=2) or a=3"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("(((a = 1) AND (f(a) = 2)) OR (a = 3))", + Assertions.assertEquals("OR[AND[(a = 1),(f(a) = 2)],(a = 3)]", rewritten.toSql()); } @@ -193,7 +194,7 @@ void test15() { String expr = "x=1 or (a=1 and b=2) or (a=2 and c=3)"; Expression expression = PARSER.parseExpression(expr); Expression rewritten = OrToIn.INSTANCE.rewriteTree(expression, context); - Assertions.assertEquals("((x = 1) OR (((a = 1) AND (b = 2)) OR ((a = 2) AND (c = 3))))", + Assertions.assertEquals("OR[(x = 1),AND[(a = 1),(b = 2)],AND[(a = 2),(c = 3)]]", rewritten.toSql()); }