This is an automated email from the ASF dual-hosted git repository.

924060929 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 0186c8a5286  [fix](infer-predicate) Preserve datetime precision in 
predicate inference (#67653)
0186c8a5286 is described below

commit 0186c8a5286ef12400a5ee955218b3c28d9e7b7a
Author: feiniaofeiafei <[email protected]>
AuthorDate: Fri Sep 11 11:49:21 2026 +0800

     [fix](infer-predicate) Preserve datetime precision in predicate inference 
(#67653)
    
    ### What problem does this PR solve?
    
    Related PR: #41731
    
    Problem Summary:
    Predicate inference unwraps narrowing DATETIMEV2 casts and incorrectly
    treats distinct raw join keys as equal. An IN predicate on one side can
    then filter valid matches on the other side. Require injective
    DATETIMEV2 casts before unwrapping, including nested casts, while
    preserving same-scale and widening inference. Add one unit test and a
    regression case comparing inference enabled and disabled.
    
    Fix missing join results caused by predicate inference across narrowing
    DATETIMEV2 casts.
---
 .../doris/nereids/util/PredicateInferUtils.java    |  4 +-
 .../rules/rewrite/InferPredicateByReplaceTest.java | 26 +++++++++++
 .../infer_datetimev2_cast_precision.out            |  7 +++
 .../infer_datetimev2_cast_precision.groovy         | 50 ++++++++++++++++++++++
 4 files changed, 86 insertions(+), 1 deletion(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PredicateInferUtils.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PredicateInferUtils.java
index d6f7dfc145c..2a3ac016c49 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PredicateInferUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PredicateInferUtils.java
@@ -156,7 +156,9 @@ public class PredicateInferUtils {
                 if (childType.isTimeStampNsType()) {
                     return Optional.empty();
                 }
-                return validForInfer(child, inferType);
+                if (!(childType instanceof DateTimeV2Type) || 
childType.isInjectiveCastTo(dataType)) {
+                    return validForInfer(child, inferType);
+                }
             }
         } else if (inferType == InferType.STRING) {
             // avoid substring cast such as cast(char(3) as char(2))
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplaceTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplaceTest.java
index 87f88157a0f..5c174cb6348 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplaceTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/InferPredicateByReplaceTest.java
@@ -173,6 +173,32 @@ public class InferPredicateByReplaceTest {
         Assertions.assertEquals(3, result.size());
     }
 
+    @Test
+    public void testInferWithDateTimeV2CastPrecision() {
+        for (int sourceScale : new int[] {0, 3, 6}) {
+            SlotReference a = new SlotReference("a", 
DateTimeV2Type.of(sourceScale));
+            SlotReference b = new SlotReference("b", 
DateTimeV2Type.of(sourceScale));
+            InPredicate predicate = new InPredicate(a, ImmutableList.of(
+                    new DateTimeV2Literal(DateTimeV2Type.of(sourceScale), 
"2025-01-01 00:00:00"),
+                    new DateTimeV2Literal(DateTimeV2Type.of(sourceScale), 
"2025-01-01 00:00:01")));
+            InPredicate expected = new InPredicate(b, predicate.getOptions());
+            for (int targetScale : new int[] {0, 3, 6}) {
+                EqualTo equality = new EqualTo(new Cast(a, 
DateTimeV2Type.of(targetScale)),
+                        new Cast(b, DateTimeV2Type.of(targetScale)));
+                Set<Expression> inputs = new 
HashSet<>(ImmutableList.of(equality, predicate));
+                Assertions.assertEquals(sourceScale <= targetScale,
+                        
InferPredicateByReplace.infer(inputs).contains(expected),
+                        "Unexpected inference for scale " + sourceScale + " -> 
" + targetScale);
+            }
+            EqualTo nestedEquality = new EqualTo(
+                    new Cast(new Cast(a, DateTimeV2Type.of(0)), 
DateTimeV2Type.of(6)),
+                    new Cast(new Cast(b, DateTimeV2Type.of(0)), 
DateTimeV2Type.of(6)));
+            Set<Expression> inputs = new 
HashSet<>(ImmutableList.of(nestedEquality, predicate));
+            Assertions.assertEquals(sourceScale == 0, 
InferPredicateByReplace.infer(inputs).contains(expected),
+                    "Nested casts must not hide precision loss");
+        }
+    }
+
     @Test
     public void testValidForInfer() {
         SlotReference a = new SlotReference("a", TinyIntType.INSTANCE);
diff --git 
a/regression-test/data/nereids_rules_p0/infer_predicate/infer_datetimev2_cast_precision.out
 
b/regression-test/data/nereids_rules_p0/infer_predicate/infer_datetimev2_cast_precision.out
new file mode 100644
index 00000000000..d037fd99f05
--- /dev/null
+++ 
b/regression-test/data/nereids_rules_p0/infer_predicate/infer_datetimev2_cast_precision.out
@@ -0,0 +1,7 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !without_inference --
+1      1       10
+
+-- !with_inference --
+1      1       10
+
diff --git 
a/regression-test/suites/nereids_rules_p0/infer_predicate/infer_datetimev2_cast_precision.groovy
 
b/regression-test/suites/nereids_rules_p0/infer_predicate/infer_datetimev2_cast_precision.groovy
new file mode 100644
index 00000000000..5047cd9a0e7
--- /dev/null
+++ 
b/regression-test/suites/nereids_rules_p0/infer_predicate/infer_datetimev2_cast_precision.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("infer_datetimev2_cast_precision", "p0") {
+    sql "DROP TABLE IF EXISTS infer_datetimev2_cast_l"
+    sql "DROP TABLE IF EXISTS infer_datetimev2_cast_r"
+    sql """
+        CREATE TABLE infer_datetimev2_cast_l (id INT, a DATETIMEV2(6))
+        DUPLICATE KEY(id)
+        DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES ("replication_num" = "1")
+    """
+    sql """
+        CREATE TABLE infer_datetimev2_cast_r (id INT, b DATETIMEV2(6))
+        DUPLICATE KEY(id)
+        DISTRIBUTED BY HASH(id) BUCKETS 1
+        PROPERTIES ("replication_num" = "1")
+    """
+    sql "INSERT INTO infer_datetimev2_cast_l VALUES (1, '2025-01-01 
00:00:00.100000')"
+    sql "INSERT INTO infer_datetimev2_cast_r VALUES (10, '2025-01-01 
00:00:00.200000')"
+
+    // Distinct raw values become equal after narrowing the fractional-second 
precision.
+    sql "SET disable_nereids_rules = 'INFER_PREDICATES'"
+    order_qt_without_inference """
+        SELECT COUNT(*) AS cnt, MIN(l.id) AS left_id, MIN(r.id) AS right_id
+        FROM infer_datetimev2_cast_l l JOIN infer_datetimev2_cast_r r
+          ON CAST(l.a AS DATETIMEV2(0)) = CAST(r.b AS DATETIMEV2(0))
+        WHERE l.a IN ('2025-01-01 00:00:00.100000', '2025-01-01 
00:00:00.300000')
+    """
+    sql "SET disable_nereids_rules = ''"
+    order_qt_with_inference """
+        SELECT COUNT(*) AS cnt, MIN(l.id) AS left_id, MIN(r.id) AS right_id
+        FROM infer_datetimev2_cast_l l JOIN infer_datetimev2_cast_r r
+          ON CAST(l.a AS DATETIMEV2(0)) = CAST(r.b AS DATETIMEV2(0))
+        WHERE l.a IN ('2025-01-01 00:00:00.100000', '2025-01-01 
00:00:00.300000')
+    """
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to