YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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
3.52k
                   order, sorting_type, pg_type_oid) {
75
3.52k
}
Unexecuted instantiation: yb::ColumnSchema::ColumnSchema(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::DataType, bool, bool, bool, bool, int, yb::SortingType, int)
yb::ColumnSchema::ColumnSchema(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::DataType, bool, bool, bool, bool, int, yb::SortingType, int)
Line
Count
Source
74
3.52k
                   order, sorting_type, pg_type_oid) {
75
3.52k
}
76
77
108M
const TypeInfo* ColumnSchema::type_info() const {
78
108M
  return type_->type_info();
79
108M
}
80
81
1.77M
bool ColumnSchema::CompTypeInfo(const ColumnSchema &a, const ColumnSchema &b) {
82
1.77M
  return a.type_info()->type == b.type_info()->type;
83
1.77M
}
84
85
0
int ColumnSchema::Compare(const void *lhs, const void *rhs) const {
86
0
  return type_info()->Compare(lhs, rhs);
87
0
}
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
78
void ColumnSchema::DoDebugCellAppend(const void* cell, std::string* ret) const {
98
78
  ret->append(type_info()->name);
99
78
  ret->append(" ");
100
78
  ret->append(name_);
101
78
  ret->append("=");
102
78
  if (is_nullable_ && 
cell == nullptr4
) {
103
1
    ret->append("NULL");
104
77
  } else {
105
77
    type_info()->AppendDebugStringForValue(cell, ret);
106
77
  }
107
78
}
108
109
// TODO: include attributes_.ToString() -- need to fix unit tests
110
// first
111
683k
string ColumnSchema::ToString() const {
112
683k
  return strings::Substitute("$0[$1]",
113
683k
                             name_,
114
683k
                             TypeToString());
115
683k
}
116
117
682k
string ColumnSchema::TypeToString() const {
118
682k
  return strings::Substitute("$0 $1 $2",
119
682k
                             type_info()->name,
120
682k
                             is_nullable_ ? 
"NULLABLE"342k
:
"NOT NULL"339k
,
121
682k
                             is_hash_key_ ? 
"PARTITION KEY"202k
:
"NOT A PARTITION KEY"480k
);
122
682k
}
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
301M
void TableProperties::ToTablePropertiesPB(TablePropertiesPB *pb) const {
138
301M
  if (HasDefaultTimeToLive()) {
139
17.5k
    pb->set_default_time_to_live(default_time_to_live_);
140
17.5k
  }
141
301M
  pb->set_contain_counters(contain_counters_);
142
301M
  pb->set_is_transactional(is_transactional_);
143
301M
  pb->set_consistency_level(consistency_level_);
144
301M
  if (HasCopartitionTableId()) {
145
0
    pb->set_copartition_table_id(copartition_table_id_);
146
0
  }
147
301M
  pb->set_use_mangled_column_name(use_mangled_column_name_);
148
301M
  if (HasNumTablets()) {
149
163k
    pb->set_num_tablets(num_tablets_);
150
163k
  }
151
301M
  pb->set_is_ysql_catalog_table(is_ysql_catalog_table_);
152
301M
  pb->set_retain_delete_markers(retain_delete_markers_);
153
301M
}
154
155
5.68M
TableProperties TableProperties::FromTablePropertiesPB(const TablePropertiesPB& pb) {
156
5.68M
  TableProperties table_properties;
157
5.68M
  if (pb.has_default_time_to_live()) {
158
132k
    table_properties.SetDefaultTimeToLive(pb.default_time_to_live());
159
132k
  }
160
5.68M
  if (pb.has_contain_counters()) {
161
5.68M
    table_properties.SetContainCounters(pb.contain_counters());
162
5.68M
  }
163
5.68M
  if (pb.has_is_transactional()) {
164
5.68M
    table_properties.SetTransactional(pb.is_transactional());
165
5.68M
  }
166
5.68M
  if (pb.has_consistency_level()) {
167
5.68M
    table_properties.SetConsistencyLevel(pb.consistency_level());
168
5.68M
  }
169
5.68M
  if (pb.has_copartition_table_id()) {
170
0
    table_properties.SetCopartitionTableId(pb.copartition_table_id());
171
0
  }
172
5.68M
  if (pb.has_use_mangled_column_name()) {
173
5.68M
    table_properties.SetUseMangledColumnName(pb.use_mangled_column_name());
174
5.68M
  }
175
5.68M
  if (pb.has_num_tablets()) {
176
131k
    table_properties.SetNumTablets(pb.num_tablets());
177
131k
  }
178
5.68M
  if (pb.has_is_ysql_catalog_table()) {
179
5.68M
    table_properties.set_is_ysql_catalog_table(pb.is_ysql_catalog_table());
180
5.68M
  }
181
5.68M
  if (pb.has_retain_delete_markers()) {
182
5.67M
    table_properties.SetRetainDeleteMarkers(pb.retain_delete_markers());
183
5.67M
  }
184
5.68M
  return table_properties;
185
5.68M
}
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
64.1k
void TableProperties::Reset() {
215
64.1k
  default_time_to_live_ = kNoDefaultTtl;
216
64.1k
  contain_counters_ = false;
217
64.1k
  is_transactional_ = false;
218
64.1k
  consistency_level_ = YBConsistencyLevel::STRONG;
219
64.1k
  copartition_table_id_ = kNoCopartitionTableId;
220
64.1k
  use_mangled_column_name_ = false;
221
64.1k
  num_tablets_ = 0;
222
64.1k
  is_ysql_catalog_table_ = false;
223
64.1k
  retain_delete_markers_ = false;
224
64.1k
}
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
2.49M
                   NameToIndexMapAllocator(&name_to_index_bytes_)) {
252
2.49M
  CopyFrom(other);
253
2.49M
}
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 ColocationId colocation_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
604k
                   NameToIndexMapAllocator(&name_to_index_bytes_)) {
266
604k
  CHECK_OK(Reset(cols, key_columns, table_properties, cotable_id, colocation_id, pgschema_name));
267
604k
}
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 ColocationId colocation_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
360k
                   NameToIndexMapAllocator(&name_to_index_bytes_)) {
281
360k
  CHECK_OK(Reset(cols, ids, key_columns, table_properties, cotable_id, colocation_id,
282
360k
                 pgschema_name));
283
360k
}
284
285
81.7k
Schema& Schema::operator=(const Schema& other) {
286
81.7k
  if (&other != this) {
287
81.7k
    CopyFrom(other);
288
81.7k
  }
289
81.7k
  return *this;
290
81.7k
}
291
292
2.57M
void Schema::CopyFrom(const Schema& other) {
293
2.57M
  num_key_columns_ = other.num_key_columns_;
294
2.57M
  num_hash_key_columns_ = other.num_hash_key_columns_;
295
2.57M
  cols_ = other.cols_;
296
2.57M
  col_ids_ = other.col_ids_;
297
2.57M
  col_offsets_ = other.col_offsets_;
298
2.57M
  id_to_index_ = other.id_to_index_;
299
300
  // We can't simply copy name_to_index_ since the GStringPiece keys
301
  // reference the other Schema's ColumnSchema objects.
302
2.57M
  name_to_index_.clear();
303
2.57M
  int i = 0;
304
15.7M
  for (const ColumnSchema &col : cols_) {
305
    // The map uses the 'name' string from within the ColumnSchema object.
306
15.7M
    name_to_index_[col.name()] = i++;
307
15.7M
  }
308
309
2.57M
  has_nullables_ = other.has_nullables_;
310
2.57M
  has_statics_ = other.has_statics_;
311
2.57M
  table_properties_ = other.table_properties_;
312
2.57M
  cotable_id_ = other.cotable_id_;
313
2.57M
  colocation_id_ = other.colocation_id_;
314
2.57M
  pgschema_name_ = other.pgschema_name_;
315
316
  // Schema cannot have both cotable ID and colocation ID.
317
2.57M
  DCHECK(cotable_id_.IsNil() || colocation_id_ == kColocationIdNotSet);
318
2.57M
}
319
320
2
void Schema::swap(Schema& other) {
321
2
  std::swap(num_key_columns_, other.num_key_columns_);
322
2
  std::swap(num_hash_key_columns_, other.num_hash_key_columns_);
323
2
  cols_.swap(other.cols_);
324
2
  col_ids_.swap(other.col_ids_);
325
2
  col_offsets_.swap(other.col_offsets_);
326
2
  name_to_index_.swap(other.name_to_index_);
327
2
  id_to_index_.swap(other.id_to_index_);
328
2
  std::swap(has_nullables_, other.has_nullables_);
329
2
  std::swap(has_statics_, other.has_statics_);
330
2
  std::swap(table_properties_, other.table_properties_);
331
2
  std::swap(cotable_id_, other.cotable_id_);
332
2
  std::swap(colocation_id_, other.colocation_id_);
333
2
  std::swap(pgschema_name_, other.pgschema_name_);
334
335
  // Schema cannot have both cotable ID and colocation ID.
336
2
  DCHECK(cotable_id_.IsNil() || colocation_id_ == kColocationIdNotSet);
337
2
}
338
339
39.9M
void Schema::ResetColumnIds(const vector<ColumnId>& ids) {
340
  // Initialize IDs mapping.
341
39.9M
  col_ids_ = ids;
342
39.9M
  id_to_index_.clear();
343
39.9M
  max_col_id_ = 0;
344
123M
  for (size_t i = 0; i < ids.size(); 
++i83.1M
) {
345
83.1M
    if (ids[i] > max_col_id_) {
346
81.6M
      max_col_id_ = ids[i];
347
81.6M
    }
348
83.1M
    id_to_index_.set(ids[i], narrow_cast<int>(i));
349
83.1M
  }
350
39.9M
}
351
352
Status Schema::Reset(const vector<ColumnSchema>& cols, size_t key_columns,
353
                     const TableProperties& table_properties,
354
                     const Uuid& cotable_id,
355
                     const ColocationId colocation_id,
356
611k
                     const PgSchemaName pgschema_name) {
357
611k
  return Reset(cols, {}, key_columns, table_properties, cotable_id, colocation_id, pgschema_name);
358
611k
}
359
360
Status Schema::Reset(const vector<ColumnSchema>& cols,
361
                     const vector<ColumnId>& ids,
362
                     size_t key_columns,
363
                     const TableProperties& table_properties,
364
                     const Uuid& cotable_id,
365
                     const ColocationId colocation_id,
366
39.8M
                     const PgSchemaName pgschema_name) {
367
39.8M
  cols_ = cols;
368
39.8M
  num_key_columns_ = key_columns;
369
39.8M
  num_hash_key_columns_ = 0;
370
39.8M
  table_properties_ = table_properties;
371
39.8M
  cotable_id_ = cotable_id;
372
39.8M
  colocation_id_ = colocation_id;
373
39.8M
  pgschema_name_ = pgschema_name;
374
375
  // Determine whether any column is nullable or static, and count number of hash columns.
376
39.8M
  has_nullables_ = false;
377
39.8M
  has_statics_ = false;
378
85.8M
  for (const ColumnSchema& col : cols_) {
379
85.8M
    if (col.is_hash_key() && 
num_hash_key_columns_ < key_columns12.4M
) {
380
4.96M
      num_hash_key_columns_++;
381
4.96M
    }
382
85.8M
    if (col.is_nullable()) {
383
49.5M
      has_nullables_ = true;
384
49.5M
    }
385
85.8M
    if (col.is_static()) {
386
5.08k
      has_statics_ = true;
387
5.08k
    }
388
85.8M
  }
389
390
39.8M
  if (PREDICT_FALSE(key_columns > cols_.size())) {
391
0
    return STATUS(InvalidArgument,
392
0
      "Bad schema", "More key columns than columns");
393
0
  }
394
395
39.8M
  if (PREDICT_FALSE(!ids.empty() && ids.size() != cols_.size())) {
396
0
    return STATUS(InvalidArgument, "Bad schema",
397
0
      "The number of ids does not match with the number of columns");
398
0
  }
399
400
39.8M
  if (PREDICT_FALSE(!cotable_id.IsNil() && colocation_id != kColocationIdNotSet)) {
401
0
    return STATUS(InvalidArgument,
402
0
                  "Bad schema", "Cannot have both cotable ID and colocation ID");
403
0
  }
404
405
  // Verify that the key columns are not nullable nor static
406
50.5M
  
for (size_t i = 0; 39.8M
i < key_columns;
++i10.6M
) {
407
10.6M
    if (PREDICT_FALSE(cols_[i].is_nullable())) {
408
0
      return STATUS(InvalidArgument,
409
0
        "Bad schema", strings::Substitute("Nullable key columns are not "
410
0
                                          "supported: $0", cols_[i].name()));
411
0
    }
412
10.6M
    if (PREDICT_FALSE(cols_[i].is_static())) {
413
0
      return STATUS(InvalidArgument,
414
0
        "Bad schema", strings::Substitute("Static key columns are not "
415
0
                                          "allowed: $0", cols_[i].name()));
416
0
    }
417
10.6M
    if (PREDICT_FALSE(cols_[i].is_counter())) {
418
0
      return STATUS(InvalidArgument,
419
0
        "Bad schema", strings::Substitute("Counter key columns are not allowed: $0",
420
0
                                          cols_[i].name()));
421
0
    }
422
10.6M
  }
423
424
  // Calculate the offset of each column in the row format.
425
39.8M
  col_offsets_.reserve(cols_.size() + 1);  // Include space for total byte size at the end.
426
39.8M
  size_t off = 0;
427
39.8M
  size_t idx = 0;
428
39.8M
  name_to_index_.clear();
429
85.9M
  for (const ColumnSchema &col : cols_) {
430
    // The map uses the 'name' string from within the ColumnSchema object.
431
85.9M
    if (!InsertIfNotPresent(&name_to_index_, col.name(), idx++)) {
432
3
      return STATUS(InvalidArgument, "Duplicate column name", col.name());
433
3
    }
434
435
85.9M
    col_offsets_.push_back(off);
436
85.9M
    off += col.type_info()->size;
437
85.9M
  }
438
439
  // Add an extra element on the end for the total
440
  // byte size
441
39.8M
  col_offsets_.push_back(off);
442
443
  // Initialize IDs mapping
444
39.8M
  ResetColumnIds(ids);
445
446
  // Ensure clustering columns have a default sorting type of 'ASC' if not specified.
447
45.5M
  for (auto i = num_hash_key_columns_; i < num_key_columns(); 
++i5.71M
) {
448
5.71M
    ColumnSchema& col = cols_[i];
449
5.71M
    if (col.sorting_type() == SortingType::kNotSpecified) {
450
83.0k
      col.set_sorting_type(SortingType::kAscending);
451
83.0k
    }
452
5.71M
  }
453
39.8M
  return Status::OK();
454
39.8M
}
455
456
Status Schema::CreateProjectionByNames(const std::vector<GStringPiece>& col_names,
457
6.97k
                                       Schema* out, size_t num_key_columns) const {
458
6.97k
  vector<ColumnId> ids;
459
6.97k
  vector<ColumnSchema> cols;
460
10.1k
  for (const GStringPiece& name : col_names) {
461
10.1k
    auto idx = find_column(name);
462
10.1k
    if (idx == kColumnNotFound) {
463
1
      return STATUS(NotFound, "Column not found", name);
464
1
    }
465
10.1k
    if (has_column_ids()) {
466
10.1k
      ids.push_back(column_id(idx));
467
10.1k
    }
468
10.1k
    cols.push_back(column(idx));
469
10.1k
  }
470
6.97k
  return out->Reset(cols, ids, num_key_columns, TableProperties(), cotable_id_,
471
6.97k
                    colocation_id_, pgschema_name_);
472
6.97k
}
473
474
Status Schema::CreateProjectionByIdsIgnoreMissing(const std::vector<ColumnId>& col_ids,
475
32.7M
                                                  Schema* out) const {
476
32.7M
  vector<ColumnSchema> cols;
477
32.7M
  vector<ColumnId> filtered_col_ids;
478
55.2M
  for (ColumnId id : col_ids) {
479
55.2M
    int idx = find_column_by_id(id);
480
55.2M
    if (idx == -1) {
481
1
      continue;
482
1
    }
483
55.2M
    cols.push_back(column(idx));
484
55.2M
    filtered_col_ids.push_back(id);
485
55.2M
  }
486
32.7M
  return out->Reset(cols, filtered_col_ids, 0, TableProperties(), cotable_id_,
487
32.7M
                    colocation_id_, pgschema_name_);
488
32.7M
}
489
490
namespace {
491
492
8.82k
vector<ColumnId> DefaultColumnIds(ColumnIdRep num_columns) {
493
8.82k
  vector<ColumnId> ids;
494
33.6k
  for (ColumnIdRep i = 0; i < num_columns; 
++i24.7k
) {
495
24.7k
    ids.push_back(ColumnId(kFirstColumnId + i));
496
24.7k
  }
497
8.82k
  return ids;
498
8.82k
}
499
500
}  // namespace
501
502
8.82k
void Schema::InitColumnIdsByDefault() {
503
8.82k
  CHECK(!has_column_ids());
504
8.82k
  ResetColumnIds(DefaultColumnIds(narrow_cast<ColumnIdRep>(cols_.size())));
505
8.82k
}
506
507
419k
Schema Schema::CopyWithoutColumnIds() const {
508
419k
  CHECK(has_column_ids());
509
419k
  return Schema(cols_, num_key_columns_, table_properties_, cotable_id_,
510
419k
                colocation_id_, pgschema_name_);
511
419k
}
512
513
421k
Status Schema::VerifyProjectionCompatibility(const Schema& projection) const {
514
421k
  DCHECK
(has_column_ids()) << "The server schema must have IDs"2.14k
;
515
516
421k
  if (projection.has_column_ids()) {
517
0
    return STATUS(InvalidArgument, "User requests should not have Column IDs");
518
0
  }
519
520
421k
  vector<string> missing_columns;
521
1.32M
  for (const ColumnSchema& pcol : projection.columns()) {
522
1.32M
    auto index = find_column(pcol.name());
523
1.32M
    if (index == kColumnNotFound) {
524
2
      missing_columns.push_back(pcol.name());
525
1.32M
    } else if (!pcol.EqualsType(cols_[index])) {
526
      // TODO: We don't support query with type adaptors yet
527
0
      return STATUS(InvalidArgument, "The column '" + pcol.name() + "' must have type " +
528
0
                                     cols_[index].TypeToString() + " found " + pcol.TypeToString());
529
0
    }
530
1.32M
  }
531
532
421k
  if (!missing_columns.empty()) {
533
1
    return STATUS(InvalidArgument, "Some columns are not present in the current schema",
534
1
                                   JoinStrings(missing_columns, ", "));
535
1
  }
536
421k
  return Status::OK();
537
421k
}
538
539
Status Schema::GetMappedReadProjection(const Schema& projection,
540
421k
                                       Schema *mapped_projection) const {
541
  // - The user projection may have different columns from the ones on the tablet
542
  // - User columns non present in the tablet are considered errors
543
  // - The user projection is not supposed to have the defaults or the nullable
544
  //   information on each field. The current tablet schema is supposed to.
545
421k
  RETURN_NOT_OK(VerifyProjectionCompatibility(projection));
546
547
  // Get the Projection Mapping
548
421k
  vector<ColumnSchema> mapped_cols;
549
421k
  vector<ColumnId> mapped_ids;
550
551
421k
  mapped_cols.reserve(projection.num_columns());
552
421k
  mapped_ids.reserve(projection.num_columns());
553
554
1.32M
  for (const ColumnSchema& col : projection.columns()) {
555
1.32M
    auto index = find_column(col.name());
556
1.32M
    DCHECK_GE
(index, 0) << col.name()0
;
557
1.32M
    mapped_cols.push_back(cols_[index]);
558
1.32M
    mapped_ids.push_back(col_ids_[index]);
559
1.32M
  }
560
561
421k
  CHECK_OK(mapped_projection->Reset(mapped_cols, mapped_ids, projection.num_key_columns()));
562
421k
  return Status::OK();
563
421k
}
564
565
150k
string Schema::ToString() const {
566
150k
  vector<string> col_strs;
567
150k
  if (has_column_ids()) {
568
832k
    for (size_t i = 0; i < cols_.size(); 
++i682k
) {
569
682k
      col_strs.push_back(Format("$0:$1", col_ids_[i], cols_[i].ToString()));
570
682k
    }
571
149k
  } else {
572
515
    for (const ColumnSchema &col : cols_) {
573
12
      col_strs.push_back(col.ToString());
574
12
    }
575
515
  }
576
577
150k
  TablePropertiesPB tablet_properties_pb;
578
150k
  table_properties_.ToTablePropertiesPB(&tablet_properties_pb);
579
580
150k
  return StrCat("Schema [\n\t",
581
150k
                JoinStrings(col_strs, ",\n\t"),
582
150k
                "\n]\nproperties: ",
583
150k
                tablet_properties_pb.ShortDebugString(),
584
150k
                cotable_id_.IsNil() ? 
""149k
:
("\ncotable_id: " + cotable_id_.ToString())539
,
585
150k
                colocation_id_ == kColocationIdNotSet
586
150k
                    ? 
""148k
:
("\ncolocation_id: " + std::to_string(colocation_id_))1.03k
);
587
150k
}
588
589
3
size_t Schema::memory_footprint_excluding_this() const {
590
3
  size_t size = 0;
591
3
  for (const ColumnSchema& col : cols_) {
592
3
    size += col.memory_footprint_excluding_this();
593
3
  }
594
595
3
  if (cols_.capacity() > 0) {
596
1
    size += malloc_usable_size(cols_.data());
597
1
  }
598
3
  if (col_ids_.capacity() > 0) {
599
0
    size += malloc_usable_size(col_ids_.data());
600
0
  }
601
3
  if (col_offsets_.capacity() > 0) {
602
1
    size += malloc_usable_size(col_offsets_.data());
603
1
  }
604
3
  size += name_to_index_bytes_;
605
3
  size += id_to_index_.memory_footprint_excluding_this();
606
607
3
  return size;
608
3
}
609
610
0
size_t Schema::memory_footprint_including_this() const {
611
0
  return malloc_usable_size(this) + memory_footprint_excluding_this();
612
0
}
613
614
124k
Result<ssize_t> Schema::ColumnIndexByName(GStringPiece col_name) const {
615
124k
  auto index = find_column(col_name);
616
124k
  if (index == kColumnNotFound) {
617
0
    return STATUS_FORMAT(Corruption, "$0 not found in schema $1", col_name, name_to_index_);
618
0
  }
619
124k
  return index;
620
124k
}
621
622
1.13M
Result<ColumnId> Schema::ColumnIdByName(const std::string& column_name) const {
623
1.13M
  auto column_index = find_column(column_name);
624
1.13M
  if (column_index == kColumnNotFound) {
625
0
    return STATUS_FORMAT(NotFound, "Couldn't find column $0 in the schema", column_name);
626
0
  }
627
1.13M
  return ColumnId(column_id(column_index));
628
1.13M
}
629
630
1.84k
ColumnId Schema::first_column_id() {
631
1.84k
  return kFirstColumnId;
632
1.84k
}
633
634
66.1M
Result<const ColumnSchema&> Schema::column_by_id(ColumnId id) const {
635
66.1M
  int idx = find_column_by_id(id);
636
66.1M
  if (idx < 0) {
637
0
    return STATUS_FORMAT(InvalidArgument, "Column id $0 not found", id.ToString());
638
0
  }
639
66.1M
  return cols_[idx];
640
66.1M
}
641
642
// ============================================================================
643
//  Schema Builder
644
// ============================================================================
645
64.1k
void SchemaBuilder::Reset() {
646
64.1k
  cols_.clear();
647
64.1k
  col_ids_.clear();
648
64.1k
  col_names_.clear();
649
64.1k
  num_key_columns_ = 0;
650
64.1k
  next_id_ = kFirstColumnId;
651
64.1k
  table_properties_.Reset();
652
64.1k
  colocation_id_ = kColocationIdNotSet;
653
64.1k
  pgschema_name_ = "";
654
64.1k
  cotable_id_ = Uuid::Nil();
655
64.1k
}
656
657
1.50k
void SchemaBuilder::Reset(const Schema& schema) {
658
1.50k
  cols_ = schema.cols_;
659
1.50k
  col_ids_ = schema.col_ids_;
660
1.50k
  num_key_columns_ = schema.num_key_columns_;
661
5.21k
  for (const auto& column : cols_) {
662
5.21k
    col_names_.insert(column.name());
663
5.21k
  }
664
665
1.50k
  if (col_ids_.empty()) {
666
3.61k
    for (ColumnIdRep i = 0; i < narrow_cast<ColumnIdRep>(cols_.size()); 
++i2.69k
) {
667
2.69k
      col_ids_.push_back(ColumnId(kFirstColumnId + i));
668
2.69k
    }
669
919
  }
670
1.50k
  if (col_ids_.empty()) {
671
0
    next_id_ = kFirstColumnId;
672
1.50k
  } else {
673
1.50k
    next_id_ = *std::max_element(col_ids_.begin(), col_ids_.end()) + 1;
674
1.50k
  }
675
1.50k
  table_properties_ = schema.table_properties_;
676
1.50k
  pgschema_name_ = schema.pgschema_name_;
677
1.50k
  cotable_id_ = schema.cotable_id_;
678
1.50k
  colocation_id_ = schema.colocation_id_;
679
1.50k
}
680
681
27.0k
Status SchemaBuilder::AddKeyColumn(const string& name, const shared_ptr<QLType>& type) {
682
27.0k
  return AddColumn(ColumnSchema(name, type), /* is_nullable */ true);
683
27.0k
}
684
685
53.0k
Status SchemaBuilder::AddKeyColumn(const string& name, DataType type) {
686
53.0k
  return AddColumn(ColumnSchema(name, QLType::Create(type)), /* is_nullable */ true);
687
53.0k
}
688
689
27.0k
Status SchemaBuilder::AddHashKeyColumn(const string& name, const shared_ptr<QLType>& type) {
690
27.0k
  return AddColumn(ColumnSchema(name, type, false, true), true);
691
27.0k
}
692
693
21.0k
Status SchemaBuilder::AddHashKeyColumn(const string& name, DataType type) {
694
21.0k
  return AddColumn(ColumnSchema(name, QLType::Create(type), false, true), true);
695
21.0k
}
696
697
37.0k
Status SchemaBuilder::AddColumn(const std::string& name, DataType type) {
698
37.0k
  return AddColumn(name, QLType::Create(type));
699
37.0k
}
700
701
Status SchemaBuilder::AddColumn(const std::string& name,
702
                                DataType type,
703
                                bool is_nullable,
704
                                bool is_hash_key,
705
                                bool is_static,
706
                                bool is_counter,
707
                                int32_t order,
708
0
                                yb::SortingType sorting_type) {
709
0
  return AddColumn(name, QLType::Create(type), is_nullable, is_hash_key, is_static, is_counter,
710
0
                   order, sorting_type);
711
0
}
712
713
Status SchemaBuilder::AddColumn(const string& name,
714
                                const std::shared_ptr<QLType>& type,
715
                                bool is_nullable,
716
                                bool is_hash_key,
717
                                bool is_static,
718
                                bool is_counter,
719
                                int32_t order,
720
331k
                                SortingType sorting_type) {
721
331k
  return AddColumn(ColumnSchema(name, type, is_nullable, is_hash_key, is_static, is_counter,
722
331k
                                order, sorting_type), false);
723
331k
}
724
725
726
2
Status SchemaBuilder::AddNullableColumn(const std::string& name, DataType type) {
727
2
  return AddNullableColumn(name, QLType::Create(type));
728
2
}
729
730
233
Status SchemaBuilder::RemoveColumn(const string& name) {
731
233
  unordered_set<string>::const_iterator it_names;
732
233
  if ((it_names = col_names_.find(name)) == col_names_.end()) {
733
0
    return STATUS(NotFound, "The specified column does not exist", name);
734
0
  }
735
736
233
  col_names_.erase(it_names);
737
801
  for (size_t i = 0; i < cols_.size(); 
++i568
) {
738
801
    if (name == cols_[i].name()) {
739
233
      cols_.erase(cols_.begin() + i);
740
233
      col_ids_.erase(col_ids_.begin() + i);
741
233
      if (i < num_key_columns_) {
742
0
        num_key_columns_--;
743
0
      }
744
233
      return Status::OK();
745
233
    }
746
801
  }
747
748
0
  LOG(FATAL) << "Should not reach here";
749
0
  return STATUS(Corruption, "Unable to remove existing column");
750
233
}
751
752
31
Status SchemaBuilder::RenameColumn(const string& old_name, const string& new_name) {
753
31
  unordered_set<string>::const_iterator it_names;
754
755
  // check if 'new_name' is already in use
756
31
  if ((it_names = col_names_.find(new_name)) != col_names_.end()) {
757
0
    return STATUS(AlreadyPresent, "The column already exists", new_name);
758
0
  }
759
760
  // check if the 'old_name' column exists
761
31
  if ((it_names = col_names_.find(old_name)) == col_names_.end()) {
762
0
    return STATUS(NotFound, "The specified column does not exist", old_name);
763
0
  }
764
765
31
  col_names_.erase(it_names);   // TODO: Should this one stay and marked as alias?
766
31
  col_names_.insert(new_name);
767
768
76
  for (ColumnSchema& col_schema : cols_) {
769
76
    if (old_name == col_schema.name()) {
770
31
      col_schema.set_name(new_name);
771
31
      return Status::OK();
772
31
    }
773
76
  }
774
775
0
  LOG(FATAL) << "Should not reach here";
776
0
  return STATUS(IllegalState, "Unable to rename existing column");
777
31
}
778
779
460k
Status SchemaBuilder::AddColumn(const ColumnSchema& column, bool is_key) {
780
460k
  if (ContainsKey(col_names_, column.name())) {
781
0
    return STATUS(AlreadyPresent, "The column already exists", column.name());
782
0
  }
783
784
460k
  col_names_.insert(column.name());
785
460k
  if (is_key) {
786
128k
    cols_.insert(cols_.begin() + num_key_columns_, column);
787
128k
    col_ids_.insert(col_ids_.begin() + num_key_columns_, next_id_);
788
128k
    num_key_columns_++;
789
332k
  } else {
790
332k
    cols_.push_back(column);
791
332k
    col_ids_.push_back(next_id_);
792
332k
  }
793
794
460k
  next_id_ = ColumnId(next_id_ + 1);
795
460k
  return Status::OK();
796
460k
}
797
798
7
Status SchemaBuilder::AlterProperties(const TablePropertiesPB& pb) {
799
7
  table_properties_.AlterFromTablePropertiesPB(pb);
800
7
  return Status::OK();
801
7
}
802
803
804
636
Status DeletedColumn::FromPB(const DeletedColumnPB& col, DeletedColumn* ret) {
805
636
  ret->id = col.column_id();
806
636
  ret->ht = HybridTime(col.deleted_hybrid_time());
807
636
  return Status::OK();
808
636
}
809
810
21.4k
void DeletedColumn::CopyToPB(DeletedColumnPB* pb) const {
811
21.4k
  pb->set_column_id(id);
812
21.4k
  pb->set_deleted_hybrid_time(ht.ToUint64());
813
21.4k
}
814
815
} // namespace yb