Coverage Report

Created: 2026-11-03 00:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/tablet/tablet_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 <gen_cpp/AgentService_types.h>
21
#include <gen_cpp/Types_types.h>
22
#include <gen_cpp/olap_common.pb.h>
23
#include <gen_cpp/olap_file.pb.h>
24
#include <gen_cpp/segment_v2.pb.h>
25
#include <parallel_hashmap/phmap.h>
26
27
#include <algorithm>
28
#include <cstdint>
29
#include <map>
30
#include <memory>
31
#include <string>
32
#include <unordered_map>
33
#include <unordered_set>
34
#include <utility>
35
#include <vector>
36
37
#include "common/consts.h"
38
#include "common/status.h"
39
#include "core/data_type/define_primitive_type.h"
40
#include "core/string_ref.h"
41
#include "core/types.h"
42
#include "exec/common/string_utils/string_utils.h"
43
#include "exprs/aggregate/aggregate_function.h"
44
#include "runtime/descriptors.h"
45
#include "runtime/memory/lru_cache_policy.h"
46
#include "storage/index/inverted/analysis/inverted_index_parser.h"
47
#include "storage/metadata_adder.h"
48
#include "storage/olap_common.h"
49
#include "storage/segment/options.h"
50
#include "util/debug_points.h"
51
#include "util/json/path_in_data.h"
52
#include "util/string_parser.hpp"
53
#include "util/string_util.h"
54
55
namespace doris {
56
class Block;
57
class PathInData;
58
class IDataType;
59
60
struct OlapTableIndexSchema;
61
class TColumn;
62
class TOlapTableIndex;
63
class TabletColumn;
64
65
using TabletColumnPtr = std::shared_ptr<TabletColumn>;
66
67
class TabletColumn : public MetadataAdder<TabletColumn> {
68
public:
69
    struct VariantParams {
70
        int32_t max_subcolumns_count = 0;
71
        bool enable_typed_paths_to_sparse = false;
72
        int32_t max_sparse_column_statistics_size =
73
                BeConsts::DEFAULT_VARIANT_MAX_SPARSE_COLUMN_STATS_SIZE;
74
        // default to 0, no shard
75
        int32_t sparse_hash_shard_count = 0;
76
77
        bool enable_doc_mode = false;
78
        int64_t doc_materialization_min_rows = 0;
79
        int32_t doc_hash_shard_count = 64;
80
81
        bool enable_nested_group = false;
82
        bool escape_dots_in_keys = false;
83
    };
84
85
    TabletColumn();
86
    TabletColumn(const ColumnPB& column);
87
    TabletColumn(const TColumn& column);
88
    TabletColumn(FieldAggregationMethod agg, FieldType type);
89
    TabletColumn(FieldAggregationMethod agg, FieldType filed_type, bool is_nullable);
90
    TabletColumn(FieldAggregationMethod agg, FieldType filed_type, bool is_nullable,
91
                 int32_t unique_id, size_t length);
92
93
#ifdef BE_TEST
94
75.2k
    virtual ~TabletColumn() = default;
95
#endif
96
97
    void init_from_pb(const ColumnPB& column);
98
    void init_from_thrift(const TColumn& column);
99
    void to_schema_pb(ColumnPB* column) const;
100
101
266k
    int32_t unique_id() const { return _unique_id; }
102
2.67k
    void set_unique_id(int32_t id) { _unique_id = id; }
103
295k
    const std::string& name() const { return _col_name; }
104
23.8k
    const std::string& name_lower_case() const { return _col_name_lower_case; }
105
9.10k
    void set_name(std::string col_name) {
106
9.10k
        _col_name = col_name;
107
9.10k
        _col_name_lower_case = to_lower(_col_name);
108
9.10k
    }
109
6.93M
    MOCK_FUNCTION FieldType type() const { return _type; }
110
8.82k
    void set_type(FieldType type) { _type = type; }
111
48.1k
    bool is_key() const { return _is_key; }
112
926k
    bool is_nullable() const { return _is_nullable; }
113
1
    bool is_auto_increment() const { return _is_auto_increment; }
114
0
    bool is_seqeunce_col() const { return _col_name == SEQUENCE_COL; }
115
41
    bool is_on_update_current_timestamp() const { return _is_on_update_current_timestamp; }
116
111k
    bool is_variant_type() const { return _type == FieldType::OLAP_FIELD_TYPE_VARIANT; }
117
23.0k
    bool is_bf_column() const { return _is_bf_column; }
118
59.6k
    bool is_array_type() const { return _type == FieldType::OLAP_FIELD_TYPE_ARRAY; }
119
10.6k
    bool is_agg_state_type() const { return _type == FieldType::OLAP_FIELD_TYPE_AGG_STATE; }
120
0
    bool is_jsonb_type() const { return _type == FieldType::OLAP_FIELD_TYPE_JSONB; }
121
177
    bool is_length_variable_type() const {
122
177
        return _type == FieldType::OLAP_FIELD_TYPE_CHAR ||
123
177
               _type == FieldType::OLAP_FIELD_TYPE_VARCHAR ||
124
177
               _type == FieldType::OLAP_FIELD_TYPE_STRING ||
125
177
               _type == FieldType::OLAP_FIELD_TYPE_HLL ||
126
177
               _type == FieldType::OLAP_FIELD_TYPE_BITMAP ||
127
177
               _type == FieldType::OLAP_FIELD_TYPE_QUANTILE_STATE ||
128
177
               _type == FieldType::OLAP_FIELD_TYPE_AGG_STATE;
129
177
    }
130
1.37k
    bool has_default_value() const { return _has_default_value; }
131
660
    std::string default_value() const { return _default_value; }
132
215
    bool has_default_value_expr() const { return _has_default_value_expr; }
133
3
    const std::string& default_value_expr() const { return _default_value_expr; }
134
788k
    int32_t length() const { return _length; }
135
3.91k
    void set_length(int32_t length) { _length = length; }
136
859
    void set_default_value(const std::string& default_value) {
137
859
        _default_value = default_value;
138
859
        _has_default_value = true;
139
859
    }
140
1
    void set_default_value_expr(const std::string& default_value_expr) {
141
1
        _default_value_expr = default_value_expr;
142
1
        _has_default_value_expr = true;
143
1
    }
144
6.45k
    int32_t index_length() const { return _index_length; }
145
3.38k
    void set_index_length(int32_t index_length) { _index_length = index_length; }
146
2.51k
    void set_is_key(bool is_key) { _is_key = is_key; }
147
4.57k
    void set_is_nullable(bool is_nullable) { _is_nullable = is_nullable; }
148
0
    void set_is_auto_increment(bool is_auto_increment) { _is_auto_increment = is_auto_increment; }
149
0
    void set_is_on_update_current_timestamp(bool is_on_update_current_timestamp) {
150
0
        _is_on_update_current_timestamp = is_on_update_current_timestamp;
151
0
    }
152
    void set_path_info(const PathInData& path);
153
2.79k
    FieldAggregationMethod aggregation() const { return _aggregation; }
154
    AggregateFunctionPtr get_aggregate_function_union(DataTypePtr type,
155
                                                      int current_be_exec_version) const;
156
    AggregateFunctionPtr get_aggregate_function(std::string suffix,
157
                                                int current_be_exec_version) const;
158
    AggregateFunctionPtr get_aggregate_function(std::string suffix, int current_be_exec_version,
159
                                                DataTypePtr runtime_type) const;
160
776k
    int precision() const { return _precision; }
161
777k
    int frac() const { return _frac; }
162
514
    inline bool visible() const { return _visible; }
163
    bool has_char_type() const;
164
165
2.83k
    void set_aggregation_method(FieldAggregationMethod agg) {
166
2.83k
        _aggregation = agg;
167
2.83k
        _aggregation_name = get_string_by_aggregation_type(agg);
168
2.83k
    }
169
170
    /**
171
     * Add a sub column.
172
     */
173
    void add_sub_column(TabletColumn& sub_column);
174
175
40.5k
    uint32_t get_subtype_count() const { return _sub_column_count; }
176
6.86k
    MOCK_FUNCTION const TabletColumn& get_sub_column(uint64_t i) const { return *_sub_columns[i]; }
177
8.16k
    const std::vector<TabletColumnPtr>& get_sub_columns() const { return _sub_columns; }
178
179
    friend bool operator==(const TabletColumn& a, const TabletColumn& b);
180
    friend bool operator!=(const TabletColumn& a, const TabletColumn& b);
181
182
    static std::string get_string_by_field_type(FieldType type);
183
    static std::string get_string_by_aggregation_type(FieldAggregationMethod aggregation_type);
184
    static FieldType get_field_type_by_string(const std::string& str);
185
    static FieldAggregationMethod get_aggregation_type_by_string(const std::string& str);
186
    static uint32_t get_field_length_by_type(TPrimitiveType::type type, uint32_t string_length);
187
    bool is_row_store_column() const;
188
19.2k
    std::string get_aggregation_name() const { return _aggregation_name; }
189
19.2k
    bool get_result_is_nullable() const { return _result_is_nullable; }
190
19.2k
    int get_be_exec_version() const { return _be_exec_version; }
191
97.5k
    bool has_path_info() const { return _column_path != nullptr && !_column_path->empty(); }
192
24.5k
    const PathInDataPtr& path_info_ptr() const { return _column_path; }
193
    // If it is an extracted column from variant column
194
180k
    bool is_extracted_column() const {
195
180k
        return _column_path != nullptr && !_column_path->empty() && _parent_col_unique_id >= 0;
196
180k
    };
197
29.0k
    std::string suffix_path() const {
198
29.0k
        return is_extracted_column() ? _column_path->get_path() : "";
199
29.0k
    }
200
195
    bool is_nested_subcolumn() const {
201
195
        return _column_path != nullptr && _column_path->has_nested_part();
202
195
    }
203
11.8k
    int32_t parent_unique_id() const { return _parent_col_unique_id; }
204
3.33k
    void set_parent_unique_id(int32_t col_unique_id) { _parent_col_unique_id = col_unique_id; }
205
1.47k
    void set_is_bf_column(bool is_bf_column) { _is_bf_column = is_bf_column; }
206
    std::shared_ptr<const IDataType> get_vec_type() const;
207
    // Returns schema metadata suitable for diagnostics. The default value itself is omitted.
208
    std::string debug_string() const;
209
210
1.84k
    Status check_valid() const {
211
1.84k
        if (type() != FieldType::OLAP_FIELD_TYPE_ARRAY &&
212
1.84k
            type() != FieldType::OLAP_FIELD_TYPE_STRUCT &&
213
1.84k
            type() != FieldType::OLAP_FIELD_TYPE_MAP) {
214
1.81k
            return Status::OK();
215
1.81k
        }
216
36
        if (is_bf_column()) {
217
0
            return Status::NotSupported("Do not support bloom filter index, type={}",
218
0
                                        get_string_by_field_type(type()));
219
0
        }
220
36
        return Status::OK();
221
36
    }
222
223
126
    void set_precision(int precision) {
224
126
        _precision = precision;
225
126
        _is_decimal = true;
226
126
    }
227
228
479
    void set_frac(int frac) { _frac = frac; }
229
230
0
    const VariantParams& variant_params() const { return _variant; }
231
0
    VariantParams* mutable_variant_params() { return &_variant; }
232
233
3.78k
    int32_t variant_max_subcolumns_count() const { return _variant.max_subcolumns_count; }
234
235
125
    void set_variant_max_subcolumns_count(int32_t variant_max_subcolumns_count) {
236
125
        _variant.max_subcolumns_count = variant_max_subcolumns_count;
237
125
    }
238
239
632
    PatternTypePB pattern_type() const { return _pattern_type; }
240
241
1.09k
    bool variant_enable_typed_paths_to_sparse() const {
242
1.09k
        return _variant.enable_typed_paths_to_sparse;
243
1.09k
    }
244
245
21.6k
    int32_t variant_max_sparse_column_statistics_size() const {
246
21.6k
        return _variant.max_sparse_column_statistics_size;
247
21.6k
    }
248
249
1.20k
    int32_t variant_sparse_hash_shard_count() const { return _variant.sparse_hash_shard_count; }
250
251
4.45k
    bool variant_enable_doc_mode() const { return _variant.enable_doc_mode; }
252
253
560
    int64_t variant_doc_materialization_min_rows() const {
254
560
        return _variant.doc_materialization_min_rows;
255
560
    }
256
257
577
    int32_t variant_doc_hash_shard_count() const { return _variant.doc_hash_shard_count; }
258
259
24
    void set_variant_doc_materialization_min_rows(int64_t variant_doc_materialization_min_rows) {
260
24
        _variant.doc_materialization_min_rows = variant_doc_materialization_min_rows;
261
24
    }
262
263
24
    void set_variant_doc_hash_shard_count(int32_t variant_doc_hash_shard_count) {
264
24
        _variant.doc_hash_shard_count = variant_doc_hash_shard_count;
265
24
    }
266
267
    void set_variant_max_sparse_column_statistics_size(
268
26
            int32_t variant_max_sparse_column_statistics_size) {
269
26
        _variant.max_sparse_column_statistics_size = variant_max_sparse_column_statistics_size;
270
26
    }
271
272
26
    void set_variant_sparse_hash_shard_count(int32_t variant_sparse_hash_shard_count) {
273
26
        _variant.sparse_hash_shard_count = variant_sparse_hash_shard_count;
274
26
    }
275
276
72
    void set_variant_enable_doc_mode(bool variant_enable_doc_mode) {
277
72
        _variant.enable_doc_mode = variant_enable_doc_mode;
278
72
    }
279
280
1
    void set_variant_enable_typed_paths_to_sparse(bool variant_enable_typed_paths_to_sparse) {
281
1
        _variant.enable_typed_paths_to_sparse = variant_enable_typed_paths_to_sparse;
282
1
    }
283
284
41.2k
    bool variant_escape_dots_in_keys() const { return _variant.escape_dots_in_keys; }
285
2.07k
    void set_variant_escape_dots_in_keys(bool value) { _variant.escape_dots_in_keys = value; }
286
287
6.29k
    bool variant_enable_nested_group() const { return _variant.enable_nested_group; }
288
289
25
    void set_variant_enable_nested_group(bool val) { _variant.enable_nested_group = val; }
290
291
352
    bool is_decimal() const { return _is_decimal; }
292
293
private:
294
    int32_t _unique_id = -1;
295
    std::string _col_name;
296
    std::string _col_name_lower_case;
297
    // the field _type will change from TPrimitiveType
298
    // to string by 'EnumToString(TPrimitiveType, tcolumn.column_type.type, data_type);' (reference: TabletMeta::init_column_from_tcolumn)
299
    // to FieldType by 'TabletColumn::get_field_type_by_string' (reference: TabletColumn::init_from_pb).
300
    // And the _type in columnPB is string and it changed from FieldType by 'get_string_by_field_type' (reference: TabletColumn::to_schema_pb).
301
    FieldType _type;
302
    bool _is_key = false;
303
    FieldAggregationMethod _aggregation;
304
    std::string _aggregation_name;
305
    bool _is_nullable = false;
306
    bool _is_auto_increment = false;
307
    bool _is_on_update_current_timestamp {false};
308
309
    bool _has_default_value = false;
310
    std::string _default_value;
311
    bool _has_default_value_expr = false;
312
    std::string _default_value_expr;
313
314
    bool _is_decimal = false;
315
    int32_t _precision = -1;
316
    int32_t _frac = -1;
317
318
    int32_t _length = -1;
319
    int32_t _index_length = -1;
320
321
    bool _is_bf_column = false;
322
323
    bool _visible = true;
324
325
    std::vector<TabletColumnPtr> _sub_columns;
326
    uint32_t _sub_column_count = 0;
327
328
    bool _result_is_nullable = false;
329
    int _be_exec_version = -1;
330
331
    // The extracted sub-columns from "variant" contain the following information:
332
    int32_t _parent_col_unique_id = -1; // "variant" -> col_unique_id
333
    PathInDataPtr _column_path;         // the path of the sub-columns themselves
334
    PatternTypePB _pattern_type = PatternTypePB::MATCH_NAME_GLOB;
335
336
    VariantParams _variant;
337
};
338
339
bool operator==(const TabletColumn& a, const TabletColumn& b);
340
bool operator!=(const TabletColumn& a, const TabletColumn& b);
341
342
class TabletIndex : public MetadataAdder<TabletIndex> {
343
public:
344
8.99k
    TabletIndex() = default;
345
    void init_from_thrift(const TOlapTableIndex& index, const TabletSchema& tablet_schema);
346
    void init_from_thrift(const TOlapTableIndex& index, const std::vector<int32_t>& column_uids);
347
    void init_from_pb(const TabletIndexPB& index);
348
    void to_schema_pb(TabletIndexPB* index) const;
349
350
28.2k
    int64_t index_id() const { return _index_id; }
351
43
    const std::string& index_name() const { return _index_name; }
352
16.7k
    MOCK_FUNCTION IndexType index_type() const { return _index_type; }
353
11.7k
    const std::vector<int32_t>& col_unique_ids() const { return _col_unique_ids; }
354
38.1k
    MOCK_FUNCTION const std::map<std::string, std::string>& properties() const {
355
38.1k
        return _properties;
356
38.1k
    }
357
17
    int32_t get_gram_size() const {
358
17
        if (_properties.contains("gram_size")) {
359
17
            return std::stoi(_properties.at("gram_size"));
360
17
        }
361
362
0
        return 0;
363
17
    }
364
17
    int32_t get_gram_bf_size() const {
365
17
        if (_properties.contains("bf_size")) {
366
17
            return std::stoi(_properties.at("bf_size"));
367
17
        }
368
369
0
        return 0;
370
17
    }
371
372
24.9k
    const std::string& get_index_suffix() const { return _escaped_index_suffix_path; }
373
374
    void set_escaped_escaped_index_suffix_path(const std::string& name,
375
                                               bool escape_percent = false);
376
377
2.74k
    bool is_inverted_index() const { return _index_type == IndexType::INVERTED; }
378
379
47
    bool is_ann_index() const { return _index_type == IndexType::ANN; }
380
381
24
    void remove_parser_and_analyzer() {
382
24
        _properties.erase(INVERTED_INDEX_PARSER_KEY);
383
24
        _properties.erase(INVERTED_INDEX_PARSER_KEY_ALIAS);
384
24
        _properties.erase(INVERTED_INDEX_ANALYZER_NAME_KEY);
385
24
        _properties.erase(INVERTED_INDEX_NORMALIZER_NAME_KEY);
386
24
    }
387
388
9.85k
    std::string field_pattern() const {
389
9.85k
        if (_properties.contains("field_pattern")) {
390
353
            return _properties.at("field_pattern");
391
353
        }
392
9.50k
        return "";
393
9.85k
    }
394
395
9
    bool is_same_except_id(const TabletIndex* other) const {
396
9
        return _escaped_index_suffix_path == other->_escaped_index_suffix_path &&
397
9
               _index_name == other->_index_name && _index_type == other->_index_type &&
398
9
               _col_unique_ids == other->_col_unique_ids && _properties == other->_properties;
399
9
    }
400
401
private:
402
    int64_t _index_id = -1;
403
    // Identify the different index with the same _index_id
404
    std::string _escaped_index_suffix_path;
405
    std::string _index_name;
406
    IndexType _index_type;
407
    std::vector<int32_t> _col_unique_ids;
408
    std::map<std::string, std::string> _properties;
409
};
410
411
using TabletIndexPtr = std::shared_ptr<TabletIndex>;
412
using TabletIndexes = std::vector<std::shared_ptr<TabletIndex>>;
413
using PathSet = phmap::flat_hash_set<std::string>;
414
415
class TabletSchema : public MetadataAdder<TabletSchema> {
416
public:
417
    enum class ColumnType { NORMAL = 0, VARIANT = 1 };
418
    // TODO(yingchun): better to make constructor as private to avoid
419
    // manually init members incorrectly, and define a new function like
420
    // void create_from_pb(const TabletSchemaPB& schema, TabletSchema* tablet_schema).
421
    TabletSchema();
422
    ~TabletSchema() override;
423
424
    // Init from pb
425
    // ignore_extracted_columns: ignore the extracted columns from variant column
426
    // reuse_cached_column: reuse the cached column in the schema if they are the same, to reduce memory usage
427
    void init_from_pb(const TabletSchemaPB& schema, bool ignore_extracted_columns = false,
428
                      bool reuse_cached_column = false);
429
    // Notice: Use deterministic way to serialize protobuf,
430
    // since serialize Map in protobuf may could lead to un-deterministic by default
431
    template <class PbType>
432
12.6k
    static std::string deterministic_string_serialize(const PbType& pb) {
433
12.6k
        std::string output;
434
12.6k
        google::protobuf::io::StringOutputStream string_output_stream(&output);
435
12.6k
        google::protobuf::io::CodedOutputStream output_stream(&string_output_stream);
436
12.6k
        output_stream.SetSerializationDeterministic(true);
437
12.6k
        pb.SerializeToCodedStream(&output_stream);
438
12.6k
        return output;
439
12.6k
    }
_ZN5doris12TabletSchema30deterministic_string_serializeINS_10segment_v212ColumnMetaPBEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
432
1.38k
    static std::string deterministic_string_serialize(const PbType& pb) {
433
1.38k
        std::string output;
434
1.38k
        google::protobuf::io::StringOutputStream string_output_stream(&output);
435
1.38k
        google::protobuf::io::CodedOutputStream output_stream(&string_output_stream);
436
1.38k
        output_stream.SetSerializationDeterministic(true);
437
1.38k
        pb.SerializeToCodedStream(&output_stream);
438
1.38k
        return output;
439
1.38k
    }
_ZN5doris12TabletSchema30deterministic_string_serializeINS_10segment_v215SegmentFooterPBEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
432
40
    static std::string deterministic_string_serialize(const PbType& pb) {
433
40
        std::string output;
434
40
        google::protobuf::io::StringOutputStream string_output_stream(&output);
435
40
        google::protobuf::io::CodedOutputStream output_stream(&string_output_stream);
436
40
        output_stream.SetSerializationDeterministic(true);
437
40
        pb.SerializeToCodedStream(&output_stream);
438
40
        return output;
439
40
    }
_ZN5doris12TabletSchema30deterministic_string_serializeINS_8ColumnPBEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
432
1.21k
    static std::string deterministic_string_serialize(const PbType& pb) {
433
1.21k
        std::string output;
434
1.21k
        google::protobuf::io::StringOutputStream string_output_stream(&output);
435
1.21k
        google::protobuf::io::CodedOutputStream output_stream(&string_output_stream);
436
1.21k
        output_stream.SetSerializationDeterministic(true);
437
1.21k
        pb.SerializeToCodedStream(&output_stream);
438
1.21k
        return output;
439
1.21k
    }
_ZN5doris12TabletSchema30deterministic_string_serializeINS_13TabletIndexPBEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
432
269
    static std::string deterministic_string_serialize(const PbType& pb) {
433
269
        std::string output;
434
269
        google::protobuf::io::StringOutputStream string_output_stream(&output);
435
269
        google::protobuf::io::CodedOutputStream output_stream(&string_output_stream);
436
269
        output_stream.SetSerializationDeterministic(true);
437
269
        pb.SerializeToCodedStream(&output_stream);
438
269
        return output;
439
269
    }
_ZN5doris12TabletSchema30deterministic_string_serializeINS_14TabletSchemaPBEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
432
9.73k
    static std::string deterministic_string_serialize(const PbType& pb) {
433
9.73k
        std::string output;
434
9.73k
        google::protobuf::io::StringOutputStream string_output_stream(&output);
435
9.73k
        google::protobuf::io::CodedOutputStream output_stream(&string_output_stream);
436
9.73k
        output_stream.SetSerializationDeterministic(true);
437
9.73k
        pb.SerializeToCodedStream(&output_stream);
438
9.73k
        return output;
439
9.73k
    }
_ZN5doris12TabletSchema30deterministic_string_serializeINS_21POlapTableIndexSchemaEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_
Line
Count
Source
432
40
    static std::string deterministic_string_serialize(const PbType& pb) {
433
40
        std::string output;
434
40
        google::protobuf::io::StringOutputStream string_output_stream(&output);
435
40
        google::protobuf::io::CodedOutputStream output_stream(&string_output_stream);
436
40
        output_stream.SetSerializationDeterministic(true);
437
40
        pb.SerializeToCodedStream(&output_stream);
438
40
        return output;
439
40
    }
440
    void to_schema_pb(TabletSchemaPB* tablet_meta_pb) const;
441
    void append_column(TabletColumn column, ColumnType col_type = ColumnType::NORMAL);
442
    void append_index(TabletIndex&& index);
443
    void remove_index(int64_t index_id);
444
    void clear_index();
445
    // Must make sure the row column is always the last column
446
    void add_row_column();
447
    void copy_from(const TabletSchema& tablet_schema);
448
    // lightweight copy, take care of lifecycle of TabletColumn
449
    void shawdow_copy_without_columns(const TabletSchema& tablet_schema);
450
    void update_index_info_from(const TabletSchema& tablet_schema);
451
    std::string to_key() const;
452
    // get_metadata_size is only the memory of the TabletSchema itself, not include child objects.
453
345
    int64_t mem_size() const { return get_metadata_size(); }
454
    size_t row_size() const;
455
    int32_t field_index(const std::string& field_name) const;
456
    int32_t field_index(const PathInData& path) const;
457
    int32_t field_index(int32_t col_unique_id) const;
458
    const TabletColumn& column(size_t ordinal) const;
459
    Result<const TabletColumn*> column(const std::string& field_name) const;
460
    Status have_column(const std::string& field_name) const;
461
    bool exist_column(const std::string& field_name) const;
462
    bool has_column_unique_id(int32_t col_unique_id) const;
463
    const TabletColumn& column_by_uid(int32_t col_unique_id) const;
464
    TabletColumn& mutable_column_by_uid(int32_t col_unique_id);
465
    TabletColumn& mutable_column(size_t ordinal);
466
    void replace_column(size_t pos, TabletColumn new_col);
467
    const std::vector<TabletColumnPtr>& columns() const;
468
805k
    size_t num_columns() const { return _num_columns; }
469
0
    size_t num_visible_columns() const {
470
0
        return std::count_if(_cols.begin(), _cols.end(),
471
0
                             [](const TabletColumnPtr& column) { return column->visible(); });
472
0
    }
473
1
    size_t num_visible_value_columns() const {
474
2
        return std::count_if(_cols.begin(), _cols.end(), [](const TabletColumnPtr& column) {
475
2
            return column->visible() && !column->is_key();
476
2
        });
477
1
    }
478
    // num_key_columns: Total number of sort key columns in the table, determined by the key columns
479
    // specified in DUPLICATE KEY/UNIQUE KEY/AGGREGATE KEY when creating the table, used for complete data sorting
480
    // Example: CREATE TABLE t(a INT, b DATE, c VARCHAR) DUPLICATE KEY(a, b, c)
481
    //          Then num_key_columns = 3 (columns a, b, c are all sort keys)
482
307k
    size_t num_key_columns() const { return _num_key_columns; }
483
144k
    const std::vector<uint32_t>& cluster_key_uids() const { return _cluster_key_uids; }
484
0
    size_t num_null_columns() const { return _num_null_columns; }
485
    // num_short_key_columns: Number of columns used to build the Short Key Index, automatically calculated by FE
486
    // Limited by max column count (default 3) and max bytes (default 36 bytes). Types like float/double/STRING/JSONB
487
    // cannot be used as short keys. VARCHAR can only be the last short key column. Optimizes index size and query performance.
488
    // Example: CREATE TABLE t(a INT, b DATE, c VARCHAR) DUPLICATE KEY(a, b, c)
489
    //          Then num_short_key_columns = 3 (a, b, c all meet criteria, c as VARCHAR is the last short key)
490
    // Example: CREATE TABLE t(a INT, b DOUBLE, c DATE) DUPLICATE KEY(a, b, c)
491
    //          Then num_short_key_columns = 1 (b is DOUBLE type which cannot be short key, stops at b)
492
    // short key's size is limited to 36 bytes, because it will be loaded to memory during segment loaded.
493
11.1k
    size_t num_short_key_columns() const { return _num_short_key_columns; }
494
2
    size_t num_rows_per_row_block() const { return _num_rows_per_row_block; }
495
1.50k
    size_t num_variant_columns() const { return _num_variant_columns; };
496
0
    size_t num_virtual_columns() const { return _num_virtual_columns; }
497
7.19M
    KeysType keys_type() const { return _keys_type; }
498
4.58k
    SortType sort_type() const { return _sort_type; }
499
2
    size_t sort_col_num() const { return _sort_col_num; }
500
2
    CompressKind compress_kind() const { return _compress_kind; }
501
3
    size_t next_column_unique_id() const { return _next_column_unique_id; }
502
176
    bool has_bf_fpp() const { return _has_bf_fpp; }
503
163
    double bloom_filter_fpp() const { return _bf_fpp; }
504
12.0k
    bool is_in_memory() const { return _is_in_memory; }
505
0
    void set_is_in_memory(bool is_in_memory) { _is_in_memory = is_in_memory; }
506
1
    void set_disable_auto_compaction(bool disable_auto_compaction) {
507
1
        _disable_auto_compaction = disable_auto_compaction;
508
1
    }
509
20.2k
    bool disable_auto_compaction() const { return _disable_auto_compaction; }
510
    // Deprecated legacy switch for flatten-nested variant behavior.
511
    // It is distinct from variant_enable_nested_group.
512
0
    void set_deprecated_variant_flatten_nested(bool flatten_nested) {
513
0
        _deprecated_enable_variant_flatten_nested = flatten_nested;
514
0
    }
515
1.20k
    bool deprecated_variant_flatten_nested() const {
516
1.20k
        return _deprecated_enable_variant_flatten_nested;
517
1.20k
    }
518
    // indicate if full row store column(all the columns encodes as row) exists
519
216
    bool has_row_store_for_all_columns() const {
520
216
        return _store_row_column && row_columns_uids().empty();
521
216
    }
522
0
    void set_skip_write_index_on_load(bool skip) { _skip_write_index_on_load = skip; }
523
4.95k
    bool skip_write_index_on_load() const { return _skip_write_index_on_load; }
524
4.35k
    int32_t delete_sign_idx() const { return _delete_sign_idx; }
525
226k
    bool has_sequence_col() const { return _sequence_col_idx != -1; }
526
66.5k
    int32_t sequence_col_idx() const { return _sequence_col_idx; }
527
0
    void set_version_col_idx(int32_t version_col_idx) { _version_col_idx = version_col_idx; }
528
150
    int32_t version_col_idx() const { return _version_col_idx; }
529
71
    bool has_skip_bitmap_col() const { return _skip_bitmap_col_idx != -1; }
530
240
    int32_t skip_bitmap_col_idx() const { return _skip_bitmap_col_idx; }
531
33
    bool is_tso_enabled() const {
532
33
        return _commit_tso_col_idx != -1 || _changelog_tso_col_idx != -1;
533
33
    }
534
1.11k
    int32_t commit_tso_col_idx() const { return _commit_tso_col_idx; }
535
1.52k
    int32_t row_lsn_col_idx() const { return _row_lsn_col_idx; }
536
747
    bool has_ttl_col() const { return _ttl_col_idx != -1; }
537
27
    int32_t ttl_col_idx() const { return _ttl_col_idx; }
538
21.6k
    int64_t row_ttl_duration_us() const { return _row_ttl_duration_us; }
539
12
    int32_t row_ttl_time_zone_offset_seconds() const { return _row_ttl_time_zone_offset_seconds; }
540
288
    int32_t changelog_tso_col_idx() const { return _changelog_tso_col_idx; }
541
235
    int32_t changelog_lsn_col_idx() const { return _changelog_lsn_col_idx; }
542
204
    int32_t changelog_op_col_idx() const { return _changelog_op_col_idx; }
543
3.87k
    segment_v2::CompressionTypePB compression_type() const { return _compression_type; }
544
0
    void set_row_store_page_size(long page_size) { _row_store_page_size = page_size; }
545
102
    long row_store_page_size() const { return _row_store_page_size; }
546
52
    void set_storage_page_size(long storage_page_size) { _storage_page_size = storage_page_size; }
547
18.0k
    long storage_page_size() const { return _storage_page_size; }
548
0
    void set_storage_dict_page_size(long storage_dict_page_size) {
549
0
        _storage_dict_page_size = storage_dict_page_size;
550
0
    }
551
18.0k
    long storage_dict_page_size() const { return _storage_dict_page_size; }
552
0
    bool has_global_row_id() const {
553
0
        for (auto [col_name, _] : _field_name_to_index) {
554
0
            if (col_name.start_with(StringRef(BeConsts::GLOBAL_ROWID_COL.data(),
555
0
                                              BeConsts::GLOBAL_ROWID_COL.size()))) {
556
0
                return true;
557
0
            }
558
0
        }
559
0
        return false;
560
0
    }
561
562
175
    const std::vector<const TabletIndex*> inverted_indexes() const {
563
175
        std::vector<const TabletIndex*> inverted_indexes;
564
1.33k
        for (const auto& index : _indexes) {
565
1.33k
            if (index->index_type() == IndexType::INVERTED) {
566
1.32k
                inverted_indexes.emplace_back(index.get());
567
1.32k
            }
568
1.33k
        }
569
175
        return inverted_indexes;
570
175
    }
571
    // True when anything at all lives in this schema's inverted index FILE.
572
    //
573
    // Spelled out as `has_inverted_index() || has_ann_index()` at ~27 call sites
574
    // before this existed -- rowset writers, segment creation, segcompaction,
575
    // snapshot and migration, and most of the cloud paths. Every one of them is
576
    // asking the same question ("is there an index file to carry, warm, link or
577
    // rewrite?"), and each open-coded copy is a place a third index type would
578
    // have to be remembered.
579
9.06k
    bool has_inverted_or_ann_index() const { return has_inverted_index() || has_ann_index(); }
580
581
    // Both index types that live in the inverted index FILE, in schema order.
582
    // Every storage format stores them together: V1/V2/V3 as CLucene directories,
583
    // SNII as text metadata groups plus an ANN blob logical index. A rewrite that
584
    // enumerated only the inverted ones would seal a file missing every ANN index
585
    // while the schema still claimed them.
586
44
    const std::vector<const TabletIndex*> inverted_and_ann_indexes() const {
587
44
        std::vector<const TabletIndex*> indexes;
588
57
        for (const auto& index : _indexes) {
589
57
            if (index->index_type() == IndexType::INVERTED ||
590
57
                index->index_type() == IndexType::ANN) {
591
57
                indexes.emplace_back(index.get());
592
57
            }
593
57
        }
594
44
        return indexes;
595
44
    }
596
10.8k
    bool has_inverted_index() const {
597
10.8k
        for (const auto& index : _indexes) {
598
1.61k
            DBUG_EXECUTE_IF("tablet_schema::has_inverted_index", {
599
1.61k
                if (index->col_unique_ids().empty()) {
600
1.61k
                    throw Exception(Status::InternalError("col unique ids cannot be empty"));
601
1.61k
                }
602
1.61k
            });
603
604
1.61k
            if (index->index_type() == IndexType::INVERTED) {
605
                //if index_id == -1, ignore it.
606
1.45k
                if (!index->col_unique_ids().empty() && index->col_unique_ids()[0] >= 0) {
607
1.45k
                    return true;
608
1.45k
                }
609
1.45k
            }
610
1.61k
        }
611
9.38k
        return false;
612
10.8k
    }
613
614
8.49k
    bool has_ann_index() const {
615
8.49k
        for (const auto& index : _indexes) {
616
153
            if (index->index_type() == IndexType::ANN) {
617
87
                if (!index->col_unique_ids().empty() && index->col_unique_ids()[0] >= 0) {
618
87
                    return true;
619
87
                }
620
87
            }
621
153
        }
622
8.41k
        return false;
623
8.49k
    }
624
625
    bool has_inverted_index_with_index_id(int64_t index_id) const;
626
627
    std::vector<const TabletIndex*> inverted_indexs(const TabletColumn& col) const;
628
629
    std::vector<const TabletIndex*> inverted_indexs(int32_t col_unique_id,
630
                                                    const std::string& suffix_path = "") const;
631
    const TabletIndex* ann_index(const TabletColumn& col) const;
632
633
    // Regardless of whether this column supports inverted index
634
    // TabletIndex information will be returned as long as it exists.
635
    const TabletIndex* ann_index(int32_t col_unique_id, const std::string& suffix_path = "") const;
636
637
    std::vector<TabletIndexPtr> inverted_index_by_field_pattern(
638
            int32_t col_unique_id, const std::string& field_pattern) const;
639
640
    bool has_ngram_bf_index(int32_t col_unique_id) const;
641
    const TabletIndex* get_ngram_bf_index(int32_t col_unique_id) const;
642
    double get_bloom_filter_fpp(int32_t col_unique_id) const;
643
    double get_bloom_filter_fpp(const TabletColumn& column) const;
644
    const TabletIndex* get_index(int32_t col_unique_id, IndexType index_type,
645
                                 const std::string& suffix_path) const;
646
    void update_indexes_from_thrift(const std::vector<doris::TOlapTableIndex>& indexes);
647
    // If schema version is not set, it should be -1
648
10.0k
    int32_t schema_version() const { return _schema_version; }
649
    void clear_columns();
650
    // Each column id is an ordinal in TabletSchema::_cols, not a unique id or ReadSchema ordinal.
651
    // The resulting Block uses the selected physical TabletSchema column types.
652
    Block create_storage_block(const std::vector<uint32_t>& column_ids) const;
653
    Block create_storage_block() const;
654
15
    void set_schema_version(int32_t version) { _schema_version = version; }
655
0
    void set_auto_increment_column(const std::string& auto_increment_column) {
656
0
        _auto_increment_column = auto_increment_column;
657
0
    }
658
11
    std::string auto_increment_column() const { return _auto_increment_column; }
659
660
22
    void set_table_id(int64_t table_id) { _table_id = table_id; }
661
1.15k
    int64_t table_id() const { return _table_id; }
662
20
    void set_db_id(int64_t db_id) { _db_id = db_id; }
663
454
    int64_t db_id() const { return _db_id; }
664
    void build_current_tablet_schema(int64_t index_id, int32_t version,
665
                                     const OlapTableIndexSchema* index,
666
                                     const TabletSchema& out_tablet_schema);
667
668
    // copy extracted columns from src_schema
669
    void copy_extracted_columns(const TabletSchema& src_schema);
670
671
    // only reserve extracted columns
672
    void reserve_extracted_columns();
673
674
4.04k
    std::string get_all_field_names() const {
675
4.04k
        std::string str = "[";
676
4.04k
        for (auto p : _field_name_to_index) {
677
4.04k
            if (str.size() > 1) {
678
0
                str += ", ";
679
0
            }
680
4.04k
            str += p.first.to_string() + "(" + std::to_string(_cols[p.second]->unique_id()) + ")";
681
4.04k
        }
682
4.04k
        str += "]";
683
4.04k
        return str;
684
4.04k
    }
685
686
    // Dump [(name, type, is_nullable), ...]
687
5
    std::string dump_structure() const {
688
5
        std::string str = "[";
689
28
        for (auto p : _cols) {
690
28
            if (str.size() > 1) {
691
23
                str += ", ";
692
23
            }
693
28
            str += "(";
694
28
            str += p->name();
695
28
            str += ", ";
696
28
            str += TabletColumn::get_string_by_field_type(p->type());
697
28
            str += ", ";
698
28
            str += "is_nullable:";
699
28
            str += (p->is_nullable() ? "true" : "false");
700
28
            str += ")";
701
28
        }
702
5
        str += "]";
703
5
        return str;
704
5
    }
705
706
1
    std::string dump_full_schema() const {
707
1
        std::string str = "[";
708
4
        for (auto p : _cols) {
709
4
            if (str.size() > 1) {
710
3
                str += ", ";
711
3
            }
712
4
            ColumnPB col_pb;
713
4
            p->to_schema_pb(&col_pb);
714
4
            str += "(";
715
4
            str += col_pb.ShortDebugString();
716
4
            str += ")";
717
4
        }
718
1
        str += "]";
719
1
        return str;
720
1
    }
721
722
    std::shared_ptr<TabletSchema> copy_without_variant_extracted_columns();
723
10.4k
    InvertedIndexStorageFormatPB get_inverted_index_storage_format() const {
724
10.4k
        return _inverted_index_storage_format;
725
10.4k
    }
726
727
    void update_tablet_columns(const TabletSchema& tablet_schema,
728
                               const std::vector<TColumn>& t_columns);
729
730
251
    const std::vector<int32_t>& row_columns_uids() const { return _row_store_column_unique_ids; }
731
732
    int64_t get_metadata_size() const override;
733
734
    struct SubColumnInfo {
735
        TabletColumn column;
736
        TabletIndexes indexes;
737
    };
738
739
6
    bool need_record_variant_extended_schema() const { return variant_max_subcolumns_count() == 0; }
740
741
11
    int32_t variant_max_subcolumns_count() const {
742
12
        for (const auto& col : _cols) {
743
12
            if (col->is_variant_type()) {
744
7
                return col->variant_max_subcolumns_count();
745
7
            }
746
12
        }
747
4
        return 0;
748
11
    }
749
    const std::unordered_map<uint32_t, std::vector<uint32_t>>& seq_col_idx_to_value_cols_idx()
750
1
            const {
751
1
        return _seq_col_idx_to_value_cols_idx;
752
1
    }
753
754
11.3k
    bool has_seq_map() const { return !_seq_col_idx_to_value_cols_idx.empty(); }
755
756
21.9k
    TabletStorageFormatPB storage_format() const { return _storage_format; }
757
202
    void set_storage_format(TabletStorageFormatPB v) { _storage_format = v; }
758
759
private:
760
    friend bool operator==(const TabletSchema& a, const TabletSchema& b);
761
    friend bool operator!=(const TabletSchema& a, const TabletSchema& b);
762
17
    TabletSchema(const TabletSchema&) = default;
763
764
    KeysType _keys_type = DUP_KEYS;
765
    SortType _sort_type = SortType::LEXICAL;
766
    size_t _sort_col_num = 0;
767
    std::vector<TabletColumnPtr> _cols;
768
769
    std::vector<TabletIndexPtr> _indexes;
770
    std::unordered_map<StringRef, int32_t, StringRefHash> _field_name_to_index;
771
    std::unordered_map<int32_t, int32_t> _field_uniqueid_to_index;
772
    std::unordered_map<PathInDataRef, int32_t, PathInDataRef::Hash> _field_path_to_index;
773
774
    // index_type/col_unique_id/suffix -> idxs in _indexes
775
    using IndexKey = std::tuple<IndexType, int32_t, std::string>;
776
    struct IndexKeyHash {
777
62.1k
        size_t operator()(const IndexKey& t) const {
778
62.1k
            uint32_t seed = 0;
779
62.1k
            seed = doris::HashUtil::hash((const char*)&std::get<0>(t), sizeof(std::get<0>(t)),
780
62.1k
                                         seed);
781
62.1k
            seed = doris::HashUtil::hash((const char*)&std::get<1>(t), sizeof(std::get<1>(t)),
782
62.1k
                                         seed);
783
62.1k
            seed = doris::HashUtil::hash((const char*)std::get<2>(t).c_str(),
784
62.1k
                                         static_cast<uint32_t>(std::get<2>(t).size()), seed);
785
62.1k
            return seed;
786
62.1k
        }
787
    };
788
    std::unordered_map<IndexKey, std::vector<size_t>, IndexKeyHash> _col_id_suffix_to_index;
789
790
    int32_t _num_columns = 0;
791
    size_t _num_variant_columns = 0;
792
    size_t _num_virtual_columns = 0;
793
    size_t _num_key_columns = 0;
794
    std::vector<uint32_t> _cluster_key_uids;
795
    size_t _num_null_columns = 0;
796
    size_t _num_short_key_columns = 0;
797
    size_t _num_rows_per_row_block = 0;
798
    CompressKind _compress_kind = COMPRESS_NONE;
799
    segment_v2::CompressionTypePB _compression_type = segment_v2::CompressionTypePB::LZ4F;
800
    long _row_store_page_size = segment_v2::ROW_STORE_PAGE_SIZE_DEFAULT_VALUE;
801
    long _storage_page_size = segment_v2::STORAGE_PAGE_SIZE_DEFAULT_VALUE;
802
    long _storage_dict_page_size = segment_v2::STORAGE_DICT_PAGE_SIZE_DEFAULT_VALUE;
803
    size_t _next_column_unique_id = 0;
804
    std::string _auto_increment_column;
805
806
    bool _has_bf_fpp = false;
807
    double _bf_fpp = 0;
808
    bool _is_in_memory = false;
809
    int32_t _delete_sign_idx = -1;
810
    int32_t _sequence_col_idx = -1;
811
    int32_t _version_col_idx = -1;
812
    int32_t _skip_bitmap_col_idx = -1;
813
    int32_t _commit_tso_col_idx = -1;
814
    int32_t _row_lsn_col_idx = -1;
815
    int32_t _ttl_col_idx = -1;
816
    int64_t _row_ttl_duration_us = -1;
817
    int32_t _row_ttl_time_zone_offset_seconds {0};
818
    int32_t _changelog_tso_col_idx = -1;
819
    int32_t _changelog_lsn_col_idx = -1;
820
    int32_t _changelog_op_col_idx = -1;
821
    int32_t _schema_version = -1;
822
    int64_t _table_id = -1;
823
    int64_t _db_id = -1;
824
    bool _disable_auto_compaction = false;
825
    bool _store_row_column = false;
826
    bool _skip_write_index_on_load = false;
827
    InvertedIndexStorageFormatPB _inverted_index_storage_format = InvertedIndexStorageFormatPB::V1;
828
829
    // Contains column ids of which columns should be encoded into row store.
830
    // ATTN: For compability reason empty cids means all columns of tablet schema are encoded to row column
831
    std::vector<int32_t> _row_store_column_unique_ids;
832
    bool _deprecated_enable_variant_flatten_nested = false;
833
834
    std::map<size_t, int32_t> _vir_col_idx_to_unique_id;
835
836
    // key: field_pattern
837
    // value: indexes
838
    using PatternToIndex = std::unordered_map<std::string, std::vector<TabletIndexPtr>>;
839
    std::unordered_map<int32_t, PatternToIndex> _index_by_unique_id_with_pattern;
840
841
    // Default behavior for new segments: use external ColumnMeta region + CMO table if true
842
    // Persisted tablet storage format. Authoritative source for "is this tablet V3?"
843
    // decisions in the segment write paths. Old PBs without this field are upgraded in
844
    // init_from_pb() by deriving V3 from any of the three legacy V3-flavor flags.
845
    TabletStorageFormatPB _storage_format {TabletStorageFormatPB::TABLET_STORAGE_FORMAT_V2};
846
    // Sequence column unique id mapping to value columns unique id
847
    std::unordered_map<uint32_t, std::vector<uint32_t>> _seq_col_uid_to_value_cols_uid;
848
    // Value column unique id mapping to sequence column unique id(also map sequence column it self)
849
    std::unordered_map<uint32_t, uint32_t> _value_col_uid_to_seq_col_uid;
850
    // Sequence column index mapping to value column index
851
    std::unordered_map<uint32_t, std::vector<uint32_t>> _seq_col_idx_to_value_cols_idx;
852
};
853
854
bool operator==(const TabletSchema& a, const TabletSchema& b);
855
bool operator!=(const TabletSchema& a, const TabletSchema& b);
856
857
using TabletSchemaSPtr = std::shared_ptr<TabletSchema>;
858
859
} // namespace doris