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

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new e4207f6a6d7 branch-4.0: [fix](expr)Ensure short-circuit expressions 
never receive a count of 0 #60594 (#60658)
e4207f6a6d7 is described below

commit e4207f6a6d761b429f3af6677ec16d254ce939c0
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Feb 12 23:35:31 2026 +0800

    branch-4.0: [fix](expr)Ensure short-circuit expressions never receive a 
count of 0 #60594 (#60658)
    
    Cherry-picked from #60594
    
    Co-authored-by: Mryange <[email protected]>
---
 be/src/vec/exprs/short_circuit_evaluation_expr.cpp | 79 +++++++++++++++++-----
 1 file changed, 62 insertions(+), 17 deletions(-)

diff --git a/be/src/vec/exprs/short_circuit_evaluation_expr.cpp 
b/be/src/vec/exprs/short_circuit_evaluation_expr.cpp
index b0bdada922f..accfa70a743 100644
--- a/be/src/vec/exprs/short_circuit_evaluation_expr.cpp
+++ b/be/src/vec/exprs/short_circuit_evaluation_expr.cpp
@@ -84,6 +84,22 @@ std::string ShortCircuitExpr::debug_string() const {
     return result;
 }
 
+// Returns empty result column if count==0
+// For some exprs, executing with a size-0 column may cause errors.
+// These are issues with the exprs themselves, but for convenience, we handle 
this case uniformly in short-circuit expr.
+/// TODO: Once all exprs support size-0 columns in the future, this function 
can be removed.
+[[nodiscard]] Status try_early_return_on_empty(const VExprSPtr& expr, 
VExprContext* context,
+                                               const Block* block, Selector* 
selector, size_t count,
+                                               ColumnPtr& result_columnn) {
+    if (count == 0) {
+        result_columnn = expr->execute_type(block)->create_column();
+        DCHECK_EQ(result_columnn->size(), 0);
+        return Status::OK();
+    }
+
+    return expr->execute_column(context, block, selector, count, 
result_columnn);
+}
+
 ShortCircuitCaseExpr::ShortCircuitCaseExpr(const TExprNode& node)
         : ShortCircuitExpr(node), _has_else_expr(node.case_expr.has_else_expr) 
{}
 
@@ -167,7 +183,8 @@ Status ShortCircuitIfExpr::execute_column(VExprContext* 
context, const Block* bl
     DCHECK(_open_finished || block == nullptr) << debug_string();
     DCHECK(selector == nullptr || selector->size() == count);
     ColumnPtr cond_column;
-    RETURN_IF_ERROR(_children[0]->execute_column(context, block, selector, 
count, cond_column));
+    RETURN_IF_ERROR(
+            try_early_return_on_empty(_children[0], context, block, selector, 
count, cond_column));
     DCHECK_EQ(cond_column->size(), count);
 
     Selector true_executor_selector;
@@ -179,12 +196,13 @@ Status ShortCircuitIfExpr::execute_column(VExprContext* 
context, const Block* bl
                         false_executor_selector, false_self_selector);
 
     ColumnPtr true_column;
-    RETURN_IF_ERROR(_children[1]->execute_column(context, block, 
&true_executor_selector,
-                                                 
true_executor_selector.size(), true_column));
 
+    RETURN_IF_ERROR(try_early_return_on_empty(_children[1], context, block, 
&true_executor_selector,
+                                              true_executor_selector.size(), 
true_column));
     ColumnPtr false_column;
-    RETURN_IF_ERROR(_children[2]->execute_column(context, block, 
&false_executor_selector,
-                                                 
false_executor_selector.size(), false_column));
+    RETURN_IF_ERROR(try_early_return_on_empty(_children[2], context, block,
+                                              &false_executor_selector,
+                                              false_executor_selector.size(), 
false_column));
 
     result_column = dispatch_fill_columns(true_column, true_self_selector, 
false_column,
                                           false_self_selector, count);
@@ -264,10 +282,14 @@ Status ShortCircuitCaseExpr::execute_column(VExprContext* 
context, const Block*
     Selector left_not_matched_executor_selector;
     Selector left_not_matched_current_selector;
 
+    int64_t executed_branches = 0;
+
     for (int64_t i = 0; i < static_cast<int64_t>(_children.size()) - 
_has_else_expr; i += 2) {
+        executed_branches++;
         ColumnPtr when_column_ptr;
-        RETURN_IF_ERROR(_children[i]->execute_column(context, block, 
executor_selector,
-                                                     executor_count, 
when_column_ptr));
+
+        RETURN_IF_ERROR(try_early_return_on_empty(_children[i], context, 
block, executor_selector,
+                                                  executor_count, 
when_column_ptr));
 
         DCHECK(executor_selector == nullptr ||
                executor_selector->size() == when_column_ptr->size());
@@ -282,9 +304,10 @@ Status ShortCircuitCaseExpr::execute_column(VExprContext* 
context, const Block*
                               not_matched_executor_selector, 
not_matched_current_selector);
 
         ColumnPtr then_column_ptr;
-        RETURN_IF_ERROR(_children[i + 1]->execute_column(context, block, 
&matched_executor_selector,
-                                                         
matched_executor_selector.size(),
-                                                         then_column_ptr));
+        RETURN_IF_ERROR(try_early_return_on_empty(
+                _children[i + 1], context, block, &matched_executor_selector,
+                matched_executor_selector.size(), then_column_ptr));
+
         columns_and_selectors[i / 2].column = then_column_ptr;
         columns_and_selectors[i / 2].selector.swap(matched_current_selector);
 
@@ -294,6 +317,13 @@ Status ShortCircuitCaseExpr::execute_column(VExprContext* 
context, const Block*
         executor_selector = &left_not_matched_executor_selector;
         executor_count = left_not_matched_executor_selector.size();
         current_selector = &left_not_matched_current_selector;
+
+        if (executor_count == 0) {
+            columns_and_selectors.resize(executed_branches);
+            // All rows have been matched; no need to process other branch
+            result_column = dispatch_fill_columns(columns_and_selectors, 
count);
+            return Status::OK();
+        }
     }
 
     // handle the else branch
@@ -301,8 +331,10 @@ Status ShortCircuitCaseExpr::execute_column(VExprContext* 
context, const Block*
         DCHECK_EQ(columns_and_selectors.size(), (_children.size() + 1) / 2);
 
         ColumnPtr else_column_ptr;
-        RETURN_IF_ERROR(_children.back()->execute_column(context, block, 
executor_selector,
-                                                         executor_count, 
else_column_ptr));
+
+        RETURN_IF_ERROR(try_early_return_on_empty(_children.back(), context, 
block,
+                                                  executor_selector, 
executor_count,
+                                                  else_column_ptr));
         columns_and_selectors.back().column = else_column_ptr;
         
columns_and_selectors.back().selector.swap(left_not_matched_current_selector);
     } else {
@@ -348,7 +380,8 @@ Status ShortCircuitIfNullExpr::execute_column(VExprContext* 
context, const Block
     DCHECK(_open_finished || block == nullptr) << debug_string();
     DCHECK(selector == nullptr || selector->size() == count);
     ColumnPtr expr1_column;
-    RETURN_IF_ERROR(_children[0]->execute_column(context, block, selector, 
count, expr1_column));
+    RETURN_IF_ERROR(
+            try_early_return_on_empty(_children[0], context, block, selector, 
count, expr1_column));
     DCHECK_EQ(expr1_column->size(), count);
     Selector null_executor_selector;
     Selector null_current_selector;
@@ -361,8 +394,9 @@ Status ShortCircuitIfNullExpr::execute_column(VExprContext* 
context, const Block
                                                not_null_self_selector.size());
 
     ColumnPtr expr2_column;
-    RETURN_IF_ERROR(_children[1]->execute_column(context, block, 
&null_executor_selector,
-                                                 
null_executor_selector.size(), expr2_column));
+
+    RETURN_IF_ERROR(try_early_return_on_empty(_children[1], context, block, 
&null_executor_selector,
+                                              null_executor_selector.size(), 
expr2_column));
 
     result_column = dispatch_fill_columns(expr1_column, 
not_null_self_selector, expr2_column,
                                           null_current_selector, count);
@@ -423,10 +457,14 @@ Status 
ShortCircuitCoalesceExpr::execute_column(VExprContext* context, const Blo
     Selector left_null_executor_selector;
     Selector left_null_current_selector;
 
+    int64_t executed_branches = 0;
+
     for (int64_t i = 0; i < _children.size(); ++i) {
+        executed_branches++;
         ColumnPtr child_column_ptr;
-        RETURN_IF_ERROR(_children[i]->execute_column(context, block, 
executor_selector,
-                                                     executor_count, 
child_column_ptr));
+
+        RETURN_IF_ERROR(try_early_return_on_empty(_children[i], context, 
block, executor_selector,
+                                                  executor_count, 
child_column_ptr));
 
         DCHECK(executor_selector == nullptr ||
                executor_selector->size() == child_column_ptr->size());
@@ -453,6 +491,13 @@ Status 
ShortCircuitCoalesceExpr::execute_column(VExprContext* context, const Blo
         executor_selector = &left_null_executor_selector;
         executor_count = left_null_executor_selector.size();
         current_selector = &left_null_current_selector;
+
+        if (executor_count == 0) {
+            columns_and_selectors.resize(executed_branches);
+            // All rows have been matched; no need to process other branch
+            result_column = dispatch_fill_columns(columns_and_selectors, 
count);
+            return Status::OK();
+        }
     }
 
     // the remaining null rows at the end


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

Reply via email to