Coverage Report

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