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 2023/01/06 06:08:11 UTC

[doris] branch master updated: [fix](nereids) Convert to datetime when binary expr's left is date and right is int type (#15615)

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 7f84db310a [fix](nereids) Convert to datetime when binary expr's left is date and right is int type (#15615)
7f84db310a is described below

commit 7f84db310a5f8310b5e308606efd6351a854bb9f
Author: AKIRA <33...@users.noreply.github.com>
AuthorDate: Fri Jan 6 14:08:05 2023 +0800

    [fix](nereids) Convert to datetime when binary expr's left is date and right is int type (#15615)
    
    In the below case, expression ` date > 20200101` should implicit cast date both side to datetime instead of bigint
    
    ```sql
            CREATE TABLE `part_by_date`
            (
                `date`                  date   NOT NULL COMMENT '',
                `id`                      int(11) NOT NULL COMMENT ''
            ) ENGINE=OLAP
            UNIQUE KEY(`date`, `id`)
            PARTITION BY RANGE(`date`)
            (PARTITION p201912 VALUES [('0000-01-01'), ('2020-01-01')),
            PARTITION p202001 VALUES [('2020-01-01'), ('2020-02-01')))
            DISTRIBUTED BY HASH(`id`) BUCKETS 3
            PROPERTIES (
            "replication_allocation" = "tag.location.default: 1"
            );
    
            INSERT INTO  part_by_date VALUES('0001-02-01', 1),('2020-01-15', 2);
    
            SELECT
                id
            FROM
               part_by_date
            WHERE date > 20200101;
    ```
---
 .../expression/rewrite/rules/TypeCoercion.java     | 14 +++---
 .../trees/expressions/BinaryArithmetic.java        |  3 +-
 .../trees/plans/logical/LogicalSetOperation.java   |  2 +-
 .../doris/nereids/util/TypeCoercionUtils.java      | 29 ++++++++++---
 .../org/apache/doris/planner/OriginalPlanner.java  |  2 -
 .../doris/nereids/util/TypeCoercionUtilsTest.java  |  3 +-
 .../data/nereids_syntax_p0/test_convert.out        |  4 ++
 .../suites/nereids_syntax_p0/test_convert.groovy   | 50 ++++++++++++++++++++++
 8 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/TypeCoercion.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/TypeCoercion.java
index a81aefc986..e1bb596a00 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/TypeCoercion.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/TypeCoercion.java
@@ -77,23 +77,23 @@ public class TypeCoercion extends AbstractExpressionRewriteRule {
     // TODO: add other expression visitor function to do type coercion if necessary.
 
     @Override
-    public Expression visitBinaryOperator(BinaryOperator binaryOperator, ExpressionRewriteContext context) {
-        Expression left = rewrite(binaryOperator.left(), context);
-        Expression right = rewrite(binaryOperator.right(), context);
+    public Expression visitBinaryOperator(BinaryOperator op, ExpressionRewriteContext context) {
+        Expression left = rewrite(op.left(), context);
+        Expression right = rewrite(op.right(), context);
 
         return Optional.of(TypeCoercionUtils.canHandleTypeCoercion(left.getDataType(), right.getDataType()))
                 .filter(Boolean::booleanValue)
-                .map(b -> TypeCoercionUtils.findTightestCommonType(left.getDataType(), right.getDataType()))
+                .map(b -> TypeCoercionUtils.findTightestCommonType(op, left.getDataType(), right.getDataType()))
                 .filter(Optional::isPresent)
                 .map(Optional::get)
-                .filter(ct -> binaryOperator.inputType().acceptsType(ct))
+                .filter(ct -> op.inputType().acceptsType(ct))
                 .filter(ct -> !left.getDataType().equals(ct) || !right.getDataType().equals(ct))
                 .map(commonType -> {
                     Expression newLeft = TypeCoercionUtils.castIfNotSameType(left, commonType);
                     Expression newRight = TypeCoercionUtils.castIfNotSameType(right, commonType);
-                    return binaryOperator.withChildren(newLeft, newRight);
+                    return op.withChildren(newLeft, newRight);
                 })
-                .orElse(binaryOperator.withChildren(left, right));
+                .orElse(op.withChildren(left, right));
     }
 
     @Override
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryArithmetic.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryArithmetic.java
index ec45b4f707..942252ccaf 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryArithmetic.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryArithmetic.java
@@ -48,7 +48,8 @@ public abstract class BinaryArithmetic extends BinaryOperator implements Propaga
             try {
                 return TypeCoercionUtils.findCommonNumericsType(left().getDataType(), right().getDataType());
             } catch (Exception e) {
-                return TypeCoercionUtils.findTightestCommonType(left().getDataType(), right().getDataType())
+                return TypeCoercionUtils.findTightestCommonType(this,
+                                left().getDataType(), right().getDataType())
                         .orElseGet(() -> left().getDataType());
             }
         }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java
index 10c5eb275c..1e69cda49c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java
@@ -134,7 +134,7 @@ public abstract class LogicalSetOperation extends AbstractLogicalPlan implements
             Slot right = child(1).getOutput().get(i);
             if (TypeCoercionUtils.canHandleTypeCoercion(left.getDataType(), right.getDataType())) {
                 Optional<DataType> tightestCommonType =
-                        TypeCoercionUtils.findTightestCommonType(left.getDataType(), right.getDataType());
+                        TypeCoercionUtils.findTightestCommonType(null, left.getDataType(), right.getDataType());
                 if (tightestCommonType.isPresent()) {
                     Expression newLeft = TypeCoercionUtils.castIfNotSameType(left, tightestCommonType.get());
                     Expression newRight = TypeCoercionUtils.castIfNotSameType(right, tightestCommonType.get());
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 ccb0796ae6..bc357e4fef 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
@@ -19,6 +19,8 @@ package org.apache.doris.nereids.util;
 
 import org.apache.doris.nereids.annotation.Developing;
 import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.BinaryArithmetic;
+import org.apache.doris.nereids.trees.expressions.BinaryOperator;
 import org.apache.doris.nereids.trees.expressions.Cast;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.literal.Literal;
@@ -186,7 +188,8 @@ public class TypeCoercionUtils {
      * find the tightest common type for two type
      */
     @Developing
-    public static Optional<DataType> findTightestCommonType(DataType left, DataType right) {
+    public static Optional<DataType> findTightestCommonType(BinaryOperator binaryOperator,
+            DataType left, DataType right) {
         // TODO: compatible with origin planner and BE
         // TODO: when add new type, add it to here
         DataType tightestCommonType = null;
@@ -234,9 +237,12 @@ public class TypeCoercionUtils {
             } else if (left instanceof DateV2Type || right instanceof DateV2Type) {
                 tightestCommonType = DateV2Type.INSTANCE;
             }
-        } else if ((left instanceof DateLikeType && right instanceof IntegralType)
-                    || (right instanceof DateLikeType && left instanceof IntegralType)) {
-            tightestCommonType = BigIntType.INSTANCE;
+        } else if (canCompareDate(left, right)) {
+            if (binaryOperator instanceof BinaryArithmetic) {
+                tightestCommonType = IntegerType.INSTANCE;
+            } else {
+                tightestCommonType = DateTimeType.INSTANCE;
+            }
         }
         return tightestCommonType == null ? Optional.of(DoubleType.INSTANCE) : Optional.of(tightestCommonType);
     }
@@ -302,7 +308,7 @@ public class TypeCoercionUtils {
         // TODO: need to rethink how to handle char and varchar to return char or varchar as much as possible.
         return Stream
                 .<Supplier<Optional<DataType>>>of(
-                        () -> findTightestCommonType(left, right),
+                        () -> findTightestCommonType(null, left, right),
                         () -> findWiderTypeForDecimal(left, right),
                         () -> characterPromotion(left, right),
                         () -> findTypeForComplex(left, right))
@@ -381,4 +387,17 @@ public class TypeCoercionUtils {
             return new Cast(input, dataType);
         }
     }
+
+    private static boolean canCompareDate(DataType left, DataType right) {
+        if (left instanceof DateLikeType) {
+            return right.isDateType() || right.isStringType() || right instanceof TinyIntType
+                    || right instanceof SmallIntType || right instanceof IntegerType
+                    || right instanceof BigIntType;
+        } else if (right instanceof DateLikeType) {
+            return left.isStringType() || left instanceof TinyIntType
+                    || left instanceof SmallIntType || left instanceof IntegerType
+                    || left instanceof BigIntType;
+        }
+        return false;
+    }
 }
diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/OriginalPlanner.java b/fe/fe-core/src/main/java/org/apache/doris/planner/OriginalPlanner.java
index d882c65119..c2c15c5c31 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/planner/OriginalPlanner.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/planner/OriginalPlanner.java
@@ -91,8 +91,6 @@ public class OriginalPlanner extends Planner {
         return analyzer.getAssignedRuntimeFilter();
     }
 
-    /**
-     */
     private void setResultExprScale(Analyzer analyzer, ArrayList<Expr> outputExprs) {
         for (TupleDescriptor tupleDesc : analyzer.getDescTbl().getTupleDescs()) {
             for (SlotDescriptor slotDesc : tupleDesc.getSlots()) {
diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/TypeCoercionUtilsTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/TypeCoercionUtilsTest.java
index bbd75d48c2..16ac52b8ec 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/TypeCoercionUtilsTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/TypeCoercionUtilsTest.java
@@ -155,7 +155,8 @@ public class TypeCoercionUtilsTest {
     }
 
     private void testFindTightestCommonType(DataType commonType, DataType left, DataType right) {
-        Assertions.assertEquals(Optional.ofNullable(commonType), TypeCoercionUtils.findTightestCommonType(left, right));
+        Assertions.assertEquals(Optional.ofNullable(commonType), TypeCoercionUtils.findTightestCommonType(null,
+                left, right));
     }
 
     @Test
diff --git a/regression-test/data/nereids_syntax_p0/test_convert.out b/regression-test/data/nereids_syntax_p0/test_convert.out
new file mode 100644
index 0000000000..4ee136aef2
--- /dev/null
+++ b/regression-test/data/nereids_syntax_p0/test_convert.out
@@ -0,0 +1,4 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !sql --
+2
+
diff --git a/regression-test/suites/nereids_syntax_p0/test_convert.groovy b/regression-test/suites/nereids_syntax_p0/test_convert.groovy
new file mode 100644
index 0000000000..9f402c4a7e
--- /dev/null
+++ b/regression-test/suites/nereids_syntax_p0/test_convert.groovy
@@ -0,0 +1,50 @@
+// 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("test_implicit_convert") {
+
+    sql """
+        DROP TABLE IF EXISTS part_by_date
+    """
+    sql """
+        CREATE TABLE `part_by_date`
+        (
+            `date`                       date         NOT NULL COMMENT '',
+            `id`                      int(11) NOT NULL COMMENT ''
+        ) ENGINE=OLAP
+        UNIQUE KEY(`date`, `id`)
+        PARTITION BY RANGE(`date`) 
+        (PARTITION p201912 VALUES [('0000-01-01'), ('2020-01-01')),
+        PARTITION p202001 VALUES [('2020-01-01'), ('2020-02-01')))
+        DISTRIBUTED BY HASH(`id`) BUCKETS 3
+        PROPERTIES (
+        "replication_allocation" = "tag.location.default: 1"
+        );
+    """
+
+    sql """
+        INSERT INTO  part_by_date VALUES('0001-02-01', 1),('2020-01-15', 2);
+    """
+
+    qt_sql """
+        SELECT
+            id
+        FROM
+           part_by_date
+        WHERE date > 20200101;
+    """
+}
\ 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