Coverage Report

Created: 2026-09-16 14:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/schema.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 <stddef.h>
21
#include <stdint.h>
22
23
#include <algorithm>
24
#include <cstdint>
25
#include <memory>
26
#include <string>
27
#include <unordered_map>
28
#include <utility>
29
#include <vector>
30
31
#include "common/consts.h"
32
#include "common/status.h"
33
#include "core/column/column.h"
34
#include "exprs/aggregate/aggregate_function.h"
35
#include "gen_cpp/PlanNodes_types.h"
36
#include "io/io_common.h"
37
#include "runtime/thread_context.h"
38
#include "storage/olap_common.h"
39
#include "storage/tablet/tablet_schema.h"
40
#include "storage/utils.h"
41
42
namespace doris {
43
44
class ReadSchema;
45
class Block;
46
class TupleDescriptor;
47
using ReadSchemaSPtr = std::shared_ptr<ReadSchema>;
48
49
// Select columns by their ordinal in `columns`, preserving the requested order and duplicates.
50
// Keeping this source-layout operation outside ReadSchema prevents those ordinals from being
51
// confused with the dense ordinals of the resulting ReadSchema.
52
std::vector<TabletColumnPtr> project_columns_by_ordinal(
53
        const std::vector<TabletColumnPtr>& columns,
54
        const std::vector<ColumnId>& source_column_ordinals);
55
56
// The dense, ordered column layout consumed by one storage reader. For example, if the caller's
57
// Block is [k1, v1] and a historical delete predicate needs dropped_v2, the layout is
58
// [k1, v1, dropped_v2]: num_block_columns() is 2, num_read_columns() is 3, and every reader-side
59
// ColumnId is an ordinal in this list. TabletColumn keeps physical storage metadata, while
60
// data_type() records the expected materialized type, such as a pruned STRUCT type.
61
class ReadSchema {
62
public:
63
    using SequenceMap = std::unordered_map<ColumnId, std::vector<ColumnId>>;
64
    using RowBinlogValueColumnPairs = std::vector<std::pair<ColumnId, ColumnId>>;
65
66
    explicit ReadSchema(std::vector<TabletColumnPtr> columns);
67
68
    // Every column is initially caller-visible. Historical delete-predicate columns may be
69
    // appended later without changing num_block_columns().
70
    explicit ReadSchema(std::vector<TabletColumnPtr> columns, std::vector<DataTypePtr> read_types);
71
72
    static IColumn::MutablePtr get_predicate_column_ptr(const DataTypePtr& data_type,
73
                                                        const ReaderType reader_type);
74
75
10.1k
    const std::vector<TabletColumnPtr>& columns() const { return _read_columns; }
76
77
83.4k
    DataTypePtr data_type(size_t ordinal) const {
78
83.4k
        DCHECK_LT(ordinal, _read_types.size());
79
83.4k
        return _read_types[ordinal];
80
83.4k
    }
81
82
    // Append private historical delete-predicate columns without extending the Block prefix.
83
    void append_dropped_columns(std::vector<TabletColumn> columns);
84
85
    // Create caller-visible Blocks from the FE-slot prefix.
86
    Block create_read_block() const;
87
88
    std::string read_columns_to_string() const;
89
90
    Status init_sequence_map(const TabletSchema& tablet_schema);
91
92
0
    const SequenceMap& sequence_map() const { return _sequence_map; }
93
94
    // Initialize row-binlog relationships using dense ordinals in this ReadSchema. Special
95
    // ordinals are -1 when absent.
96
    Status init_row_binlog_column_mappings(RowBinlogValueColumnPairs value_pairs,
97
                                           int32_t tso_ordinal, int32_t lsn_ordinal,
98
                                           int32_t op_ordinal);
99
100
    // Resolve TabletSchema special columns to dense ReadSchema ordinals by unique id.
101
    Status init_row_binlog_column_mappings(RowBinlogValueColumnPairs value_pairs,
102
                                           const TabletSchema& tablet_schema);
103
104
    // Parse query mappings and validate the scan-mode requirements. nullptr means an absent
105
    // mapping field, while an empty vector is an explicitly supplied empty mapping. The tuple
106
    // slots must match this ReadSchema's caller-visible columns in order. Inputs are not retained.
107
    Status init_row_binlog_column_mappings(const std::vector<TSlotId>* current_slot_ids,
108
                                           const std::vector<TSlotId>* before_slot_ids,
109
                                           const TupleDescriptor& scan_tuple,
110
                                           const TabletSchema& tablet_schema,
111
                                           TBinlogScanType::type scan_type);
112
113
    // Return the matching before-image ordinal for a Row Binlog value column. For example, in
114
    // [v1, v2, __BEFORE__v1__, __BEFORE__v2__], 0 maps to 2 and 1 maps to 3.
115
    // Columns without a before image, including TSO/LSN/OP, map to themselves.
116
105
    ColumnId before_column_ordinal(ColumnId ordinal) const {
117
105
        DCHECK_LT(ordinal, _before_column_ordinals.size());
118
105
        return _before_column_ordinals[ordinal];
119
105
    }
120
121
26
    const RowBinlogValueColumnPairs& row_binlog_value_column_pairs() const {
122
26
        return _row_binlog_value_column_pairs;
123
26
    }
124
125
23
    bool row_binlog_value_pairs_complete() const { return _row_binlog_value_pairs_complete; }
126
127
1.23M
    const TabletColumn* column(size_t ordinal) const { return _read_columns[ordinal].get(); }
128
129
    // Total columns used inside storage, including appended storage-only columns.
130
    // Use this for per-column state and iteration over the complete ReadSchema.
131
158k
    size_t num_read_columns() const { return _read_columns.size(); }
132
133
    // Columns materialized in caller Blocks. They are the ReadSchema prefix before
134
    // appended storage-only columns; use this for Block layout and position bounds.
135
1.04M
    size_t num_block_columns() const { return _num_block_columns; }
136
137
    // Number of key columns present in the caller-visible ReadSchema. This is deliberately not the
138
    // full TabletSchema key count. Merge readers additionally require these columns to be the full,
139
    // leading storage-key prefix; direct/projected readers may contain fewer key columns.
140
1.06M
    size_t num_key_columns() const { return _num_key_columns; }
141
142
    // All special-column ordinals below address the caller-visible Block prefix and are -1 when
143
    // absent. A Row Binlog layout may be [k1, v1, __BEFORE__v1__, TSO, LSN, OP]; a snapshot layout
144
    // may instead contain COMMIT_TSO.
145
    // Logical-delete marker used by unique-key reads.
146
2.98k
    int32_t delete_sign_ordinal() const { return _delete_sign_ordinal; }
147
    // Sequence column used to choose the winning row during merge.
148
482
    int32_t sequence_ordinal() const { return _sequence_ordinal; }
149
    // Synthetic row identifier returned by rowid-producing scans.
150
7
    int32_t rowid_ordinal() const { return _rowid_ordinal; }
151
    // Rowset version synthesized for single-version reads.
152
12.9k
    int32_t version_ordinal() const { return _version_ordinal; }
153
    // Row Binlog transaction timestamp.
154
1.65k
    int32_t tso_ordinal() const { return _tso_ordinal; }
155
    // Row Binlog log-sequence number.
156
31
    int32_t lsn_ordinal() const { return _lsn_ordinal; }
157
    // Row Binlog operation kind, such as INSERT, UPDATE, or DELETE.
158
81
    int32_t op_ordinal() const { return _op_ordinal; }
159
    // Snapshot commit timestamp.
160
66
    int32_t commit_tso_ordinal() const { return _commit_tso_ordinal; }
161
162
    // -1 if no column with this unique id is present.
163
312
    int32_t ordinal_by_uid(int32_t unique_id) const {
164
312
        auto it = _uid_to_ordinal.find(unique_id);
165
312
        return it == _uid_to_ordinal.end() ? -1 : it->second;
166
312
    }
167
168
private:
169
    void _init_read_types();
170
171
1.00k
    void _init_descriptors() {
172
1.00k
        DORIS_CHECK_LE(_num_block_columns, _read_columns.size());
173
1.00k
        DORIS_CHECK_EQ(_read_columns.size(), _read_types.size());
174
1.00k
        _num_key_columns = 0;
175
1.00k
        _delete_sign_ordinal = -1;
176
1.00k
        _sequence_ordinal = -1;
177
1.00k
        _rowid_ordinal = -1;
178
1.00k
        _version_ordinal = -1;
179
1.00k
        _tso_ordinal = -1;
180
1.00k
        _lsn_ordinal = -1;
181
1.00k
        _op_ordinal = -1;
182
1.00k
        _commit_tso_ordinal = -1;
183
1.00k
        _before_column_ordinals.resize(_num_block_columns);
184
1.00k
        _uid_to_ordinal.clear();
185
6.60k
        for (uint32_t i = 0; i < _read_columns.size(); ++i) {
186
5.60k
            const auto& col = *_read_columns[i];
187
5.60k
            if (col.unique_id() >= 0) {
188
5.41k
                _uid_to_ordinal.emplace(col.unique_id(), i);
189
5.41k
            }
190
5.60k
        }
191
6.60k
        for (uint32_t i = 0; i < _num_block_columns; ++i) {
192
5.60k
            const auto& col = *_read_columns[i];
193
5.60k
            _before_column_ordinals[i] = i;
194
5.60k
            if (col.is_key()) {
195
1.34k
                ++_num_key_columns;
196
1.34k
            }
197
5.60k
            if (col.name() == DELETE_SIGN) {
198
116
                _delete_sign_ordinal = i;
199
116
            }
200
5.60k
            if (col.name() == SEQUENCE_COL) {
201
52
                _sequence_ordinal = i;
202
52
            }
203
5.60k
            if (col.name().starts_with(BeConsts::GLOBAL_ROWID_COL)) {
204
0
                _rowid_ordinal = i;
205
0
            }
206
5.60k
            if (col.name() == VERSION_COL) {
207
21
                _version_ordinal = i;
208
21
            }
209
5.60k
            if (col.name() == COMMIT_TSO_COL) {
210
5
                _commit_tso_ordinal = i;
211
5
            }
212
5.60k
        }
213
1.00k
    }
214
215
    // Example: storage has k(uid=1, INT) and
216
    // s(uid=2, STRUCT<a:INT,b:STRING,c:BIGINT>). The scan needs k and only s.a/s.c, while
217
    // a historical delete predicate `old_v = 0` needs the dropped column old_v(uid=3, INT):
218
    //   [0] _read_columns: k:INT (uid=1)
219
    //       _read_types:   INT
220
    //   [1] _read_columns: s:STRUCT<a:INT,b:STRING,c:BIGINT> (uid=2)
221
    //       _read_types:   STRUCT<a:INT,c:BIGINT>
222
    //   [2] _read_columns: old_v:INT (uid=3, dropped)
223
    //       _read_types:   INT
224
    // `_num_block_columns` is 2, so create_read_block() materializes ordinals [0, 2). Ordinal 2
225
    // is read only for delete filtering and never appears in the caller Block.
226
    std::vector<TabletColumnPtr> _read_columns;
227
    // Types aligned by ordinal with `_read_columns`.
228
    std::vector<DataTypePtr> _read_types;
229
    // Boundary between the columns materialized in Blocks and the appended dropped columns.
230
    size_t _num_block_columns = 0;
231
232
    size_t _num_key_columns = 0;
233
    int32_t _delete_sign_ordinal = -1;
234
    int32_t _sequence_ordinal = -1;
235
    int32_t _rowid_ordinal = -1;
236
    int32_t _version_ordinal = -1;
237
    int32_t _tso_ordinal = -1;
238
    int32_t _lsn_ordinal = -1;
239
    int32_t _op_ordinal = -1;
240
    int32_t _commit_tso_ordinal = -1;
241
    std::unordered_map<int32_t, int32_t> _uid_to_ordinal;
242
    SequenceMap _sequence_map;
243
    std::vector<ColumnId> _before_column_ordinals;
244
    RowBinlogValueColumnPairs _row_binlog_value_column_pairs;
245
    bool _row_binlog_value_pairs_complete = false;
246
};
247
248
} // namespace doris