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 166892f48a9db6..2fdb7eb89649f8 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 @@ -52,6 +52,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; @@ -383,6 +384,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 a0187112c96113..12dca848ac415f 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 @@ -416,6 +416,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; @@ -3846,9 +3847,10 @@ private Expression withPredicate(Expression valueExpression, PredicateContext ct 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)) + outExpression = new Between( + valueExpression, + getExpression(ctx.lower), + getExpression(ctx.upper) ); } break; 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 d7f0f637250103..292a4fd29f4420 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 @@ -42,6 +42,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; @@ -679,6 +680,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 135f80111e980c..a70e4a205ed03c 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.ConvertAggStateCast; import org.apache.doris.nereids.rules.expression.rules.DigitalMaskingConvert; import org.apache.doris.nereids.rules.expression.rules.FoldConstantRule; @@ -47,6 +48,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 baa5ebfe078da4..8002126d8b2de7 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 90b044e2b81be7..d275bade59ce87 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; @@ -193,7 +194,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..0a16715872ade4 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Between.java @@ -0,0 +1,124 @@ +// 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.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 { + + 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) { + super(ImmutableList.of(compareExpr, lowerBound, upperBound)); + this.compareExpr = compareExpr; + this.lowerBound = lowerBound; + this.upperBound = 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 boolean nullable() throws UnboundException { + return lowerBound.nullable() || upperBound.nullable(); + } + + @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); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Between that = (Between) o; + return Objects.equals(compareExpr, that.compareExpr) + && Objects.equals(lowerBound, that.lowerBound) + && Objects.equals(upperBound, that.upperBound) + && Objects.equals(children, that.children); + } + + @Override + public int hashCode() { + return Objects.hash(compareExpr, lowerBound, upperBound); + } +} 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 406d0835610a17..47200bd4dc77e1 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; @@ -333,6 +334,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/TypeCoercionUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/TypeCoercionUtils.java index 5f8be613552c78..313feb597fca73 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 @@ -25,6 +25,7 @@ import org.apache.doris.nereids.annotation.Developing; import org.apache.doris.nereids.exceptions.AnalysisException; 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; @@ -1208,6 +1209,71 @@ 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/parser/BetweenTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/BetweenTest.java index c9ef4fbee27cbe..1ecdd28e3aa2ad 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,7 +17,7 @@ package org.apache.doris.nereids.parser; -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; @@ -35,6 +35,6 @@ public void testBetween() { expression = "A between 1 and 2"; result = PARSER.parseExpression(expression); - Assertions.assertInstanceOf(And.class, result); + 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 0db6295a3daa07..0d40b30c7178ed 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; @@ -240,6 +241,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( @@ -310,7 +324,8 @@ void testDeadLoop() { void testAddMinMax() { executor = new ExpressionRuleExecutor(ImmutableList.of( bottomUp( - AddMinMax.INSTANCE + AddMinMax.INSTANCE, + BetweenToCompound.INSTANCE ) )); @@ -376,7 +391,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 b5d5aaab88ee49..fbb6a78d4b00e0 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"); @@ -240,6 +244,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[((TA + random(1, 10)) > 10),((TA + 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/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 +}