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 8cebfdebfda [fix](nereids) fix  rewrite avg to sum / count change 
nullable  (#53787)
8cebfdebfda is described below

commit 8cebfdebfda1f409e9afdbb1b8d5c0877906a900
Author: yujun <[email protected]>
AuthorDate: Thu Jul 24 19:54:42 2025 +0800

    [fix](nereids) fix  rewrite avg to sum / count change nullable  (#53787)
    
    ### What problem does this PR solve?
    
    for sql
    select avg(distinct a), sum(distinct b) from t group by c
    if "a" is not nullable, then "avg" is not nullable,
    
    AvgDistinctToSumDivCount will rewrite "avg" to
    "sum(distinct a) / count(distinct a)", but the divide "/" is nullable,
    
    then AdjustNullable will throw exception for this changed nullable
    (introduced by #52748):
    "AdjustNullable convert slot avg(..)#10 from not-nullable to nullable. You 
can disable check by set fe_debug = false."
    
    need add a nonNullable function to make the rewritten expression 
not-nullable.
---
 .../rules/analysis/AvgDistinctToSumDivCount.java   |  10 +++++-
 .../adjust_nullable/test_adjust_nullable.out       | Bin 0 -> 489 bytes
 .../adjust_nullable/test_adjust_nullable.groovy    |  36 +++++++++++++++++++++
 3 files changed, 45 insertions(+), 1 deletion(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AvgDistinctToSumDivCount.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AvgDistinctToSumDivCount.java
index dfc4a2c7432..9b612d7299f 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AvgDistinctToSumDivCount.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AvgDistinctToSumDivCount.java
@@ -27,6 +27,7 @@ import 
org.apache.doris.nereids.trees.expressions.functions.agg.AggregateFunctio
 import org.apache.doris.nereids.trees.expressions.functions.agg.Avg;
 import org.apache.doris.nereids.trees.expressions.functions.agg.Count;
 import org.apache.doris.nereids.trees.expressions.functions.agg.Sum;
+import org.apache.doris.nereids.trees.expressions.functions.scalar.NonNullable;
 import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate;
 import org.apache.doris.nereids.util.ExpressionUtils;
 import org.apache.doris.nereids.util.TypeCoercionUtils;
@@ -56,7 +57,14 @@ public class AvgDistinctToSumDivCount extends 
OneRewriteRuleFactory {
                                                 ((Avg) function).child()));
                                 Count count = (Count) 
TypeCoercionUtils.processBoundFunction(
                                         new Count(true, ((Avg) 
function).child()));
-                                return TypeCoercionUtils.processDivide(new 
Divide(sum, count));
+                                Expression divide = 
TypeCoercionUtils.processDivide(new Divide(sum, count));
+                                if (!function.nullable() && divide.nullable()) 
{
+                                    // add NonNullable to ensure the result of 
divide is not nullable,
+                                    // otherwise AdjustNullable rule will 
throw exception
+                                    return new NonNullable(divide);
+                                } else {
+                                    return divide;
+                                }
                             }));
                     if (!avgToSumDivCount.isEmpty()) {
                         List<NamedExpression> newOutput = 
agg.getOutputExpressions().stream()
diff --git 
a/regression-test/data/nereids_rules_p0/adjust_nullable/test_adjust_nullable.out
 
b/regression-test/data/nereids_rules_p0/adjust_nullable/test_adjust_nullable.out
new file mode 100644
index 00000000000..05ca7f01e20
Binary files /dev/null and 
b/regression-test/data/nereids_rules_p0/adjust_nullable/test_adjust_nullable.out
 differ
diff --git 
a/regression-test/suites/nereids_rules_p0/adjust_nullable/test_adjust_nullable.groovy
 
b/regression-test/suites/nereids_rules_p0/adjust_nullable/test_adjust_nullable.groovy
new file mode 100644
index 00000000000..72737cae115
--- /dev/null
+++ 
b/regression-test/suites/nereids_rules_p0/adjust_nullable/test_adjust_nullable.groovy
@@ -0,0 +1,36 @@
+// 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_adjust_nullable') {
+    // test AjustNullable not throw exception:
+    // 'AdjustNullable convert slot xx from not-nullable to nullable. You can 
disable check by set fe_debug = false.'
+    // NOTICE: the pipeline need set global fe_debug = true
+    def tbl = 'test_adjust_nullable_t'
+    sql "SET detail_shape_nodes='PhysicalProject'"
+    sql "DROP TABLE IF EXISTS ${tbl} FORCE"
+    sql "CREATE TABLE ${tbl}(a int not null, b int, c int not null) 
distributed by hash(a) properties('replication_num' = '1')"
+    sql "INSERT INTO ${tbl} VALUES(1, 2, 3)"
+
+    // avg => sum / count
+    // avg is not nullable,  while divide '/' is nullable, need add 
non_nullable
+    // avg => non_nullable(sum / count)
+    qt_avg_shape """explain shape plan
+        SELECT AVG(distinct a), AVG(distinct b) FROM ${tbl} GROUP BY c
+    """
+
+    sql "DROP TABLE IF EXISTS ${tbl} FORCE"
+}


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

Reply via email to