Coverage Report

Created: 2026-07-08 18:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/aggregate/aggregate_function_count.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
// This file is copied from
18
// https://github.com/ClickHouse/ClickHouse/blob/master/src/AggregateFunctions/AggregateFunctionCount.h
19
// and modified by Doris
20
21
#pragma once
22
23
#include <stddef.h>
24
25
#include <algorithm>
26
#include <boost/iterator/iterator_facade.hpp>
27
#include <memory>
28
#include <vector>
29
30
#include "core/assert_cast.h"
31
#include "core/column/column.h"
32
#include "core/column/column_fixed_length_object.h"
33
#include "core/column/column_nullable.h"
34
#include "core/column/column_vector.h"
35
#include "core/data_type/data_type.h"
36
#include "core/data_type/data_type_fixed_length_object.h"
37
#include "core/data_type/data_type_number.h"
38
#include "core/types.h"
39
#include "exprs/aggregate/aggregate_function.h"
40
#include "util/simd/bits.h"
41
42
namespace doris {
43
class Arena;
44
class BufferReadable;
45
class BufferWritable;
46
47
struct AggregateFunctionCountData {
48
    UInt64 count = 0;
49
};
50
51
/// Simply count number of calls.
52
class AggregateFunctionCount final
53
        : public IAggregateFunctionDataHelper<AggregateFunctionCountData, AggregateFunctionCount>,
54
          VarargsExpression,
55
          NotNullableAggregateFunction {
56
public:
57
    AggregateFunctionCount(const DataTypes& argument_types_)
58
24.8k
            : IAggregateFunctionDataHelper(argument_types_) {}
59
60
4.52k
    bool is_simple_count() const override { return true; }
61
159
    String get_name() const override { return "count"; }
62
63
93.1k
    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeInt64>(); }
64
65
0
    bool is_trivial() const override { return true; }
66
67
7.25M
    void add(AggregateDataPtr __restrict place, const IColumn**, ssize_t, Arena&) const override {
68
7.25M
        ++data(place).count;
69
7.25M
    }
70
71
    void add_batch_single_place(size_t batch_size, AggregateDataPtr place, const IColumn**,
72
50.7k
                                Arena&) const override {
73
50.7k
        data(place).count += batch_size;
74
50.7k
    }
75
76
124
    void reset(AggregateDataPtr place) const override {
77
124
        AggregateFunctionCount::data(place).count = 0;
78
124
    }
79
80
    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs,
81
5.36k
               Arena&) const override {
82
5.36k
        data(place).count += data(rhs).count;
83
5.36k
    }
84
85
69
    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
86
69
        buf.write_var_uint(data(place).count);
87
69
    }
88
89
    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf,
90
69
                     Arena&) const override {
91
69
        buf.read_var_uint(data(place).count);
92
69
    }
93
94
103k
    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
95
103k
        assert_cast<ColumnInt64&, TypeCheckOnRelease::DISABLE>(to).get_data().push_back(
96
103k
                data(place).count);
97
103k
    }
98
99
    void serialize_to_column(const std::vector<AggregateDataPtr>& places, size_t offset,
100
2.66k
                             MutableColumnPtr& dst, const size_t num_rows) const override {
101
2.66k
        auto& col = assert_cast<ColumnFixedLengthObject&>(*dst);
102
18.4E
        DCHECK(col.item_size() == sizeof(Data))
103
18.4E
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
104
2.66k
        col.resize(num_rows);
105
2.66k
        auto* data = col.get_data().data();
106
7.86k
        for (size_t i = 0; i != num_rows; ++i) {
107
5.20k
            *reinterpret_cast<Data*>(&data[sizeof(Data) * i]) =
108
5.20k
                    *reinterpret_cast<Data*>(places[i] + offset);
109
5.20k
        }
110
2.66k
    }
111
112
    void streaming_agg_serialize_to_column(const IColumn** columns, MutableColumnPtr& dst,
113
66
                                           const size_t num_rows, Arena&) const override {
114
66
        auto& dst_col = assert_cast<ColumnFixedLengthObject&>(*dst);
115
66
        DCHECK(dst_col.item_size() == sizeof(Data))
116
0
                << "size is not equal: " << dst_col.item_size() << " " << sizeof(Data);
117
66
        dst_col.resize(num_rows);
118
66
        auto* data = dst_col.get_data().data();
119
341
        for (size_t i = 0; i != num_rows; ++i) {
120
275
            auto& state = *reinterpret_cast<Data*>(&data[sizeof(Data) * i]);
121
275
            state.count = 1;
122
275
        }
123
66
    }
124
125
    void deserialize_and_merge_from_column_range(AggregateDataPtr __restrict place,
126
                                                 const IColumn& column, size_t begin, size_t end,
127
5.00k
                                                 Arena&) const override {
128
5.00k
        DCHECK(end <= column.size() && begin <= end)
129
0
                << ", begin:" << begin << ", end:" << end << ", column.size():" << column.size();
130
5.00k
        auto& col = assert_cast<const ColumnFixedLengthObject&>(column);
131
5.00k
        auto* data = reinterpret_cast<const Data*>(col.get_data().data());
132
10.0k
        for (size_t i = begin; i <= end; ++i) {
133
5.02k
            doris::AggregateFunctionCount::data(place).count += data[i].count;
134
5.02k
        }
135
5.00k
    }
136
137
    void deserialize_and_merge_vec(const AggregateDataPtr* places, size_t offset,
138
                                   AggregateDataPtr rhs, const IColumn* column, Arena& arena,
139
2.21k
                                   const size_t num_rows) const override {
140
2.21k
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(*column);
141
2.21k
        const auto* data = col.get_data().data();
142
2.21k
        this->merge_vec(places, offset, AggregateDataPtr(data), arena, num_rows);
143
2.21k
    }
144
145
    void deserialize_and_merge_vec_selected(const AggregateDataPtr* places, size_t offset,
146
                                            AggregateDataPtr rhs, const IColumn* column,
147
1
                                            Arena& arena, const size_t num_rows) const override {
148
1
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(*column);
149
1
        const auto* data = col.get_data().data();
150
1
        this->merge_vec_selected(places, offset, AggregateDataPtr(data), arena, num_rows);
151
1
    }
152
153
    void serialize_without_key_to_column(ConstAggregateDataPtr __restrict place,
154
4.71k
                                         IColumn& to) const override {
155
4.71k
        auto& col = assert_cast<ColumnFixedLengthObject&>(to);
156
4.71k
        DCHECK(col.item_size() == sizeof(Data))
157
6
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
158
4.71k
        size_t old_size = col.size();
159
4.71k
        col.resize(old_size + 1);
160
4.71k
        (reinterpret_cast<Data*>(col.get_data().data()) + old_size)->count =
161
4.71k
                AggregateFunctionCount::data(place).count;
162
4.71k
    }
163
164
8.60k
    MutableColumnPtr create_serialize_column() const override {
165
8.60k
        return ColumnFixedLengthObject::create(sizeof(Data));
166
8.60k
    }
167
168
8.66k
    DataTypePtr get_serialized_type() const override {
169
8.66k
        return std::make_shared<DataTypeFixedLengthObject>();
170
8.66k
    }
171
172
    void add_range_single_place(int64_t partition_start, int64_t partition_end, int64_t frame_start,
173
                                int64_t frame_end, AggregateDataPtr place, const IColumn** columns,
174
                                Arena& arena, UInt8* use_null_result,
175
240
                                UInt8* could_use_previous_result) const override {
176
240
        frame_start = std::max<int64_t>(frame_start, partition_start);
177
240
        frame_end = std::min<int64_t>(frame_end, partition_end);
178
240
        if (frame_start >= frame_end) {
179
12
            if (!*could_use_previous_result) {
180
0
                *use_null_result = true;
181
0
            }
182
228
        } else {
183
228
            AggregateFunctionCount::data(place).count += frame_end - frame_start;
184
228
            *use_null_result = false;
185
228
            *could_use_previous_result = true;
186
228
        }
187
240
    }
188
};
189
190
// Used for unary count(nullable_expr). SQL count(expr) counts non-NULL values.
191
class AggregateFunctionCountNotNullUnary final
192
        : public IAggregateFunctionDataHelper<AggregateFunctionCountData,
193
                                              AggregateFunctionCountNotNullUnary> {
194
public:
195
    AggregateFunctionCountNotNullUnary(const DataTypes& argument_types_)
196
10.2k
            : IAggregateFunctionDataHelper(argument_types_) {}
197
198
188
    String get_name() const override { return "count"; }
199
200
37.1k
    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeInt64>(); }
201
202
0
    bool is_trivial() const override { return true; }
203
204
    void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num,
205
1.19M
             Arena&) const override {
206
1.19M
        data(place).count +=
207
1.19M
                !assert_cast<const ColumnNullable&, TypeCheckOnRelease::DISABLE>(*columns[0])
208
1.19M
                         .is_null_at(row_num);
209
1.19M
    }
210
211
    void add_batch_single_place(size_t batch_size, AggregateDataPtr place, const IColumn** columns,
212
12.4k
                                Arena&) const override {
213
12.4k
        const auto& nullable_column =
214
12.4k
                assert_cast<const ColumnNullable&, TypeCheckOnRelease::DISABLE>(*columns[0]);
215
12.4k
        const auto& null_map = nullable_column.get_null_map_data();
216
12.4k
        DCHECK_LE(batch_size, null_map.size());
217
12.4k
        if (!nullable_column.has_null(0, batch_size)) {
218
10.0k
            data(place).count += batch_size;
219
10.0k
            return;
220
10.0k
        }
221
2.31k
        data(place).count +=
222
2.31k
                simd::count_zero_num(reinterpret_cast<const int8_t*>(null_map.data()), batch_size);
223
2.31k
    }
224
225
224
    void reset(AggregateDataPtr place) const override { data(place).count = 0; }
226
227
    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs,
228
27.6k
               Arena&) const override {
229
27.6k
        data(place).count += data(rhs).count;
230
27.6k
    }
231
232
11
    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
233
11
        buf.write_var_uint(data(place).count);
234
11
    }
235
236
    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf,
237
11
                     Arena&) const override {
238
11
        buf.read_var_uint(data(place).count);
239
11
    }
240
241
95.9k
    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
242
95.9k
        if (is_column_nullable(to)) {
243
1
            auto& null_column = assert_cast<ColumnNullable&, TypeCheckOnRelease::DISABLE>(to);
244
1
            null_column.get_null_map_data().push_back(0);
245
1
            assert_cast<ColumnInt64&, TypeCheckOnRelease::DISABLE>(null_column.get_nested_column())
246
1
                    .get_data()
247
1
                    .push_back(data(place).count);
248
95.9k
        } else {
249
95.9k
            assert_cast<ColumnInt64&, TypeCheckOnRelease::DISABLE>(to).get_data().push_back(
250
95.9k
                    data(place).count);
251
95.9k
        }
252
95.9k
    }
253
254
10.9k
    void check_result_column_type(const IColumn& to) const override {
255
10.9k
        if (const auto* null_column = check_and_get_column<ColumnNullable>(to)) {
256
1
            IAggregateFunction::check_result_column_type(null_column->get_nested_column());
257
1
            return;
258
1
        }
259
10.9k
        IAggregateFunction::check_result_column_type(to);
260
10.9k
    }
261
262
    void serialize_to_column(const std::vector<AggregateDataPtr>& places, size_t offset,
263
1.66k
                             MutableColumnPtr& dst, const size_t num_rows) const override {
264
1.66k
        auto& col = assert_cast<ColumnFixedLengthObject&>(*dst);
265
1.66k
        DCHECK(col.item_size() == sizeof(Data))
266
1
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
267
1.66k
        col.resize(num_rows);
268
1.66k
        auto* data = col.get_data().data();
269
29.3k
        for (size_t i = 0; i != num_rows; ++i) {
270
27.7k
            *reinterpret_cast<Data*>(&data[sizeof(Data) * i]) =
271
27.7k
                    *reinterpret_cast<Data*>(places[i] + offset);
272
27.7k
        }
273
1.66k
    }
274
275
    void streaming_agg_serialize_to_column(const IColumn** columns, MutableColumnPtr& dst,
276
2
                                           const size_t num_rows, Arena&) const override {
277
2
        auto& col = assert_cast<ColumnFixedLengthObject&>(*dst);
278
2
        DCHECK(col.item_size() == sizeof(Data))
279
0
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
280
2
        col.resize(num_rows);
281
2
        auto& data = col.get_data();
282
2
        const ColumnNullable& input_col = assert_cast<const ColumnNullable&>(*columns[0]);
283
11
        for (size_t i = 0; i < num_rows; i++) {
284
9
            auto& state = *reinterpret_cast<Data*>(&data[sizeof(Data) * i]);
285
9
            state.count = !input_col.is_null_at(i);
286
9
        }
287
2
    }
288
289
    void deserialize_and_merge_from_column_range(AggregateDataPtr __restrict place,
290
                                                 const IColumn& column, size_t begin, size_t end,
291
3.70k
                                                 Arena&) const override {
292
3.70k
        DCHECK(end <= column.size() && begin <= end)
293
0
                << ", begin:" << begin << ", end:" << end << ", column.size():" << column.size();
294
3.70k
        auto& col = assert_cast<const ColumnFixedLengthObject&>(column);
295
3.70k
        auto* data = reinterpret_cast<const Data*>(col.get_data().data());
296
7.42k
        for (size_t i = begin; i <= end; ++i) {
297
3.71k
            doris::AggregateFunctionCountNotNullUnary::data(place).count += data[i].count;
298
3.71k
        }
299
3.70k
    }
300
301
    void deserialize_and_merge_vec(const AggregateDataPtr* places, size_t offset,
302
                                   AggregateDataPtr rhs, const IColumn* column, Arena& arena,
303
1.38k
                                   const size_t num_rows) const override {
304
1.38k
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(*column);
305
1.38k
        const auto* data = col.get_data().data();
306
1.38k
        this->merge_vec(places, offset, AggregateDataPtr(data), arena, num_rows);
307
1.38k
    }
308
309
    void deserialize_and_merge_vec_selected(const AggregateDataPtr* places, size_t offset,
310
                                            AggregateDataPtr rhs, const IColumn* column,
311
2
                                            Arena& arena, const size_t num_rows) const override {
312
2
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(*column);
313
2
        const auto* data = col.get_data().data();
314
2
        this->merge_vec_selected(places, offset, AggregateDataPtr(data), arena, num_rows);
315
2
    }
316
317
    void serialize_without_key_to_column(ConstAggregateDataPtr __restrict place,
318
3.69k
                                         IColumn& to) const override {
319
3.69k
        auto& col = assert_cast<ColumnFixedLengthObject&>(to);
320
3.69k
        DCHECK(col.item_size() == sizeof(Data))
321
5
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
322
3.69k
        col.resize(1);
323
3.69k
        reinterpret_cast<Data*>(col.get_data().data())->count =
324
3.69k
                AggregateFunctionCountNotNullUnary::data(place).count;
325
3.69k
    }
326
327
5.35k
    MutableColumnPtr create_serialize_column() const override {
328
5.35k
        return ColumnFixedLengthObject::create(sizeof(Data));
329
5.35k
    }
330
331
5.35k
    DataTypePtr get_serialized_type() const override {
332
5.35k
        return std::make_shared<DataTypeFixedLengthObject>();
333
5.35k
    }
334
335
    void add_range_single_place(int64_t partition_start, int64_t partition_end, int64_t frame_start,
336
                                int64_t frame_end, AggregateDataPtr place, const IColumn** columns,
337
                                Arena& arena, UInt8* use_null_result,
338
330
                                UInt8* could_use_previous_result) const override {
339
330
        frame_start = std::max<int64_t>(frame_start, partition_start);
340
330
        frame_end = std::min<int64_t>(frame_end, partition_end);
341
330
        if (frame_start >= frame_end) {
342
14
            if (!*could_use_previous_result) {
343
0
                *use_null_result = true;
344
0
            }
345
316
        } else {
346
316
            const auto& nullable_column =
347
316
                    assert_cast<const ColumnNullable&, TypeCheckOnRelease::DISABLE>(*columns[0]);
348
316
            size_t count = 0;
349
316
            if (nullable_column.has_null()) {
350
365
                for (int64_t i = frame_start; i < frame_end; ++i) {
351
218
                    if (!nullable_column.is_null_at(i)) {
352
184
                        ++count;
353
184
                    }
354
218
                }
355
169
            } else {
356
169
                count = frame_end - frame_start;
357
169
            }
358
316
            *use_null_result = false;
359
316
            *could_use_previous_result = true;
360
316
            AggregateFunctionCountNotNullUnary::data(place).count += count;
361
316
        }
362
330
    }
363
};
364
365
} // namespace doris