From 2f0eec03c8b799ee1d4780f6b2481a40c04fb442 Mon Sep 17 00:00:00 2001 From: yujun Date: Fri, 29 Aug 2025 19:12:27 +0800 Subject: [PATCH 1/7] add between back --- .../glue/translator/ExpressionTranslator.java | 8 ++ .../nereids/parser/LogicalPlanBuilder.java | 20 ++-- .../rules/analysis/ExpressionAnalyzer.java | 9 ++ .../expression/ExpressionNormalization.java | 2 + .../rules/expression/ExpressionRuleType.java | 1 + .../expression/rules/BetweenToCompound.java | 58 +++++++++++ .../rules/FoldConstantRuleOnBE.java | 5 +- .../nereids/trees/expressions/Between.java | 97 +++++++++++++++++++ .../expressions/functions/scalar/Random.java | 5 +- .../visitor/ExpressionVisitor.java | 5 + .../apache/doris/nereids/util/PlanUtils.java | 2 +- .../doris/nereids/util/TypeCoercionUtils.java | 66 +++++++++++++ .../doris/nereids/parser/BetweenTest.java | 11 ++- .../expression/ExpressionRewriteTest.java | 20 +++- .../rules/expression/SimplifyRangeTest.java | 13 ++- .../expressions/ExpressionEqualsTest.java | 8 ++ .../expressions/ExpressionParserTest.java | 7 +- .../agg_with_unique_function.out | 10 +- .../between_with_unique_function.out | 6 ++ .../test_date_function_prune_mono.groovy | 6 +- .../test_date_trunc_prune.groovy | 6 +- .../between_with_unique_function.groovy | 21 ++++ 22 files changed, 348 insertions(+), 38 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java create mode 100644 regression-test/data/nereids_rules_p0/unique_function/between_with_unique_function.out create mode 100644 regression-test/suites/nereids_rules_p0/unique_function/between_with_unique_function.groovy 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 9ec0f5094452b9..a7d8f4b281661b 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 @@ -54,6 +54,7 @@ import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.ArrayItemReference; import org.apache.doris.nereids.trees.expressions.AssertNumRowsElement; +import org.apache.doris.nereids.trees.expressions.Between; import org.apache.doris.nereids.trees.expressions.BinaryArithmetic; import org.apache.doris.nereids.trees.expressions.CaseWhen; import org.apache.doris.nereids.trees.expressions.Cast; @@ -388,6 +389,13 @@ private Expr toBalancedTree(int low, int high, List children, return results.pop(); } + @Override + public Expr visitBetween(Between between, PlanTranslatorContext context) { + And and = new And(new GreaterThanEqual(between.getCompareExpr(), between.getLowerBound()), + new LessThanEqual(between.getCompareExpr(), between.getUpperBound())); + return and.accept(this, context); + } + @Override public Expr visitAnd(And and, PlanTranslatorContext context) { List children = and.children().stream().map( 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 b3e6a3406453d7..e40b83bfe48adc 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 @@ -495,6 +495,7 @@ import org.apache.doris.nereids.trees.expressions.Add; import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.And; +import org.apache.doris.nereids.trees.expressions.Between; import org.apache.doris.nereids.trees.expressions.BitAnd; import org.apache.doris.nereids.trees.expressions.BitNot; import org.apache.doris.nereids.trees.expressions.BitOr; @@ -4427,16 +4428,15 @@ private Expression withPredicate(Expression valueExpression, PredicateContext ct Expression outExpression; switch (ctx.kind.getType()) { case DorisParser.BETWEEN: - Expression lower = getExpression(ctx.lower); - Expression upper = getExpression(ctx.upper); - if (lower.equals(upper)) { - outExpression = new EqualTo(valueExpression, lower); - } else { - outExpression = new And( - new GreaterThanEqual(valueExpression, getExpression(ctx.lower)), - new LessThanEqual(valueExpression, getExpression(ctx.upper)) - ); - } + // don't compare lower and upper before bind expression, + // for `a between random() and random()` + // the two unbound `'random()` equal, but after bind expression, + // the two `random()` are different. + outExpression = new Between( + valueExpression, + getExpression(ctx.lower), + getExpression(ctx.upper) + ); break; case DorisParser.LIKE: if (ctx.ESCAPE() == null) { 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 62dc65f96dd371..9cfb60d4d40326 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 @@ -43,6 +43,7 @@ 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.Between; import org.apache.doris.nereids.trees.expressions.BinaryArithmetic; import org.apache.doris.nereids.trees.expressions.BitNot; import org.apache.doris.nereids.trees.expressions.BoundStar; @@ -738,6 +739,14 @@ public Expression visitInPredicate(InPredicate inPredicate, ExpressionRewriteCon return TypeCoercionUtils.processInPredicate(newInPredicate); } + @Override + public Expression visitBetween(Between between, ExpressionRewriteContext context) { + List rewrittenChildren = between.children().stream() + .map(e -> e.accept(this, context)).collect(Collectors.toList()); + Between newBetween = between.withChildren(rewrittenChildren); + return TypeCoercionUtils.processBetween(newBetween); + } + @Override public Expression visitInSubquery(InSubquery inSubquery, ExpressionRewriteContext context) { // analyze subquery diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java index 2e24f7895e6692..831d2b260dc479 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java @@ -18,6 +18,7 @@ package org.apache.doris.nereids.rules.expression; import org.apache.doris.nereids.rules.expression.check.CheckCast; +import org.apache.doris.nereids.rules.expression.rules.BetweenToCompound; import org.apache.doris.nereids.rules.expression.rules.ConcatWsMultiArrayToOne; import org.apache.doris.nereids.rules.expression.rules.ConvertAggStateCast; import org.apache.doris.nereids.rules.expression.rules.DigitalMaskingConvert; @@ -54,6 +55,7 @@ public class ExpressionNormalization extends ExpressionRewrite { bottomUp( SupportJavaDateFormatter.INSTANCE, NormalizeBinaryPredicatesRule.INSTANCE, + BetweenToCompound.INSTANCE, InPredicateDedup.INSTANCE, InPredicateExtractNonConstant.INSTANCE, InPredicateToEqualToRule.INSTANCE, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java index 8094ec5dac0786..328498d6852eb5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java @@ -23,6 +23,7 @@ public enum ExpressionRuleType { ADD_MIN_MAX, ARRAY_CONTAIN_TO_ARRAY_OVERLAP, + BETWEEN_TO_COMPOUND, BETWEEN_TO_EQUAL, CASE_WHEN_TO_IF, CHECK_CAST, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java new file mode 100644 index 00000000000000..5384c37f539e46 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java @@ -0,0 +1,58 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.rules.expression.rules; + +import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher; +import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory; +import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext; +import org.apache.doris.nereids.rules.expression.ExpressionRuleType; +import org.apache.doris.nereids.trees.expressions.And; +import org.apache.doris.nereids.trees.expressions.Between; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.GreaterThanEqual; +import org.apache.doris.nereids.trees.expressions.LessThanEqual; + +import com.google.common.collect.ImmutableList; + +import java.util.List; + +/** + * Rewrites BetweenPredicates into an equivalent conjunctive CompoundPredicate, + * "not between" is first processed by the BetweenToCompoundRule and then by the SimplifyNotExprRule. + * Examples: + * A BETWEEN X AND Y ==> A >= X AND A <= Y + */ +public class BetweenToCompound implements ExpressionPatternRuleFactory { + + public static BetweenToCompound INSTANCE = new BetweenToCompound(); + + @Override + public List> buildRules() { + return ImmutableList.of( + matchesType(Between.class) + .thenApply(ctx -> rewrite(ctx.expr, ctx.rewriteContext)) + .toRule(ExpressionRuleType.BETWEEN_TO_COMPOUND) + ); + } + + public Expression rewrite(Between expr, ExpressionRewriteContext context) { + Expression left = new GreaterThanEqual(expr.getCompareExpr(), expr.getLowerBound()); + Expression right = new LessThanEqual(expr.getCompareExpr(), expr.getUpperBound()); + return new And(left, right); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java index 3a99a8ffedcd6e..1b335fe5077e1e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java @@ -34,6 +34,7 @@ import org.apache.doris.nereids.rules.expression.ExpressionRuleType; import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.ArrayItemReference; +import org.apache.doris.nereids.trees.expressions.Between; import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Match; @@ -198,7 +199,9 @@ private static Expression replace( private static void collectConst(Expression expr, Map constMap, Map tExprMap, IdGenerator idGenerator) { - if (expr.isConstant() && !expr.isLiteral() && !expr.anyMatch(e -> shouldSkipFold((Expression) e))) { + // skip BetweenPredicate need to be rewrite to CompoundPredicate + if (expr.isConstant() && !expr.isLiteral() && !(expr instanceof Between) + && !expr.anyMatch(e -> shouldSkipFold((Expression) e))) { String id = idGenerator.getNextId().toString(); constMap.put(id, expr); Expr staleExpr; diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java new file mode 100644 index 00000000000000..2cd5da27cfd565 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java @@ -0,0 +1,97 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.trees.expressions; + +import org.apache.doris.nereids.exceptions.UnboundException; +import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable; +import org.apache.doris.nereids.trees.expressions.shape.TernaryExpression; +import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; +import org.apache.doris.nereids.types.BooleanType; +import org.apache.doris.nereids.types.DataType; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Objects; + +/** + * Between predicate expression. + */ +public class Between extends Expression implements TernaryExpression, PropagateNullable { + + private final Expression compareExpr; + private final Expression lowerBound; + private final Expression upperBound; + /** + * Constructor of ComparisonPredicate. + * + * @param compareExpr compare of expression + * @param lowerBound left child of between predicate + * @param upperBound right child of between predicate + */ + + public Between(Expression compareExpr, Expression lowerBound, + Expression upperBound) { + this(ImmutableList.of(compareExpr, lowerBound, upperBound)); + } + + public Between(List children) { + super(children); + this.compareExpr = children.get(0); + this.lowerBound = children.get(1); + this.upperBound = children.get(2); + } + + @Override + public DataType getDataType() throws UnboundException { + return BooleanType.INSTANCE; + } + + @Override + public String computeToSql() { + return compareExpr.toSql() + " BETWEEN " + lowerBound.toSql() + " AND " + upperBound.toSql(); + } + + @Override + public String toString() { + return compareExpr + " BETWEEN " + lowerBound + " AND " + upperBound; + } + + public R accept(ExpressionVisitor visitor, C context) { + return visitor.visitBetween(this, context); + } + + public Expression getCompareExpr() { + return compareExpr; + } + + public Expression getLowerBound() { + return lowerBound; + } + + public Expression getUpperBound() { + return upperBound; + } + + @Override + public Between withChildren(List children) { + Preconditions.checkArgument(children.size() == 3); + return new Between(children); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java index 5797a4293421be..625a06ce52b39f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java @@ -37,10 +37,7 @@ * ScalarFunction 'random'. This class is generated by GenerateFunction. * has three signatures: * 1. random(): random a double value between 0 and 1. - * 2. random(seed): random a double value between 0 and 1 with the given seed value, - * in fact, this signature is deterministic and fold-able, - * for example, random(100) always equals 0.9616644308453555. - * but for simple reason, we still treat it as non-deterministic. + * 2. random(seed): random a fix double value sequence between 0 and 1 with the given seed value. * 3. random(a, b): random a big int value between a and b. */ public class Random extends UniqueFunction 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 428e4ab6df467d..25578570964809 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 @@ -28,6 +28,7 @@ import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.Any; import org.apache.doris.nereids.trees.expressions.ArrayItemReference; +import org.apache.doris.nereids.trees.expressions.Between; import org.apache.doris.nereids.trees.expressions.BinaryArithmetic; import org.apache.doris.nereids.trees.expressions.BinaryOperator; import org.apache.doris.nereids.trees.expressions.BitAnd; @@ -337,6 +338,10 @@ public R visitStructLiteral(StructLiteral structLiteral, C context) { return visitLiteral(structLiteral, context); } + public R visitBetween(Between between, C context) { + return visit(between, context); + } + public R visitCompoundPredicate(CompoundPredicate compoundPredicate, C context) { return visit(compoundPredicate, context); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java index 71b1b216797668..9c18c6ba32c7db 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java @@ -160,7 +160,7 @@ public static List replaceExpressionByProjections(List new AnalysisException("Cannot find common type for case when " + caseWhen)); } + /** + * process between type coercion. + */ + public static Expression processBetween(Between between) { + // check + between.checkLegalityBeforeTypeCoercion(); + + if (between.getLowerBound().getDataType().equals(between.getCompareExpr().getDataType()) + && between.getUpperBound().getDataType().equals(between.getCompareExpr().getDataType())) { + return between; + } + + // process string literal + boolean hitString = false; + Expression newLowerBound = between.getLowerBound(); + Expression newUpperBound = between.getUpperBound(); + if (!(between.getCompareExpr().getDataType().isStringLikeType())) { + if (newLowerBound instanceof Literal && ((Literal) newLowerBound).isStringLikeLiteral()) { + Optional boundOpt = TypeCoercionUtils.characterLiteralTypeCoercion( + ((Literal) newLowerBound).getStringValue(), between.getCompareExpr().getDataType()); + if (boundOpt.isPresent()) { + newLowerBound = boundOpt.get(); + hitString = true; + } + } + if (newUpperBound instanceof Literal && ((Literal) newUpperBound).isStringLikeLiteral()) { + Optional boundOpt = TypeCoercionUtils.characterLiteralTypeCoercion( + ((Literal) newUpperBound).getStringValue(), between.getCompareExpr().getDataType()); + if (boundOpt.isPresent()) { + newUpperBound = boundOpt.get(); + hitString = true; + } + } + } + if (hitString) { + between = new Between(between.getCompareExpr(), newLowerBound, newUpperBound); + } + + Optional optionalCommonType = TypeCoercionUtils.findWiderCommonTypeForComparison( + between.children() + .stream() + .map(Expression::getDataType) + .collect(Collectors.toList())); + + if (optionalCommonType.isPresent()) { + optionalCommonType = Optional.of(downgradeDecimalAndDateLikeType( + optionalCommonType.get(), + between.getCompareExpr(), + between.getLowerBound(), + between.getUpperBound())); + } + + // lambda need a final variable + final Between finalBetween = between; + + return optionalCommonType + .map(commonType -> { + List newChildren = finalBetween.children().stream() + .map(e -> TypeCoercionUtils.castIfNotMatchType(e, commonType)) + .collect(Collectors.toList()); + return finalBetween.withChildren(newChildren); + }) + .orElse(between); + } + 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/parser/BetweenTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/BetweenTest.java index c9ef4fbee27cbe..f903763bfdd33d 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/BetweenTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/BetweenTest.java @@ -17,8 +17,7 @@ package org.apache.doris.nereids.parser; -import org.apache.doris.nereids.trees.expressions.And; -import org.apache.doris.nereids.trees.expressions.EqualTo; +import org.apache.doris.nereids.trees.expressions.Between; import org.apache.doris.nereids.trees.expressions.Expression; import org.junit.jupiter.api.Assertions; @@ -31,10 +30,14 @@ public class BetweenTest { public void testBetween() { String expression = "A between 1 and 1"; // Expression result = PARSER.parseExpression(expression); - Assertions.assertInstanceOf(EqualTo.class, result); + Assertions.assertInstanceOf(Between.class, result); expression = "A between 1 and 2"; result = PARSER.parseExpression(expression); - Assertions.assertInstanceOf(And.class, result); + Assertions.assertInstanceOf(Between.class, result); + + expression = "A between random() and random()"; + result = PARSER.parseExpression(expression); + Assertions.assertInstanceOf(Between.class, result); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java index 43e44255f66611..bb5c722098a5a4 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java @@ -18,6 +18,7 @@ package org.apache.doris.nereids.rules.expression; import org.apache.doris.nereids.rules.expression.rules.AddMinMax; +import org.apache.doris.nereids.rules.expression.rules.BetweenToCompound; import org.apache.doris.nereids.rules.expression.rules.DistinctPredicatesRule; import org.apache.doris.nereids.rules.expression.rules.ExtractCommonFactorRule; import org.apache.doris.nereids.rules.expression.rules.InPredicateDedup; @@ -242,6 +243,19 @@ void testInPredicateDedup() { assertRewrite("a in (1, 2, 1, 2)", "a in (1, 2)"); } + @Test + void testBetweenToCompoundRule() { + executor = new ExpressionRuleExecutor(ImmutableList.of( + bottomUp( + BetweenToCompound.INSTANCE, + SimplifyNotExprRule.INSTANCE) + )); + + assertRewrite("a between c and d", "(a >= c) and (a <= d)"); + assertRewrite("a not between c and d", "(a < c) or (a > d)"); + + } + @Test void testSimplifyCastRule() { executor = new ExpressionRuleExecutor(ImmutableList.of( @@ -312,7 +326,8 @@ void testDeadLoop() { void testAddMinMax() { executor = new ExpressionRuleExecutor(ImmutableList.of( bottomUp( - AddMinMax.INSTANCE + AddMinMax.INSTANCE, + BetweenToCompound.INSTANCE ) )); @@ -378,7 +393,8 @@ void testSimplifyRangeAndAddMinMax() { executor = new ExpressionRuleExecutor(ImmutableList.of( bottomUp( SimplifyRange.INSTANCE, - AddMinMax.INSTANCE + AddMinMax.INSTANCE, + BetweenToCompound.INSTANCE ) )); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java index 3a1e34deded837..6caad716b611f7 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.analyzer.UnboundSlot; import org.apache.doris.nereids.parser.NereidsParser; import org.apache.doris.nereids.rules.analysis.ExpressionAnalyzer; +import org.apache.doris.nereids.rules.expression.rules.BetweenToCompound; import org.apache.doris.nereids.rules.expression.rules.RangeInference; import org.apache.doris.nereids.rules.expression.rules.RangeInference.EmptyValue; import org.apache.doris.nereids.rules.expression.rules.RangeInference.RangeValue; @@ -95,7 +96,10 @@ public void testRangeInference() { @Test public void testSimplify() { executor = new ExpressionRuleExecutor(ImmutableList.of( - bottomUp(SimplifyRange.INSTANCE) + bottomUp( + SimplifyRange.INSTANCE, + BetweenToCompound.INSTANCE + ) )); assertRewrite("TA", "TA"); assertRewrite("TA > 3 or TA > null", "TA > 3 OR NULL"); @@ -109,7 +113,7 @@ public void testSimplify() { assertRewrite("TA > 3 or TA <=> null", "TA > 3 or TA <=> null"); assertRewrite("(TA < 1 or TA > 2) or (TA >= 0 and TA <= 3)", "TA IS NOT NULL OR NULL"); assertRewrite("TA between 10 and 20 or TA between 100 and 120 or TA between 15 and 25 or TA between 115 and 125", - "TA between 10 and 25 or TA between 100 and 125"); + "TA >= 10 and TA <= 25 or TA >= 100 and TA <= 125"); assertRewriteNotNull("TA > 3 and TA > null", "TA > 3 and NULL"); assertRewriteNotNull("TA > 3 and TA < null", "TA > 3 and NULL"); assertRewriteNotNull("TA > 3 and TA = null", "TA > 3 and NULL"); @@ -242,6 +246,11 @@ public void testSimplify() { // random is non-foldable, so the two random(1, 10) are distinct, cann't merge range for them. Expression expr = rewrite("TA + random(1, 10) > 10 AND TA + random(1, 10) < 1", Maps.newHashMap()); Assertions.assertEquals("AND[((cast(TA as BIGINT) + random(1, 10)) > 10),((cast(TA as BIGINT) + random(1, 10)) < 1)]", expr.toSql()); + + expr = rewrite("TA + random(1, 10) between 10 and 20", Maps.newHashMap()); + Assertions.assertEquals("AND[((TA + random(1, 10)) >= 10),((TA + random(1, 10)) <= 20)]", expr.toSql()); + expr = rewrite("TA + random(1, 10) between 20 and 10", Maps.newHashMap()); + Assertions.assertEquals("AND[(TA + random(1, 10)) IS NULL,NULL]", expr.toSql()); } @Test diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ExpressionEqualsTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ExpressionEqualsTest.java index ca5793b687c092..c26c0205634832 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ExpressionEqualsTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ExpressionEqualsTest.java @@ -83,6 +83,14 @@ public void testComparisonPredicate() { Assertions.assertEquals(greaterThanEqual1.hashCode(), greaterThanEqual2.hashCode()); } + @Test + public void testBetween() { + Between between1 = new Between(child1, left1, right1); + Between between2 = new Between(child2, left2, right2); + Assertions.assertEquals(between1, between2); + Assertions.assertEquals(between1.hashCode(), between2.hashCode()); + } + @Test public void testNot() { Not not1 = new Not(child1); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ExpressionParserTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ExpressionParserTest.java index cd0e21bb71d7d4..f33bd493824845 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ExpressionParserTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/ExpressionParserTest.java @@ -84,9 +84,10 @@ public void testSqlBetweenPredicate() { public void testExprBetweenPredicate() { parseExpression("c BETWEEN a AND b") .assertEquals( - new And( - new GreaterThanEqual(new UnboundSlot("c"), new UnboundSlot("a")), - new LessThanEqual(new UnboundSlot("c"), new UnboundSlot("b")) + new Between( + new UnboundSlot("c"), + new UnboundSlot("a"), + new UnboundSlot("b") ) ); } diff --git a/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out b/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out index b57fe2df5cb445..a59eb1d160d45e 100644 --- a/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out +++ b/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out @@ -16,7 +16,7 @@ PhysicalResultSink -- !check_equal_no_agg_4_shape -- PhysicalResultSink ---PhysicalProject[(a + random()) AS `a + random()`, (a + random()) AS `a + random()`, sum(a + random()) over(), sum(a + random()) over()] +--PhysicalProject[(a + random()) AS `a + random()`, (a + random()) AS `a + random()`, sum(a + random()) over() AS `sum(a + random()) over()`, sum(a + random()) over() AS `sum(a + random()) over()`] ----PhysicalWindow ------PhysicalProject[(a + random()) AS `(a + random())`, (a + random()) AS `(a + random())`, tbl_unique_function_with_one_row.a] --------PhysicalOlapScan[tbl_unique_function_with_one_row] @@ -45,7 +45,7 @@ PhysicalResultSink -- !check_equal_one_row_to_agg_1_shape -- PhysicalResultSink ---PhysicalProject[random() AS `random()`, random() AS `random()`, sum(random()), sum(random()), sum(random()) over(), sum(random()) over()] +--PhysicalProject[random() AS `random()`, random() AS `random()`, sum(random()), sum(random()), sum(random()) over() AS `sum(random()) over()`, sum(random()) over() AS `sum(random()) over()`] ----PhysicalWindow ------PhysicalProject[random() AS `random()`, random() AS `random()`, sum(random()), sum(random())] --------hashAgg[GLOBAL] @@ -168,7 +168,7 @@ PhysicalResultSink -- !check_equal_agg_with_groupby_7_shape -- PhysicalResultSink ---PhysicalProject[a + random(), a + random() AS `a + random()`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over()] +--PhysicalProject[a + random(), a + random() AS `a + random()`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over() AS `sum(a + random()) over()`] ----PhysicalWindow ------hashAgg[GLOBAL] --------hashAgg[LOCAL] @@ -177,7 +177,7 @@ PhysicalResultSink -- !check_equal_agg_with_groupby_8_shape -- PhysicalResultSink ---PhysicalProject[a + random(), a + random() AS `a + random()`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over()] +--PhysicalProject[a + random(), a + random() AS `a + random()`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over() AS `sum(a + random()) over()`] ----PhysicalWindow ------hashAgg[GLOBAL] --------hashAgg[LOCAL] @@ -189,7 +189,7 @@ PhysicalResultSink PhysicalResultSink --PhysicalQuickSort[MERGE_SORT] ----PhysicalQuickSort[LOCAL_SORT] -------PhysicalProject[a + random(), a + random() AS `a + random()`, abs(a + random()) AS `abs(a + random())`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over()] +------PhysicalProject[a + random(), a + random() AS `a + random()`, abs(a + random()) AS `abs(a + random())`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over() AS `sum(a + random()) over()`] --------PhysicalWindow ----------hashAgg[GLOBAL] ------------hashAgg[LOCAL] diff --git a/regression-test/data/nereids_rules_p0/unique_function/between_with_unique_function.out b/regression-test/data/nereids_rules_p0/unique_function/between_with_unique_function.out new file mode 100644 index 00000000000000..9e489a3bfb10c1 --- /dev/null +++ b/regression-test/data/nereids_rules_p0/unique_function/between_with_unique_function.out @@ -0,0 +1,6 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !between_two_num -- +PhysicalResultSink +--filter((cast(id as DOUBLE) <= random()) and (cast(id as DOUBLE) >= random())) +----PhysicalOlapScan[t1] + diff --git a/regression-test/suites/nereids_rules_p0/partition_prune/test_date_function_prune_mono.groovy b/regression-test/suites/nereids_rules_p0/partition_prune/test_date_function_prune_mono.groovy index 7af54e3162b5e2..6ff101c84f2f26 100644 --- a/regression-test/suites/nereids_rules_p0/partition_prune/test_date_function_prune_mono.groovy +++ b/regression-test/suites/nereids_rules_p0/partition_prune/test_date_function_prune_mono.groovy @@ -124,9 +124,9 @@ suite("test_date_prune_mono") { for (int i = 0; i < 2; i++) { if (i == 0) { // forbid rewrite not a>1 to a<=1 - sql "set disable_nereids_rules = 'REWRITE_FILTER_EXPRESSION'" + sql "set disable_nereids_expression_rules = 'SIMPLIFY_NOT_EXPR'" } else { - sql "set disable_nereids_rules = ''" + sql "set disable_nereids_expression_rules = ''" } explain { sql """select * from mal_test_partition_range5_date_mono where not date(b)<="2020-01-14" """ @@ -307,4 +307,4 @@ suite("test_date_prune_mono") { sql "select * from mal_test_partition_range2_two_date_int_date_mono where date_trunc(date(dt),'minute') > '2017-2-1 00:00:00' and id>100;" contains("partitions=2/3 (p201702_2000,p201703_all)") } -} \ No newline at end of file +} diff --git a/regression-test/suites/nereids_rules_p0/partition_prune/test_date_trunc_prune.groovy b/regression-test/suites/nereids_rules_p0/partition_prune/test_date_trunc_prune.groovy index c5eb3855247ad0..9a34d489527d78 100644 --- a/regression-test/suites/nereids_rules_p0/partition_prune/test_date_trunc_prune.groovy +++ b/regression-test/suites/nereids_rules_p0/partition_prune/test_date_trunc_prune.groovy @@ -124,9 +124,9 @@ suite("test_date_trunc_prune") { for (int i = 0; i < 2; i++) { if (i == 0) { // forbid rewrite not a>1 to a<=1 - sql "set disable_nereids_rules = 'REWRITE_FILTER_EXPRESSION'" + sql "set disable_nereids_expression_rules = 'SIMPLIFY_NOT_EXPR'" } else { - sql "set disable_nereids_rules = ''" + sql "set disable_nereids_expression_rules = ''" } explain { sql """select * from mal_test_partition_range5 where not date_trunc(b,'day')<="2020-01-14" """ @@ -359,4 +359,4 @@ suite("test_date_trunc_prune") { sql """select * from t_multi_column_partition where a=2 and date_trunc(dt,'day') <'2024-01-1 00:00:00';""" contains ("partitions=1/5 (p0)") } -} \ No newline at end of file +} diff --git a/regression-test/suites/nereids_rules_p0/unique_function/between_with_unique_function.groovy b/regression-test/suites/nereids_rules_p0/unique_function/between_with_unique_function.groovy new file mode 100644 index 00000000000000..654af1506ab8f3 --- /dev/null +++ b/regression-test/suites/nereids_rules_p0/unique_function/between_with_unique_function.groovy @@ -0,0 +1,21 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite('between_with_unique_function') { + sql "SET ignore_shape_nodes='PhysicalDistribute'" + qt_between_two_num 'explain shape plan select * from t1 where id between random() and random()' +} From 7214fe6ebe25dc32282aec5991fa7ce33a968a2d Mon Sep 17 00:00:00 2001 From: yujun Date: Thu, 28 Aug 2025 11:44:34 +0800 Subject: [PATCH 2/7] update --- .../nereids/glue/translator/ExpressionTranslator.java | 11 ++++++++--- .../rules/expression/rules/BetweenToCompound.java | 11 ++++++++--- .../rules/expression/ExpressionRewriteTest.java | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) 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 a7d8f4b281661b..61056c8ed55150 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 @@ -391,9 +391,14 @@ private Expr toBalancedTree(int low, int high, List children, @Override public Expr visitBetween(Between between, PlanTranslatorContext context) { - And and = new And(new GreaterThanEqual(between.getCompareExpr(), between.getLowerBound()), - new LessThanEqual(between.getCompareExpr(), between.getUpperBound())); - return and.accept(this, context); + if (between.getLowerBound().equals(between.getUpperBound())) { + EqualTo equalTo = new EqualTo(between.getCompareExpr(), between.getLowerBound()); + return equalTo.accept(this, context); + } else { + And and = new And(new GreaterThanEqual(between.getCompareExpr(), between.getLowerBound()), + new LessThanEqual(between.getCompareExpr(), between.getUpperBound())); + return and.accept(this, context); + } } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java index 5384c37f539e46..fcfaa896e828cc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.expression.ExpressionRuleType; import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.Between; +import org.apache.doris.nereids.trees.expressions.EqualTo; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.GreaterThanEqual; import org.apache.doris.nereids.trees.expressions.LessThanEqual; @@ -51,8 +52,12 @@ public List> buildRules() { } public Expression rewrite(Between expr, ExpressionRewriteContext context) { - Expression left = new GreaterThanEqual(expr.getCompareExpr(), expr.getLowerBound()); - Expression right = new LessThanEqual(expr.getCompareExpr(), expr.getUpperBound()); - return new And(left, right); + if (expr.getLowerBound().equals(expr.getUpperBound())) { + return new EqualTo(expr.getCompareExpr(), expr.getLowerBound()); + } else { + Expression left = new GreaterThanEqual(expr.getCompareExpr(), expr.getLowerBound()); + Expression right = new LessThanEqual(expr.getCompareExpr(), expr.getUpperBound()); + return new And(left, right); + } } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java index bb5c722098a5a4..6d2acdf6f4003f 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java @@ -253,7 +253,7 @@ void testBetweenToCompoundRule() { assertRewrite("a between c and d", "(a >= c) and (a <= d)"); assertRewrite("a not between c and d", "(a < c) or (a > d)"); - + assertRewrite("a between c and c", "a = c"); } @Test From 76a929cbedbb878053492f9165dd0d3e5d51d8d9 Mon Sep 17 00:00:00 2001 From: yujun Date: Thu, 28 Aug 2025 14:18:06 +0800 Subject: [PATCH 3/7] update --- .../apache/doris/nereids/trees/expressions/Between.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java index 2cd5da27cfd565..14cc02dadff046 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java @@ -28,7 +28,6 @@ import com.google.common.collect.ImmutableList; import java.util.List; -import java.util.Objects; /** * Between predicate expression. @@ -38,6 +37,7 @@ public class Between extends Expression implements TernaryExpression, PropagateN private final Expression compareExpr; private final Expression lowerBound; private final Expression upperBound; + /** * Constructor of ComparisonPredicate. * @@ -45,12 +45,16 @@ public class Between extends Expression implements TernaryExpression, PropagateN * @param lowerBound left child of between predicate * @param upperBound right child of between predicate */ - public Between(Expression compareExpr, Expression lowerBound, Expression upperBound) { this(ImmutableList.of(compareExpr, lowerBound, upperBound)); } + /** + * Constructor of ComparisonPredicate. + * + * @param children 3 children: compareExpr, lowerBound, upperBound + */ public Between(List children) { super(children); this.compareExpr = children.get(0); From 39b34306926da36af554f239fb2899a5d019309b Mon Sep 17 00:00:00 2001 From: yujun Date: Thu, 28 Aug 2025 15:02:29 +0800 Subject: [PATCH 4/7] fix check style --- .../doris/nereids/rules/expression/rules/BetweenToCompound.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java index fcfaa896e828cc..6e6c1c8d2b8e27 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java @@ -51,7 +51,7 @@ public List> buildRules() { ); } - public Expression rewrite(Between expr, ExpressionRewriteContext context) { + private Expression rewrite(Between expr, ExpressionRewriteContext context) { if (expr.getLowerBound().equals(expr.getUpperBound())) { return new EqualTo(expr.getCompareExpr(), expr.getLowerBound()); } else { From d8590a05ca27066a616bf17f4dd8e6f9a580ed73 Mon Sep 17 00:00:00 2001 From: yujun Date: Thu, 28 Aug 2025 16:57:13 +0800 Subject: [PATCH 5/7] fix test --- .../doris/nereids/rules/expression/SimplifyRangeTest.java | 4 ++-- .../unique_function/between_with_unique_function.groovy | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java index 6caad716b611f7..b315505a458963 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java @@ -248,9 +248,9 @@ public void testSimplify() { Assertions.assertEquals("AND[((cast(TA as BIGINT) + random(1, 10)) > 10),((cast(TA as BIGINT) + random(1, 10)) < 1)]", expr.toSql()); expr = rewrite("TA + random(1, 10) between 10 and 20", Maps.newHashMap()); - Assertions.assertEquals("AND[((TA + random(1, 10)) >= 10),((TA + random(1, 10)) <= 20)]", expr.toSql()); + Assertions.assertEquals("AND[((cast(TA as BIGINT) + random(1, 10)) >= 10),((cast(TA as BIGINT) + random(1, 10)) <= 20)]", expr.toSql()); expr = rewrite("TA + random(1, 10) between 20 and 10", Maps.newHashMap()); - Assertions.assertEquals("AND[(TA + random(1, 10)) IS NULL,NULL]", expr.toSql()); + Assertions.assertEquals("AND[(cast(TA as BIGINT) + random(1, 10)) IS NULL,NULL]", expr.toSql()); } @Test diff --git a/regression-test/suites/nereids_rules_p0/unique_function/between_with_unique_function.groovy b/regression-test/suites/nereids_rules_p0/unique_function/between_with_unique_function.groovy index 654af1506ab8f3..b6b633807fd7f1 100644 --- a/regression-test/suites/nereids_rules_p0/unique_function/between_with_unique_function.groovy +++ b/regression-test/suites/nereids_rules_p0/unique_function/between_with_unique_function.groovy @@ -16,6 +16,7 @@ // under the License. suite('between_with_unique_function') { + sql "set disable_nereids_rules='PRUNE_EMPTY_PARTITION'" sql "SET ignore_shape_nodes='PhysicalDistribute'" qt_between_two_num 'explain shape plan select * from t1 where id between random() and random()' } From 2ae4038cfb3b7cf4f1b82c921d6027bf555caa7c Mon Sep 17 00:00:00 2001 From: yujun Date: Fri, 29 Aug 2025 18:50:38 +0800 Subject: [PATCH 6/7] delete rule BetweenToCompoun --- .../glue/translator/ExpressionTranslator.java | 13 ---- .../rules/analysis/ExpressionAnalyzer.java | 17 +++-- .../expression/ExpressionNormalization.java | 2 - .../rules/expression/ExpressionRuleType.java | 1 - .../expression/rules/BetweenToCompound.java | 63 ------------------ .../rules/FoldConstantRuleOnBE.java | 5 +- .../doris/nereids/util/TypeCoercionUtils.java | 66 ------------------- .../expression/ExpressionRewriteTest.java | 20 +----- .../rules/expression/SimplifyRangeTest.java | 6 +- .../test_date_function_prune_mono.groovy | 6 +- .../test_date_trunc_prune.groovy | 6 +- 11 files changed, 23 insertions(+), 182 deletions(-) delete mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java 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 61056c8ed55150..9ec0f5094452b9 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 @@ -54,7 +54,6 @@ import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.ArrayItemReference; import org.apache.doris.nereids.trees.expressions.AssertNumRowsElement; -import org.apache.doris.nereids.trees.expressions.Between; import org.apache.doris.nereids.trees.expressions.BinaryArithmetic; import org.apache.doris.nereids.trees.expressions.CaseWhen; import org.apache.doris.nereids.trees.expressions.Cast; @@ -389,18 +388,6 @@ private Expr toBalancedTree(int low, int high, List children, return results.pop(); } - @Override - public Expr visitBetween(Between between, PlanTranslatorContext context) { - if (between.getLowerBound().equals(between.getUpperBound())) { - EqualTo equalTo = new EqualTo(between.getCompareExpr(), between.getLowerBound()); - return equalTo.accept(this, context); - } else { - And and = new And(new GreaterThanEqual(between.getCompareExpr(), between.getLowerBound()), - new LessThanEqual(between.getCompareExpr(), between.getUpperBound())); - return and.accept(this, context); - } - } - @Override public Expr visitAnd(And and, PlanTranslatorContext context) { List children = and.children().stream().map( 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 9cfb60d4d40326..b7f5c98d49ef35 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 @@ -54,9 +54,11 @@ import org.apache.doris.nereids.trees.expressions.EqualTo; import org.apache.doris.nereids.trees.expressions.ExprId; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.GreaterThanEqual; import org.apache.doris.nereids.trees.expressions.InPredicate; import org.apache.doris.nereids.trees.expressions.InSubquery; import org.apache.doris.nereids.trees.expressions.IntegralDivide; +import org.apache.doris.nereids.trees.expressions.LessThanEqual; import org.apache.doris.nereids.trees.expressions.Match; import org.apache.doris.nereids.trees.expressions.Not; import org.apache.doris.nereids.trees.expressions.Or; @@ -741,10 +743,17 @@ public Expression visitInPredicate(InPredicate inPredicate, ExpressionRewriteCon @Override public Expression visitBetween(Between between, ExpressionRewriteContext context) { - List rewrittenChildren = between.children().stream() - .map(e -> e.accept(this, context)).collect(Collectors.toList()); - Between newBetween = between.withChildren(rewrittenChildren); - return TypeCoercionUtils.processBetween(newBetween); + Expression compareExpr = between.getCompareExpr().accept(this, context); + Expression lowerBound = between.getLowerBound().accept(this, context); + Expression upperBound = between.getUpperBound().accept(this, context); + if (lowerBound.equals(upperBound)) { + // rewrite `x between a and a` to `x = a` + return TypeCoercionUtils.processComparisonPredicate(new EqualTo(compareExpr, lowerBound)); + } else { + return new And( + TypeCoercionUtils.processComparisonPredicate(new GreaterThanEqual(compareExpr, lowerBound)), + TypeCoercionUtils.processComparisonPredicate(new LessThanEqual(compareExpr, upperBound))); + } } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java index 831d2b260dc479..2e24f7895e6692 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionNormalization.java @@ -18,7 +18,6 @@ package org.apache.doris.nereids.rules.expression; import org.apache.doris.nereids.rules.expression.check.CheckCast; -import org.apache.doris.nereids.rules.expression.rules.BetweenToCompound; import org.apache.doris.nereids.rules.expression.rules.ConcatWsMultiArrayToOne; import org.apache.doris.nereids.rules.expression.rules.ConvertAggStateCast; import org.apache.doris.nereids.rules.expression.rules.DigitalMaskingConvert; @@ -55,7 +54,6 @@ public class ExpressionNormalization extends ExpressionRewrite { bottomUp( SupportJavaDateFormatter.INSTANCE, NormalizeBinaryPredicatesRule.INSTANCE, - BetweenToCompound.INSTANCE, InPredicateDedup.INSTANCE, InPredicateExtractNonConstant.INSTANCE, InPredicateToEqualToRule.INSTANCE, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java index 328498d6852eb5..8094ec5dac0786 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRuleType.java @@ -23,7 +23,6 @@ public enum ExpressionRuleType { ADD_MIN_MAX, ARRAY_CONTAIN_TO_ARRAY_OVERLAP, - BETWEEN_TO_COMPOUND, BETWEEN_TO_EQUAL, CASE_WHEN_TO_IF, CHECK_CAST, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java deleted file mode 100644 index 6e6c1c8d2b8e27..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/BetweenToCompound.java +++ /dev/null @@ -1,63 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package org.apache.doris.nereids.rules.expression.rules; - -import org.apache.doris.nereids.rules.expression.ExpressionPatternMatcher; -import org.apache.doris.nereids.rules.expression.ExpressionPatternRuleFactory; -import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext; -import org.apache.doris.nereids.rules.expression.ExpressionRuleType; -import org.apache.doris.nereids.trees.expressions.And; -import org.apache.doris.nereids.trees.expressions.Between; -import org.apache.doris.nereids.trees.expressions.EqualTo; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.GreaterThanEqual; -import org.apache.doris.nereids.trees.expressions.LessThanEqual; - -import com.google.common.collect.ImmutableList; - -import java.util.List; - -/** - * Rewrites BetweenPredicates into an equivalent conjunctive CompoundPredicate, - * "not between" is first processed by the BetweenToCompoundRule and then by the SimplifyNotExprRule. - * Examples: - * A BETWEEN X AND Y ==> A >= X AND A <= Y - */ -public class BetweenToCompound implements ExpressionPatternRuleFactory { - - public static BetweenToCompound INSTANCE = new BetweenToCompound(); - - @Override - public List> buildRules() { - return ImmutableList.of( - matchesType(Between.class) - .thenApply(ctx -> rewrite(ctx.expr, ctx.rewriteContext)) - .toRule(ExpressionRuleType.BETWEEN_TO_COMPOUND) - ); - } - - private Expression rewrite(Between expr, ExpressionRewriteContext context) { - if (expr.getLowerBound().equals(expr.getUpperBound())) { - return new EqualTo(expr.getCompareExpr(), expr.getLowerBound()); - } else { - Expression left = new GreaterThanEqual(expr.getCompareExpr(), expr.getLowerBound()); - Expression right = new LessThanEqual(expr.getCompareExpr(), expr.getUpperBound()); - return new And(left, right); - } - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java index 1b335fe5077e1e..3a99a8ffedcd6e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnBE.java @@ -34,7 +34,6 @@ import org.apache.doris.nereids.rules.expression.ExpressionRuleType; import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.ArrayItemReference; -import org.apache.doris.nereids.trees.expressions.Between; import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Match; @@ -199,9 +198,7 @@ private static Expression replace( private static void collectConst(Expression expr, Map constMap, Map tExprMap, IdGenerator idGenerator) { - // skip BetweenPredicate need to be rewrite to CompoundPredicate - if (expr.isConstant() && !expr.isLiteral() && !(expr instanceof Between) - && !expr.anyMatch(e -> shouldSkipFold((Expression) e))) { + if (expr.isConstant() && !expr.isLiteral() && !expr.anyMatch(e -> shouldSkipFold((Expression) e))) { String id = idGenerator.getNextId().toString(); constMap.put(id, expr); Expr staleExpr; 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 40bde59a6b2c7c..73832e9436f648 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 @@ -26,7 +26,6 @@ import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext; import org.apache.doris.nereids.rules.expression.rules.FoldConstantRuleOnFE; import org.apache.doris.nereids.trees.expressions.Add; -import org.apache.doris.nereids.trees.expressions.Between; import org.apache.doris.nereids.trees.expressions.BinaryArithmetic; import org.apache.doris.nereids.trees.expressions.BinaryOperator; import org.apache.doris.nereids.trees.expressions.BitAnd; @@ -1213,71 +1212,6 @@ public static Expression processCaseWhen(CaseWhen caseWhen) { .orElseThrow(() -> new AnalysisException("Cannot find common type for case when " + caseWhen)); } - /** - * process between type coercion. - */ - public static Expression processBetween(Between between) { - // check - between.checkLegalityBeforeTypeCoercion(); - - if (between.getLowerBound().getDataType().equals(between.getCompareExpr().getDataType()) - && between.getUpperBound().getDataType().equals(between.getCompareExpr().getDataType())) { - return between; - } - - // process string literal - boolean hitString = false; - Expression newLowerBound = between.getLowerBound(); - Expression newUpperBound = between.getUpperBound(); - if (!(between.getCompareExpr().getDataType().isStringLikeType())) { - if (newLowerBound instanceof Literal && ((Literal) newLowerBound).isStringLikeLiteral()) { - Optional boundOpt = TypeCoercionUtils.characterLiteralTypeCoercion( - ((Literal) newLowerBound).getStringValue(), between.getCompareExpr().getDataType()); - if (boundOpt.isPresent()) { - newLowerBound = boundOpt.get(); - hitString = true; - } - } - if (newUpperBound instanceof Literal && ((Literal) newUpperBound).isStringLikeLiteral()) { - Optional boundOpt = TypeCoercionUtils.characterLiteralTypeCoercion( - ((Literal) newUpperBound).getStringValue(), between.getCompareExpr().getDataType()); - if (boundOpt.isPresent()) { - newUpperBound = boundOpt.get(); - hitString = true; - } - } - } - if (hitString) { - between = new Between(between.getCompareExpr(), newLowerBound, newUpperBound); - } - - Optional optionalCommonType = TypeCoercionUtils.findWiderCommonTypeForComparison( - between.children() - .stream() - .map(Expression::getDataType) - .collect(Collectors.toList())); - - if (optionalCommonType.isPresent()) { - optionalCommonType = Optional.of(downgradeDecimalAndDateLikeType( - optionalCommonType.get(), - between.getCompareExpr(), - between.getLowerBound(), - between.getUpperBound())); - } - - // lambda need a final variable - final Between finalBetween = between; - - return optionalCommonType - .map(commonType -> { - List newChildren = finalBetween.children().stream() - .map(e -> TypeCoercionUtils.castIfNotMatchType(e, commonType)) - .collect(Collectors.toList()); - return finalBetween.withChildren(newChildren); - }) - .orElse(between); - } - 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/expression/ExpressionRewriteTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java index 6d2acdf6f4003f..43e44255f66611 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/ExpressionRewriteTest.java @@ -18,7 +18,6 @@ package org.apache.doris.nereids.rules.expression; import org.apache.doris.nereids.rules.expression.rules.AddMinMax; -import org.apache.doris.nereids.rules.expression.rules.BetweenToCompound; import org.apache.doris.nereids.rules.expression.rules.DistinctPredicatesRule; import org.apache.doris.nereids.rules.expression.rules.ExtractCommonFactorRule; import org.apache.doris.nereids.rules.expression.rules.InPredicateDedup; @@ -243,19 +242,6 @@ void testInPredicateDedup() { assertRewrite("a in (1, 2, 1, 2)", "a in (1, 2)"); } - @Test - void testBetweenToCompoundRule() { - executor = new ExpressionRuleExecutor(ImmutableList.of( - bottomUp( - BetweenToCompound.INSTANCE, - SimplifyNotExprRule.INSTANCE) - )); - - assertRewrite("a between c and d", "(a >= c) and (a <= d)"); - assertRewrite("a not between c and d", "(a < c) or (a > d)"); - assertRewrite("a between c and c", "a = c"); - } - @Test void testSimplifyCastRule() { executor = new ExpressionRuleExecutor(ImmutableList.of( @@ -326,8 +312,7 @@ void testDeadLoop() { void testAddMinMax() { executor = new ExpressionRuleExecutor(ImmutableList.of( bottomUp( - AddMinMax.INSTANCE, - BetweenToCompound.INSTANCE + AddMinMax.INSTANCE ) )); @@ -393,8 +378,7 @@ void testSimplifyRangeAndAddMinMax() { executor = new ExpressionRuleExecutor(ImmutableList.of( bottomUp( SimplifyRange.INSTANCE, - AddMinMax.INSTANCE, - BetweenToCompound.INSTANCE + AddMinMax.INSTANCE ) )); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java index b315505a458963..36c96179f0fdae 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/SimplifyRangeTest.java @@ -22,7 +22,6 @@ import org.apache.doris.nereids.analyzer.UnboundSlot; import org.apache.doris.nereids.parser.NereidsParser; import org.apache.doris.nereids.rules.analysis.ExpressionAnalyzer; -import org.apache.doris.nereids.rules.expression.rules.BetweenToCompound; import org.apache.doris.nereids.rules.expression.rules.RangeInference; import org.apache.doris.nereids.rules.expression.rules.RangeInference.EmptyValue; import org.apache.doris.nereids.rules.expression.rules.RangeInference.RangeValue; @@ -96,10 +95,7 @@ public void testRangeInference() { @Test public void testSimplify() { executor = new ExpressionRuleExecutor(ImmutableList.of( - bottomUp( - SimplifyRange.INSTANCE, - BetweenToCompound.INSTANCE - ) + bottomUp(SimplifyRange.INSTANCE) )); assertRewrite("TA", "TA"); assertRewrite("TA > 3 or TA > null", "TA > 3 OR NULL"); diff --git a/regression-test/suites/nereids_rules_p0/partition_prune/test_date_function_prune_mono.groovy b/regression-test/suites/nereids_rules_p0/partition_prune/test_date_function_prune_mono.groovy index 6ff101c84f2f26..7af54e3162b5e2 100644 --- a/regression-test/suites/nereids_rules_p0/partition_prune/test_date_function_prune_mono.groovy +++ b/regression-test/suites/nereids_rules_p0/partition_prune/test_date_function_prune_mono.groovy @@ -124,9 +124,9 @@ suite("test_date_prune_mono") { for (int i = 0; i < 2; i++) { if (i == 0) { // forbid rewrite not a>1 to a<=1 - sql "set disable_nereids_expression_rules = 'SIMPLIFY_NOT_EXPR'" + sql "set disable_nereids_rules = 'REWRITE_FILTER_EXPRESSION'" } else { - sql "set disable_nereids_expression_rules = ''" + sql "set disable_nereids_rules = ''" } explain { sql """select * from mal_test_partition_range5_date_mono where not date(b)<="2020-01-14" """ @@ -307,4 +307,4 @@ suite("test_date_prune_mono") { sql "select * from mal_test_partition_range2_two_date_int_date_mono where date_trunc(date(dt),'minute') > '2017-2-1 00:00:00' and id>100;" contains("partitions=2/3 (p201702_2000,p201703_all)") } -} +} \ No newline at end of file diff --git a/regression-test/suites/nereids_rules_p0/partition_prune/test_date_trunc_prune.groovy b/regression-test/suites/nereids_rules_p0/partition_prune/test_date_trunc_prune.groovy index 9a34d489527d78..c5eb3855247ad0 100644 --- a/regression-test/suites/nereids_rules_p0/partition_prune/test_date_trunc_prune.groovy +++ b/regression-test/suites/nereids_rules_p0/partition_prune/test_date_trunc_prune.groovy @@ -124,9 +124,9 @@ suite("test_date_trunc_prune") { for (int i = 0; i < 2; i++) { if (i == 0) { // forbid rewrite not a>1 to a<=1 - sql "set disable_nereids_expression_rules = 'SIMPLIFY_NOT_EXPR'" + sql "set disable_nereids_rules = 'REWRITE_FILTER_EXPRESSION'" } else { - sql "set disable_nereids_expression_rules = ''" + sql "set disable_nereids_rules = ''" } explain { sql """select * from mal_test_partition_range5 where not date_trunc(b,'day')<="2020-01-14" """ @@ -359,4 +359,4 @@ suite("test_date_trunc_prune") { sql """select * from t_multi_column_partition where a=2 and date_trunc(dt,'day') <'2024-01-1 00:00:00';""" contains ("partitions=1/5 (p0)") } -} +} \ No newline at end of file From c97458f1cfd44c716a1fb882c6148b435f0aa06a Mon Sep 17 00:00:00 2001 From: yujun Date: Fri, 29 Aug 2025 19:20:31 +0800 Subject: [PATCH 7/7] fix test --- .../unique_function/agg_with_unique_function.out | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out b/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out index a59eb1d160d45e..b57fe2df5cb445 100644 --- a/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out +++ b/regression-test/data/nereids_rules_p0/unique_function/agg_with_unique_function.out @@ -16,7 +16,7 @@ PhysicalResultSink -- !check_equal_no_agg_4_shape -- PhysicalResultSink ---PhysicalProject[(a + random()) AS `a + random()`, (a + random()) AS `a + random()`, sum(a + random()) over() AS `sum(a + random()) over()`, sum(a + random()) over() AS `sum(a + random()) over()`] +--PhysicalProject[(a + random()) AS `a + random()`, (a + random()) AS `a + random()`, sum(a + random()) over(), sum(a + random()) over()] ----PhysicalWindow ------PhysicalProject[(a + random()) AS `(a + random())`, (a + random()) AS `(a + random())`, tbl_unique_function_with_one_row.a] --------PhysicalOlapScan[tbl_unique_function_with_one_row] @@ -45,7 +45,7 @@ PhysicalResultSink -- !check_equal_one_row_to_agg_1_shape -- PhysicalResultSink ---PhysicalProject[random() AS `random()`, random() AS `random()`, sum(random()), sum(random()), sum(random()) over() AS `sum(random()) over()`, sum(random()) over() AS `sum(random()) over()`] +--PhysicalProject[random() AS `random()`, random() AS `random()`, sum(random()), sum(random()), sum(random()) over(), sum(random()) over()] ----PhysicalWindow ------PhysicalProject[random() AS `random()`, random() AS `random()`, sum(random()), sum(random())] --------hashAgg[GLOBAL] @@ -168,7 +168,7 @@ PhysicalResultSink -- !check_equal_agg_with_groupby_7_shape -- PhysicalResultSink ---PhysicalProject[a + random(), a + random() AS `a + random()`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over() AS `sum(a + random()) over()`] +--PhysicalProject[a + random(), a + random() AS `a + random()`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over()] ----PhysicalWindow ------hashAgg[GLOBAL] --------hashAgg[LOCAL] @@ -177,7 +177,7 @@ PhysicalResultSink -- !check_equal_agg_with_groupby_8_shape -- PhysicalResultSink ---PhysicalProject[a + random(), a + random() AS `a + random()`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over() AS `sum(a + random()) over()`] +--PhysicalProject[a + random(), a + random() AS `a + random()`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over()] ----PhysicalWindow ------hashAgg[GLOBAL] --------hashAgg[LOCAL] @@ -189,7 +189,7 @@ PhysicalResultSink PhysicalResultSink --PhysicalQuickSort[MERGE_SORT] ----PhysicalQuickSort[LOCAL_SORT] -------PhysicalProject[a + random(), a + random() AS `a + random()`, abs(a + random()) AS `abs(a + random())`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over() AS `sum(a + random()) over()`] +------PhysicalProject[a + random(), a + random() AS `a + random()`, abs(a + random()) AS `abs(a + random())`, sum(a + random()) AS `sum(a + random())`, sum(a + random()) over()] --------PhysicalWindow ----------hashAgg[GLOBAL] ------------hashAgg[LOCAL]