1#include "duckdb/execution/expression_executor.hpp"
2#include "duckdb/planner/expression/bound_function_expression.hpp"
3
4namespace duckdb {
5
6ExecuteFunctionState::ExecuteFunctionState(const Expression &expr, ExpressionExecutorState &root)
7 : ExpressionState(expr, root) {
8}
9
10ExecuteFunctionState::~ExecuteFunctionState() {
11}
12
13unique_ptr<ExpressionState> ExpressionExecutor::InitializeState(const BoundFunctionExpression &expr,
14 ExpressionExecutorState &root) {
15 auto result = make_uniq<ExecuteFunctionState>(args: expr, args&: root);
16 for (auto &child : expr.children) {
17 result->AddChild(expr: child.get());
18 }
19 result->Finalize();
20 if (expr.function.init_local_state) {
21 result->local_state = expr.function.init_local_state(*result, expr, expr.bind_info.get());
22 }
23 return std::move(result);
24}
25
26static void VerifyNullHandling(const BoundFunctionExpression &expr, DataChunk &args, Vector &result) {
27#ifdef DEBUG
28 if (args.data.empty() || expr.function.null_handling != FunctionNullHandling::DEFAULT_NULL_HANDLING) {
29 return;
30 }
31
32 // Combine all the argument validity masks into a flat validity mask
33 idx_t count = args.size();
34 ValidityMask combined_mask(count);
35 for (auto &arg : args.data) {
36 UnifiedVectorFormat arg_data;
37 arg.ToUnifiedFormat(count, arg_data);
38
39 for (idx_t i = 0; i < count; i++) {
40 auto idx = arg_data.sel->get_index(i);
41 if (!arg_data.validity.RowIsValid(idx)) {
42 combined_mask.SetInvalid(i);
43 }
44 }
45 }
46
47 // Default is that if any of the arguments are NULL, the result is also NULL
48 UnifiedVectorFormat result_data;
49 result.ToUnifiedFormat(count, result_data);
50 for (idx_t i = 0; i < count; i++) {
51 if (!combined_mask.RowIsValid(i)) {
52 auto idx = result_data.sel->get_index(i);
53 D_ASSERT(!result_data.validity.RowIsValid(idx));
54 }
55 }
56#endif
57}
58
59void ExpressionExecutor::Execute(const BoundFunctionExpression &expr, ExpressionState *state,
60 const SelectionVector *sel, idx_t count, Vector &result) {
61 state->intermediate_chunk.Reset();
62 auto &arguments = state->intermediate_chunk;
63 if (!state->types.empty()) {
64 for (idx_t i = 0; i < expr.children.size(); i++) {
65 D_ASSERT(state->types[i] == expr.children[i]->return_type);
66 Execute(expr: *expr.children[i], state: state->child_states[i].get(), sel, count, result&: arguments.data[i]);
67#ifdef DEBUG
68 if (expr.children[i]->return_type.id() == LogicalTypeId::VARCHAR) {
69 arguments.data[i].UTFVerify(count);
70 }
71#endif
72 }
73 arguments.Verify();
74 }
75 arguments.SetCardinality(count);
76
77 state->profiler.BeginSample();
78 D_ASSERT(expr.function.function);
79 expr.function.function(arguments, *state, result);
80 state->profiler.EndSample(chunk_size: count);
81
82 VerifyNullHandling(expr, args&: arguments, result);
83 D_ASSERT(result.GetType() == expr.return_type);
84}
85
86} // namespace duckdb
87