Coverage Report

Created: 2026-04-20 15:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/format/count_reader.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 <cstddef>
21
#include <cstdint>
22
#include <memory>
23
24
#include "common/status.h"
25
#include "core/block/block.h"
26
#include "format/generic_reader.h"
27
28
namespace doris {
29
30
/// A lightweight reader that emits row counts without reading any actual data.
31
/// Used as a decorator to replace the real reader when COUNT(*) push down is active.
32
///
33
/// Instead of duplicating the COUNT short-circuit logic in every format reader
34
/// (ORC, Parquet, etc.), FileScanner creates a CountReader after the real reader
35
/// is initialized and the total row count is known. The CountReader then serves
36
/// all subsequent get_next_block calls by simply resizing columns.
37
///
38
/// This cleanly separates the "how many rows" concern from the actual data reading,
39
/// eliminating duplicated COUNT blocks across format readers.
40
class CountReader : public GenericReader {
41
public:
42
    /// @param total_rows   Total number of rows to emit (post-filter).
43
    /// @param batch_size   Maximum rows per batch.
44
    /// @param inner_reader The original reader, kept alive for profile collection
45
    ///                     and lifecycle management. Ownership is transferred.
46
    CountReader(int64_t total_rows, size_t batch_size,
47
                std::unique_ptr<GenericReader> inner_reader = nullptr)
48
11
            : _total_rows(total_rows),
49
11
              _remaining_rows(total_rows),
50
11
              _batch_size(batch_size),
51
11
              _inner_reader(std::move(inner_reader)) {
52
11
        set_push_down_agg_type(TPushAggOp::type::COUNT);
53
11
    }
54
55
11
    ~CountReader() override = default;
56
57
15
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
58
15
        auto rows = std::min(_remaining_rows, static_cast<int64_t>(_batch_size));
59
15
        _remaining_rows -= rows;
60
61
15
        auto mutate_columns = block->mutate_columns();
62
17
        for (auto& col : mutate_columns) {
63
17
            col->resize(rows);
64
17
        }
65
15
        block->set_columns(std::move(mutate_columns));
66
67
15
        *read_rows = rows;
68
15
        *eof = (_remaining_rows == 0);
69
15
        return Status::OK();
70
15
    }
71
72
    /// CountReader counts rows by definition.
73
1
    bool count_read_rows() override { return true; }
74
75
    /// Delegate to inner reader if available, otherwise return our total.
76
4
    int64_t get_total_rows() const override {
77
4
        return _inner_reader ? _inner_reader->get_total_rows() : _initial_total_rows();
78
4
    }
79
80
1
    Status close() override {
81
1
        if (_inner_reader) {
82
0
            return _inner_reader->close();
83
0
        }
84
1
        return Status::OK();
85
1
    }
86
87
    /// Access the inner reader for profile collection or other lifecycle needs.
88
1
    GenericReader* inner_reader() const { return _inner_reader.get(); }
89
90
protected:
91
0
    void _collect_profile_before_close() override {
92
0
        if (_inner_reader) {
93
0
            _inner_reader->collect_profile_before_close();
94
0
        }
95
0
    }
96
97
private:
98
3
    int64_t _initial_total_rows() const { return _total_rows; }
99
100
    const int64_t _total_rows;
101
    int64_t _remaining_rows;
102
    size_t _batch_size;
103
    std::unique_ptr<GenericReader> _inner_reader;
104
};
105
106
} // namespace doris