This is an automated email from the ASF dual-hosted git repository. yiguolei pushed a commit to branch branch-2.1 in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-2.1 by this push: new 4979d706127 branch-2.1: [fix](nereids) Add unique id to non foldable expression #48103 (#48456) 4979d706127 is described below commit 4979d706127044598b1af853d1c2d69ab3f2cebb Author: yujun <yu...@selectdb.com> AuthorDate: Sat Mar 1 08:51:29 2025 +0800 branch-2.1: [fix](nereids) Add unique id to non foldable expression #48103 (#48456) cherry pick from #48103 --- .../trees/expressions/functions/scalar/Random.java | 61 ++++++++++++++++++--- .../expressions/functions/scalar/RandomBytes.java | 39 ++++++++++++- .../trees/expressions/functions/scalar/Uuid.java | 36 ++++++++++++ .../expressions/functions/scalar/UuidNumeric.java | 36 ++++++++++++ .../rules/expression/ExpressionRewriteTest.java | 11 ++++ .../rules/expression/SimplifyRangeTest.java | 14 ++++- .../functions/NonfoldableFunctionTest.java | 58 ++++++++++++++++++++ .../data/nereids_rules_p0/test_nonfoldable.out | Bin 2819 -> 2891 bytes 8 files changed, 243 insertions(+), 12 deletions(-) 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 82cd56118f8..6101c7f510a 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 @@ -19,9 +19,12 @@ package org.apache.doris.nereids.trees.expressions.functions.scalar; import org.apache.doris.catalog.FunctionSignature; import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.nereids.trees.expressions.ExprId; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; import org.apache.doris.nereids.trees.expressions.literal.Literal; +import org.apache.doris.nereids.trees.expressions.literal.NumericLiteral; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.BigIntType; import org.apache.doris.nereids.types.DoubleType; @@ -43,27 +46,44 @@ public class Random extends ScalarFunction FunctionSignature.ret(BigIntType.INSTANCE).args(BigIntType.INSTANCE, BigIntType.INSTANCE) ); + private final ExprId exprId; + /** * constructor with 0 argument. */ public Random() { - super("random"); + this(StatementScopeIdGenerator.newExprId()); } /** * constructor with 1 argument. */ public Random(Expression arg) { - super("random", arg); - // align with original planner behavior, refer to: org/apache/doris/analysis/Expr.getBuiltinFunction() - Preconditions.checkState(arg instanceof Literal, "The param of rand function must be literal"); + this(StatementScopeIdGenerator.newExprId(), arg); } /** * constructor with 2 argument. */ public Random(Expression lchild, Expression rchild) { + this(StatementScopeIdGenerator.newExprId(), lchild, rchild); + } + + public Random(ExprId exprId) { + super("random"); + this.exprId = exprId; + } + + public Random(ExprId exprId, Expression arg) { + super("random", arg); + this.exprId = exprId; + // align with original planner behavior, refer to: org/apache/doris/analysis/Expr.getBuiltinFunction() + Preconditions.checkState(arg instanceof Literal, "The param of rand function must be literal"); + } + + public Random(ExprId exprId, Expression lchild, Expression rchild) { super("random", lchild, rchild); + this.exprId = exprId; } @Override @@ -94,12 +114,20 @@ public class Random extends ScalarFunction */ @Override public Random withChildren(List<Expression> children) { + ExprId newExprId = exprId; + List<Expression> myChildren = this.children(); + if (myChildren.stream().allMatch(arg -> arg instanceof NumericLiteral) + && children.stream().allMatch(arg -> arg instanceof NumericLiteral) + && !children.equals(myChildren)) { + newExprId = StatementScopeIdGenerator.newExprId(); + } + if (children.isEmpty()) { - return new Random(); + return new Random(newExprId); } else if (children.size() == 1) { - return new Random(children.get(0)); + return new Random(newExprId, children.get(0)); } else if (children.size() == 2) { - return new Random(children.get(0), children.get(1)); + return new Random(newExprId, children.get(0), children.get(1)); } throw new AnalysisException("random function only accept 0-2 arguments"); } @@ -123,4 +151,23 @@ public class Random extends ScalarFunction public boolean foldable() { return false; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Random other = (Random) o; + return exprId.equals(other.exprId); + } + + // The contains method needs to use hashCode, so similar to equals, it only compares exprId + @Override + public int computeHashCode() { + // direct return exprId to speed up + return exprId.asInt(); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RandomBytes.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RandomBytes.java index 000b83bbc34..156e0024e64 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RandomBytes.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/RandomBytes.java @@ -18,9 +18,12 @@ package org.apache.doris.nereids.trees.expressions.functions.scalar; import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.nereids.trees.expressions.ExprId; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; import org.apache.doris.nereids.trees.expressions.functions.PropagateNullable; +import org.apache.doris.nereids.trees.expressions.literal.NumericLiteral; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.IntegerType; import org.apache.doris.nereids.types.StringType; @@ -42,13 +45,19 @@ public class RandomBytes extends ScalarFunction FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args(IntegerType.INSTANCE) ); + private final ExprId exprId; + /** * constructor with 1 argument. */ public RandomBytes(Expression arg0) { - super("random_bytes", arg0); + this(StatementScopeIdGenerator.newExprId(), arg0); } + public RandomBytes(ExprId exprId, Expression arg0) { + super("random_bytes", arg0); + this.exprId = exprId; + } /** * withChildren. @@ -56,7 +65,14 @@ public class RandomBytes extends ScalarFunction @Override public RandomBytes withChildren(List<Expression> children) { Preconditions.checkArgument(children.size() == 1); - return new RandomBytes(children.get(0)); + ExprId newExprId = exprId; + List<Expression> myChildren = this.children(); + if (children.stream().allMatch(arg -> arg instanceof NumericLiteral) + && myChildren.stream().allMatch(arg -> arg instanceof NumericLiteral) + && !children.equals(myChildren)) { + newExprId = StatementScopeIdGenerator.newExprId(); + } + return new RandomBytes(newExprId, children.get(0)); } @Override @@ -78,4 +94,23 @@ public class RandomBytes extends ScalarFunction public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) { return visitor.visitRandomBytes(this, context); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RandomBytes other = (RandomBytes) o; + return exprId.equals(other.exprId); + } + + // The contains method needs to use hashCode, so similar to equals, it only compares exprId + @Override + public int computeHashCode() { + // direct return exprId to speed up + return exprId.asInt(); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uuid.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uuid.java index 1df31219697..fd715875346 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uuid.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uuid.java @@ -18,12 +18,16 @@ package org.apache.doris.nereids.trees.expressions.functions.scalar; import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.nereids.trees.expressions.ExprId; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator; import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; import org.apache.doris.nereids.trees.expressions.shape.LeafExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.VarcharType; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.List; @@ -38,11 +42,24 @@ public class Uuid extends ScalarFunction FunctionSignature.ret(VarcharType.SYSTEM_DEFAULT).args() ); + private final ExprId exprId; + /** * constructor with 0 argument. */ public Uuid() { + this(StatementScopeIdGenerator.newExprId()); + } + + public Uuid(ExprId exprId) { super("uuid"); + this.exprId = exprId; + } + + @Override + public Uuid withChildren(List<Expression> children) { + Preconditions.checkArgument(children.isEmpty()); + return new Uuid(exprId); } @Override @@ -64,4 +81,23 @@ public class Uuid extends ScalarFunction public boolean isDeterministic() { return false; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Uuid other = (Uuid) o; + return exprId.equals(other.exprId); + } + + // The contains method needs to use hashCode, so similar to equals, it only compares exprId + @Override + public int computeHashCode() { + // direct return exprId to speed up + return exprId.asInt(); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidNumeric.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidNumeric.java index 141d64bb418..37bf709a622 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidNumeric.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidNumeric.java @@ -18,12 +18,16 @@ package org.apache.doris.nereids.trees.expressions.functions.scalar; import org.apache.doris.catalog.FunctionSignature; +import org.apache.doris.nereids.trees.expressions.ExprId; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.StatementScopeIdGenerator; import org.apache.doris.nereids.trees.expressions.functions.AlwaysNotNullable; import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature; import org.apache.doris.nereids.trees.expressions.shape.LeafExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.LargeIntType; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.List; @@ -38,11 +42,24 @@ public class UuidNumeric extends ScalarFunction FunctionSignature.ret(LargeIntType.INSTANCE).args() ); + private final ExprId exprId; + /** * constructor with 0 argument. */ public UuidNumeric() { + this(StatementScopeIdGenerator.newExprId()); + } + + public UuidNumeric(ExprId exprId) { super("uuid_numeric"); + this.exprId = exprId; + } + + @Override + public UuidNumeric withChildren(List<Expression> children) { + Preconditions.checkArgument(children.isEmpty()); + return new UuidNumeric(exprId); } @Override @@ -64,4 +81,23 @@ public class UuidNumeric extends ScalarFunction public boolean isDeterministic() { return false; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + UuidNumeric other = (UuidNumeric) o; + return exprId.equals(other.exprId); + } + + // The contains method needs to use hashCode, so similar to equals, it only compares exprId + @Override + public int computeHashCode() { + // direct return exprId to speed up + return exprId.asInt(); + } } 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 c5f69b1edbb..0f270978225 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 @@ -81,6 +81,17 @@ class ExpressionRewriteTest extends ExpressionRewriteTestHelper { } + @Test + void testSimplifyRange() { + executor = new ExpressionRuleExecutor(ImmutableList.of( + ExpressionRewrite.bottomUp(SimplifyRange.INSTANCE) + )); + + // random is non-foldable expression, the two RANDOM are not equals + assertRewriteAfterTypeCoercion("a + random(1, 10) > 20 and a + random(1, 10) < 10", + "a + random(1, 10) > 20 and a + random(1, 10) < 10"); + } + @Test void testNormalizeExpressionRewrite() { executor = new ExpressionRuleExecutor(ImmutableList.of( 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 79906880f53..3ce4bb9bff4 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 @@ -197,6 +197,9 @@ public class SimplifyRangeTest extends ExpressionRewrite { assertRewrite("(TA + TC > 3 OR TA < 1) AND TB = 2) AND IA =1", "(TA + TC > 3 OR TA < 1) AND TB = 2) AND IA =1"); + // 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("(((TA + random(1, 10)) > 10) AND ((TA + random(1, 10)) < 1))", expr.toSql()); } @Test @@ -366,14 +369,19 @@ public class SimplifyRangeTest extends ExpressionRewrite { private void assertRewrite(String expression, String expected) { Map<String, Slot> mem = Maps.newHashMap(); - Expression needRewriteExpression = replaceUnboundSlot(PARSER.parseExpression(expression), mem); - needRewriteExpression = typeCoercion(needRewriteExpression); + Expression rewrittenExpression = rewrite(expression, mem); Expression expectedExpression = replaceUnboundSlot(PARSER.parseExpression(expected), mem); expectedExpression = typeCoercion(expectedExpression); - Expression rewrittenExpression = sortChildren(executor.rewrite(needRewriteExpression, context)); Assertions.assertEquals(expectedExpression, rewrittenExpression); } + private Expression rewrite(String expression, Map<String, Slot> mem) { + Expression rewriteExpression = replaceUnboundSlot(PARSER.parseExpression(expression), mem); + rewriteExpression = typeCoercion(rewriteExpression); + rewriteExpression = executor.rewrite(rewriteExpression, context); + return sortChildren(rewriteExpression); + } + private void assertRewriteNotNull(String expression, String expected) { Map<String, Slot> mem = Maps.newHashMap(); Expression needRewriteExpression = replaceNotNullUnboundSlot(PARSER.parseExpression(expression), mem); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/NonfoldableFunctionTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/NonfoldableFunctionTest.java new file mode 100644 index 00000000000..debd613226a --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/functions/NonfoldableFunctionTest.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.trees.expressions.functions; + +import org.apache.doris.nereids.trees.expressions.functions.scalar.Random; +import org.apache.doris.nereids.trees.expressions.functions.scalar.RandomBytes; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Uuid; +import org.apache.doris.nereids.trees.expressions.functions.scalar.UuidNumeric; +import org.apache.doris.nereids.trees.expressions.literal.BigIntLiteral; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class NonfoldableFunctionTest { + + @Test + void testEquals() { + Random rand0 = new Random(); + Random rand1 = new Random(new BigIntLiteral(10L)); + Random rand2 = new Random(new BigIntLiteral(1L), new BigIntLiteral(10L)); + Assertions.assertNotEquals(rand0, new Random()); + Assertions.assertEquals(rand0, rand0.withChildren()); + Assertions.assertNotEquals(rand0, rand0.withChildren(new BigIntLiteral(10L))); + Assertions.assertNotEquals(rand1, new Random(new BigIntLiteral(10L))); + Assertions.assertEquals(rand1, rand1.withChildren(new BigIntLiteral(10L))); + Assertions.assertNotEquals(rand1, rand1.withChildren(new BigIntLiteral(1L), new BigIntLiteral(10L))); + Assertions.assertNotEquals(rand2, new Random(new BigIntLiteral(1L), new BigIntLiteral(10L))); + Assertions.assertEquals(rand2, rand2.withChildren(new BigIntLiteral(1L), new BigIntLiteral(10L))); + + RandomBytes randb = new RandomBytes(new BigIntLiteral(10L)); + Assertions.assertNotEquals(randb, new RandomBytes(new BigIntLiteral(10L))); + Assertions.assertEquals(randb, randb.withChildren(new BigIntLiteral(10L))); + Assertions.assertNotEquals(randb, randb.withChildren(new BigIntLiteral(1L))); + + Uuid uuid = new Uuid(); + Assertions.assertNotEquals(uuid, new Uuid()); + Assertions.assertEquals(uuid, uuid.withChildren()); + + UuidNumeric uuidNum = new UuidNumeric(); + Assertions.assertNotEquals(uuidNum, new UuidNumeric()); + Assertions.assertEquals(uuidNum, uuidNum.withChildren()); + } +} diff --git a/regression-test/data/nereids_rules_p0/test_nonfoldable.out b/regression-test/data/nereids_rules_p0/test_nonfoldable.out index 3c96406efb6..656331679d6 100644 Binary files a/regression-test/data/nereids_rules_p0/test_nonfoldable.out and b/regression-test/data/nereids_rules_p0/test_nonfoldable.out differ --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org