YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/common/schema.cc
Line
Count
Source (jump to first uncovered line)
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
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include "yb/common/schema.h"
34
35
#include <algorithm>
36
#include <set>
37
38
#include "yb/common/common.pb.h"
39
#include "yb/common/key_encoder.h"
40
#include "yb/common/ql_type.h"
41
#include "yb/common/row.h"
42
43
#include "yb/gutil/casts.h"
44
#include "yb/gutil/map-util.h"
45
#include "yb/gutil/stringprintf.h"
46
#include "yb/gutil/strings/join.h"
47
48
#include "yb/util/malloc.h"
49
#include "yb/util/result.h"
50
#include "yb/util/status_format.h"
51
#include "yb/util/status_log.h"
52
53
namespace yb {
54
55
using std::shared_ptr;
56
using std::set;
57
using std::unordered_map;
58
using std::unordered_set;
59
60
// ------------------------------------------------------------------------------------------------
61
// ColumnSchema
62
// ------------------------------------------------------------------------------------------------
63
64
ColumnSchema::ColumnSchema(std::string name,
65
                           DataType type,
66
                           bool is_nullable,
67
                           bool is_hash_key,
68
                           bool is_static,
69
                           bool is_counter,
70
                           int32_t order,
71
                           SortingType sorting_type,
72
                           int32_t pg_type_oid)
73
    : ColumnSchema(name, QLType::Create(type), is_nullable, is_hash_key, is_static, is_counter,
74
1.52k
                   order, sorting_type, pg_type_oid) {
75
1.52k
}
Unexecuted instantiation: _ZN2yb12ColumnSchemaC2ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_8DataTypeEbbbbiNS_11SortingTypeEi
_ZN2yb12ColumnSchemaC1ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_8DataTypeEbbbbiNS_11SortingTypeEi
Line
Count
Source
74
1.52k
                   order, sorting_type, pg_type_oid) {
75
1.52k
}
76
77
59.4M
const TypeInfo* ColumnSchema::type_info() const {
78
59.4M
  return type_->type_info();
79
59.4M
}
80
81
752k
bool ColumnSchema::CompTypeInfo(const ColumnSchema &a, const ColumnSchema &b) {
82
752k
  return a.type_info()->type() == b.type_info()->type();
83
752k
}
84
85
2
int ColumnSchema::Compare(const void *lhs, const void *rhs) const {
86
2
  return type_info()->Compare(lhs, rhs);
87
2
}
88
89
// Stringify the given cell. This just stringifies the cell contents,
90
// and doesn't include the column name or type.
91
0
std::string ColumnSchema::Stringify(const void *cell) const {
92
0
  std::string ret;
93
0
  type_info()->AppendDebugStringForValue(cell, &ret);
94
0
  return ret;
95
0
}
96
97
43
void ColumnSchema::DoDebugCellAppend(const void* cell, std::string* ret) const {
98
43
  ret->append(type_info()->name());
99
43
  ret->append(" ");
100
43
  ret->append(name_);
101
43
  ret->append("=");
102
43
  if (is_nullable_ && cell == nullptr) {
103
1
    ret->append("NULL");
104
42
  } else {
105
42
    type_info()->AppendDebugStringForValue(cell, ret);
106
42
  }
107
43
}
108
109
// TODO: include attributes_.ToString() -- need to fix unit tests
110
// first
111
530k
string ColumnSchema::ToString() const {
112
530k
  return strings::Substitute("$0[$1]",
113
530k
                             name_,
114
530k
                             TypeToString());
115
530k
}
116
117
530k
string ColumnSchema::TypeToString() const {
118
530k
  return strings::Substitute("$0 $1 $2",
119
530k
                             type_info()->name(),
120
278k
                             is_nullable_ ? "NULLABLE" : "NOT NULL",
121
375k
                             is_hash_key_ ? "PARTITION KEY" : "NOT A PARTITION KEY");
122
530k
}
123
124
3
size_t ColumnSchema::memory_footprint_excluding_this() const {
125
  // Rough approximation.
126
3
  return name_.capacity();
127
3
}
128
129
0
size_t ColumnSchema::memory_footprint_including_this() const {
130
0
  return malloc_usable_size(this) + memory_footprint_excluding_this();
131
0
}
132
133
// ------------------------------------------------------------------------------------------------
134
// TableProperties
135
// ------------------------------------------------------------------------------------------------
136
137
140M
void TableProperties::ToTablePropertiesPB(TablePropertiesPB *pb) const {
138
140M
  if (HasDefaultTimeToLive()) {
139
11.4k
    pb->set_default_time_to_live(default_time_to_live_);
140
11.4k
  }
141
140M
  pb->set_contain_counters(contain_counters_);
142
140M
  pb->set_is_transactional(is_transactional_);
143
140M
  pb->set_consistency_level(consistency_level_);
144
140M
  if (HasCopartitionTableId()) {
145
0
    pb->set_copartition_table_id(copartition_table_id_);
146
0
  }
147
140M
  pb->set_use_mangled_column_name(use_mangled_column_name_);
148
140M
  if (HasNumTablets()) {
149
96.3k
    pb->set_num_tablets(num_tablets_);
150
96.3k
  }
151
140M
  pb->set_is_ysql_catalog_table(is_ysql_catalog_table_);
152
140M
  pb->set_retain_delete_markers(retain_delete_markers_);
153
140M
}
154
155
1.34M
TableProperties TableProperties::FromTablePropertiesPB(const TablePropertiesPB& pb) {
156
1.34M
  TableProperties table_properties;
157
1.34M
  if (pb.has_default_time_to_live()) {
158
4.11k
    table_properties.SetDefaultTimeToLive(pb.default_time_to_live());
159
4.11k
  }
160
1.34M
  if (pb.has_contain_counters()) {
161
1.34M
    table_properties.SetContainCounters(pb.contain_counters());
162
1.34M
  }
163
1.34M
  if (pb.has_is_transactional()) {
164
1.34M
    table_properties.SetTransactional(pb.is_transactional());
165
1.34M
  }
166
1.34M
  if (pb.has_consistency_level()) {
167
1.34M
    table_properties.SetConsistencyLevel(pb.consistency_level());
168
1.34M
  }
169
1.34M
  if (pb.has_copartition_table_id()) {
170
0
    table_properties.SetCopartitionTableId(pb.copartition_table_id());
171
0
  }
172
1.34M
  if (pb.has_use_mangled_column_name()) {
173
1.34M
    table_properties.SetUseMangledColumnName(pb.use_mangled_column_name());
174
1.34M
  }
175
1.34M
  if (pb.has_num_tablets()) {
176
32.9k
    table_properties.SetNumTablets(pb.num_tablets());
177
32.9k
  }
178
1.34M
  if (pb.has_is_ysql_catalog_table()) {
179
1.34M
    table_properties.set_is_ysql_catalog_table(pb.is_ysql_catalog_table());
180
1.34M
  }
181
1.34M
  if (pb.has_retain_delete_markers()) {
182
1.34M
    table_properties.SetRetainDeleteMarkers(pb.retain_delete_markers());
183
1.34M
  }
184
1.34M
  return table_properties;
185
1.34M
}
186
187
7
void TableProperties::AlterFromTablePropertiesPB(const TablePropertiesPB& pb) {
188
7
  if (pb.has_default_time_to_live()) {
189
7
    SetDefaultTimeToLive(pb.default_time_to_live());
190
7
  }
191
7
  if (pb.has_is_transactional()) {
192
7
    SetTransactional(pb.is_transactional());
193
7
  }
194
7
  if (pb.has_consistency_level()) {
195
7
    SetConsistencyLevel(pb.consistency_level());
196
7
  }
197
7
  if (pb.has_copartition_table_id()) {
198
0
    SetCopartitionTableId(pb.copartition_table_id());
199
0
  }
200
7
  if (pb.has_use_mangled_column_name()) {
201
7
    SetUseMangledColumnName(pb.use_mangled_column_name());
202
7
  }
203
7
  if (pb.has_num_tablets()) {
204
0
    SetNumTablets(pb.num_tablets());
205
0
  }
206
7
  if (pb.has_is_ysql_catalog_table()) {
207
7
    set_is_ysql_catalog_table(pb.is_ysql_catalog_table());
208
7
  }
209
7
  if (pb.has_retain_delete_markers()) {
210
7
    SetRetainDeleteMarkers(pb.retain_delete_markers());
211
7
  }
212
7
}
213
214
42.9k
void TableProperties::Reset() {
215
42.9k
  default_time_to_live_ = kNoDefaultTtl;
216
42.9k
  contain_counters_ = false;
217
42.9k
  is_transactional_ = false;
218
42.9k
  consistency_level_ = YBConsistencyLevel::STRONG;
219
42.9k
  copartition_table_id_ = kNoCopartitionTableId;
220
42.9k
  use_mangled_column_name_ = false;
221
42.9k
  num_tablets_ = 0;
222
42.9k
  is_ysql_catalog_table_ = false;
223
42.9k
  retain_delete_markers_ = false;
224
42.9k
}
225
226
0
string TableProperties::ToString() const {
227
0
  std::string result("{ ");
228
0
  if (HasDefaultTimeToLive()) {
229
0
    result += Format("default_time_to_live: $0 ", default_time_to_live_);
230
0
  }
231
0
  result += Format("contain_counters: $0 is_transactional: $1 ",
232
0
                   contain_counters_, is_transactional_);
233
0
  if (HasCopartitionTableId()) {
234
0
    result += Format("copartition_table_id: $0 ", copartition_table_id_);
235
0
  }
236
0
  return result + Format(
237
0
      "consistency_level: $0 is_ysql_catalog_table: $1 }",
238
0
      consistency_level_,
239
0
      is_ysql_catalog_table_);
240
0
}
241
242
// ------------------------------------------------------------------------------------------------
243
// Schema
244
// ------------------------------------------------------------------------------------------------
245
246
Schema::Schema(const Schema& other)
247
  : // TODO: C++11 provides a single-arg constructor
248
    name_to_index_(10,
249
                   NameToIndexMap::hasher(),
250
                   NameToIndexMap::key_equal(),
251
1.72M
                   NameToIndexMapAllocator(&name_to_index_bytes_)) {
252
1.72M
  CopyFrom(other);
253
1.72M
}
254
255
Schema::Schema(const vector<ColumnSchema>& cols,
256
               size_t key_columns,
257
               const TableProperties& table_properties,
258
               const Uuid& cotable_id,
259
               const PgTableOid pgtable_id,
260
               const PgSchemaName pgschema_name)
261
  : // TODO: C++11 provides a single-arg constructor
262
    name_to_index_(10,
263
                   NameToIndexMap::hasher(),
264
                   NameToIndexMap::key_equal(),
265
310k
                   NameToIndexMapAllocator(&name_to_index_bytes_)) {
266
310k
  CHECK_OK(Reset(cols, key_columns, table_properties, cotable_id, pgtable_id, pgschema_name));
267
310k
}
268
269
Schema::Schema(const vector<ColumnSchema>& cols,
270
               const vector<ColumnId>& ids,
271
               size_t key_columns,
272
               const TableProperties& table_properties,
273
               const Uuid& cotable_id,
274
               const PgTableOid pgtable_id,
275
               const PgSchemaName pgschema_name)
276
  : // TODO: C++11 provides a single-arg constructor
277
    name_to_index_(10,
278
                   NameToIndexMap::hasher(),
279
                   NameToIndexMap::key_equal(),
280
211k
                   NameToIndexMapAllocator(&name_to_index_bytes_)) {
281
211k
  CHECK_OK(Reset(cols, ids, key_columns, table_properties, cotable_id, pgtable_id, pgschema_name));
282
211k
}
283
284
57.0k
Schema& Schema::operator=(const Schema& other) {
285
57.0k
  if (&other != this) {
286
57.0k
    CopyFrom(other);
287
57.0k
  }
288
57.0k
  return *this;
289
57.0k
}
290
291
1.77M
void Schema::CopyFrom(const Schema& other) {
292
1.77M
  num_key_columns_ = other.num_key_columns_;
293
1.77M
  num_hash_key_columns_ = other.num_hash_key_columns_;
294
1.77M
  cols_ = other.cols_;
295
1.77M
  col_ids_ = other.col_ids_;
296
1.77M
  col_offsets_ = other.col_offsets_;
297
1.77M
  id_to_index_ = other.id_to_index_;
298
299
  // We can't simply copy name_to_index_ since the GStringPiece keys
300
  // reference the other Schema's ColumnSchema objects.
301
1.77M
  name_to_index_.clear();
302
1.77M
  int i = 0;
303
11.4M
  for (const ColumnSchema &col : cols_) {
304
    // The map uses the 'name' string from within the ColumnSchema object.
305
11.4M
    name_to_index_[col.name()] = i++;
306
11.4M
  }
307
308
1.77M
  has_nullables_ = other.has_nullables_;
309
1.77M
  has_statics_ = other.has_statics_;
310
1.77M
  table_properties_ = other.table_properties_;
311
1.77M
  cotable_id_ = other.cotable_id_;
312
1.77M
  pgtable_id_ = other.pgtable_id_;
313
1.77M
  pgschema_name_ = other.pgschema_name_;
314
315
  // Schema cannot have both, cotable ID and pgtable ID.
316
1.77M
  DCHECK(cotable_id_.IsNil() || pgtable_id_ == 0);
317
1.77M
}
318
319
2
void Schema::swap(Schema& other) {
320
2
  std::swap(num_key_columns_, other.num_key_columns_);
321
2
  std::swap(num_hash_key_columns_, other.num_hash_key_columns_);
322
2
  cols_.swap(other.cols_);
323
2
  col_ids_.swap(other.col_ids_);
324
2
  col_offsets_.swap(other.col_offsets_);
325
2
  name_to_index_.swap(other.name_to_index_);
326
2
  id_to_index_.swap(other.id_to_index_);
327
2
  std::swap(has_nullables_, other.has_nullables_);
328
2
  std::swap(has_statics_, other.has_statics_);
329
2
  std::swap(table_properties_, other.table_properties_);
330
2
  std::swap(cotable_id_, other.cotable_id_);
331
2
  std::swap(pgtable_id_, other.pgtable_id_);
332
2
  std::swap(pgschema_name_, other.pgschema_name_);
333
334
  // Schema cannot have both, cotable ID or pgtable ID.
335
2
  DCHECK(cotable_id_.IsNil() || pgtable_id_ == 0);
336
2
}
337
338
17.4M
void Schema::ResetColumnIds(const vector<ColumnId>& ids) {
339
  // Initialize IDs mapping.
340
17.4M
  col_ids_ = ids;
341
17.4M
  id_to_index_.clear();
342
17.4M
  max_col_id_ = 0;
343
54.5M
  for (size_t i = 0; i < ids.size(); ++i) {
344
37.1M
    if (ids[i] > max_col_id_) {
345
35.6M
      max_col_id_ = ids[i];
346
35.6M
    }
347
37.1M
    id_to_index_.set(ids[i], narrow_cast<int>(i));
348
37.1M
  }
349
17.4M
}
350
351
Status Schema::Reset(const vector<ColumnSchema>& cols, size_t key_columns,
352
                     const TableProperties& table_properties,
353
                     const Uuid& cotable_id,
354
                     const PgTableOid pgtable_id,
355
312k
                     const PgSchemaName pgschema_name) {
356
312k
  return Reset(cols, {}, key_columns, table_properties, cotable_id, pgtable_id, pgschema_name);
357
312k
}
358
359
Status Schema::Reset(const vector<ColumnSchema>& cols,
360
                     const vector<ColumnId>& ids,
361
                     size_t key_columns,
362
                     const TableProperties& table_properties,
363
                     const Uuid& cotable_id,
364
                     const PgTableOid pgtable_id,
365
17.3M
                     const PgSchemaName pgschema_name) {
366
17.3M
  cols_ = cols;
367
17.3M
  num_key_columns_ = key_columns;
368
17.3M
  num_hash_key_columns_ = 0;
369
17.3M
  table_properties_ = table_properties;
370
17.3M
  cotable_id_ = cotable_id;
371
17.3M
  pgtable_id_ = pgtable_id;
372
17.3M
  pgschema_name_ = pgschema_name;
373
374
  // Determine whether any column is nullable or static, and count number of hash columns.
375
17.3M
  has_nullables_ = false;
376
17.3M
  has_statics_ = false;
377
38.5M
  for (const ColumnSchema& col : cols_) {
378
38.5M
    if (col.is_hash_key() && num_hash_key_columns_ < key_columns) {
379
1.03M
      num_hash_key_columns_++;
380
1.03M
    }
381
38.5M
    if (col.is_nullable()) {
382
18.8M
      has_nullables_ = true;
383
18.8M
    }
384
38.5M
    if (col.is_static()) {
385
2.72k
      has_statics_ = true;
386
2.72k
    }
387
38.5M
  }
388
389
17.3M
  if (PREDICT_FALSE(key_columns > cols_.size())) {
390
0
    return STATUS(InvalidArgument,
391
0
      "Bad schema", "More key columns than columns");
392
0
  }
393
394
17.3M
  if (PREDICT_FALSE(!ids.empty() && ids.size() != cols_.size())) {
395
0
    return STATUS(InvalidArgument, "Bad schema",
396
0
      "The number of ids does not match with the number of columns");
397
0
  }
398
399
17.3M
  if (PREDICT_FALSE(!cotable_id.IsNil() && pgtable_id > 0)) {
400
0
    return STATUS(InvalidArgument,
401
0
                  "Bad schema", "Cannot have both cotable ID and pgtable ID");
402
0
  }
403
404
  // Verify that the key columns are not nullable nor static
405
20.7M
  for (size_t i = 0; i < key_columns; ++i) {
406
3.43M
    if (PREDICT_FALSE(cols_[i].is_nullable())) {
407
0
      return STATUS(InvalidArgument,
408
0
        "Bad schema", strings::Substitute("Nullable key columns are not "
409
0
                                          "supported: $0", cols_[i].name()));
410
0
    }
411
3.43M
    if (PREDICT_FALSE(cols_[i].is_static())) {
412
0
      return STATUS(InvalidArgument,
413
0
        "Bad schema", strings::Substitute("Static key columns are not "
414
0
                                          "allowed: $0", cols_[i].name()));
415
0
    }
416
3.43M
    if (PREDICT_FALSE(cols_[i].is_counter())) {
417
0
      return STATUS(InvalidArgument,
418
0
        "Bad schema", strings::Substitute("Counter key columns are not allowed: $0",
419
0
                                          cols_[i].name()));
420
0
    }
421
3.43M
  }
422
423
  // Calculate the offset of each column in the row format.
424
17.3M
  col_offsets_.reserve(cols_.size() + 1);  // Include space for total byte size at the end.
425
17.3M
  size_t off = 0;
426
17.3M
  size_t idx = 0;
427
17.3M
  name_to_index_.clear();
428
38.5M
  for (const ColumnSchema &col : cols_) {
429
    // The map uses the 'name' string from within the ColumnSchema object.
430
38.5M
    if (!InsertIfNotPresent(&name_to_index_, col.name(), idx++)) {
431
0
      return STATUS(InvalidArgument, "Duplicate column name", col.name());
432
0
    }
433
434
38.5M
    col_offsets_.push_back(off);
435
38.5M
    off += col.type_info()->size();
436
38.5M
  }
437
438
  // Add an extra element on the end for the total
439
  // byte size
440
17.3M
  col_offsets_.push_back(off);
441
442
  // Initialize IDs mapping
443
17.3M
  ResetColumnIds(ids);
444
445
  // Ensure clustering columns have a default sorting type of 'ASC' if not specified.
446
19.6M
  for (auto i = num_hash_key_columns_; i < num_key_columns(); ++i) {
447
2.39M
    ColumnSchema& col = cols_[i];
448
2.39M
    if (col.sorting_type() == SortingType::kNotSpecified) {
449
46.0k
      col.set_sorting_type(SortingType::kAscending);
450
46.0k
    }
451
2.39M
  }
452
17.3M
  return Status::OK();
453
17.3M
}
454
455
Status Schema::CreateProjectionByNames(const std::vector<GStringPiece>& col_names,
456
1.43k
                                       Schema* out, size_t num_key_columns) const {
457
1.43k
  vector<ColumnId> ids;
458
1.43k
  vector<ColumnSchema> cols;
459
1.44k
  for (const GStringPiece& name : col_names) {
460
1.44k
    auto idx = find_column(name);
461
1.44k
    if (idx == kColumnNotFound) {
462
1
      return STATUS(NotFound, "Column not found", name);
463
1
    }
464
1.44k
    if (has_column_ids()) {
465
1.43k
      ids.push_back(column_id(idx));
466
1.43k
    }
467
1.44k
    cols.push_back(column(idx));
468
1.44k
  }
469
1.43k
  return out->Reset(cols, ids, num_key_columns, TableProperties(), cotable_id_,
470
1.43k
                    pgtable_id_, pgschema_name_);
471
1.43k
}
472
473
Status Schema::CreateProjectionByIdsIgnoreMissing(const std::vector<ColumnId>& col_ids,
474
15.3M
                                                  Schema* out) const {
475
15.3M
  vector<ColumnSchema> cols;
476
15.3M
  vector<ColumnId> filtered_col_ids;
477
26.3M
  for (ColumnId id : col_ids) {
478
26.3M
    int idx = find_column_by_id(id);
479
26.3M
    if (idx == -1) {
480
1
      continue;
481
1
    }
482
26.3M
    cols.push_back(column(idx));
483
26.3M
    filtered_col_ids.push_back(id);
484
26.3M
  }
485
15.3M
  return out->Reset(cols, filtered_col_ids, 0, TableProperties(), cotable_id_,
486
15.3M
                    pgtable_id_, pgschema_name_);
487
15.3M
}
488
489
namespace {
490
491
4.09k
vector<ColumnId> DefaultColumnIds(ColumnIdRep num_columns) {
492
4.09k
  vector<ColumnId> ids;
493
15.9k
  for (ColumnIdRep i = 0; i < num_columns; ++i) {
494
11.8k
    ids.push_back(ColumnId(kFirstColumnId + i));
495
11.8k
  }
496
4.09k
  return ids;
497
4.09k
}
498
499
}  // namespace
500
501
4.09k
void Schema::InitColumnIdsByDefault() {
502
4.09k
  CHECK(!has_column_ids());
503
4.09k
  ResetColumnIds(DefaultColumnIds(narrow_cast<ColumnIdRep>(cols_.size())));
504
4.09k
}
505
506
130k
Schema Schema::CopyWithoutColumnIds() const {
507
130k
  CHECK(has_column_ids());
508
130k
  return Schema(cols_, num_key_columns_, table_properties_, cotable_id_,
509
130k
                pgtable_id_, pgschema_name_);
510
130k
}
511
512
132k
Status Schema::VerifyProjectionCompatibility(const Schema& projection) const {
513
106
  DCHECK(has_column_ids()) << "The server schema must have IDs";
514
515
132k
  if (projection.has_column_ids()) {
516
0
    return STATUS(InvalidArgument, "User requests should not have Column IDs");
517
0
  }
518
519
132k
  vector<string> missing_columns;
520
419k
  for (const ColumnSchema& pcol : projection.columns()) {
521
419k
    auto index = find_column(pcol.name());
522
419k
    if (index == kColumnNotFound) {
523
2
      missing_columns.push_back(pcol.name());
524
419k
    } else if (!pcol.EqualsType(cols_[index])) {
525
      // TODO: We don't support query with type adaptors yet
526
0
      return STATUS(InvalidArgument, "The column '" + pcol.name() + "' must have type " +
527
0
                                     cols_[index].TypeToString() + " found " + pcol.TypeToString());
528
0
    }
529
419k
  }
530
531
132k
  if (!missing_columns.empty()) {
532
1
    return STATUS(InvalidArgument, "Some columns are not present in the current schema",
533
1
                                   JoinStrings(missing_columns, ", "));
534
1
  }
535
132k
  return Status::OK();
536
132k
}
537
538
Status Schema::GetMappedReadProjection(const Schema& projection,
539
132k
                                       Schema *mapped_projection) const {
540
  // - The user projection may have different columns from the ones on the tablet
541
  // - User columns non present in the tablet are considered errors
542
  // - The user projection is not supposed to have the defaults or the nullable
543
  //   information on each field. The current tablet schema is supposed to.
544
132k
  RETURN_NOT_OK(VerifyProjectionCompatibility(projection));
545
546
  // Get the Projection Mapping
547
132k
  vector<ColumnSchema> mapped_cols;
548
132k
  vector<ColumnId> mapped_ids;
549
550
132k
  mapped_cols.reserve(projection.num_columns());
551
132k
  mapped_ids.reserve(projection.num_columns());
552
553
418k
  for (const ColumnSchema& col : projection.columns()) {
554
418k
    auto index = find_column(col.name());
555
0
    DCHECK_GE(index, 0) << col.name();
556
418k
    mapped_cols.push_back(cols_[index]);
557
418k
    mapped_ids.push_back(col_ids_[index]);
558
418k
  }
559
560
132k
  CHECK_OK(mapped_projection->Reset(mapped_cols, mapped_ids, projection.num_key_columns()));
561
132k
  return Status::OK();
562
132k
}
563
564
103k
string Schema::ToString() const {
565
103k
  vector<string> col_strs;
566
103k
  if (has_column_ids()) {
567
632k
    for (size_t i = 0; i < cols_.size(); ++i) {
568
529k
      col_strs.push_back(Format("$0:$1", col_ids_[i], cols_[i].ToString()));
569
529k
    }
570
448
  } else {
571
12
    for (const ColumnSchema &col : cols_) {
572
12
      col_strs.push_back(col.ToString());
573
12
    }
574
448
  }
575
576
103k
  TablePropertiesPB tablet_properties_pb;
577
103k
  table_properties_.ToTablePropertiesPB(&tablet_properties_pb);
578
579
103k
  return StrCat("Schema [\n\t",
580
103k
                JoinStrings(col_strs, ",\n\t"),
581
103k
                "\n]\nproperties: ",
582
103k
                tablet_properties_pb.ShortDebugString(),
583
102k
                cotable_id_.IsNil() ? "" : ("\ncotable_id: " + cotable_id_.ToString()),
584
102k
                pgtable_id_ == 0 ? "" : ("\npgtable_id: " + std::to_string(pgtable_id_)));
585
103k
}
586
587
Status Schema::DecodeRowKey(Slice encoded_key,
588
                            uint8_t* buffer,
589
6
                            Arena* arena) const {
590
6
  ContiguousRow row(this, buffer);
591
592
14
  for (size_t col_idx = 0; col_idx < num_key_columns(); ++col_idx) {
593
11
    const ColumnSchema& col = column(col_idx);
594
11
    const KeyEncoder<faststring>& key_encoder = GetKeyEncoder<faststring>(col.type_info());
595
11
    bool is_last = col_idx == (num_key_columns() - 1);
596
11
    RETURN_NOT_OK_PREPEND(key_encoder.Decode(&encoded_key,
597
11
                                             is_last,
598
11
                                             arena,
599
11
                                             row.mutable_cell_ptr(col_idx)),
600
11
                          strings::Substitute("Error decoding composite key component '$0'",
601
8
                                              col.name()));
602
8
  }
603
3
  return Status::OK();
604
6
}
605
606
8
string Schema::DebugEncodedRowKey(Slice encoded_key, StartOrEnd start_or_end) const {
607
8
  if (encoded_key.empty()) {
608
2
    switch (start_or_end) {
609
1
      case START_KEY: return "<start of table>";
610
1
      case END_KEY:   return "<end of table>";
611
6
    }
612
6
  }
613
614
6
  Arena arena(1024, 128 * 1024);
615
6
  uint8_t* buf = reinterpret_cast<uint8_t*>(arena.AllocateBytes(key_byte_size()));
616
6
  Status s = DecodeRowKey(encoded_key, buf, &arena);
617
6
  if (!s.ok()) {
618
3
    return "<invalid key: " + s.ToString(/* no file/line */ false) + ">";
619
3
  }
620
3
  ConstContiguousRow row(this, buf);
621
3
  return DebugRowKey(row);
622
3
}
623
624
3
size_t Schema::memory_footprint_excluding_this() const {
625
3
  size_t size = 0;
626
3
  for (const ColumnSchema& col : cols_) {
627
3
    size += col.memory_footprint_excluding_this();
628
3
  }
629
630
3
  if (cols_.capacity() > 0) {
631
1
    size += malloc_usable_size(cols_.data());
632
1
  }
633
3
  if (col_ids_.capacity() > 0) {
634
0
    size += malloc_usable_size(col_ids_.data());
635
0
  }
636
3
  if (col_offsets_.capacity() > 0) {
637
1
    size += malloc_usable_size(col_offsets_.data());
638
1
  }
639
3
  size += name_to_index_bytes_;
640
3
  size += id_to_index_.memory_footprint_excluding_this();
641
642
3
  return size;
643
3
}
644
645
0
size_t Schema::memory_footprint_including_this() const {
646
0
  return malloc_usable_size(this) + memory_footprint_excluding_this();
647
0
}
648
649
78.7k
Result<ssize_t> Schema::ColumnIndexByName(GStringPiece col_name) const {
650
78.7k
  auto index = find_column(col_name);
651
78.7k
  if (index == kColumnNotFound) {
652
0
    return STATUS_FORMAT(Corruption, "$0 not found in schema $1", col_name, name_to_index_);
653
0
  }
654
78.7k
  return index;
655
78.7k
}
656
657
431k
Result<ColumnId> Schema::ColumnIdByName(const std::string& column_name) const {
658
431k
  auto column_index = find_column(column_name);
659
431k
  if (column_index == kColumnNotFound) {
660
0
    return STATUS_FORMAT(NotFound, "Couldn't find column $0 in the schema", column_name);
661
0
  }
662
431k
  return ColumnId(column_id(column_index));
663
431k
}
664
665
919
ColumnId Schema::first_column_id() {
666
919
  return kFirstColumnId;
667
919
}
668
669
21.4M
Result<const ColumnSchema&> Schema::column_by_id(ColumnId id) const {
670
21.4M
  int idx = find_column_by_id(id);
671
21.4M
  if (idx < 0) {
672
0
    return STATUS_FORMAT(InvalidArgument, "Column id $0 not found", id.ToString());
673
0
  }
674
21.4M
  return cols_[idx];
675
21.4M
}
676
677
// ============================================================================
678
//  Schema Builder
679
// ============================================================================
680
42.9k
void SchemaBuilder::Reset() {
681
42.9k
  cols_.clear();
682
42.9k
  col_ids_.clear();
683
42.9k
  col_names_.clear();
684
42.9k
  num_key_columns_ = 0;
685
42.9k
  next_id_ = kFirstColumnId;
686
42.9k
  table_properties_.Reset();
687
42.9k
  pgtable_id_ = 0;
688
42.9k
  pgschema_name_ = "";
689
42.9k
  cotable_id_ = Uuid::Nil();
690
42.9k
}
691
692
1.19k
void SchemaBuilder::Reset(const Schema& schema) {
693
1.19k
  cols_ = schema.cols_;
694
1.19k
  col_ids_ = schema.col_ids_;
695
1.19k
  num_key_columns_ = schema.num_key_columns_;
696
4.62k
  for (const auto& column : cols_) {
697
4.62k
    col_names_.insert(column.name());
698
4.62k
  }
699
700
1.19k
  if (col_ids_.empty()) {
701
3.61k
    for (ColumnIdRep i = 0; i < narrow_cast<ColumnIdRep>(cols_.size()); ++i) {
702
2.69k
      col_ids_.push_back(ColumnId(kFirstColumnId + i));
703
2.69k
    }
704
919
  }
705
1.19k
  if (col_ids_.empty()) {
706
0
    next_id_ = kFirstColumnId;
707
1.19k
  } else {
708
1.19k
    next_id_ = *std::max_element(col_ids_.begin(), col_ids_.end()) + 1;
709
1.19k
  }
710
1.19k
  table_properties_ = schema.table_properties_;
711
1.19k
  pgtable_id_ = schema.pgtable_id_;
712
1.19k
  pgschema_name_ = schema.pgschema_name_;
713
1.19k
  cotable_id_ = schema.cotable_id_;
714
1.19k
}
715
716
18.0k
Status SchemaBuilder::AddKeyColumn(const string& name, const shared_ptr<QLType>& type) {
717
18.0k
  return AddColumn(ColumnSchema(name, type), /* is_nullable */ true);
718
18.0k
}
719
720
35.6k
Status SchemaBuilder::AddKeyColumn(const string& name, DataType type) {
721
35.6k
  return AddColumn(ColumnSchema(name, QLType::Create(type)), /* is_nullable */ true);
722
35.6k
}
723
724
18.0k
Status SchemaBuilder::AddHashKeyColumn(const string& name, const shared_ptr<QLType>& type) {
725
18.0k
  return AddColumn(ColumnSchema(name, type, false, true), true);
726
18.0k
}
727
728
14.0k
Status SchemaBuilder::AddHashKeyColumn(const string& name, DataType type) {
729
14.0k
  return AddColumn(ColumnSchema(name, QLType::Create(type), false, true), true);
730
14.0k
}
731
732
24.8k
Status SchemaBuilder::AddColumn(const std::string& name, DataType type) {
733
24.8k
  return AddColumn(name, QLType::Create(type));
734
24.8k
}
735
736
Status SchemaBuilder::AddColumn(const std::string& name,
737
                                DataType type,
738
                                bool is_nullable,
739
                                bool is_hash_key,
740
                                bool is_static,
741
                                bool is_counter,
742
                                int32_t order,
743
0
                                yb::SortingType sorting_type) {
744
0
  return AddColumn(name, QLType::Create(type), is_nullable, is_hash_key, is_static, is_counter,
745
0
                   order, sorting_type);
746
0
}
747
748
Status SchemaBuilder::AddColumn(const string& name,
749
                                const std::shared_ptr<QLType>& type,
750
                                bool is_nullable,
751
                                bool is_hash_key,
752
                                bool is_static,
753
                                bool is_counter,
754
                                int32_t order,
755
221k
                                SortingType sorting_type) {
756
221k
  return AddColumn(ColumnSchema(name, type, is_nullable, is_hash_key, is_static, is_counter,
757
221k
                                order, sorting_type), false);
758
221k
}
759
760
761
2
Status SchemaBuilder::AddNullableColumn(const std::string& name, DataType type) {
762
2
  return AddNullableColumn(name, QLType::Create(type));
763
2
}
764
765
97
Status SchemaBuilder::RemoveColumn(const string& name) {
766
97
  unordered_set<string>::const_iterator it_names;
767
97
  if ((it_names = col_names_.find(name)) == col_names_.end()) {
768
0
    return STATUS(NotFound, "The specified column does not exist", name);
769
0
  }
770
771
97
  col_names_.erase(it_names);
772
489
  for (size_t i = 0; i < cols_.size(); ++i) {
773
489
    if (name == cols_[i].name()) {
774
97
      cols_.erase(cols_.begin() + i);
775
97
      col_ids_.erase(col_ids_.begin() + i);
776
97
      if (i < num_key_columns_) {
777
0
        num_key_columns_--;
778
0
      }
779
97
      return Status::OK();
780
97
    }
781
489
  }
782
783
0
  LOG(FATAL) << "Should not reach here";
784
0
  return STATUS(Corruption, "Unable to remove existing column");
785
97
}
786
787
17
Status SchemaBuilder::RenameColumn(const string& old_name, const string& new_name) {
788
17
  unordered_set<string>::const_iterator it_names;
789
790
  // check if 'new_name' is already in use
791
17
  if ((it_names = col_names_.find(new_name)) != col_names_.end()) {
792
0
    return STATUS(AlreadyPresent, "The column already exists", new_name);
793
0
  }
794
795
  // check if the 'old_name' column exists
796
17
  if ((it_names = col_names_.find(old_name)) == col_names_.end()) {
797
0
    return STATUS(NotFound, "The specified column does not exist", old_name);
798
0
  }
799
800
17
  col_names_.erase(it_names);   // TODO: Should this one stay and marked as alias?
801
17
  col_names_.insert(new_name);
802
803
45
  for (ColumnSchema& col_schema : cols_) {
804
45
    if (old_name == col_schema.name()) {
805
17
      col_schema.set_name(new_name);
806
17
      return Status::OK();
807
17
    }
808
45
  }
809
810
0
  LOG(FATAL) << "Should not reach here";
811
0
  return STATUS(IllegalState, "Unable to rename existing column");
812
17
}
813
814
307k
Status SchemaBuilder::AddColumn(const ColumnSchema& column, bool is_key) {
815
307k
  if (ContainsKey(col_names_, column.name())) {
816
0
    return STATUS(AlreadyPresent, "The column already exists", column.name());
817
0
  }
818
819
307k
  col_names_.insert(column.name());
820
307k
  if (is_key) {
821
85.8k
    cols_.insert(cols_.begin() + num_key_columns_, column);
822
85.8k
    col_ids_.insert(col_ids_.begin() + num_key_columns_, next_id_);
823
85.8k
    num_key_columns_++;
824
221k
  } else {
825
221k
    cols_.push_back(column);
826
221k
    col_ids_.push_back(next_id_);
827
221k
  }
828
829
307k
  next_id_ = ColumnId(next_id_ + 1);
830
307k
  return Status::OK();
831
307k
}
832
833
7
Status SchemaBuilder::AlterProperties(const TablePropertiesPB& pb) {
834
7
  table_properties_.AlterFromTablePropertiesPB(pb);
835
7
  return Status::OK();
836
7
}
837
838
839
657
Status DeletedColumn::FromPB(const DeletedColumnPB& col, DeletedColumn* ret) {
840
657
  ret->id = col.column_id();
841
657
  ret->ht = HybridTime(col.deleted_hybrid_time());
842
657
  return Status::OK();
843
657
}
844
845
12.5k
void DeletedColumn::CopyToPB(DeletedColumnPB* pb) const {
846
12.5k
  pb->set_column_id(id);
847
12.5k
  pb->set_deleted_hybrid_time(ht.ToUint64());
848
12.5k
}
849
850
} // namespace yb