Coverage Report

Created: 2026-07-26 18:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/storage/tablet_info.cpp
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
#include "storage/tablet_info.h"
19
20
#include <butil/logging.h>
21
#include <gen_cpp/Descriptors_types.h>
22
#include <gen_cpp/Exprs_types.h>
23
#include <gen_cpp/Partitions_types.h>
24
#include <gen_cpp/Types_types.h>
25
#include <gen_cpp/descriptors.pb.h>
26
#include <gen_cpp/olap_file.pb.h>
27
#include <glog/logging.h>
28
29
#include <algorithm>
30
#include <cstddef>
31
#include <cstdint>
32
#include <memory>
33
#include <ostream>
34
#include <string>
35
#include <tuple>
36
37
#include "common/check.h"
38
#include "common/exception.h"
39
#include "common/logging.h"
40
#include "common/status.h"
41
#include "core/column/column.h"
42
#include "core/data_type/data_type.h"
43
#include "core/data_type/data_type_factory.hpp"
44
#include "core/data_type/define_primitive_type.h"
45
#include "core/data_type/primitive_type.h"
46
#include "core/value/large_int_value.h"
47
#include "runtime/descriptors.h"
48
#include "runtime/memory/mem_tracker.h"
49
#include "storage/tablet/tablet_schema.h"
50
#include "util/raw_value.h"
51
#include "util/string_parser.hpp"
52
#include "util/string_util.h"
53
// NOLINTNEXTLINE(unused-includes)
54
#include "core/value/vdatetime_value.h"
55
#include "exprs/function/cast/cast_to_date_or_datetime_impl.hpp"
56
#include "exprs/function/cast/cast_to_datetimev2_impl.hpp"
57
#include "exprs/function/cast/cast_to_datev2_impl.hpp"
58
#include "exprs/function/cast/cast_to_timestamptz.h"
59
#include "exprs/vexpr_context.h" // IWYU pragma: keep
60
#include "exprs/vliteral.h"
61
62
namespace doris {
63
64
281k
void OlapTableIndexSchema::to_protobuf(POlapTableIndexSchema* pindex) const {
65
281k
    pindex->set_id(index_id);
66
281k
    pindex->set_schema_hash(schema_hash);
67
281k
    if (row_binlog_id > 0) {
68
1
        pindex->set_row_binlog_id(row_binlog_id);
69
1
    }
70
2.66M
    for (auto* slot : slots) {
71
2.66M
        pindex->add_columns(slot->col_name());
72
2.66M
    }
73
2.71M
    for (auto* column : columns) {
74
2.71M
        column->to_schema_pb(pindex->add_columns_desc());
75
2.71M
    }
76
281k
    for (auto* index : indexes) {
77
132k
        index->to_schema_pb(pindex->add_indexes_desc());
78
132k
    }
79
281k
}
80
81
bool VOlapTablePartKeyComparator::operator()(const BlockRowWithIndicator& lhs,
82
60.7M
                                             const BlockRowWithIndicator& rhs) const {
83
60.7M
    Block* l_block = std::get<0>(lhs);
84
60.7M
    Block* r_block = std::get<0>(rhs);
85
60.7M
    int32_t l_row = std::get<1>(lhs);
86
60.7M
    int32_t r_row = std::get<1>(rhs);
87
60.7M
    bool l_use_new = std::get<2>(lhs);
88
60.7M
    bool r_use_new = std::get<2>(rhs);
89
90
18.4E
    VLOG_TRACE << '\n' << l_block->dump_data() << '\n' << r_block->dump_data();
91
92
60.7M
    if (l_row == -1) {
93
178
        return false;
94
60.7M
    } else if (r_row == -1) {
95
31.4M
        return true;
96
31.4M
    }
97
98
29.2M
    if (_param_locs.empty()) { // no transform, use origin column
99
28.3M
        for (auto slot_loc : _slot_locs) {
100
28.3M
            auto res = l_block->get_by_position(slot_loc).column->compare_at(
101
28.3M
                    l_row, r_row, *r_block->get_by_position(slot_loc).column, -1);
102
28.3M
            if (res != 0) {
103
28.1M
                return res < 0;
104
28.1M
            }
105
28.3M
        }
106
28.3M
    } else { // use transformed column to compare
107
18.4E
        DCHECK(_slot_locs.size() == _param_locs.size())
108
18.4E
                << _slot_locs.size() << ' ' << _param_locs.size();
109
110
966k
        const std::vector<uint16_t>* l_index = l_use_new ? &_param_locs : &_slot_locs;
111
966k
        const std::vector<uint16_t>* r_index = r_use_new ? &_param_locs : &_slot_locs;
112
113
1.35M
        for (int i = 0; i < _slot_locs.size(); i++) {
114
1.00M
            ColumnPtr l_col = l_block->get_by_position((*l_index)[i]).column;
115
1.00M
            ColumnPtr r_col = r_block->get_by_position((*r_index)[i]).column;
116
117
1.00M
            auto res = l_col->compare_at(l_row, r_row, *r_col, -1);
118
1.00M
            if (res != 0) {
119
620k
                return res < 0;
120
620k
            }
121
1.00M
        }
122
966k
    }
123
124
    // equal, return false
125
458k
    return false;
126
29.2M
}
127
128
36.3k
Status OlapTableSchemaParam::init(const POlapTableSchemaParam& pschema) {
129
36.3k
    _db_id = pschema.db_id();
130
36.3k
    _table_id = pschema.table_id();
131
36.3k
    _version = pschema.version();
132
36.3k
    if (pschema.has_unique_key_update_mode()) {
133
36.3k
        _unique_key_update_mode = pschema.unique_key_update_mode();
134
36.3k
        if (pschema.has_sequence_map_col_unique_id()) {
135
36.3k
            _sequence_map_col_uid = pschema.sequence_map_col_unique_id();
136
36.3k
        }
137
36.3k
    } else {
138
        // for backward compatibility
139
2
        if (pschema.has_partial_update() && pschema.partial_update()) {
140
0
            _unique_key_update_mode = UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS;
141
2
        } else {
142
2
            _unique_key_update_mode = UniqueKeyUpdateModePB::UPSERT;
143
2
        }
144
2
    }
145
36.3k
    _is_strict_mode = pschema.is_strict_mode();
146
36.3k
    if (_unique_key_update_mode == UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS) {
147
2.96k
        _auto_increment_column = pschema.auto_increment_column();
148
2.96k
        if (!_auto_increment_column.empty() && pschema.auto_increment_column_unique_id() == -1) {
149
0
            return Status::InternalError(
150
0
                    "Auto increment column id is not set in FE. Maybe FE is an older version "
151
0
                    "different from BE.");
152
0
        }
153
2.96k
        _auto_increment_column_unique_id = pschema.auto_increment_column_unique_id();
154
2.96k
    }
155
36.3k
    if (_unique_key_update_mode != UniqueKeyUpdateModePB::UPSERT) {
156
3.12k
        if (pschema.has_partial_update_new_key_policy()) {
157
3.12k
            _partial_update_new_row_policy = pschema.partial_update_new_key_policy();
158
3.12k
        }
159
3.12k
    }
160
36.3k
    _timestamp_ms = pschema.timestamp_ms();
161
36.3k
    if (pschema.has_nano_seconds()) {
162
36.3k
        _nano_seconds = pschema.nano_seconds();
163
36.3k
    }
164
36.3k
    _timezone = pschema.timezone();
165
36.3k
    _row_ttl_source_column_uid = pschema.row_ttl_source_column_unique_id();
166
36.3k
    if (pschema.has_row_ttl_source_column()) {
167
0
        _row_ttl_source_column = _obj_pool.add(new TabletColumn());
168
0
        _row_ttl_source_column->init_from_pb(pschema.row_ttl_source_column());
169
0
    }
170
171
36.3k
    for (const auto& col : pschema.partial_update_input_columns()) {
172
18.5k
        _partial_update_input_columns.insert(col);
173
18.5k
    }
174
36.3k
    std::unordered_map<std::string, SlotDescriptor*> slots_map;
175
176
36.3k
    _tuple_desc = _obj_pool.add(new TupleDescriptor(pschema.tuple_desc()));
177
178
307k
    for (const auto& p_slot_desc : pschema.slot_descs()) {
179
307k
        auto* slot_desc = _obj_pool.add(new SlotDescriptor(p_slot_desc));
180
307k
        _tuple_desc->add_slot(slot_desc);
181
307k
        std::string data_type;
182
307k
        EnumToString(TPrimitiveType, to_thrift(slot_desc->col_type()), data_type);
183
307k
        std::string is_null_str = slot_desc->is_nullable() ? "true" : "false";
184
307k
        std::string data_type_str =
185
307k
                std::to_string(int64_t(TabletColumn::get_field_type_by_string(data_type)));
186
307k
        slots_map.emplace(to_lower(slot_desc->col_name()) + "+" + data_type_str + is_null_str,
187
307k
                          slot_desc);
188
307k
    }
189
190
44.4k
    for (const auto& p_index : pschema.indexes()) {
191
44.4k
        auto* index = _obj_pool.add(new OlapTableIndexSchema());
192
44.4k
        index->index_id = p_index.id();
193
44.4k
        index->schema_hash = p_index.schema_hash();
194
44.4k
        if (p_index.has_row_binlog_id()) {
195
0
            index->row_binlog_id = p_index.row_binlog_id();
196
0
        }
197
332k
        for (const auto& pcolumn_desc : p_index.columns_desc()) {
198
332k
            if (_unique_key_update_mode != UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS ||
199
332k
                _partial_update_input_columns.contains(pcolumn_desc.name())) {
200
309k
                std::string is_null_str = pcolumn_desc.is_nullable() ? "true" : "false";
201
309k
                std::string data_type_str = std::to_string(
202
309k
                        int64_t(TabletColumn::get_field_type_by_string(pcolumn_desc.type())));
203
309k
                auto it = slots_map.find(to_lower(pcolumn_desc.name()) + "+" + data_type_str +
204
309k
                                         is_null_str);
205
309k
                if (it == std::end(slots_map)) {
206
0
                    std::string keys {};
207
0
                    for (const auto& [key, _] : slots_map) {
208
0
                        keys += fmt::format("{},", key);
209
0
                    }
210
0
                    LOG_EVERY_SECOND(WARNING) << fmt::format(
211
0
                            "[OlapTableSchemaParam::init(const POlapTableSchemaParam& pschema)]: "
212
0
                            "unknown index column, column={}, type={}, data_type_str={}, "
213
0
                            "is_null_str={}, slots_map.keys()=[{}], {}\npschema={}",
214
0
                            pcolumn_desc.name(), pcolumn_desc.type(), data_type_str, is_null_str,
215
0
                            keys, debug_string(), pschema.ShortDebugString());
216
217
0
                    return Status::InternalError("unknown index column, column={}, type={}",
218
0
                                                 pcolumn_desc.name(), pcolumn_desc.type());
219
0
                }
220
309k
                index->slots.emplace_back(it->second);
221
309k
            }
222
332k
            TabletColumn* tc = _obj_pool.add(new TabletColumn());
223
332k
            tc->init_from_pb(pcolumn_desc);
224
332k
            index->columns.emplace_back(tc);
225
332k
        }
226
44.4k
        for (const auto& pindex_desc : p_index.indexes_desc()) {
227
5.91k
            TabletIndex* ti = _obj_pool.add(new TabletIndex());
228
5.91k
            ti->init_from_pb(pindex_desc);
229
5.91k
            index->indexes.emplace_back(ti);
230
5.91k
        }
231
44.4k
        _indexes.emplace_back(index);
232
44.4k
    }
233
234
36.3k
    if (pschema.has_row_binlog_index_schema()) {
235
0
        const auto& p_index = pschema.row_binlog_index_schema();
236
0
        auto* index = _obj_pool.add(new OlapTableIndexSchema());
237
0
        index->index_id = p_index.id();
238
0
        index->schema_hash = p_index.schema_hash();
239
0
        if (p_index.has_row_binlog_id()) {
240
0
            index->row_binlog_id = p_index.row_binlog_id();
241
0
        }
242
0
        for (const auto& pcolumn_desc : p_index.columns_desc()) {
243
0
            TabletColumn* tc = _obj_pool.add(new TabletColumn());
244
0
            tc->init_from_pb(pcolumn_desc);
245
0
            index->columns.emplace_back(tc);
246
0
        }
247
0
        for (const auto& pindex_desc : p_index.indexes_desc()) {
248
0
            TabletIndex* ti = _obj_pool.add(new TabletIndex());
249
0
            ti->init_from_pb(pindex_desc);
250
0
            index->indexes.emplace_back(ti);
251
0
        }
252
0
        _row_binlog_index_schema = index;
253
0
    }
254
255
36.3k
    std::sort(_indexes.begin(), _indexes.end(),
256
36.3k
              [](const OlapTableIndexSchema* lhs, const OlapTableIndexSchema* rhs) {
257
33.1k
                  return lhs->index_id < rhs->index_id;
258
33.1k
              });
259
36.3k
    return Status::OK();
260
36.3k
}
261
262
117k
Status OlapTableSchemaParam::init_unique_key_update_mode(const TOlapTableSchemaParam& tschema) {
263
117k
    if (tschema.__isset.unique_key_update_mode) {
264
117k
        switch (tschema.unique_key_update_mode) {
265
106k
        case doris::TUniqueKeyUpdateMode::UPSERT: {
266
106k
            _unique_key_update_mode = UniqueKeyUpdateModePB::UPSERT;
267
106k
            break;
268
0
        }
269
10.4k
        case doris::TUniqueKeyUpdateMode::UPDATE_FIXED_COLUMNS: {
270
10.4k
            _unique_key_update_mode = UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS;
271
10.4k
            break;
272
0
        }
273
157
        case doris::TUniqueKeyUpdateMode::UPDATE_FLEXIBLE_COLUMNS: {
274
157
            _unique_key_update_mode = UniqueKeyUpdateModePB::UPDATE_FLEXIBLE_COLUMNS;
275
157
            break;
276
0
        }
277
0
        default: {
278
0
            return Status::InternalError(
279
0
                    "Unknown unique_key_update_mode: {}, should be one of "
280
0
                    "UPSERT/UPDATE_FIXED_COLUMNS/UPDATE_FLEXIBLE_COLUMNS",
281
0
                    tschema.unique_key_update_mode);
282
0
        }
283
117k
        }
284
117k
        if (tschema.__isset.sequence_map_col_unique_id) {
285
117k
            _sequence_map_col_uid = tschema.sequence_map_col_unique_id;
286
117k
        }
287
18.4E
    } else {
288
        // for backward compatibility
289
18.4E
        if (tschema.__isset.is_partial_update && tschema.is_partial_update) {
290
0
            _unique_key_update_mode = UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS;
291
18.4E
        } else {
292
18.4E
            _unique_key_update_mode = UniqueKeyUpdateModePB::UPSERT;
293
18.4E
        }
294
18.4E
    }
295
117k
    return Status::OK();
296
117k
}
297
298
117k
Status OlapTableSchemaParam::init(const TOlapTableSchemaParam& tschema) {
299
117k
    _db_id = tschema.db_id;
300
117k
    _table_id = tschema.table_id;
301
117k
    _version = tschema.version;
302
117k
    RETURN_IF_ERROR(init_unique_key_update_mode(tschema));
303
117k
    if (tschema.__isset.is_strict_mode) {
304
117k
        _is_strict_mode = tschema.is_strict_mode;
305
117k
    }
306
117k
    if (_unique_key_update_mode == UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS) {
307
10.4k
        _auto_increment_column = tschema.auto_increment_column;
308
10.4k
        if (!_auto_increment_column.empty() && tschema.auto_increment_column_unique_id == -1) {
309
0
            return Status::InternalError(
310
0
                    "Auto increment column id is not set in FE. Maybe FE is an older version "
311
0
                    "different from BE.");
312
0
        }
313
10.4k
        _auto_increment_column_unique_id = tschema.auto_increment_column_unique_id;
314
10.4k
    }
315
316
117k
    if (_unique_key_update_mode != UniqueKeyUpdateModePB::UPSERT) {
317
10.6k
        if (tschema.__isset.partial_update_new_key_policy) {
318
10.6k
            switch (tschema.partial_update_new_key_policy) {
319
10.5k
            case doris::TPartialUpdateNewRowPolicy::APPEND: {
320
10.5k
                _partial_update_new_row_policy = PartialUpdateNewRowPolicyPB::APPEND;
321
10.5k
                break;
322
0
            }
323
107
            case doris::TPartialUpdateNewRowPolicy::ERROR: {
324
107
                _partial_update_new_row_policy = PartialUpdateNewRowPolicyPB::ERROR;
325
107
                break;
326
0
            }
327
0
            default: {
328
0
                return Status::InvalidArgument(
329
0
                        "Unknown partial_update_new_key_behavior: {}, should be one of "
330
0
                        "'APPEND' or 'ERROR'",
331
0
                        tschema.partial_update_new_key_policy);
332
0
            }
333
10.6k
            }
334
10.6k
        }
335
10.6k
    }
336
337
117k
    for (const auto& tcolumn : tschema.partial_update_input_columns) {
338
50.2k
        _partial_update_input_columns.insert(tcolumn);
339
50.2k
    }
340
117k
    _row_ttl_source_column_uid = tschema.row_ttl_source_column_unique_id;
341
117k
    DORIS_CHECK_EQ(_row_ttl_source_column_uid >= 0,
342
117k
                   tschema.__isset.row_ttl_source_column);
343
117k
    if (_row_ttl_source_column_uid >= 0) {
344
0
        _row_ttl_source_column = _obj_pool.add(new TabletColumn());
345
0
        _row_ttl_source_column->init_from_thrift(tschema.row_ttl_source_column);
346
0
    }
347
117k
    std::unordered_map<std::string, SlotDescriptor*> slots_map;
348
117k
    _tuple_desc = _obj_pool.add(new TupleDescriptor(tschema.tuple_desc));
349
844k
    for (const auto& t_slot_desc : tschema.slot_descs) {
350
844k
        auto* slot_desc = _obj_pool.add(new SlotDescriptor(t_slot_desc));
351
844k
        _tuple_desc->add_slot(slot_desc);
352
844k
        std::string is_null_str = slot_desc->is_nullable() ? "true" : "false";
353
844k
        std::string data_type_str = std::to_string(int64_t(slot_desc->col_type()));
354
844k
        slots_map.emplace(to_lower(slot_desc->col_name()) + "+" + data_type_str + is_null_str,
355
844k
                          slot_desc);
356
844k
    }
357
358
120k
    for (const auto& t_index : tschema.indexes) {
359
120k
        std::unordered_map<std::string, int32_t> index_slots_map;
360
120k
        auto* index = _obj_pool.add(new OlapTableIndexSchema());
361
120k
        index->index_id = t_index.id;
362
120k
        index->schema_hash = t_index.schema_hash;
363
120k
        if (t_index.__isset.row_binlog_id) {
364
120k
            index->row_binlog_id = t_index.row_binlog_id;
365
120k
        }
366
908k
        for (const auto& tcolumn_desc : t_index.columns_desc) {
367
908k
            if (_unique_key_update_mode != UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS ||
368
908k
                _partial_update_input_columns.contains(tcolumn_desc.column_name)) {
369
847k
                std::string is_null_str = tcolumn_desc.is_allow_null ? "true" : "false";
370
847k
                std::string data_type_str =
371
847k
                        std::to_string(int64_t(thrift_to_type(tcolumn_desc.column_type.type)));
372
847k
                auto it = slots_map.find(to_lower(tcolumn_desc.column_name) + "+" + data_type_str +
373
847k
                                         is_null_str);
374
847k
                if (it == slots_map.end()) {
375
0
                    std::stringstream ss;
376
0
                    ss << tschema;
377
0
                    std::string keys {};
378
0
                    for (const auto& [key, _] : slots_map) {
379
0
                        keys += fmt::format("{},", key);
380
0
                    }
381
0
                    LOG_EVERY_SECOND(WARNING) << fmt::format(
382
0
                            "[OlapTableSchemaParam::init(const TOlapTableSchemaParam& tschema)]: "
383
0
                            "unknown index column, column={}, type={}, data_type_str={}, "
384
0
                            "is_null_str={}, slots_map.keys()=[{}], {}\ntschema={}",
385
0
                            tcolumn_desc.column_name, tcolumn_desc.column_type.type, data_type_str,
386
0
                            is_null_str, keys, debug_string(), ss.str());
387
0
                    return Status::InternalError("unknown index column, column={}, type={}",
388
0
                                                 tcolumn_desc.column_name,
389
0
                                                 tcolumn_desc.column_type.type);
390
0
                }
391
847k
                index->slots.emplace_back(it->second);
392
847k
            }
393
908k
            index_slots_map.emplace(to_lower(tcolumn_desc.column_name), tcolumn_desc.col_unique_id);
394
908k
            TabletColumn* tc = _obj_pool.add(new TabletColumn());
395
908k
            tc->init_from_thrift(tcolumn_desc);
396
908k
            index->columns.emplace_back(tc);
397
908k
        }
398
120k
        if (t_index.__isset.indexes_desc) {
399
119k
            for (const auto& tindex_desc : t_index.indexes_desc) {
400
15.1k
                std::vector<int32_t> column_unique_ids(tindex_desc.columns.size());
401
30.2k
                for (size_t i = 0; i < tindex_desc.columns.size(); i++) {
402
15.1k
                    auto it = index_slots_map.find(to_lower(tindex_desc.columns[i]));
403
15.1k
                    if (it != index_slots_map.end()) {
404
15.1k
                        column_unique_ids[i] = it->second;
405
15.1k
                    }
406
15.1k
                }
407
15.1k
                TabletIndex* ti = _obj_pool.add(new TabletIndex());
408
15.1k
                ti->init_from_thrift(tindex_desc, column_unique_ids);
409
15.1k
                index->indexes.emplace_back(ti);
410
15.1k
            }
411
119k
        }
412
120k
        if (t_index.__isset.where_clause) {
413
99
            RETURN_IF_ERROR(VExpr::create_expr_tree(t_index.where_clause, index->where_clause));
414
99
        }
415
120k
        _indexes.emplace_back(index);
416
120k
    }
417
418
117k
    if (tschema.__isset.row_binlog_index_schema) {
419
4
        const auto& t_index = tschema.row_binlog_index_schema;
420
4
        auto* index = _obj_pool.add(new OlapTableIndexSchema());
421
4
        index->index_id = t_index.id;
422
4
        index->schema_hash = t_index.schema_hash;
423
4
        if (t_index.__isset.row_binlog_id) {
424
0
            index->row_binlog_id = t_index.row_binlog_id;
425
0
        }
426
14
        for (const auto& tcolumn_desc : t_index.columns_desc) {
427
14
            TabletColumn* tc = _obj_pool.add(new TabletColumn());
428
14
            tc->init_from_thrift(tcolumn_desc);
429
14
            index->columns.emplace_back(tc);
430
14
        }
431
4
        _row_binlog_index_schema = index;
432
4
    }
433
434
117k
    std::sort(_indexes.begin(), _indexes.end(),
435
117k
              [](const OlapTableIndexSchema* lhs, const OlapTableIndexSchema* rhs) {
436
6.20k
                  return lhs->index_id < rhs->index_id;
437
6.20k
              });
438
117k
    return Status::OK();
439
117k
}
440
441
53.0k
void OlapTableSchemaParam::to_protobuf(POlapTableSchemaParam* pschema) const {
442
53.0k
    pschema->set_db_id(_db_id);
443
53.0k
    pschema->set_table_id(_table_id);
444
53.0k
    pschema->set_version(_version);
445
53.0k
    pschema->set_unique_key_update_mode(_unique_key_update_mode);
446
53.0k
    if (_unique_key_update_mode == UniqueKeyUpdateModePB::UPDATE_FIXED_COLUMNS) {
447
        // for backward compatibility
448
6.08k
        pschema->set_partial_update(true);
449
6.08k
    }
450
53.0k
    pschema->set_partial_update_new_key_policy(_partial_update_new_row_policy);
451
53.0k
    pschema->set_is_strict_mode(_is_strict_mode);
452
53.0k
    pschema->set_auto_increment_column(_auto_increment_column);
453
53.0k
    pschema->set_auto_increment_column_unique_id(_auto_increment_column_unique_id);
454
53.0k
    pschema->set_timestamp_ms(_timestamp_ms);
455
53.0k
    pschema->set_timezone(_timezone);
456
53.0k
    pschema->set_nano_seconds(_nano_seconds);
457
53.0k
    pschema->set_sequence_map_col_unique_id(_sequence_map_col_uid);
458
53.0k
    pschema->set_row_ttl_source_column_unique_id(_row_ttl_source_column_uid);
459
53.0k
    if (_row_ttl_source_column != nullptr) {
460
0
        _row_ttl_source_column->to_schema_pb(pschema->mutable_row_ttl_source_column());
461
0
    }
462
53.0k
    for (auto col : _partial_update_input_columns) {
463
27.4k
        *pschema->add_partial_update_input_columns() = col;
464
27.4k
    }
465
53.0k
    _tuple_desc->to_protobuf(pschema->mutable_tuple_desc());
466
385k
    for (auto* slot : _tuple_desc->slots()) {
467
385k
        slot->to_protobuf(pschema->add_slot_descs());
468
385k
    }
469
54.2k
    for (auto* index : _indexes) {
470
54.2k
        index->to_protobuf(pschema->add_indexes());
471
54.2k
    }
472
53.0k
    if (_row_binlog_index_schema != nullptr) {
473
0
        _row_binlog_index_schema->to_protobuf(pschema->mutable_row_binlog_index_schema());
474
0
    }
475
53.0k
}
476
477
0
std::string OlapTableSchemaParam::debug_string() const {
478
0
    std::stringstream ss;
479
0
    ss << "tuple_desc=" << _tuple_desc->debug_string();
480
0
    return ss.str();
481
0
}
482
483
VOlapTablePartitionParam::VOlapTablePartitionParam(std::shared_ptr<OlapTableSchemaParam>& schema,
484
                                                   const TOlapTablePartitionParam& t_param)
485
59.2k
        : _schema(schema),
486
59.2k
          _t_param(t_param),
487
59.2k
          _slots(_schema->tuple_desc()->slots()),
488
59.2k
          _mem_tracker(std::make_unique<MemTracker>("OlapTablePartitionParam")),
489
59.2k
          _part_type(t_param.partition_type) {
490
59.2k
    if (t_param.__isset.enable_automatic_partition && t_param.enable_automatic_partition) {
491
293
        _is_auto_partition = true;
492
293
        auto size = t_param.partition_function_exprs.size();
493
293
        _part_func_ctx.resize(size);
494
293
        _partition_function.resize(size);
495
18.4E
        DCHECK((t_param.partition_type == TPartitionType::RANGE_PARTITIONED && size == 1) ||
496
18.4E
               (t_param.partition_type == TPartitionType::LIST_PARTITIONED && size >= 1))
497
18.4E
                << "now support only 1 partition column for auto range partitions. "
498
18.4E
                << t_param.partition_type << " " << size;
499
600
        for (int i = 0; i < size; ++i) {
500
307
            Status st =
501
307
                    VExpr::create_expr_tree(t_param.partition_function_exprs[i], _part_func_ctx[i]);
502
307
            if (!st.ok()) {
503
0
                throw Exception(Status::InternalError("Partition function expr is not valid"),
504
0
                                "Partition function expr is not valid");
505
0
            }
506
307
            _partition_function[i] = _part_func_ctx[i]->root();
507
307
        }
508
293
    }
509
510
59.2k
    if (t_param.__isset.enable_auto_detect_overwrite && t_param.enable_auto_detect_overwrite) {
511
36
        _is_auto_detect_overwrite = true;
512
36
        DCHECK(t_param.__isset.overwrite_group_id);
513
36
        _overwrite_group_id = t_param.overwrite_group_id;
514
36
    }
515
516
59.2k
    if (t_param.__isset.master_address) {
517
40
        _master_address = std::make_shared<TNetworkAddress>(t_param.master_address);
518
40
    }
519
520
59.2k
    if (_is_auto_partition) {
521
        // the nullable mode depends on partition_exprs. not column slots. so use them.
522
18.4E
        DCHECK(_partition_function.size() <= _slots.size())
523
18.4E
                << _partition_function.size() << ", " << _slots.size();
524
525
        // suppose (k0, [k1], [k2]), so get [k1, 0], [k2, 1]
526
295
        std::map<std::string, int> partition_slots_map; // name to idx in part_exprs
527
601
        for (size_t i = 0; i < t_param.partition_columns.size(); i++) {
528
306
            partition_slots_map.emplace(t_param.partition_columns[i], i);
529
306
        }
530
531
        // here we rely on the same order and number of the _part_funcs and _slots in the prefix
532
        // _part_block contains all slots of table.
533
1.11k
        for (auto* slot : _slots) {
534
            // try to replace with partition expr.
535
1.11k
            if (auto it = partition_slots_map.find(slot->col_name());
536
1.11k
                it != partition_slots_map.end()) { // it's a partition column slot
537
307
                auto& expr_type = _partition_function[it->second]->data_type();
538
307
                _partition_block.insert({expr_type->create_column(), expr_type, slot->col_name()});
539
805
            } else {
540
805
                _partition_block.insert({slot->get_empty_mutable_column(),
541
805
                                         slot->get_data_type_ptr(), slot->col_name()});
542
805
            }
543
1.11k
        }
544
18.4E
        VLOG_TRACE << _partition_block.dump_structure();
545
58.9k
    } else {
546
        // we insert all. but not all will be used. it will controlled by _partition_slot_locs
547
394k
        for (auto* slot : _slots) {
548
394k
            _partition_block.insert({slot->get_empty_mutable_column(), slot->get_data_type_ptr(),
549
394k
                                     slot->col_name()});
550
394k
        }
551
58.9k
    }
552
59.2k
}
553
554
59.4k
VOlapTablePartitionParam::~VOlapTablePartitionParam() {
555
59.4k
    _mem_tracker->release(_mem_usage);
556
59.4k
}
557
558
58.8k
Status VOlapTablePartitionParam::init() {
559
58.8k
    std::vector<std::string> slot_column_names;
560
395k
    for (auto* slot_desc : _schema->tuple_desc()->slots()) {
561
395k
        slot_column_names.emplace_back(slot_desc->col_name());
562
395k
    }
563
564
58.8k
    auto find_slot_locs = [&slot_column_names](const std::string& slot_name,
565
58.8k
                                               std::vector<uint16_t>& locs,
566
90.8k
                                               const std::string& column_type) {
567
90.8k
        auto it = std::find(slot_column_names.begin(), slot_column_names.end(), slot_name);
568
90.8k
        if (it == slot_column_names.end()) {
569
0
            return Status::InternalError("{} column not found, column ={}", column_type, slot_name);
570
0
        }
571
90.8k
        locs.emplace_back(it - slot_column_names.begin());
572
90.8k
        return Status::OK();
573
90.8k
    };
574
575
    // here we find the partition columns. others maybe non-partition columns/special columns.
576
58.8k
    if (_t_param.__isset.partition_columns) {
577
7.76k
        for (auto& part_col : _t_param.partition_columns) {
578
7.76k
            RETURN_IF_ERROR(find_slot_locs(part_col, _partition_slot_locs, "partition"));
579
7.76k
        }
580
7.61k
    }
581
582
58.8k
    _partitions_map = std::make_unique<
583
58.8k
            std::map<BlockRowWithIndicator, VOlapTablePartition*, VOlapTablePartKeyComparator>>(
584
58.8k
            VOlapTablePartKeyComparator(_partition_slot_locs, _transformed_slot_locs));
585
58.9k
    if (_t_param.__isset.distributed_columns) {
586
83.0k
        for (auto& col : _t_param.distributed_columns) {
587
83.0k
            RETURN_IF_ERROR(find_slot_locs(col, _distributed_slot_locs, "distributed"));
588
83.0k
        }
589
58.9k
    }
590
591
    // for both auto/non-auto partition table.
592
58.8k
    _is_in_partition = _part_type == TPartitionType::type::LIST_PARTITIONED;
593
594
    // initial partitions. if meet dummy partitions only for open BE nodes, not generate key of them for finding
595
74.3k
    for (const auto& t_part : _t_param.partitions) {
596
74.3k
        VOlapTablePartition* part = nullptr;
597
74.3k
        RETURN_IF_ERROR(generate_partition_from(t_part, part));
598
74.3k
        _partitions.emplace_back(part);
599
600
74.3k
        if (!_t_param.partitions_is_fake) {
601
74.3k
            if (_is_in_partition) {
602
8.17k
                for (auto& in_key : part->in_keys) {
603
8.17k
                    _partitions_map->emplace(std::tuple {in_key.first, in_key.second, false}, part);
604
8.17k
                }
605
69.1k
            } else {
606
69.1k
                _partitions_map->emplace(
607
69.1k
                        std::tuple {part->end_key.first, part->end_key.second, false}, part);
608
69.1k
            }
609
74.3k
        }
610
74.3k
    }
611
612
58.8k
    _mem_usage = _partition_block.allocated_bytes();
613
58.8k
    _mem_tracker->consume(_mem_usage);
614
58.8k
    return Status::OK();
615
58.8k
}
616
617
bool VOlapTablePartitionParam::_part_contains(VOlapTablePartition* part,
618
38.3M
                                              BlockRowWithIndicator key) const {
619
38.3M
    VOlapTablePartKeyComparator comparator(_partition_slot_locs, _transformed_slot_locs);
620
    // we have used upper_bound to find to ensure key < part.right and this part is closest(right - key is min)
621
    // now we only have to check (key >= part.left). the comparator(a,b) means a < b, so we use anti
622
38.3M
    return part->start_key.second == -1 /* spj: start_key.second == -1 means only single partition*/
623
38.3M
           || !comparator(key, std::tuple {part->start_key.first, part->start_key.second, false});
624
38.3M
}
625
626
// insert value into _partition_block's column
627
// NOLINTBEGIN(readability-function-size)
628
43.8k
static Status _create_partition_key(const TExprNode& t_expr, BlockRow* part_key, uint16_t pos) {
629
43.8k
    auto column = std::move(*part_key->first->get_by_position(pos).column).mutate();
630
43.8k
    switch (t_expr.node_type) {
631
27.9k
    case TExprNodeType::DATE_LITERAL: {
632
27.9k
        auto primitive_type =
633
27.9k
                DataTypeFactory::instance().create_data_type(t_expr.type)->get_primitive_type();
634
27.9k
        if (primitive_type == TYPE_DATEV2) {
635
21.3k
            DateV2Value<DateV2ValueType> dt;
636
21.3k
            CastParameters params;
637
21.3k
            if (!CastToDateV2::from_string_strict_mode<DatelikeParseMode::STRICT>(
638
21.3k
                        {t_expr.date_literal.value.c_str(), t_expr.date_literal.value.size()}, dt,
639
21.3k
                        nullptr, params)) {
640
0
                std::stringstream ss;
641
0
                ss << "invalid date literal in partition column, date=" << t_expr.date_literal;
642
0
                return Status::InternalError(ss.str());
643
0
            }
644
21.3k
            column->insert_data(reinterpret_cast<const char*>(&dt), 0);
645
21.3k
        } else if (primitive_type == TYPE_DATETIMEV2) {
646
5.85k
            DateV2Value<DateTimeV2ValueType> dt;
647
5.85k
            const int32_t scale =
648
5.85k
                    t_expr.type.types.empty() ? -1 : t_expr.type.types.front().scalar_type.scale;
649
5.85k
            CastParameters params;
650
5.85k
            if (!CastToDatetimeV2::from_string_strict_mode<DatelikeParseMode::STRICT>(
651
5.85k
                        {t_expr.date_literal.value.c_str(), t_expr.date_literal.value.size()}, dt,
652
5.85k
                        nullptr, scale, params)) {
653
0
                std::stringstream ss;
654
0
                ss << "invalid date literal in partition column, date=" << t_expr.date_literal;
655
0
                return Status::InternalError(ss.str());
656
0
            }
657
5.85k
            column->insert_data(reinterpret_cast<const char*>(&dt), 0);
658
5.85k
        } else if (primitive_type == TYPE_TIMESTAMPTZ) {
659
409
            TimestampTzValue res;
660
409
            CastParameters params {.status = Status::OK(), .is_strict = true};
661
409
            const int32_t scale =
662
409
                    t_expr.type.types.empty() ? -1 : t_expr.type.types.front().scalar_type.scale;
663
409
            if (!CastToTimestampTz::from_string(
664
409
                        {t_expr.date_literal.value.c_str(), t_expr.date_literal.value.size()}, res,
665
409
                        params, nullptr, scale)) [[unlikely]] {
666
0
                std::stringstream ss;
667
0
                ss << "invalid timestamptz literal in partition column, value="
668
0
                   << t_expr.date_literal;
669
0
                return Status::InternalError(ss.str());
670
0
            }
671
409
            column->insert_data(reinterpret_cast<const char*>(&res), 0);
672
409
        } else {
673
240
            VecDateTimeValue dt;
674
240
            CastParameters params;
675
240
            if (!CastToDateOrDatetime::from_string_strict_mode<DatelikeParseMode::STRICT,
676
240
                                                               DatelikeTargetType::DATE_TIME>(
677
240
                        {t_expr.date_literal.value.c_str(), t_expr.date_literal.value.size()}, dt,
678
240
                        nullptr, params)) {
679
0
                std::stringstream ss;
680
0
                ss << "invalid date literal in partition column, date=" << t_expr.date_literal;
681
0
                return Status::InternalError(ss.str());
682
0
            }
683
240
            if (primitive_type == TYPE_DATE) {
684
120
                dt.cast_to_date();
685
120
            }
686
240
            column->insert_data(reinterpret_cast<const char*>(&dt), 0);
687
240
        }
688
27.9k
        break;
689
27.9k
    }
690
27.9k
    case TExprNodeType::INT_LITERAL: {
691
13.1k
        switch (t_expr.type.types[0].scalar_type.type) {
692
2.37k
        case TPrimitiveType::TINYINT: {
693
2.37k
            auto value = cast_set<int8_t>(t_expr.int_literal.value);
694
2.37k
            column->insert_data(reinterpret_cast<const char*>(&value), 0);
695
2.37k
            break;
696
0
        }
697
384
        case TPrimitiveType::SMALLINT: {
698
384
            auto value = cast_set<int16_t>(t_expr.int_literal.value);
699
384
            column->insert_data(reinterpret_cast<const char*>(&value), 0);
700
384
            break;
701
0
        }
702
9.78k
        case TPrimitiveType::INT: {
703
9.78k
            auto value = cast_set<int32_t>(t_expr.int_literal.value);
704
9.78k
            column->insert_data(reinterpret_cast<const char*>(&value), 0);
705
9.78k
            break;
706
0
        }
707
593
        default:
708
593
            int64_t value = t_expr.int_literal.value;
709
593
            column->insert_data(reinterpret_cast<const char*>(&value), 0);
710
13.1k
        }
711
13.0k
        break;
712
13.1k
    }
713
13.0k
    case TExprNodeType::LARGE_INT_LITERAL: {
714
129
        StringParser::ParseResult parse_result = StringParser::PARSE_SUCCESS;
715
129
        auto value = StringParser::string_to_int<__int128>(t_expr.large_int_literal.value.c_str(),
716
129
                                                           t_expr.large_int_literal.value.size(),
717
129
                                                           &parse_result);
718
129
        if (parse_result != StringParser::PARSE_SUCCESS) {
719
0
            value = MAX_INT128;
720
0
        }
721
129
        column->insert_data(reinterpret_cast<const char*>(&value), 0);
722
129
        break;
723
13.1k
    }
724
2.47k
    case TExprNodeType::STRING_LITERAL: {
725
2.47k
        size_t len = t_expr.string_literal.value.size();
726
2.47k
        const char* str_val = t_expr.string_literal.value.c_str();
727
2.47k
        column->insert_data(str_val, len);
728
2.47k
        break;
729
13.1k
    }
730
23
    case TExprNodeType::BOOL_LITERAL: {
731
23
        column->insert_data(reinterpret_cast<const char*>(&t_expr.bool_literal.value), 0);
732
23
        break;
733
13.1k
    }
734
123
    case TExprNodeType::NULL_LITERAL: {
735
        // insert a null literal
736
123
        if (!column->is_nullable()) {
737
            // https://github.com/apache/doris/pull/39449 have forbid this cause. always add this check as protective measures
738
0
            return Status::InternalError("The column {} is not null, can't insert into NULL value.",
739
0
                                         part_key->first->get_by_position(pos).name);
740
0
        }
741
123
        column->insert_data(nullptr, 0);
742
123
        break;
743
123
    }
744
0
    default: {
745
0
        return Status::InternalError("unsupported partition column node type, type={}",
746
0
                                     t_expr.node_type);
747
123
    }
748
43.8k
    }
749
43.8k
    part_key->second = cast_set<int32_t>(column->size() - 1);
750
43.8k
    return Status::OK();
751
43.8k
}
752
// NOLINTEND(readability-function-size)
753
754
Status VOlapTablePartitionParam::_create_partition_keys(const std::vector<TExprNode>& t_exprs,
755
42.9k
                                                        BlockRow* part_key) {
756
86.8k
    for (int i = 0; i < t_exprs.size(); i++) {
757
43.8k
        RETURN_IF_ERROR(_create_partition_key(t_exprs[i], part_key, _partition_slot_locs[i]));
758
43.8k
    }
759
42.9k
    return Status::OK();
760
42.9k
}
761
762
Status VOlapTablePartitionParam::generate_partition_from(const TOlapTablePartition& t_part,
763
74.6k
                                                         VOlapTablePartition*& part_result) {
764
74.6k
    DCHECK(part_result == nullptr);
765
    // here we set the default value of partition bounds first! if it doesn't have some key, it will be -1.
766
74.6k
    part_result = _obj_pool.add(new VOlapTablePartition(&_partition_block));
767
74.6k
    part_result->id = t_part.id;
768
74.6k
    part_result->is_mutable = t_part.is_mutable;
769
74.6k
    if (t_part.__isset.load_tablet_idx) {
770
11.8k
        part_result->load_tablet_idx = t_part.load_tablet_idx;
771
11.8k
    }
772
74.6k
    if (t_part.__isset.bucket_be_id) {
773
9.27k
        part_result->bucket_be_id = t_part.bucket_be_id;
774
9.27k
    }
775
74.6k
    if (t_part.__isset.local_bucket_seqs) {
776
9.22k
        part_result->local_bucket_seqs = t_part.local_bucket_seqs;
777
9.22k
    }
778
779
74.6k
    if (_is_in_partition) {
780
8.40k
        for (const auto& keys : t_part.in_keys) {
781
8.40k
            RETURN_IF_ERROR(_create_partition_keys(
782
8.40k
                    keys, &part_result->in_keys.emplace_back(&_partition_block, -1)));
783
8.40k
        }
784
5.46k
        if (t_part.__isset.is_default_partition && t_part.is_default_partition &&
785
5.46k
            _default_partition == nullptr) {
786
19
            _default_partition = part_result;
787
19
        }
788
69.1k
    } else { // range
789
69.1k
        if (t_part.__isset.start_keys) {
790
16.3k
            RETURN_IF_ERROR(_create_partition_keys(t_part.start_keys, &part_result->start_key));
791
16.3k
        }
792
        // we generate the right bound but not insert into partition map
793
69.1k
        if (t_part.__isset.end_keys) {
794
17.6k
            RETURN_IF_ERROR(_create_partition_keys(t_part.end_keys, &part_result->end_key));
795
17.6k
        }
796
69.1k
    }
797
798
74.6k
    part_result->num_buckets = t_part.num_buckets;
799
74.6k
    auto num_indexes = _schema->indexes().size();
800
74.6k
    if (t_part.indexes.size() != num_indexes) {
801
0
        return Status::InternalError(
802
0
                "number of partition's index is not equal with schema's"
803
0
                ", num_part_indexes={}, num_schema_indexes={}",
804
0
                t_part.indexes.size(), num_indexes);
805
0
    }
806
74.6k
    part_result->indexes = t_part.indexes;
807
74.6k
    std::sort(part_result->indexes.begin(), part_result->indexes.end(),
808
74.6k
              [](const OlapTableIndexTablets& lhs, const OlapTableIndexTablets& rhs) {
809
5.33k
                  return lhs.index_id < rhs.index_id;
810
5.33k
              });
811
    // check index
812
151k
    for (int j = 0; j < num_indexes; ++j) {
813
77.0k
        if (part_result->indexes[j].index_id != _schema->indexes()[j]->index_id) {
814
0
            return Status::InternalError(
815
0
                    "partition's index is not equal with schema's"
816
0
                    ", part_index={}, schema_index={}",
817
0
                    part_result->indexes[j].index_id, _schema->indexes()[j]->index_id);
818
0
        }
819
77.0k
    }
820
74.7k
    if (t_part.__isset.total_replica_num) {
821
74.7k
        part_result->total_replica_num = t_part.total_replica_num;
822
74.7k
    }
823
74.7k
    if (t_part.__isset.load_required_replica_num) {
824
74.7k
        part_result->load_required_replica_num = t_part.load_required_replica_num;
825
74.7k
    }
826
74.6k
    if (t_part.__isset.tablet_version_gap_backends) {
827
0
        for (const auto& [tablet_id, backend_ids] : t_part.tablet_version_gap_backends) {
828
0
            auto& gap_set = part_result->tablet_version_gap_backends[tablet_id];
829
0
            for (auto backend_id : backend_ids) {
830
0
                gap_set.insert(backend_id);
831
0
            }
832
0
        }
833
0
    }
834
74.6k
    return Status::OK();
835
74.6k
}
836
837
Status VOlapTablePartitionParam::add_partitions(
838
174
        const std::vector<TOlapTablePartition>& partitions) {
839
360
    for (const auto& t_part : partitions) {
840
360
        auto* part = _obj_pool.add(new VOlapTablePartition(&_partition_block));
841
360
        part->id = t_part.id;
842
360
        part->is_mutable = t_part.is_mutable;
843
844
        // we dont pass right keys when it's MAX_VALUE. so there's possibility we only have start_key but not end_key
845
        // range partition
846
360
        if (t_part.__isset.start_keys) {
847
154
            RETURN_IF_ERROR(_create_partition_keys(t_part.start_keys, &part->start_key));
848
154
        }
849
360
        if (t_part.__isset.end_keys) {
850
153
            RETURN_IF_ERROR(_create_partition_keys(t_part.end_keys, &part->end_key));
851
153
        }
852
        // list partition - we only set 1 value in 1 partition for new created ones
853
360
        if (t_part.__isset.in_keys) {
854
203
            for (const auto& keys : t_part.in_keys) {
855
203
                RETURN_IF_ERROR(_create_partition_keys(
856
203
                        keys, &part->in_keys.emplace_back(&_partition_block, -1)));
857
203
            }
858
203
            if (t_part.__isset.is_default_partition && t_part.is_default_partition) {
859
0
                _default_partition = part;
860
0
            }
861
203
        }
862
863
360
        part->num_buckets = t_part.num_buckets;
864
360
        if (t_part.__isset.load_tablet_idx) {
865
0
            part->load_tablet_idx = t_part.load_tablet_idx;
866
0
        }
867
360
        if (t_part.__isset.bucket_be_id) {
868
0
            part->bucket_be_id = t_part.bucket_be_id;
869
0
        }
870
360
        if (t_part.__isset.local_bucket_seqs) {
871
0
            part->local_bucket_seqs = t_part.local_bucket_seqs;
872
0
        }
873
360
        auto num_indexes = _schema->indexes().size();
874
360
        if (t_part.indexes.size() != num_indexes) {
875
0
            return Status::InternalError(
876
0
                    "number of partition's index is not equal with schema's"
877
0
                    ", num_part_indexes={}, num_schema_indexes={}",
878
0
                    t_part.indexes.size(), num_indexes);
879
0
        }
880
360
        part->indexes = t_part.indexes;
881
360
        std::sort(part->indexes.begin(), part->indexes.end(),
882
360
                  [](const OlapTableIndexTablets& lhs, const OlapTableIndexTablets& rhs) {
883
0
                      return lhs.index_id < rhs.index_id;
884
0
                  });
885
        // check index
886
720
        for (int j = 0; j < num_indexes; ++j) {
887
360
            if (part->indexes[j].index_id != _schema->indexes()[j]->index_id) {
888
0
                return Status::InternalError(
889
0
                        "partition's index is not equal with schema's"
890
0
                        ", part_index={}, schema_index={}",
891
0
                        part->indexes[j].index_id, _schema->indexes()[j]->index_id);
892
0
            }
893
360
        }
894
360
        _partitions.emplace_back(part);
895
        // after _creating_partiton_keys
896
360
        if (_is_in_partition) {
897
203
            for (auto& in_key : part->in_keys) {
898
203
                _partitions_map->emplace(std::tuple {in_key.first, in_key.second, false}, part);
899
203
            }
900
203
        } else {
901
157
            _partitions_map->emplace(std::tuple {part->end_key.first, part->end_key.second, false},
902
157
                                     part);
903
157
        }
904
360
    }
905
906
174
    return Status::OK();
907
174
}
908
909
Status VOlapTablePartitionParam::replace_partitions(
910
        std::vector<int64_t>& old_partition_ids,
911
20
        const std::vector<TOlapTablePartition>& new_partitions) {
912
    // remove old replaced partitions
913
20
    DCHECK(old_partition_ids.size() == new_partitions.size());
914
915
    // init and add new partitions. insert into _partitions
916
52
    for (int i = 0; i < new_partitions.size(); i++) {
917
32
        const auto& t_part = new_partitions[i];
918
        // pair old_partition_ids and new_partitions one by one. TODO: sort to opt performance
919
32
        VOlapTablePartition* old_part = nullptr;
920
32
        auto old_part_id = old_partition_ids[i];
921
32
        if (auto it = std::find_if(
922
32
                    _partitions.begin(), _partitions.end(),
923
74
                    [=](const VOlapTablePartition* lhs) { return lhs->id == old_part_id; });
924
32
            it != _partitions.end()) {
925
32
            old_part = *it;
926
32
        } else {
927
0
            return Status::InternalError("Cannot find old tablet {} in replacing", old_part_id);
928
0
        }
929
930
32
        auto* part = _obj_pool.add(new VOlapTablePartition(&_partition_block));
931
32
        part->id = t_part.id;
932
32
        part->is_mutable = t_part.is_mutable;
933
934
        /// just substitute directly. no need to remove and reinsert keys.
935
        // range partition
936
32
        part->start_key = std::move(old_part->start_key);
937
32
        part->end_key = std::move(old_part->end_key);
938
        // list partition
939
32
        part->in_keys = std::move(old_part->in_keys);
940
32
        if (t_part.__isset.is_default_partition && t_part.is_default_partition) {
941
0
            _default_partition = part;
942
0
        }
943
944
32
        part->num_buckets = t_part.num_buckets;
945
32
        if (t_part.__isset.load_tablet_idx) {
946
0
            part->load_tablet_idx = t_part.load_tablet_idx;
947
0
        }
948
32
        if (t_part.__isset.bucket_be_id) {
949
0
            part->bucket_be_id = t_part.bucket_be_id;
950
0
        }
951
32
        if (t_part.__isset.local_bucket_seqs) {
952
0
            part->local_bucket_seqs = t_part.local_bucket_seqs;
953
0
        }
954
32
        auto num_indexes = _schema->indexes().size();
955
32
        if (t_part.indexes.size() != num_indexes) {
956
0
            return Status::InternalError(
957
0
                    "number of partition's index is not equal with schema's"
958
0
                    ", num_part_indexes={}, num_schema_indexes={}",
959
0
                    t_part.indexes.size(), num_indexes);
960
0
        }
961
32
        part->indexes = t_part.indexes;
962
32
        std::sort(part->indexes.begin(), part->indexes.end(),
963
32
                  [](const OlapTableIndexTablets& lhs, const OlapTableIndexTablets& rhs) {
964
0
                      return lhs.index_id < rhs.index_id;
965
0
                  });
966
        // check index
967
64
        for (int j = 0; j < num_indexes; ++j) {
968
32
            if (part->indexes[j].index_id != _schema->indexes()[j]->index_id) {
969
0
                return Status::InternalError(
970
0
                        "partition's index is not equal with schema's"
971
0
                        ", part_index={}, schema_index={}",
972
0
                        part->indexes[j].index_id, _schema->indexes()[j]->index_id);
973
0
            }
974
32
        }
975
976
        // add new partitions with new id.
977
32
        _partitions.emplace_back(part);
978
32
        VLOG_NOTICE << "params add new partition " << part->id;
979
980
        // replace items in _partition_maps
981
32
        if (_is_in_partition) {
982
44
            for (auto& in_key : part->in_keys) {
983
44
                (*_partitions_map)[std::tuple {in_key.first, in_key.second, false}] = part;
984
44
            }
985
21
        } else {
986
11
            (*_partitions_map)[std::tuple {part->end_key.first, part->end_key.second, false}] =
987
11
                    part;
988
11
        }
989
32
    }
990
    // remove old partitions by id
991
20
    std::ranges::sort(old_partition_ids);
992
129
    for (auto it = _partitions.begin(); it != _partitions.end();) {
993
109
        if (std::ranges::binary_search(old_partition_ids, (*it)->id)) {
994
32
            it = _partitions.erase(it);
995
77
        } else {
996
77
            it++;
997
77
        }
998
109
    }
999
1000
20
    return Status::OK();
1001
20
}
1002
1003
} // namespace doris