Coverage Report

Created: 2026-04-05 12:58

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