You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by mo...@apache.org on 2024/04/24 07:59:12 UTC
(doris) branch master updated: [Feat](nereids) add expression rewrite rule LikeToEqualRewrite (#33803)
This is an automated email from the ASF dual-hosted git repository.
morrysnow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new fc9423ffee3 [Feat](nereids) add expression rewrite rule LikeToEqualRewrite (#33803)
fc9423ffee3 is described below
commit fc9423ffee3970b1875c6f1eae41a6a126e97d4b
Author: feiniaofeiafei <53...@users.noreply.github.com>
AuthorDate: Wed Apr 24 15:59:00 2024 +0800
[Feat](nereids) add expression rewrite rule LikeToEqualRewrite (#33803)
like expressions without fuzzy matching are rewritten into equivalent expressions
---
.../rules/expression/ExpressionOptimization.java | 4 +-
.../rules/expression/rules/LikeToEqualRewrite.java | 70 ++++++++++
.../expression/rules/LikeToEqualRewriteTest.java | 147 +++++++++++++++++++++
.../like_to_equal_to_rewrite.out | 24 ++++
.../like_to_equal_to_rewrite.groovy | 53 ++++++++
5 files changed, 297 insertions(+), 1 deletion(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionOptimization.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionOptimization.java
index b3bb18163ea..abf57057601 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionOptimization.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionOptimization.java
@@ -22,6 +22,7 @@ import org.apache.doris.nereids.rules.expression.rules.CaseWhenToIf;
import org.apache.doris.nereids.rules.expression.rules.DateFunctionRewrite;
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.LikeToEqualRewrite;
import org.apache.doris.nereids.rules.expression.rules.NullSafeEqualToEqual;
import org.apache.doris.nereids.rules.expression.rules.OrToIn;
import org.apache.doris.nereids.rules.expression.rules.SimplifyComparisonPredicate;
@@ -51,7 +52,8 @@ public class ExpressionOptimization extends ExpressionRewrite {
ArrayContainToArrayOverlap.INSTANCE,
CaseWhenToIf.INSTANCE,
TopnToMax.INSTANCE,
- NullSafeEqualToEqual.INSTANCE
+ NullSafeEqualToEqual.INSTANCE,
+ LikeToEqualRewrite.INSTANCE
)
);
private static final ExpressionRuleExecutor EXECUTOR = new ExpressionRuleExecutor(OPTIMIZE_REWRITE_RULES);
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/LikeToEqualRewrite.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/LikeToEqualRewrite.java
new file mode 100644
index 00000000000..e2836204cdc
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/LikeToEqualRewrite.java
@@ -0,0 +1,70 @@
+// 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.trees.expressions.EqualTo;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Like;
+import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * LikeToEqualRewrite
+ */
+public class LikeToEqualRewrite implements ExpressionPatternRuleFactory {
+ public static LikeToEqualRewrite INSTANCE = new LikeToEqualRewrite();
+
+ @Override
+ public List<ExpressionPatternMatcher<? extends Expression>> buildRules() {
+ return ImmutableList.of(
+ matchesType(Like.class).then(LikeToEqualRewrite::rewriteLikeToEqual)
+ );
+ }
+
+ private static Expression rewriteLikeToEqual(Like like) {
+ Expression left = like.child(0);
+ Expression right = like.child(1);
+ if (!(right instanceof VarcharLiteral)) {
+ return like;
+ }
+ String str = ((VarcharLiteral) right).value;
+ StringBuilder sb = new StringBuilder();
+ int len = str.length();
+ char escapeChar = '\\';
+ for (int i = 0; i < len;) {
+ char c = str.charAt(i);
+ if (c == escapeChar && (i + 1) < len
+ && (str.charAt(i + 1) == '%' || str.charAt(i + 1) == '_' || str.charAt(i + 1) == escapeChar)) {
+ sb.append(str.charAt(i + 1));
+ i += 2;
+ } else {
+ if (c == '%' || c == '_') {
+ return like;
+ }
+ sb.append(c);
+ i++;
+ }
+ }
+ return new EqualTo(left, new VarcharLiteral(sb.toString()));
+ }
+}
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/LikeToEqualRewriteTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/LikeToEqualRewriteTest.java
new file mode 100644
index 00000000000..463efc1a224
--- /dev/null
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/LikeToEqualRewriteTest.java
@@ -0,0 +1,147 @@
+// 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.ExpressionRewriteTestHelper;
+import org.apache.doris.nereids.rules.expression.ExpressionRuleExecutor;
+import org.apache.doris.nereids.trees.expressions.EqualTo;
+import org.apache.doris.nereids.trees.expressions.Like;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
+import org.apache.doris.nereids.types.StringType;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Test;
+
+public class LikeToEqualRewriteTest extends ExpressionRewriteTestHelper {
+ @Test
+ public void testLikeRegularConst() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc");
+ assertRewrite(new Like(slot, str), new EqualTo(slot, str));
+ }
+
+ @Test
+ public void testLikeEscapePercentSignConst() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc\\%");
+ VarcharLiteral strForEqual = new VarcharLiteral("abc%");
+ assertRewrite(new Like(slot, str), new EqualTo(slot, strForEqual));
+ }
+
+ @Test
+ public void testLikeEscapeUnderlineConst() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc\\_");
+ VarcharLiteral strForEqual = new VarcharLiteral("abc_");
+ assertRewrite(new Like(slot, str), new EqualTo(slot, strForEqual));
+ }
+
+ @Test
+ public void testLikeNotEscapePercentSignConst() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc%");
+ assertRewrite(new Like(slot, str), new Like(slot, str));
+ }
+
+ @Test
+ public void testLikeNotEscapeUnderlineConst() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc_");
+ assertRewrite(new Like(slot, str), new Like(slot, str));
+ }
+
+ @Test
+ public void testLikeTwoEscape() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc\\\\");
+ VarcharLiteral strForEqual = new VarcharLiteral("abc\\");
+ assertRewrite(new Like(slot, str), new EqualTo(slot, strForEqual));
+ }
+
+ @Test
+ public void testLikeThreeEscape() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc\\\\\\");
+ VarcharLiteral strForEqual = new VarcharLiteral("abc\\\\");
+ assertRewrite(new Like(slot, str), new EqualTo(slot, strForEqual));
+ }
+
+ @Test
+ public void testLikeFourEscape() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc\\\\\\\\");
+ VarcharLiteral strForEqual = new VarcharLiteral("abc\\\\");
+ assertRewrite(new Like(slot, str), new EqualTo(slot, strForEqual));
+ }
+
+ @Test
+ public void testLikeTwoEscapeAndPercentSign() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc\\\\%");
+ assertRewrite(new Like(slot, str), new Like(slot, str));
+ }
+
+ @Test
+ public void testLikeThreeEscapeAndPercentSign() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc\\\\\\%");
+ VarcharLiteral strForEqual = new VarcharLiteral("abc\\%");
+ assertRewrite(new Like(slot, str), new EqualTo(slot, strForEqual));
+ }
+
+ @Test
+ public void testLikeFourEscapeAndPercentSign() {
+ executor = new ExpressionRuleExecutor(ImmutableList.of(
+ bottomUp(LikeToEqualRewrite.INSTANCE)
+ ));
+ SlotReference slot = new SlotReference("a", StringType.INSTANCE, true);
+ VarcharLiteral str = new VarcharLiteral("abc\\\\\\\\%");
+ assertRewrite(new Like(slot, str), new Like(slot, str));
+ }
+}
diff --git a/regression-test/data/nereids_rules_p0/like_to_equal_to_rewrite/like_to_equal_to_rewrite.out b/regression-test/data/nereids_rules_p0/like_to_equal_to_rewrite/like_to_equal_to_rewrite.out
new file mode 100644
index 00000000000..50a9a1981c8
--- /dev/null
+++ b/regression-test/data/nereids_rules_p0/like_to_equal_to_rewrite/like_to_equal_to_rewrite.out
@@ -0,0 +1,24 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !test_regular --
+abc 1
+
+-- !test_const_percent_sign --
+abc% 1
+
+-- !test_underline --
+abc_ 1
+
+-- !test_backslash1 --
+abc\\ 1
+
+-- !test_backslash2 --
+abc\\ 1
+
+-- !test_backslash_percent_sign_odd --
+abc\\% 1
+
+-- !test_backslash_percent_sign_even_match --
+abc\\\\% 1
+
+-- !test_backslash_percent_sign_even_cannot_match --
+
diff --git a/regression-test/suites/nereids_rules_p0/like_to_equal_to_rewrite/like_to_equal_to_rewrite.groovy b/regression-test/suites/nereids_rules_p0/like_to_equal_to_rewrite/like_to_equal_to_rewrite.groovy
new file mode 100644
index 00000000000..b42b0159db4
--- /dev/null
+++ b/regression-test/suites/nereids_rules_p0/like_to_equal_to_rewrite/like_to_equal_to_rewrite.groovy
@@ -0,0 +1,53 @@
+// 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("like_to_equal_to_rewrite") {
+ sql "SET enable_nereids_planner=true"
+ sql "SET enable_fallback_to_original_planner=false"
+ sql "drop table if exists mal_test_to_equal_to"
+ sql """
+ create table mal_test_to_equal_to(a varchar(10), b int)
+ distributed by hash(a) buckets 32
+ properties(
+ "replication_allocation"="tag.location.default: 1"
+ );"""
+
+ sql "insert into mal_test_to_equal_to values('abc',1);"
+ qt_test_regular "select * from mal_test_to_equal_to where a like 'abc';"
+
+ sql "truncate table mal_test_to_equal_to;"
+ sql "insert into mal_test_to_equal_to values('abc%',1);"
+ qt_test_const_percent_sign "select * from mal_test_to_equal_to where a like 'abc\\%';"
+
+ sql "truncate table mal_test_to_equal_to;"
+ sql "insert into mal_test_to_equal_to values('abc_',1);"
+ qt_test_underline """select * from mal_test_to_equal_to where a like 'abc\\_';"""
+
+ sql "truncate table mal_test_to_equal_to;"
+ sql "insert into mal_test_to_equal_to values('abc\\\\',1);"
+ qt_test_backslash1 "select * from mal_test_to_equal_to where a like 'abc\\\\\\\\';"
+ qt_test_backslash2 "select * from mal_test_to_equal_to where a like 'abc\\\\';"
+
+ sql "truncate table mal_test_to_equal_to;"
+ sql "insert into mal_test_to_equal_to values('abc\\\\%',1);"
+ qt_test_backslash_percent_sign_odd "select * from mal_test_to_equal_to where a like 'abc\\\\\\\\\\%';"
+
+ sql "truncate table mal_test_to_equal_to;"
+ sql "insert into mal_test_to_equal_to values('abc\\\\\\%',1);"
+ qt_test_backslash_percent_sign_even_match "select * from mal_test_to_equal_to where a like 'abc\\\\\\\\\\\\\\\\\\\\%';"
+ qt_test_backslash_percent_sign_even_cannot_match "select * from mal_test_to_equal_to where a like 'abc\\\\\\\\\\\\\\\\\\\\\\\\%';"
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org