Coverage Report

Created: 2026-04-10 18:35

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
798
            : _remaining_rows(total_rows),
49
798
              _batch_size(batch_size),
50
798
              _inner_reader(std::move(inner_reader)) {
51
798
        set_push_down_agg_type(TPushAggOp::type::COUNT);
52
798
    }
53
54
798
    ~CountReader() override = default;
55
56
2.26k
    Status _do_get_next_block(Block* block, size_t* read_rows, bool* eof) override {
57
2.26k
        auto rows = std::min(_remaining_rows, static_cast<int64_t>(_batch_size));
58
2.26k
        _remaining_rows -= rows;
59
60
2.26k
        auto mutate_columns = block->mutate_columns();
61
2.26k
        for (auto& col : mutate_columns) {
62
2.26k
            col->resize(rows);
63
2.26k
        }
64
2.26k
        block->set_columns(std::move(mutate_columns));
65
66
2.26k
        *read_rows = rows;
67
2.26k
        *eof = (_remaining_rows == 0);
68
2.26k
        return Status::OK();
69
2.26k
    }
70
71
    /// CountReader counts rows by definition.
72
2.26k
    bool count_read_rows() override { return true; }
73
74
    /// Delegate to inner reader if available, otherwise return our total.
75
0
    int64_t get_total_rows() const override {
76
0
        return _inner_reader ? _inner_reader->get_total_rows() : _initial_total_rows();
77
0
    }
78
79
798
    Status close() override {
80
798
        if (_inner_reader) {
81
798
            return _inner_reader->close();
82
798
        }
83
0
        return Status::OK();
84
798
    }
85
86
    /// Access the inner reader for profile collection or other lifecycle needs.
87
0
    GenericReader* inner_reader() const { return _inner_reader.get(); }
88
89
protected:
90
798
    void _collect_profile_before_close() override {
91
798
        if (_inner_reader) {
92
798
            _inner_reader->collect_profile_before_close();
93
798
        }
94
798
    }
95
96
private:
97
0
    int64_t _initial_total_rows() const { return _remaining_rows; }
98
99
    int64_t _remaining_rows;
100
    size_t _batch_size;
101
    std::unique_ptr<GenericReader> _inner_reader;
102
};
103
104
} // namespace doris