Coverage Report

Created: 2026-10-13 04:29

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
29.7k
            : IAggregateFunctionDataHelper(argument_types_) {}
59
60
5.31k
    bool is_simple_count() const override { return true; }
61
162
    String get_name() const override { return "count"; }
62
63
109k
    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeInt64>(); }
64
65
1
    bool is_trivial() const override { return true; }
66
67
9.92M
    void add(AggregateDataPtr __restrict place, const IColumn**, ssize_t, Arena&) const override {
68
9.92M
        ++data(place).count;
69
9.92M
    }
70
71
    void add_batch_single_place(size_t batch_size, AggregateDataPtr place, const IColumn**,
72
56.6k
                                Arena&) const override {
73
56.6k
        data(place).count += batch_size;
74
56.6k
    }
75
76
149
    void reset(AggregateDataPtr place) const override {
77
149
        AggregateFunctionCount::data(place).count = 0;
78
149
    }
79
80
    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs,
81
108k
               Arena&) const override {
82
108k
        data(place).count += data(rhs).count;
83
108k
    }
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
120k
    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
95
120k
        assert_cast<ColumnInt64&, TypeCheckOnRelease::DISABLE>(to).get_data().push_back(
96
120k
                data(place).count);
97
120k
    }
98
99
    void serialize_to_column(const std::vector<AggregateDataPtr>& places, size_t offset,
100
4.77k
                             MutableColumnPtr& dst, const size_t num_rows) const override {
101
4.77k
        auto& col = assert_cast<ColumnFixedLengthObject&>(*dst);
102
4.77k
        DCHECK(col.item_size() == sizeof(Data))
103
0
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
104
4.77k
        col.resize(num_rows);
105
4.77k
        auto* data = col.get_data().data();
106
216k
        for (size_t i = 0; i != num_rows; ++i) {
107
211k
            *reinterpret_cast<Data*>(&data[sizeof(Data) * i]) =
108
211k
                    *reinterpret_cast<Data*>(places[i] + offset);
109
211k
        }
110
4.77k
    }
111
112
    void streaming_agg_serialize_to_column(const IColumn** columns, MutableColumnPtr& dst,
113
60
                                           const size_t num_rows, Arena&) const override {
114
60
        auto& dst_col = assert_cast<ColumnFixedLengthObject&>(*dst);
115
60
        DCHECK(dst_col.item_size() == sizeof(Data))
116
0
                << "size is not equal: " << dst_col.item_size() << " " << sizeof(Data);
117
60
        dst_col.resize(num_rows);
118
60
        auto* data = dst_col.get_data().data();
119
335
        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
60
    }
124
125
    void deserialize_from_column_row(AggregateDataPtr __restrict place, const IColumn& column,
126
12
                                     size_t row, Arena&) const override {
127
12
        DCHECK_LT(row, column.size());
128
12
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(column);
129
12
        const auto* data = reinterpret_cast<const Data*>(col.get_data().data());
130
12
        AggregateFunctionCount::data(place) = data[row];
131
12
    }
132
133
    void deserialize_and_merge_from_column_range(AggregateDataPtr __restrict place,
134
                                                 const IColumn& column, size_t begin, size_t end,
135
6.89k
                                                 Arena&) const override {
136
18.4E
        DCHECK(end <= column.size() && begin <= end)
137
18.4E
                << ", begin:" << begin << ", end:" << end << ", column.size():" << column.size();
138
6.89k
        auto& col = assert_cast<const ColumnFixedLengthObject&>(column);
139
6.89k
        auto* data = reinterpret_cast<const Data*>(col.get_data().data());
140
116k
        for (size_t i = begin; i <= end; ++i) {
141
109k
            doris::AggregateFunctionCount::data(place).count += data[i].count;
142
109k
        }
143
6.89k
    }
144
145
131
    bool needs_deserialize_and_merge_scratch() const override { return false; }
146
147
    void deserialize_and_merge_vec(const AggregateDataPtr* places, size_t offset,
148
                                   AggregateDataPtr rhs, const IColumn* column, Arena& arena,
149
3.49k
                                   const size_t num_rows) const override {
150
3.49k
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(*column);
151
3.49k
        const auto* data = col.get_data().data();
152
3.49k
        this->merge_vec(places, offset, AggregateDataPtr(data), arena, num_rows);
153
3.49k
    }
154
155
    void deserialize_and_merge_vec_selected(const AggregateDataPtr* places, size_t offset,
156
                                            AggregateDataPtr rhs, const IColumn* column,
157
21
                                            Arena& arena, const size_t num_rows) const override {
158
21
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(*column);
159
21
        const auto* data = col.get_data().data();
160
21
        this->merge_vec_selected(places, offset, AggregateDataPtr(data), arena, num_rows);
161
21
    }
162
163
    void serialize_without_key_to_column(ConstAggregateDataPtr __restrict place,
164
6.34k
                                         IColumn& to) const override {
165
6.34k
        auto& col = assert_cast<ColumnFixedLengthObject&>(to);
166
18.4E
        DCHECK(col.item_size() == sizeof(Data))
167
18.4E
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
168
6.34k
        size_t old_size = col.size();
169
6.34k
        col.resize(old_size + 1);
170
6.34k
        (reinterpret_cast<Data*>(col.get_data().data()) + old_size)->count =
171
6.34k
                AggregateFunctionCount::data(place).count;
172
6.34k
    }
173
174
12.4k
    MutableColumnPtr create_serialize_column() const override {
175
12.4k
        return ColumnFixedLengthObject::create(sizeof(Data));
176
12.4k
    }
177
178
12.5k
    DataTypePtr get_serialized_type() const override {
179
12.5k
        return std::make_shared<DataTypeFixedLengthObject>();
180
12.5k
    }
181
182
    void add_range_single_place(int64_t partition_start, int64_t partition_end, int64_t frame_start,
183
                                int64_t frame_end, AggregateDataPtr place, const IColumn** columns,
184
                                Arena& arena, UInt8* use_null_result,
185
264
                                UInt8* could_use_previous_result) const override {
186
264
        frame_start = std::max<int64_t>(frame_start, partition_start);
187
264
        frame_end = std::min<int64_t>(frame_end, partition_end);
188
264
        if (frame_start >= frame_end) {
189
19
            if (!*could_use_previous_result) {
190
2
                *use_null_result = true;
191
2
            }
192
245
        } else {
193
245
            AggregateFunctionCount::data(place).count += frame_end - frame_start;
194
245
            *use_null_result = false;
195
245
            *could_use_previous_result = true;
196
245
        }
197
264
    }
198
};
199
200
// Used for unary count(nullable_expr). SQL count(expr) counts non-NULL values.
201
class AggregateFunctionCountNotNullUnary final
202
        : public IAggregateFunctionDataHelper<AggregateFunctionCountData,
203
                                              AggregateFunctionCountNotNullUnary> {
204
public:
205
    AggregateFunctionCountNotNullUnary(const DataTypes& argument_types_)
206
14.2k
            : IAggregateFunctionDataHelper(argument_types_) {}
207
208
175
    String get_name() const override { return "count"; }
209
210
48.2k
    DataTypePtr get_return_type() const override { return std::make_shared<DataTypeInt64>(); }
211
212
8
    bool is_trivial() const override { return true; }
213
214
    void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num,
215
1.46M
             Arena&) const override {
216
1.46M
        data(place).count +=
217
1.46M
                !assert_cast<const ColumnNullable&, TypeCheckOnRelease::DISABLE>(*columns[0])
218
1.46M
                         .is_null_at(row_num);
219
1.46M
    }
220
221
    void add_batch_single_place(size_t batch_size, AggregateDataPtr place, const IColumn** columns,
222
14.9k
                                Arena&) const override {
223
14.9k
        const auto& nullable_column =
224
14.9k
                assert_cast<const ColumnNullable&, TypeCheckOnRelease::DISABLE>(*columns[0]);
225
14.9k
        const auto& null_map = nullable_column.get_null_map_data();
226
14.9k
        DCHECK_LE(batch_size, null_map.size());
227
14.9k
        if (!nullable_column.has_null(0, batch_size)) {
228
12.2k
            data(place).count += batch_size;
229
12.2k
            return;
230
12.2k
        }
231
2.71k
        data(place).count +=
232
2.71k
                simd::count_zero_num(reinterpret_cast<const int8_t*>(null_map.data()), batch_size);
233
2.71k
    }
234
235
246
    void reset(AggregateDataPtr place) const override { data(place).count = 0; }
236
237
    void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs,
238
103k
               Arena&) const override {
239
103k
        data(place).count += data(rhs).count;
240
103k
    }
241
242
318
    void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
243
318
        buf.write_var_uint(data(place).count);
244
318
    }
245
246
    void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf,
247
318
                     Arena&) const override {
248
318
        buf.read_var_uint(data(place).count);
249
318
    }
250
251
113k
    void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
252
113k
        if (is_column_nullable(to)) {
253
1
            auto& null_column = assert_cast<ColumnNullable&, TypeCheckOnRelease::DISABLE>(to);
254
1
            null_column.get_null_map_data().push_back(0);
255
1
            assert_cast<ColumnInt64&, TypeCheckOnRelease::DISABLE>(null_column.get_nested_column())
256
1
                    .get_data()
257
1
                    .push_back(data(place).count);
258
113k
        } else {
259
113k
            assert_cast<ColumnInt64&, TypeCheckOnRelease::DISABLE>(to).get_data().push_back(
260
113k
                    data(place).count);
261
113k
        }
262
113k
    }
263
264
14.0k
    void check_result_column_type(const IColumn& to) const override {
265
14.0k
        if (const auto* null_column = check_and_get_column<ColumnNullable>(to)) {
266
1
            IAggregateFunction::check_result_column_type(null_column->get_nested_column());
267
1
            return;
268
1
        }
269
14.0k
        IAggregateFunction::check_result_column_type(to);
270
14.0k
    }
271
272
    void serialize_to_column(const std::vector<AggregateDataPtr>& places, size_t offset,
273
3.53k
                             MutableColumnPtr& dst, const size_t num_rows) const override {
274
3.53k
        auto& col = assert_cast<ColumnFixedLengthObject&>(*dst);
275
3.53k
        DCHECK(col.item_size() == sizeof(Data))
276
2
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
277
3.53k
        col.resize(num_rows);
278
3.53k
        auto* data = col.get_data().data();
279
231k
        for (size_t i = 0; i != num_rows; ++i) {
280
228k
            *reinterpret_cast<Data*>(&data[sizeof(Data) * i]) =
281
228k
                    *reinterpret_cast<Data*>(places[i] + offset);
282
228k
        }
283
3.53k
    }
284
285
    void streaming_agg_serialize_to_column(const IColumn** columns, MutableColumnPtr& dst,
286
74
                                           const size_t num_rows, Arena&) const override {
287
74
        auto& col = assert_cast<ColumnFixedLengthObject&>(*dst);
288
74
        DCHECK(col.item_size() == sizeof(Data))
289
0
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
290
74
        col.resize(num_rows);
291
74
        auto& data = col.get_data();
292
74
        const ColumnNullable& input_col = assert_cast<const ColumnNullable&>(*columns[0]);
293
226
        for (size_t i = 0; i < num_rows; i++) {
294
152
            auto& state = *reinterpret_cast<Data*>(&data[sizeof(Data) * i]);
295
152
            state.count = !input_col.is_null_at(i);
296
152
        }
297
74
    }
298
299
    void deserialize_from_column_row(AggregateDataPtr __restrict place, const IColumn& column,
300
38
                                     size_t row, Arena&) const override {
301
38
        DCHECK_LT(row, column.size());
302
38
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(column);
303
38
        const auto* data = reinterpret_cast<const Data*>(col.get_data().data());
304
38
        AggregateFunctionCountNotNullUnary::data(place) = data[row];
305
38
    }
306
307
    void deserialize_and_merge_from_column_range(AggregateDataPtr __restrict place,
308
                                                 const IColumn& column, size_t begin, size_t end,
309
5.97k
                                                 Arena&) const override {
310
5.97k
        DCHECK(end <= column.size() && begin <= end)
311
3
                << ", begin:" << begin << ", end:" << end << ", column.size():" << column.size();
312
5.97k
        auto& col = assert_cast<const ColumnFixedLengthObject&>(column);
313
5.97k
        auto* data = reinterpret_cast<const Data*>(col.get_data().data());
314
86.3k
        for (size_t i = begin; i <= end; ++i) {
315
80.4k
            doris::AggregateFunctionCountNotNullUnary::data(place).count += data[i].count;
316
80.4k
        }
317
5.97k
    }
318
319
105
    bool needs_deserialize_and_merge_scratch() const override { return false; }
320
321
    void deserialize_and_merge_vec(const AggregateDataPtr* places, size_t offset,
322
                                   AggregateDataPtr rhs, const IColumn* column, Arena& arena,
323
2.57k
                                   const size_t num_rows) const override {
324
2.57k
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(*column);
325
2.57k
        const auto* data = col.get_data().data();
326
2.57k
        this->merge_vec(places, offset, AggregateDataPtr(data), arena, num_rows);
327
2.57k
    }
328
329
    void deserialize_and_merge_vec_selected(const AggregateDataPtr* places, size_t offset,
330
                                            AggregateDataPtr rhs, const IColumn* column,
331
22
                                            Arena& arena, const size_t num_rows) const override {
332
22
        const auto& col = assert_cast<const ColumnFixedLengthObject&>(*column);
333
22
        const auto* data = col.get_data().data();
334
22
        this->merge_vec_selected(places, offset, AggregateDataPtr(data), arena, num_rows);
335
22
    }
336
337
    void serialize_without_key_to_column(ConstAggregateDataPtr __restrict place,
338
5.26k
                                         IColumn& to) const override {
339
5.26k
        auto& col = assert_cast<ColumnFixedLengthObject&>(to);
340
5.26k
        DCHECK(col.item_size() == sizeof(Data))
341
0
                << "size is not equal: " << col.item_size() << " " << sizeof(Data);
342
5.26k
        size_t old_size = col.size();
343
5.26k
        col.resize(old_size + 1);
344
5.26k
        (reinterpret_cast<Data*>(col.get_data().data()) + old_size)->count =
345
5.26k
                AggregateFunctionCountNotNullUnary::data(place).count;
346
5.26k
    }
347
348
9.01k
    MutableColumnPtr create_serialize_column() const override {
349
9.01k
        return ColumnFixedLengthObject::create(sizeof(Data));
350
9.01k
    }
351
352
9.54k
    DataTypePtr get_serialized_type() const override {
353
9.54k
        return std::make_shared<DataTypeFixedLengthObject>();
354
9.54k
    }
355
356
    void add_range_single_place(int64_t partition_start, int64_t partition_end, int64_t frame_start,
357
                                int64_t frame_end, AggregateDataPtr place, const IColumn** columns,
358
                                Arena& arena, UInt8* use_null_result,
359
337
                                UInt8* could_use_previous_result) const override {
360
337
        frame_start = std::max<int64_t>(frame_start, partition_start);
361
337
        frame_end = std::min<int64_t>(frame_end, partition_end);
362
337
        if (frame_start >= frame_end) {
363
12
            if (!*could_use_previous_result) {
364
0
                *use_null_result = true;
365
0
            }
366
325
        } else {
367
325
            const auto& nullable_column =
368
325
                    assert_cast<const ColumnNullable&, TypeCheckOnRelease::DISABLE>(*columns[0]);
369
325
            size_t count = 0;
370
325
            if (nullable_column.has_null()) {
371
273
                for (int64_t i = frame_start; i < frame_end; ++i) {
372
181
                    if (!nullable_column.is_null_at(i)) {
373
114
                        ++count;
374
114
                    }
375
181
                }
376
233
            } else {
377
233
                count = frame_end - frame_start;
378
233
            }
379
325
            *use_null_result = false;
380
325
            *could_use_previous_result = true;
381
325
            AggregateFunctionCountNotNullUnary::data(place).count += count;
382
325
        }
383
337
    }
384
};
385
386
} // namespace doris