Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -383,6 +384,13 @@ private Expr toBalancedTree(int low, int high, List<Expr> 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<Expr> children = and.children().stream().map(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -679,6 +680,14 @@ public Expression visitInPredicate(InPredicate inPredicate, ExpressionRewriteCon
return TypeCoercionUtils.processInPredicate(newInPredicate);
}

@Override
public Expression visitBetween(Between between, ExpressionRewriteContext context) {
List<Expression> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -47,6 +48,7 @@ public class ExpressionNormalization extends ExpressionRewrite {
bottomUp(
SupportJavaDateFormatter.INSTANCE,
NormalizeBinaryPredicatesRule.INSTANCE,
BetweenToCompound.INSTANCE,
InPredicateDedup.INSTANCE,
InPredicateExtractNonConstant.INSTANCE,
InPredicateToEqualToRule.INSTANCE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ExpressionPatternMatcher<? extends Expression>> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -193,7 +194,9 @@ private static Expression replace(

private static void collectConst(Expression expr, Map<String, Expression> constMap,
Map<String, TExpr> tExprMap, IdGenerator<ExprId> 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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Expression> 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, C> R accept(ExpressionVisitor<R, C> 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<Expression> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Expression> 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<Expression> 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<DataType> 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<Expression> 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;
Expand Down
Loading
Loading