Coverage Report

Created: 2026-10-12 17:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/aggregate/aggregate_function_state_union.h
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
#pragma once
19
20
#include <utility>
21
22
#include "core/data_type/data_type_agg_state.h"
23
#include "exprs/aggregate/aggregate_function.h"
24
25
namespace doris {
26
const static std::string AGG_UNION_SUFFIX = "_union";
27
28
class AggregateStateUnion : public AggregateFunctionNonFinalBase,
29
                            public IAggregateFunctionHelper<AggregateStateUnion> {
30
public:
31
    AggregateStateUnion(AggregateFunctionPtr function, const DataTypes& argument_types_,
32
                        DataTypePtr return_type)
33
203
            : IAggregateFunctionHelper(argument_types_),
34
203
              _function(std::move(function)),
35
203
              _return_type(std::move(return_type)) {}
36
203
    ~AggregateStateUnion() override = default;
37
38
    static AggregateFunctionPtr create(AggregateFunctionPtr function,
39
                                       const DataTypes& argument_types_,
40
67
                                       const DataTypePtr& return_type) {
41
67
        CHECK(argument_types_.size() == 1);
42
67
        if (function == nullptr) {
43
0
            return nullptr;
44
0
        }
45
67
        return std::make_shared<AggregateStateUnion>(function, argument_types_, return_type);
46
67
    }
47
48
0
    void set_version(const int version_) override {
49
0
        IAggregateFunctionHelper::set_version(version_);
50
0
        _function->set_version(version_);
51
0
    }
52
53
3.09k
    void create(AggregateDataPtr __restrict place) const override { _function->create(place); }
54
55
0
    String get_name() const override { return _function->get_name() + AGG_UNION_SUFFIX; }
56
57
0
    DataTypePtr get_return_type() const override { return _return_type; }
58
59
    void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num,
60
15
             Arena& arena) const override {
61
        //the range is [begin, end]
62
15
        _function->deserialize_and_merge_from_column_range(place, *columns[0], row_num, row_num,
63
15
                                                           arena);
64
15
    }
65
66
    void add_batch_single_place(size_t batch_size, AggregateDataPtr place, const IColumn** columns,
67
4
                                Arena& arena) const override {
68
4
        _function->deserialize_and_merge_from_column_range(place, *columns[0], 0, batch_size - 1,
69
4
                                                           arena);
70
4
    }
71
72
    void add_batch(size_t batch_size, AggregateDataPtr* places, size_t place_offset,
73
644
                   const IColumn** columns, Arena& arena, bool agg_many) const override {
74
644
        add_batch_impl<false>(batch_size, places, place_offset, columns, arena);
75
644
    }
76
77
    void add_batch_selected(size_t batch_size, AggregateDataPtr* places, size_t place_offset,
78
896
                            const IColumn** columns, Arena& arena) const override {
79
896
        add_batch_impl<true>(batch_size, places, place_offset, columns, arena);
80
896
    }
81
14
    void reset(AggregateDataPtr place) const override { _function->reset(place); }
82
83
    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs,
84
0
               Arena& arena) const override {
85
0
        _function->merge(place, rhs, arena);
86
0
    }
87
88
0
    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
89
0
        _function->serialize(place, buf);
90
0
    }
91
92
    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf,
93
0
                     Arena& arena) const override {
94
0
        _function->deserialize(place, buf, arena);
95
0
    }
96
97
15
    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
98
15
        _function->serialize_without_key_to_column(place, to);
99
15
    }
100
101
3.09k
    void destroy(AggregateDataPtr __restrict place) const noexcept override {
102
3.09k
        _function->destroy(place);
103
3.09k
    }
104
105
0
    bool is_trivial() const override { return false; }
106
107
3.60k
    size_t size_of_data() const override { return _function->size_of_data(); }
108
109
5.12k
    size_t align_of_data() const override { return _function->align_of_data(); }
110
111
private:
112
    template <bool selected>
113
    void add_batch_impl(size_t batch_size, AggregateDataPtr* places, size_t place_offset,
114
1.54k
                        const IColumn** columns, Arena& arena) const {
115
        // Some batch implementations read the first serialized row before entering their loop.
116
1.54k
        if (batch_size == 0) {
117
512
            return;
118
512
        }
119
        // Delegate the whole batch so native state columns (e.g. SUM) can merge directly,
120
        // instead of dispatching through the range interface for every input row.
121
        // Generic implementations need aligned scratch states and manage their construction,
122
        // destruction and exception cleanup. Release only this storage after the batch;
123
        // keep passing the caller's arena for allocations that merged states may retain.
124
        // The function can be shared by evaluators, so scratch must not be a mutable member.
125
1.02k
        Arena scratch_arena;
126
1.02k
        AggregateDataPtr scratch = nullptr;
127
1.02k
        if (_function->needs_deserialize_and_merge_scratch()) {
128
513
            scratch = scratch_arena.aligned_alloc(batch_size * _function->size_of_data(),
129
513
                                                  _function->align_of_data());
130
513
        }
131
1.02k
        if constexpr (selected) {
132
640
            _function->deserialize_and_merge_vec_selected(places, place_offset, scratch, columns[0],
133
640
                                                          arena, batch_size);
134
640
        } else {
135
388
            _function->deserialize_and_merge_vec(places, place_offset, scratch, columns[0], arena,
136
388
                                                 batch_size);
137
388
        }
138
1.02k
    }
_ZNK5doris19AggregateStateUnion14add_batch_implILb0EEEvmPPcmPPKNS_7IColumnERNS_5ArenaE
Line
Count
Source
114
644
                        const IColumn** columns, Arena& arena) const {
115
        // Some batch implementations read the first serialized row before entering their loop.
116
644
        if (batch_size == 0) {
117
256
            return;
118
256
        }
119
        // Delegate the whole batch so native state columns (e.g. SUM) can merge directly,
120
        // instead of dispatching through the range interface for every input row.
121
        // Generic implementations need aligned scratch states and manage their construction,
122
        // destruction and exception cleanup. Release only this storage after the batch;
123
        // keep passing the caller's arena for allocations that merged states may retain.
124
        // The function can be shared by evaluators, so scratch must not be a mutable member.
125
388
        Arena scratch_arena;
126
388
        AggregateDataPtr scratch = nullptr;
127
388
        if (_function->needs_deserialize_and_merge_scratch()) {
128
193
            scratch = scratch_arena.aligned_alloc(batch_size * _function->size_of_data(),
129
193
                                                  _function->align_of_data());
130
193
        }
131
        if constexpr (selected) {
132
            _function->deserialize_and_merge_vec_selected(places, place_offset, scratch, columns[0],
133
                                                          arena, batch_size);
134
388
        } else {
135
388
            _function->deserialize_and_merge_vec(places, place_offset, scratch, columns[0], arena,
136
388
                                                 batch_size);
137
388
        }
138
388
    }
_ZNK5doris19AggregateStateUnion14add_batch_implILb1EEEvmPPcmPPKNS_7IColumnERNS_5ArenaE
Line
Count
Source
114
896
                        const IColumn** columns, Arena& arena) const {
115
        // Some batch implementations read the first serialized row before entering their loop.
116
896
        if (batch_size == 0) {
117
256
            return;
118
256
        }
119
        // Delegate the whole batch so native state columns (e.g. SUM) can merge directly,
120
        // instead of dispatching through the range interface for every input row.
121
        // Generic implementations need aligned scratch states and manage their construction,
122
        // destruction and exception cleanup. Release only this storage after the batch;
123
        // keep passing the caller's arena for allocations that merged states may retain.
124
        // The function can be shared by evaluators, so scratch must not be a mutable member.
125
640
        Arena scratch_arena;
126
640
        AggregateDataPtr scratch = nullptr;
127
640
        if (_function->needs_deserialize_and_merge_scratch()) {
128
320
            scratch = scratch_arena.aligned_alloc(batch_size * _function->size_of_data(),
129
320
                                                  _function->align_of_data());
130
320
        }
131
640
        if constexpr (selected) {
132
640
            _function->deserialize_and_merge_vec_selected(places, place_offset, scratch, columns[0],
133
640
                                                          arena, batch_size);
134
        } else {
135
            _function->deserialize_and_merge_vec(places, place_offset, scratch, columns[0], arena,
136
                                                 batch_size);
137
        }
138
640
    }
139
140
protected:
141
    AggregateFunctionPtr _function;
142
    DataTypePtr _return_type;
143
};
144
145
} // namespace doris