Coverage Report

Created: 2026-07-28 01:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/vectorized_agg_fn.cpp
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#include "exprs/vectorized_agg_fn.h"
19
20
#include <fmt/format.h>
21
#include <fmt/ranges.h> // IWYU pragma: keep
22
#include <gen_cpp/Exprs_types.h>
23
#include <gen_cpp/PlanNodes_types.h>
24
#include <glog/logging.h>
25
26
#include <memory>
27
#include <ostream>
28
#include <string_view>
29
#include <vector>
30
31
#include "common/config.h"
32
#include "common/object_pool.h"
33
#include "core/block/block.h"
34
#include "core/block/column_with_type_and_name.h"
35
#include "core/block/materialize_block.h"
36
#include "core/column/column_const.h"
37
#include "core/data_type/data_type_agg_state.h"
38
#include "core/data_type/data_type_factory.hpp"
39
#include "exec/common/util.hpp"
40
#include "exprs/aggregate/aggregate_function_ai_agg.h"
41
#include "exprs/aggregate/aggregate_function_java_udaf.h"
42
#include "exprs/aggregate/aggregate_function_python_udaf.h"
43
#include "exprs/aggregate/aggregate_function_rpc.h"
44
#include "exprs/aggregate/aggregate_function_simple_factory.h"
45
#include "exprs/aggregate/aggregate_function_sort.h"
46
#include "exprs/aggregate/aggregate_function_state_merge.h"
47
#include "exprs/aggregate/aggregate_function_state_union.h"
48
#include "exprs/vexpr.h"
49
#include "exprs/vexpr_context.h"
50
51
static constexpr int64_t BE_VERSION_THAT_SUPPORT_NULLABLE_CHECK = 8;
52
53
namespace doris {
54
class RowDescriptor;
55
class Arena;
56
class BufferWritable;
57
class IColumn;
58
} // namespace doris
59
60
namespace doris {
61
62
template <class FunctionType>
63
AggregateFunctionPtr get_agg_state_function(const DataTypes& argument_types,
64
0
                                            DataTypePtr return_type) {
65
0
    return FunctionType::create(
66
0
            assert_cast<const DataTypeAggState*>(argument_types[0].get())->get_nested_function(),
67
0
            argument_types, return_type);
68
0
}
Unexecuted instantiation: _ZN5doris22get_agg_state_functionINS_19AggregateStateUnionEEESt10shared_ptrINS_18IAggregateFunctionEERKSt6vectorIS2_IKNS_9IDataTypeEESaIS8_EES8_
Unexecuted instantiation: _ZN5doris22get_agg_state_functionINS_19AggregateStateMergeEEESt10shared_ptrINS_18IAggregateFunctionEERKSt6vectorIS2_IKNS_9IDataTypeEESaIS8_EES8_
69
70
AggFnEvaluator::AggFnEvaluator(const TExprNode& desc, const bool without_key,
71
                               const bool is_window_function)
72
20
        : _fn(desc.fn),
73
20
          _is_merge(desc.agg_expr.is_merge_agg),
74
20
          _without_key(without_key),
75
20
          _is_window_function(is_window_function),
76
20
          _data_type(DataTypeFactory::instance().create_data_type(
77
20
                  desc.fn.ret_type, desc.__isset.is_nullable ? desc.is_nullable : true)),
78
20
          _always_const_argument_idx(desc.num_children, false) {
79
20
    if (desc.agg_expr.__isset.param_types) {
80
20
        const auto& param_types = desc.agg_expr.param_types;
81
20
        for (const auto& param_type : param_types) {
82
20
            _argument_types_with_sort.push_back(
83
20
                    DataTypeFactory::instance().create_data_type(param_type));
84
20
        }
85
20
    }
86
20
}
87
88
Status AggFnEvaluator::create(ObjectPool* pool, const TExpr& desc, const TSortInfo& sort_info,
89
                              const bool without_key, const bool is_window_function,
90
20
                              AggFnEvaluator** result) {
91
20
    *result =
92
20
            pool->add(AggFnEvaluator::create_unique(desc.nodes[0], without_key, is_window_function)
93
20
                              .release());
94
20
    auto& agg_fn_evaluator = *result;
95
20
    int node_idx = 0;
96
40
    for (int i = 0; i < desc.nodes[0].num_children; ++i) {
97
20
        ++node_idx;
98
20
        VExprSPtr expr;
99
20
        VExprContextSPtr ctx;
100
20
        RETURN_IF_ERROR(VExpr::create_tree_from_thrift(desc.nodes, &node_idx, expr, ctx));
101
20
        agg_fn_evaluator->_input_exprs_ctxs.push_back(ctx);
102
20
    }
103
104
20
    auto sort_size = sort_info.ordering_exprs.size();
105
20
    auto real_arguments_size = agg_fn_evaluator->_argument_types_with_sort.size() - sort_size;
106
    // Child arguments contains [real arguments, order by arguments], we pass the arguments
107
    // to the order by functions
108
20
    for (int i = 0; i < sort_size; ++i) {
109
0
        agg_fn_evaluator->_sort_description.emplace_back(real_arguments_size + i,
110
0
                                                         sort_info.is_asc_order[i] ? 1 : -1,
111
0
                                                         sort_info.nulls_first[i] ? -1 : 1);
112
0
    }
113
114
    // Pass the real arguments to get functions
115
40
    for (int i = 0; i < real_arguments_size; ++i) {
116
20
        agg_fn_evaluator->_real_argument_types.emplace_back(
117
20
                agg_fn_evaluator->_argument_types_with_sort[i]);
118
20
    }
119
20
    return Status::OK();
120
20
}
121
122
Status AggFnEvaluator::prepare(RuntimeState* state, const RowDescriptor& desc,
123
                               const SlotDescriptor* intermediate_slot_desc,
124
20
                               const SlotDescriptor* output_slot_desc) {
125
20
    DCHECK(intermediate_slot_desc != nullptr);
126
20
    DCHECK(_intermediate_slot_desc == nullptr);
127
20
    _output_slot_desc = output_slot_desc;
128
20
    _intermediate_slot_desc = intermediate_slot_desc;
129
130
20
    Status status = VExpr::prepare(_input_exprs_ctxs, state, desc);
131
20
    RETURN_IF_ERROR(status);
132
133
20
    DataTypes tmp_argument_types;
134
20
    tmp_argument_types.reserve(_input_exprs_ctxs.size());
135
136
20
    std::vector<std::string_view> child_expr_name;
137
138
    // prepare for argument
139
20
    for (auto& _input_exprs_ctx : _input_exprs_ctxs) {
140
20
        auto data_type = _input_exprs_ctx->root()->data_type();
141
20
        tmp_argument_types.emplace_back(data_type);
142
20
        child_expr_name.emplace_back(_input_exprs_ctx->root()->expr_name());
143
20
    }
144
145
20
    std::vector<std::string> column_names;
146
20
    for (const auto& expr_ctx : _input_exprs_ctxs) {
147
20
        const auto& root = expr_ctx->root();
148
20
        if (!root->expr_name().empty() && !root->is_constant()) {
149
20
            column_names.emplace_back(root->expr_name());
150
20
        }
151
20
    }
152
153
20
    const DataTypes& argument_types =
154
20
            _real_argument_types.empty() ? tmp_argument_types : _real_argument_types;
155
156
20
    if (_fn.binary_type == TFunctionBinaryType::JAVA_UDF) {
157
0
        if (config::enable_java_support) {
158
0
            _function = AggregateJavaUdaf::create(_fn, argument_types, _data_type);
159
0
            RETURN_IF_ERROR(static_cast<AggregateJavaUdaf*>(_function.get())->check_udaf(_fn));
160
0
        } else {
161
0
            return Status::InternalError(
162
0
                    "Java UDAF is not enabled, you can change be config enable_java_support to "
163
0
                    "true and restart be.");
164
0
        }
165
20
    } else if (_fn.binary_type == TFunctionBinaryType::PYTHON_UDF) {
166
0
        if (config::enable_python_udf_support) {
167
0
            _function = AggregatePythonUDAF::create(_fn, argument_types, _data_type);
168
0
            RETURN_IF_ERROR(static_cast<AggregatePythonUDAF*>(_function.get())->open());
169
0
            LOG(INFO) << fmt::format(
170
0
                    "Created Python UDAF: {}, runtime_version: {}, function_code: {}",
171
0
                    _fn.name.function_name, _fn.runtime_version, _fn.function_code);
172
0
        } else {
173
0
            return Status::InternalError(
174
0
                    "Python UDAF is not enabled, you can change be config "
175
0
                    "enable_python_udf_support to true and restart be.");
176
0
        }
177
20
    } else if (_fn.binary_type == TFunctionBinaryType::RPC) {
178
0
        _function = AggregateRpcUdaf::create(_fn, argument_types, _data_type);
179
20
    } else if (_fn.binary_type == TFunctionBinaryType::AGG_STATE) {
180
0
        if (argument_types.size() != 1) {
181
0
            return Status::InternalError("Agg state Function must input 1 argument but get {}",
182
0
                                         argument_types.size());
183
0
        }
184
0
        if (argument_types[0]->is_nullable()) {
185
0
            return Status::InternalError("Agg state function input type must be not nullable");
186
0
        }
187
0
        if (argument_types[0]->get_primitive_type() != PrimitiveType::TYPE_AGG_STATE) {
188
0
            return Status::InternalError(
189
0
                    "Agg state function input type must be agg_state but get {}",
190
0
                    argument_types[0]->get_family_name());
191
0
        }
192
193
0
        std::string type_function_name =
194
0
                assert_cast<const DataTypeAggState*>(argument_types[0].get())->get_function_name();
195
0
        if (type_function_name + AGG_UNION_SUFFIX == _fn.name.function_name) {
196
0
            if (_data_type->is_nullable()) {
197
0
                return Status::InternalError(
198
0
                        "Union function return type must be not nullable, real={}",
199
0
                        _data_type->get_name());
200
0
            }
201
0
            if (_data_type->get_primitive_type() != PrimitiveType::TYPE_AGG_STATE) {
202
0
                return Status::InternalError(
203
0
                        "Union function return type must be AGG_STATE, real={}",
204
0
                        _data_type->get_name());
205
0
            }
206
0
            _function = get_agg_state_function<AggregateStateUnion>(argument_types, _data_type);
207
0
        } else if (type_function_name + AGG_MERGE_SUFFIX == _fn.name.function_name) {
208
0
            auto type = assert_cast<const DataTypeAggState*>(argument_types[0].get())
209
0
                                ->get_nested_function()
210
0
                                ->get_return_type();
211
0
            if (!type->equals(*_data_type)) {
212
0
                return Status::InternalError("{}'s expect return type is {}, but input {}",
213
0
                                             argument_types[0]->get_name(), type->get_name(),
214
0
                                             _data_type->get_name());
215
0
            }
216
0
            _function = get_agg_state_function<AggregateStateMerge>(argument_types, _data_type);
217
0
        } else {
218
0
            return Status::InternalError("{} not match function {}", argument_types[0]->get_name(),
219
0
                                         _fn.name.function_name);
220
0
        }
221
20
    } else {
222
20
        const bool is_foreach =
223
20
                AggregateFunctionSimpleFactory::is_foreach(_fn.name.function_name) ||
224
20
                AggregateFunctionSimpleFactory::is_foreachv2(_fn.name.function_name);
225
        // Here, only foreachv1 needs special treatment, and v2 can follow the normal code logic.
226
20
        if (AggregateFunctionSimpleFactory::is_foreach(_fn.name.function_name)) {
227
0
            _function = AggregateFunctionSimpleFactory::instance().get(
228
0
                    _fn.name.function_name, argument_types, _data_type,
229
0
                    AggregateFunctionSimpleFactory::result_nullable_by_foreach(_data_type),
230
0
                    state->be_exec_version(),
231
0
                    {.is_window_function = _is_window_function,
232
0
                     .is_foreach = is_foreach,
233
0
                     .enable_aggregate_function_null_v2 =
234
0
                             state->enable_aggregate_function_null_v2(),
235
0
                     .new_version_percentile =
236
0
                             state->query_options().__isset.new_version_percentile &&
237
0
                             state->query_options().new_version_percentile,
238
0
                     .column_names = std::move(column_names)});
239
20
        } else {
240
20
            _function = AggregateFunctionSimpleFactory::instance().get(
241
20
                    _fn.name.function_name, argument_types, _data_type, _data_type->is_nullable(),
242
20
                    state->be_exec_version(),
243
20
                    {.is_window_function = _is_window_function,
244
20
                     .is_foreach = is_foreach,
245
20
                     .enable_aggregate_function_null_v2 =
246
20
                             state->enable_aggregate_function_null_v2(),
247
20
                     .new_version_percentile =
248
20
                             state->query_options().__isset.new_version_percentile &&
249
20
                             state->query_options().new_version_percentile,
250
20
                     .column_names = std::move(column_names)});
251
20
        }
252
20
    }
253
20
    if (_function == nullptr) {
254
0
        return Status::InternalError("Agg Function {} is not implemented", _fn.signature);
255
0
    }
256
257
20
    if (!_sort_description.empty()) {
258
0
        _function = transform_to_sort_agg_function(_function, _argument_types_with_sort,
259
0
                                                   _sort_description, state);
260
0
    }
261
20
    if (_fn.name.function_name == "ai_agg") {
262
0
        _function->set_query_context(state->get_query_ctx());
263
0
    }
264
20
    if (!_is_merge) {
265
20
        for (auto index : _function->get_const_argument_indexes()) {
266
0
            DORIS_CHECK_LT(index, _always_const_argument_idx.size());
267
0
            _always_const_argument_idx[index] = true;
268
0
        }
269
20
    }
270
271
    // Foreachv2, like foreachv1, does not check the return type,
272
    // because its return type is related to the internal agg.
273
20
    if (!AggregateFunctionSimpleFactory::is_foreach(_fn.name.function_name) &&
274
20
        !AggregateFunctionSimpleFactory::is_foreachv2(_fn.name.function_name)) {
275
20
        if (state->be_exec_version() >= BE_VERSION_THAT_SUPPORT_NULLABLE_CHECK) {
276
20
            RETURN_IF_ERROR(
277
20
                    _function->verify_result_type(_without_key, argument_types, _data_type));
278
20
        }
279
20
    }
280
20
    _expr_name = fmt::format("{}({})", _fn.name.function_name, child_expr_name);
281
20
    return Status::OK();
282
20
}
283
284
22
Status AggFnEvaluator::open(RuntimeState* state) {
285
22
    return VExpr::open(_input_exprs_ctxs, state);
286
22
}
287
288
1.06M
void AggFnEvaluator::create(AggregateDataPtr place) {
289
1.06M
    _function->create(place);
290
1.06M
}
291
292
1.06M
void AggFnEvaluator::destroy(AggregateDataPtr place) {
293
1.06M
    _function->destroy(place);
294
1.06M
}
295
296
170
Status AggFnEvaluator::execute_single_add(Block* block, AggregateDataPtr place, Arena& arena) {
297
170
    RETURN_IF_ERROR(_calc_argument_columns(block));
298
170
    _function->check_input_columns_type(_agg_columns.data());
299
170
    _function->add_batch_single_place(block->rows(), place, _agg_columns.data(), arena);
300
170
    return Status::OK();
301
170
}
302
303
Status AggFnEvaluator::execute_batch_add(Block* block, size_t offset, AggregateDataPtr* places,
304
54
                                         Arena& arena, bool agg_many) {
305
54
    RETURN_IF_ERROR(_calc_argument_columns(block));
306
54
    _function->check_input_columns_type(_agg_columns.data());
307
54
    _function->add_batch(block->rows(), places, offset, _agg_columns.data(), arena, agg_many);
308
54
    return Status::OK();
309
54
}
310
311
Status AggFnEvaluator::execute_batch_add_selected(Block* block, size_t offset,
312
2
                                                  AggregateDataPtr* places, Arena& arena) {
313
2
    RETURN_IF_ERROR(_calc_argument_columns(block));
314
2
    _function->check_input_columns_type(_agg_columns.data());
315
2
    _function->add_batch_selected(block->rows(), places, offset, _agg_columns.data(), arena);
316
2
    return Status::OK();
317
2
}
318
319
Status AggFnEvaluator::streaming_agg_serialize_to_column(Block* block, MutableColumnPtr& dst,
320
27
                                                         const size_t num_rows, Arena& arena) {
321
27
    RETURN_IF_ERROR(_calc_argument_columns(block));
322
27
    _function->check_input_columns_type(_agg_columns.data());
323
27
    _function->streaming_agg_serialize_to_column(_agg_columns.data(), dst, num_rows, arena);
324
27
    return Status::OK();
325
27
}
326
327
void AggFnEvaluator::add_range_single_place(int64_t partition_start, int64_t partition_end,
328
                                            int64_t frame_start, int64_t frame_end,
329
                                            AggregateDataPtr place, const IColumn** columns,
330
                                            Arena& arena, UInt8* use_null_result,
331
47
                                            UInt8* could_use_previous_result) {
332
47
    _function->check_input_columns_type(columns);
333
47
    _function->add_range_single_place(partition_start, partition_end, frame_start, frame_end, place,
334
47
                                      columns, arena, use_null_result, could_use_previous_result);
335
47
}
336
337
void AggFnEvaluator::execute_function_with_incremental(
338
        int64_t partition_start, int64_t partition_end, int64_t frame_start, int64_t frame_end,
339
        AggregateDataPtr place, const IColumn** columns, Arena& arena, bool previous_is_nul,
340
20
        bool end_is_nul, bool has_null, UInt8* use_null_result, UInt8* could_use_previous_result) {
341
20
    _function->check_input_columns_type(columns);
342
20
    _function->execute_function_with_incremental(
343
20
            partition_start, partition_end, frame_start, frame_end, place, columns, arena,
344
20
            previous_is_nul, end_is_nul, has_null, use_null_result, could_use_previous_result);
345
20
}
346
347
175
void AggFnEvaluator::insert_result_info(AggregateDataPtr place, IColumn* column) {
348
175
    _function->check_result_column_type(*column);
349
175
    _function->insert_result_into(place, *column);
350
175
}
351
352
void AggFnEvaluator::insert_result_info_vec(const std::vector<AggregateDataPtr>& places,
353
13
                                            size_t offset, IColumn* column, const size_t num_rows) {
354
13
    _function->check_result_column_type(*column);
355
13
    _function->insert_result_into_vec(places, offset, *column, num_rows);
356
13
}
357
358
void AggFnEvaluator::insert_result_info_range(ConstAggregateDataPtr place, IColumn* column,
359
67
                                              size_t start, size_t end) {
360
67
    _function->check_result_column_type(*column);
361
67
    _function->insert_result_into_range(place, *column, start, end);
362
67
}
363
364
62
void AggFnEvaluator::reset(AggregateDataPtr place) {
365
62
    _function->reset(place);
366
62
}
367
368
0
std::string AggFnEvaluator::debug_string(const std::vector<AggFnEvaluator*>& exprs) {
369
0
    std::stringstream out;
370
0
    out << "[";
371
372
0
    for (int i = 0; i < exprs.size(); ++i) {
373
0
        out << (i == 0 ? "" : " ") << exprs[i]->debug_string();
374
0
    }
375
376
0
    out << "]";
377
0
    return out.str();
378
0
}
379
380
0
std::string AggFnEvaluator::debug_string() const {
381
0
    std::stringstream out;
382
0
    out << "AggFnEvaluator(";
383
0
    out << _fn.signature;
384
0
    out << ")";
385
0
    return out.str();
386
0
}
387
388
253
Status AggFnEvaluator::_calc_argument_columns(Block* block) {
389
253
    SCOPED_TIMER(_expr_timer);
390
253
    _agg_columns.resize(_input_exprs_ctxs.size());
391
392
540
    for (int i = 0; i < _input_exprs_ctxs.size(); ++i) {
393
287
        int column_id = block->columns();
394
287
        RETURN_IF_ERROR(_input_exprs_ctxs[i]->execute(block, &column_id));
395
396
287
        if (_always_const_argument_idx[i]) {
397
2
            const auto& argument = block->get_by_position(column_id);
398
2
            if (!is_column<ColumnConst>(*argument.column)) {
399
2
                auto const_argument = argument;
400
2
                const_argument.column =
401
2
                        ColumnConst::create(argument.column->cut(0, 1), block->rows());
402
2
                block->insert(std::move(const_argument));
403
2
                column_id = block->columns() - 1;
404
2
            }
405
285
        } else {
406
285
            block->replace_by_position_if_const(column_id);
407
285
        }
408
287
        _agg_columns[i] = block->get_by_position(column_id).column.get();
409
287
    }
410
253
    return Status::OK();
411
253
}
412
413
64
AggFnEvaluator* AggFnEvaluator::clone(RuntimeState* state, ObjectPool* pool) {
414
64
    return pool->add(AggFnEvaluator::create_unique(*this, state).release());
415
64
}
416
417
AggFnEvaluator::AggFnEvaluator(AggFnEvaluator& evaluator, RuntimeState* state)
418
64
        : _fn(evaluator._fn),
419
64
          _is_merge(evaluator._is_merge),
420
64
          _without_key(evaluator._without_key),
421
64
          _is_window_function(evaluator._is_window_function),
422
64
          _argument_types_with_sort(evaluator._argument_types_with_sort),
423
64
          _real_argument_types(evaluator._real_argument_types),
424
64
          _intermediate_slot_desc(evaluator._intermediate_slot_desc),
425
64
          _output_slot_desc(evaluator._output_slot_desc),
426
64
          _sort_description(evaluator._sort_description),
427
64
          _data_type(evaluator._data_type),
428
64
          _function(evaluator._function),
429
64
          _expr_name(evaluator._expr_name),
430
64
          _agg_columns(evaluator._agg_columns),
431
64
          _always_const_argument_idx(evaluator._always_const_argument_idx) {
432
64
    if (evaluator._fn.binary_type == TFunctionBinaryType::JAVA_UDF) {
433
0
        DataTypes tmp_argument_types;
434
0
        tmp_argument_types.reserve(evaluator._input_exprs_ctxs.size());
435
        // prepare for argument
436
0
        for (auto& _input_exprs_ctx : evaluator._input_exprs_ctxs) {
437
0
            auto data_type = _input_exprs_ctx->root()->data_type();
438
0
            tmp_argument_types.emplace_back(data_type);
439
0
        }
440
0
        const DataTypes& argument_types =
441
0
                _real_argument_types.empty() ? tmp_argument_types : _real_argument_types;
442
0
        _function = AggregateJavaUdaf::create(evaluator._fn, argument_types, evaluator._data_type);
443
0
        THROW_IF_ERROR(static_cast<AggregateJavaUdaf*>(_function.get())->check_udaf(evaluator._fn));
444
0
    }
445
64
    DCHECK(_function != nullptr);
446
447
64
    _input_exprs_ctxs.resize(evaluator._input_exprs_ctxs.size());
448
128
    for (size_t i = 0; i < _input_exprs_ctxs.size(); i++) {
449
64
        WARN_IF_ERROR(evaluator._input_exprs_ctxs[i]->clone(state, _input_exprs_ctxs[i]), "");
450
64
    }
451
64
}
452
453
Status AggFnEvaluator::check_agg_fn_output(uint32_t key_size,
454
                                           const std::vector<AggFnEvaluator*>& agg_fn,
455
0
                                           const RowDescriptor& output_row_desc) {
456
0
    auto name_and_types = VectorizedUtils::create_name_and_data_types(output_row_desc);
457
0
    for (uint32_t i = key_size, j = 0; i < name_and_types.size(); i++, j++) {
458
0
        auto&& [name, column_type] = name_and_types[i];
459
0
        auto agg_return_type = agg_fn[j]->get_return_type();
460
0
        if (!column_type->equals(*agg_return_type)) {
461
0
            if (!column_type->is_nullable() || agg_return_type->is_nullable() ||
462
0
                !remove_nullable(column_type)->equals(*agg_return_type)) {
463
0
                return Status::InternalError(
464
0
                        "column_type not match data_types in agg node, column_type={}, "
465
0
                        "data_types={},column name={}",
466
0
                        column_type->get_name(), agg_return_type->get_name(), name);
467
0
            }
468
0
        }
469
0
    }
470
0
    return Status::OK();
471
0
}
472
473
0
bool AggFnEvaluator::is_blockable() const {
474
0
    return _function->is_blockable() ||
475
0
           std::any_of(_input_exprs_ctxs.begin(), _input_exprs_ctxs.end(),
476
0
                       [](VExprContextSPtr ctx) { return ctx->root()->is_blockable(); });
477
0
}
478
479
} // namespace doris