Skip to content
Merged
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 @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -53,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;
Expand Down Expand Up @@ -738,6 +741,21 @@ public Expression visitInPredicate(InPredicate inPredicate, ExpressionRewriteCon
return TypeCoercionUtils.processInPredicate(newInPredicate);
}

@Override
public Expression visitBetween(Between between, ExpressionRewriteContext context) {
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
public Expression visitInSubquery(InSubquery inSubquery, ExpressionRewriteContext context) {
// analyze subquery
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// 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;

/**
* 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));
}

/**
* Constructor of ComparisonPredicate.
*
* @param children 3 children: compareExpr, lowerBound, 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 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
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 @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public static List<Expression> replaceExpressionByProjections(List<NamedExpressi
/**
* replace targetExpressions with project.
* if the target expression contains a slot which is an alias and its origin expression contains
* non-foldable expression and the slot exits multiple times, then can not replace.
* unique function and the slot exits multiple times, then can not replace.
* for example, target expressions: [a, a + 10], child project: [ t + random() as a ],
* if replace with the projects, then result expressions: [ t + random(), t + random() + 10 ],
* it will calculate random two times, this is error.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,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");
Expand Down Expand Up @@ -242,6 +242,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[((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[(cast(TA as BIGINT) + random(1, 10)) IS NULL,NULL]", expr.toSql());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
)
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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]

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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 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()'
}
Loading