YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/common/schema.h
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
#ifndef YB_COMMON_SCHEMA_H
33
#define YB_COMMON_SCHEMA_H
34
35
#include <functional>
36
#include <memory>
37
#include <string>
38
#include <unordered_map>
39
#include <unordered_set>
40
#include <utility>
41
#include <vector>
42
43
#include <boost/optional/optional.hpp>
44
45
#include <glog/logging.h>
46
47
#include "yb/common/column_id.h"
48
#include "yb/common/common_types.pb.h"
49
#include "yb/common/common_fwd.h"
50
#include "yb/common/constants.h"
51
#include "yb/common/entity_ids_types.h"
52
#include "yb/common/hybrid_time.h"
53
#include "yb/common/id_mapping.h"
54
#include "yb/common/types.h"
55
56
#include "yb/gutil/stl_util.h"
57
58
#include "yb/util/memory/arena_fwd.h"
59
#include "yb/util/status.h"
60
#include "yb/util/uuid.h"
61
62
// Check that two schemas are equal, yielding a useful error message in the case that
63
// they are not.
64
#define DCHECK_SCHEMA_EQ(s1, s2) \
65
  do { \
66
    DCHECK((s1).Equals((s2))) << "Schema " << (s1).ToString() \
67
                              << " does not match " << (s2).ToString(); \
68
  } while (0);
69
70
#define DCHECK_KEY_PROJECTION_SCHEMA_EQ(s1, s2) \
71
  do { \
72
    DCHECK((s1).KeyEquals((s2))) << "Key-Projection Schema " \
73
                                 << (s1).ToString() << " does not match " \
74
                                 << (s2).ToString(); \
75
  } while (0);
76
77
namespace yb {
78
79
class DeletedColumnPB;
80
81
// Struct for storing information about deleted columns for cleanup.
82
struct DeletedColumn {
83
  ColumnId id;
84
  HybridTime ht;
85
86
636
  DeletedColumn() { }
87
88
2.15k
  DeletedColumn(ColumnId id_, HybridTime ht_) : id(id_), ht(ht_) {}
89
90
  static CHECKED_STATUS FromPB(const DeletedColumnPB& col, DeletedColumn* ret);
91
  void CopyToPB(DeletedColumnPB* pb) const;
92
};
93
94
// The schema for a given column.
95
//
96
// Holds the data type as well as information about nullability & column name.
97
// In the future, it may hold information about annotations, etc.
98
class ColumnSchema {
99
 public:
100
  // Component comparators for combining in custom comparators.
101
140k
  static bool CompName(const ColumnSchema &a, const ColumnSchema &b) {
102
140k
    return a.name_ == b.name_;
103
140k
  }
104
105
1.77M
  static bool CompNullable(const ColumnSchema &a, const ColumnSchema &b) {
106
1.77M
    return a.is_nullable_ == b.is_nullable_;
107
1.77M
  }
108
109
1.77M
  static bool CompHashKey(const ColumnSchema &a, const ColumnSchema &b) {
110
1.77M
    return a.is_hash_key_ == b.is_hash_key_;
111
1.77M
  }
112
113
1.77M
  static bool CompSortingType(const ColumnSchema &a, const ColumnSchema &b) {
114
1.77M
    return a.sorting_type_ == b.sorting_type_;
115
1.77M
  }
116
117
  static bool CompTypeInfo(const ColumnSchema &a, const ColumnSchema &b);
118
119
0
  static bool CompOrder(const ColumnSchema &a, const ColumnSchema &b) {
120
0
    return a.order_ == b.order_;
121
0
  }
122
123
  // Combined comparators.
124
1.77M
  static bool CompareType(const ColumnSchema &a, const ColumnSchema &b) {
125
1.77M
    return CompNullable(a, b) && 
CompHashKey(a, b)1.77M
&&
126
1.77M
        
CompSortingType(a, b)1.77M
&&
CompTypeInfo(a, b)1.77M
;
127
1.77M
  }
128
129
140k
  static bool CompareByDefault(const ColumnSchema &a, const ColumnSchema &b) {
130
140k
    return 
CompareType(a, b)140k
&& CompName(a, b);
131
140k
  }
132
133
  // name: column name
134
  // type: column type (e.g. UINT8, INT32, STRING, MAP<INT32, STRING> ...)
135
  // is_nullable: true if a row value can be null
136
  // is_hash_key: true if a column's hash value can be used for partitioning.
137
  //
138
  // Example:
139
  //   ColumnSchema col_a("a", UINT32)
140
  //   ColumnSchema col_b("b", STRING, true);
141
  //   uint32_t default_i32 = -15;
142
  //   ColumnSchema col_c("c", INT32, false, &default_i32);
143
  //   Slice default_str("Hello");
144
  //   ColumnSchema col_d("d", STRING, false, &default_str);
145
  ColumnSchema(std::string name,
146
               const std::shared_ptr<QLType>& type,
147
               bool is_nullable = false,
148
               bool is_hash_key = false,
149
               bool is_static = false,
150
               bool is_counter = false,
151
               int32_t order = 0,
152
               SortingType sorting_type = SortingType::kNotSpecified,
153
               int32_t pg_type_oid = 0 /*kInvalidOid*/)
154
      : name_(std::move(name)),
155
        type_(type),
156
        is_nullable_(is_nullable),
157
        is_hash_key_(is_hash_key),
158
        is_static_(is_static),
159
        is_counter_(is_counter),
160
        order_(order),
161
        sorting_type_(sorting_type),
162
55.6M
        pg_type_oid_(pg_type_oid) {
163
55.6M
  }
164
165
  // convenience constructor for creating columns with simple (non-parametric) data types
166
  ColumnSchema(std::string name,
167
               DataType type,
168
               bool is_nullable = false,
169
               bool is_hash_key = false,
170
               bool is_static = false,
171
               bool is_counter = false,
172
               int32_t order = 0,
173
               SortingType sorting_type = SortingType::kNotSpecified,
174
               int32_t pg_type_oid = 0 /*kInvalidOid*/);
175
176
2.87G
  const std::shared_ptr<QLType>& type() const {
177
2.87G
    return type_;
178
2.87G
  }
179
180
20
  void set_type(const std::shared_ptr<QLType>& type) {
181
20
    type_ = type;
182
20
  }
183
184
  const TypeInfo* type_info() const;
185
186
2.17G
  bool is_nullable() const {
187
2.17G
    return is_nullable_;
188
2.17G
  }
189
190
2.15G
  bool is_hash_key() const {
191
2.15G
    return is_hash_key_;
192
2.15G
  }
193
194
2.18G
  bool is_static() const {
195
2.18G
    return is_static_;
196
2.18G
  }
197
198
2.08G
  bool is_counter() const {
199
2.08G
    return is_counter_;
200
2.08G
  }
201
202
2.10G
  int32_t order() const {
203
2.10G
    return order_;
204
2.10G
  }
205
206
2.06G
  int32_t pg_type_oid() const {
207
2.06G
    return pg_type_oid_;
208
2.06G
  }
209
210
2.18G
  SortingType sorting_type() const {
211
2.18G
    return sorting_type_;
212
2.18G
  }
213
214
83.0k
  void set_sorting_type(SortingType sorting_type) {
215
83.0k
    sorting_type_ = sorting_type;
216
83.0k
  }
217
218
2.01M
  const std::string sorting_type_string() const {
219
2.01M
    switch (sorting_type_) {
220
1.76M
      case kNotSpecified:
221
1.76M
        return "none";
222
248k
      case kAscending:
223
248k
        return "asc";
224
610
      case kDescending:
225
610
        return "desc";
226
0
      case kAscendingNullsLast:
227
0
        return "asc nulls last";
228
0
      case kDescendingNullsLast:
229
0
        return "desc nulls last";
230
2.01M
    }
231
0
    LOG(FATAL) << "Invalid sorting type: " << sorting_type_;
232
0
  }
233
234
2.18G
  const std::string &name() const {
235
2.18G
    return name_;
236
2.18G
  }
237
238
  // Return a string identifying this column, including its
239
  // name.
240
  std::string ToString() const;
241
242
  // Same as above, but only including the type information.
243
  // For example, "STRING NOT NULL".
244
  std::string TypeToString() const;
245
246
  template <typename Comparator>
247
1.77M
  bool Equals(const ColumnSchema &other, Comparator comp) const {
248
1.77M
    return comp(*this, other);
249
1.77M
  }
bool yb::ColumnSchema::Equals<bool (*)(yb::ColumnSchema const&, yb::ColumnSchema const&)>(yb::ColumnSchema const&, bool (*)(yb::ColumnSchema const&, yb::ColumnSchema const&)) const
Line
Count
Source
247
1.77M
  bool Equals(const ColumnSchema &other, Comparator comp) const {
248
1.77M
    return comp(*this, other);
249
1.77M
  }
Unexecuted instantiation: catalog_manager_ent.cc:bool yb::ColumnSchema::Equals<yb::master::enterprise::CatalogManager::ImportTableEntry(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::YQLDatabase>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::YQLDatabase> > > > const&, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData> > > const&, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData*)::CompareColumnsExceptNullable>(yb::ColumnSchema const&, yb::master::enterprise::CatalogManager::ImportTableEntry(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::YQLDatabase>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::YQLDatabase> > > > const&, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData> > > const&, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData*)::CompareColumnsExceptNullable) const
250
251
1.63M
  bool EqualsType(const ColumnSchema &other) const {
252
1.63M
    return Equals(other, CompareType);
253
1.63M
  }
254
255
0
  bool Equals(const ColumnSchema &other) const {
256
0
    return Equals(other, CompareByDefault);
257
0
  }
258
259
  int Compare(const void *lhs, const void *rhs) const;
260
261
  // Stringify the given cell. This just stringifies the cell contents,
262
  // and doesn't include the column name or type.
263
  std::string Stringify(const void *cell) const;
264
265
  // Append a debug string for this cell. This differs from Stringify above
266
  // in that it also includes the column info, for example 'STRING foo=bar'.
267
  template<class CellType>
268
78
  void DebugCellAppend(const CellType& cell, std::string* ret) const {
269
78
    DoDebugCellAppend((is_nullable_ && 
cell.is_null()4
) ?
nullptr1
:
cell.ptr()77
, ret);
270
78
  }
Unexecuted instantiation: void yb::ColumnSchema::DebugCellAppend<yb::ContiguousRowCell<yb::ConstContiguousRow> >(yb::ContiguousRowCell<yb::ConstContiguousRow> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
void yb::ColumnSchema::DebugCellAppend<yb::SimpleConstCell>(yb::SimpleConstCell const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
268
61
  void DebugCellAppend(const CellType& cell, std::string* ret) const {
269
61
    DoDebugCellAppend((is_nullable_ && 
cell.is_null()0
) ?
nullptr0
: cell.ptr(), ret);
270
61
  }
void yb::ColumnSchema::DebugCellAppend<yb::ContiguousRowCell<yb::ContiguousRow> >(yb::ContiguousRowCell<yb::ContiguousRow> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) const
Line
Count
Source
268
17
  void DebugCellAppend(const CellType& cell, std::string* ret) const {
269
17
    DoDebugCellAppend((is_nullable_ && 
cell.is_null()4
) ?
nullptr1
:
cell.ptr()16
, ret);
270
17
  }
271
272
  // Returns the memory usage of this object without the object itself. Should
273
  // be used when embedded inside another object.
274
  size_t memory_footprint_excluding_this() const;
275
276
  // Returns the memory usage of this object including the object itself.
277
  // Should be used when allocated on the heap.
278
  size_t memory_footprint_including_this() const;
279
280
 private:
281
  friend class SchemaBuilder;
282
283
31
  void set_name(const std::string& name) {
284
31
    name_ = name;
285
31
  }
286
287
  void DoDebugCellAppend(const void* cell, std::string* ret) const;
288
289
  std::string name_;
290
  std::shared_ptr<QLType> type_;
291
  bool is_nullable_;
292
  bool is_hash_key_;
293
  bool is_static_;
294
  bool is_counter_;
295
  int32_t order_;
296
  SortingType sorting_type_;
297
  int32_t pg_type_oid_;
298
};
299
300
class ContiguousRow;
301
const TableId kNoCopartitionTableId = "";
302
303
class TableProperties {
304
 public:
305
  // Containing counters is a internal property instead of a user-defined property, so we don't use
306
  // it when comparing table properties.
307
21.9k
  bool operator==(const TableProperties& other) const {
308
21.9k
    if (!Equivalent(other)) {
309
0
      return false;
310
0
    }
311
312
21.9k
    return default_time_to_live_ == other.default_time_to_live_ &&
313
21.9k
           use_mangled_column_name_ == other.use_mangled_column_name_ &&
314
21.9k
           contain_counters_ == other.contain_counters_;
315
316
    // Ignoring num_tablets_.
317
    // Ignoring retain_delete_markers_.
318
    // Ignoring wal_retention_secs_.
319
21.9k
  }
320
321
21.9k
  bool operator!=(const TableProperties& other) const {
322
21.9k
    return !(*this == other);
323
21.9k
  }
324
325
21.9k
  bool Equivalent(const TableProperties& other) const {
326
21.9k
    if (is_ysql_catalog_table_ != other.is_ysql_catalog_table_) {
327
0
      return false;
328
0
    }
329
330
21.9k
    if (is_transactional_ != other.is_transactional_) {
331
0
      return false;
332
0
    }
333
334
21.9k
    if (consistency_level_ != other.consistency_level_) {
335
0
      return false;
336
0
    }
337
338
21.9k
    if ((copartition_table_id_ == kNoCopartitionTableId ||
339
21.9k
         
other.copartition_table_id_ == kNoCopartitionTableId0
) &&
340
21.9k
        
copartition_table_id_ != other.copartition_table_id_21.9k
) {
341
0
      return false;
342
0
    }
343
344
    // Ignoring default_time_to_live_.
345
    // Ignoring num_tablets_.
346
    // Ignoring use_mangled_column_name_.
347
    // Ignoring contain_counters_.
348
    // Ignoring retain_delete_markers_.
349
    // Ignoring wal_retention_secs_.
350
21.9k
    return true;
351
21.9k
  }
352
353
312M
  bool HasDefaultTimeToLive() const {
354
312M
    return (default_time_to_live_ != kNoDefaultTtl);
355
312M
  }
356
357
132k
  void SetDefaultTimeToLive(uint64_t default_time_to_live) {
358
132k
    default_time_to_live_ = default_time_to_live;
359
132k
  }
360
361
7.64M
  int64_t DefaultTimeToLive() const {
362
7.64M
    return default_time_to_live_;
363
7.64M
  }
364
365
49.8k
  bool contain_counters() const {
366
49.8k
    return contain_counters_;
367
49.8k
  }
368
369
54.8M
  bool is_transactional() const {
370
54.8M
    return is_transactional_;
371
54.8M
  }
372
373
6.40k
  YBConsistencyLevel consistency_level() const {
374
6.40k
    return consistency_level_;
375
6.40k
  }
376
377
5.68M
  void SetContainCounters(bool contain_counters) {
378
5.68M
    contain_counters_ = contain_counters;
379
5.68M
  }
380
381
5.69M
  void SetTransactional(bool is_transactional) {
382
5.69M
    is_transactional_ = is_transactional;
383
5.69M
  }
384
385
5.68M
  void SetConsistencyLevel(YBConsistencyLevel consistency_level) {
386
5.68M
    consistency_level_ = consistency_level;
387
5.68M
  }
388
389
0
  TableId CopartitionTableId() const {
390
0
    return copartition_table_id_;
391
0
  }
392
393
301M
  bool HasCopartitionTableId() const {
394
301M
    return copartition_table_id_ != kNoCopartitionTableId;
395
301M
  }
396
397
0
  void SetCopartitionTableId(const TableId& copartition_table_id) {
398
0
    copartition_table_id_ = copartition_table_id;
399
0
  }
400
401
5.68M
  void SetUseMangledColumnName(bool value) {
402
5.68M
    use_mangled_column_name_ = value;
403
5.68M
  }
404
405
2.01M
  bool use_mangled_column_name() const {
406
2.01M
    return use_mangled_column_name_;
407
2.01M
  }
408
409
132k
  void SetNumTablets(int num_tablets) {
410
132k
    num_tablets_ = num_tablets;
411
132k
  }
412
413
302M
  bool HasNumTablets() const {
414
302M
    return num_tablets_ > 0;
415
302M
  }
416
417
8.51k
  int num_tablets() const {
418
8.51k
    return num_tablets_;
419
8.51k
  }
420
421
5.70M
  void set_is_ysql_catalog_table(bool is_ysql_catalog_table) {
422
5.70M
    is_ysql_catalog_table_ = is_ysql_catalog_table;
423
5.70M
  }
424
425
30.3M
  bool is_ysql_catalog_table() const {
426
30.3M
    return is_ysql_catalog_table_;
427
30.3M
  }
428
429
496
  bool retain_delete_markers() const {
430
496
    return retain_delete_markers_;
431
496
  }
432
433
5.68M
  void SetRetainDeleteMarkers(bool retain_delete_markers) {
434
5.68M
    retain_delete_markers_ = retain_delete_markers;
435
5.68M
  }
436
437
  void ToTablePropertiesPB(TablePropertiesPB *pb) const;
438
439
  static TableProperties FromTablePropertiesPB(const TablePropertiesPB& pb);
440
441
  void AlterFromTablePropertiesPB(const TablePropertiesPB& pb);
442
443
  void Reset();
444
445
  std::string ToString() const;
446
447
 private:
448
  // IMPORTANT: Every time a new property is added, we need to revisit
449
  // operator== and Equivalent methods to make sure that the new property
450
  // is being taken into consideration when deciding whether properties between
451
  // two different tables are equal or equivalent.
452
  static const int kNoDefaultTtl = -1;
453
  int64_t default_time_to_live_ = kNoDefaultTtl;
454
  bool contain_counters_ = false;
455
  bool is_transactional_ = false;
456
  bool retain_delete_markers_ = false;
457
  YBConsistencyLevel consistency_level_ = YBConsistencyLevel::STRONG;
458
  TableId copartition_table_id_ = kNoCopartitionTableId;
459
  boost::optional<uint32_t> wal_retention_secs_;
460
  bool use_mangled_column_name_ = false;
461
  int num_tablets_ = 0;
462
  bool is_ysql_catalog_table_ = false;
463
};
464
465
typedef std::string PgSchemaName;
466
467
// The schema for a set of rows.
468
//
469
// A Schema is simply a set of columns, along with information about
470
// which prefix of columns makes up the primary key.
471
//
472
// Note that, while Schema is copyable and assignable, it is a complex
473
// object that is not inexpensive to copy. You should generally prefer
474
// passing by pointer or reference, and functions that create new
475
// Schemas should generally prefer taking a Schema pointer and using
476
// Schema::swap() or Schema::Reset() rather than returning by value.
477
class Schema {
478
 public:
479
  static const ssize_t kColumnNotFound = -1;
480
481
  Schema()
482
    : num_key_columns_(0),
483
      num_hash_key_columns_(0),
484
      // TODO: C++11 provides a single-arg constructor
485
      name_to_index_(10,
486
                     NameToIndexMap::hasher(),
487
                     NameToIndexMap::key_equal(),
488
                     NameToIndexMapAllocator(&name_to_index_bytes_)),
489
      has_nullables_(false),
490
      cotable_id_(Uuid::Nil()),
491
      colocation_id_(kColocationIdNotSet),
492
41.9M
      pgschema_name_("") {
493
41.9M
  }
494
495
  Schema(const Schema& other);
496
  Schema& operator=(const Schema& other);
497
498
  void swap(Schema& other); // NOLINT(build/include_what_you_use)
499
500
  void CopyFrom(const Schema& other);
501
502
  // Construct a schema with the given information.
503
  //
504
  // NOTE: if the schema is user-provided, it's better to construct an
505
  // empty schema and then use Reset(...)  so that errors can be
506
  // caught. If an invalid schema is passed to this constructor, an
507
  // assertion will be fired!
508
  Schema(const vector<ColumnSchema>& cols,
509
         size_t key_columns,
510
         const TableProperties& table_properties = TableProperties(),
511
         const Uuid& cotable_id = Uuid::Nil(),
512
         const ColocationId colocation_id = kColocationIdNotSet,
513
         const PgSchemaName pgschema_name = "");
514
515
  // Construct a schema with the given information.
516
  //
517
  // NOTE: if the schema is user-provided, it's better to construct an
518
  // empty schema and then use Reset(...)  so that errors can be
519
  // caught. If an invalid schema is passed to this constructor, an
520
  // assertion will be fired!
521
  Schema(const vector<ColumnSchema>& cols,
522
         const vector<ColumnId>& ids,
523
         size_t key_columns,
524
         const TableProperties& table_properties = TableProperties(),
525
         const Uuid& cotable_id = Uuid::Nil(),
526
         const ColocationId colocation_id = kColocationIdNotSet,
527
         const PgSchemaName pgschema_name = "");
528
529
  // Reset this Schema object to the given schema.
530
  // If this fails, the Schema object is left in an inconsistent
531
  // state and may not be used.
532
  CHECKED_STATUS Reset(const vector<ColumnSchema>& cols, size_t key_columns,
533
                       const TableProperties& table_properties = TableProperties(),
534
                       const Uuid& cotable_id = Uuid::Nil(),
535
                       const ColocationId colocation_id = kColocationIdNotSet,
536
                       const PgSchemaName pgschema_name = "");
537
538
  // Reset this Schema object to the given schema.
539
  // If this fails, the Schema object is left in an inconsistent
540
  // state and may not be used.
541
  CHECKED_STATUS Reset(const vector<ColumnSchema>& cols,
542
                       const vector<ColumnId>& ids,
543
                       size_t key_columns,
544
                       const TableProperties& table_properties = TableProperties(),
545
                       const Uuid& cotable_id = Uuid::Nil(),
546
                       const ColocationId colocation_id = kColocationIdNotSet,
547
                       const PgSchemaName pgschema_name = "");
548
549
  // Return the number of bytes needed to represent a single row of this schema.
550
  //
551
  // This size does not include any indirected (variable length) data (eg strings)
552
163
  size_t byte_size() const {
553
163
    DCHECK(initialized());
554
163
    return col_offsets_.back();
555
163
  }
556
557
  // Return the number of columns in this schema
558
1.18G
  size_t num_columns() const {
559
1.18G
    return cols_.size();
560
1.18G
  }
561
562
  // Return the length of the key prefix in this schema.
563
2.38G
  size_t num_key_columns() const {
564
2.38G
    return num_key_columns_;
565
2.38G
  }
566
567
  // Number of hash key columns.
568
349M
  size_t num_hash_key_columns() const {
569
349M
    return num_hash_key_columns_;
570
349M
  }
571
572
  // Number of range key columns.
573
181M
  size_t num_range_key_columns() const {
574
181M
    return num_key_columns_ - num_hash_key_columns_;
575
181M
  }
576
577
  // Return the byte offset within the row for the given column index.
578
77
  size_t column_offset(size_t col_idx) const {
579
77
    DCHECK_LT(col_idx, cols_.size());
580
77
    return col_offsets_[col_idx];
581
77
  }
582
583
  // Return the ColumnSchema corresponding to the given column index.
584
969M
  inline const ColumnSchema &column(size_t idx) const {
585
969M
    DCHECK_LT(idx, cols_.size());
586
969M
    return cols_[idx];
587
969M
  }
588
589
  // Return the ColumnSchema corresponding to the given column ID.
590
  Result<const ColumnSchema&> column_by_id(ColumnId id) const;
591
592
  // Return the column ID corresponding to the given column index
593
3.06G
  ColumnId column_id(size_t idx) const {
594
3.06G
    DCHECK(has_column_ids());
595
3.06G
    DCHECK_LT(idx, cols_.size());
596
3.06G
    return col_ids_[idx];
597
3.06G
  }
598
599
  // Return true if the schema contains an ID mapping for its columns.
600
  // In the case of an empty schema, this is false.
601
5.61G
  bool has_column_ids() const {
602
5.61G
    return !col_ids_.empty();
603
5.61G
  }
604
605
318M
  const std::vector<ColumnSchema>& columns() const {
606
318M
    return cols_;
607
318M
  }
608
609
2.25M
  const std::vector<ColumnId>& column_ids() const {
610
2.25M
    return col_ids_;
611
2.25M
  }
612
613
0
  const std::vector<std::string> column_names() const {
614
0
    std::vector<std::string> column_names;
615
0
    for (const auto& col : cols_) {
616
0
      column_names.push_back(col.name());
617
0
    }
618
0
    return column_names;
619
0
  }
620
621
408M
  const TableProperties& table_properties() const {
622
408M
    return table_properties_;
623
408M
  }
624
625
13.3k
  TableProperties* mutable_table_properties() {
626
13.3k
    return &table_properties_;
627
13.3k
  }
628
629
4
  void SetDefaultTimeToLive(const uint64_t& ttl_msec) {
630
4
    table_properties_.SetDefaultTimeToLive(ttl_msec);
631
4
  }
632
633
0
  void SetCopartitionTableId(const TableId& copartition_table_id) {
634
0
    table_properties_.SetCopartitionTableId(copartition_table_id);
635
0
  }
636
637
15
  void SetTransactional(bool is_transactional) {
638
15
    table_properties_.SetTransactional(is_transactional);
639
15
  }
640
641
12.1k
  void SetRetainDeleteMarkers(bool retain_delete_markers) {
642
12.1k
    table_properties_.SetRetainDeleteMarkers(retain_delete_markers);
643
12.1k
  }
644
645
0
  bool has_pgschema_name() const {
646
0
    return !pgschema_name_.empty();
647
0
  }
648
649
5.68M
  void SetSchemaName(std::string pgschema_name) {
650
5.68M
    pgschema_name_ = pgschema_name;
651
5.68M
  }
652
653
301M
  PgSchemaName SchemaName() const {
654
301M
    return pgschema_name_;
655
301M
  }
656
657
  // Return the column index corresponding to the given column,
658
  // or kColumnNotFound if the column is not in this schema.
659
22.8M
  ssize_t find_column(const GStringPiece col_name) const {
660
22.8M
    auto iter = name_to_index_.find(col_name);
661
22.8M
    if (PREDICT_FALSE(iter == name_to_index_.end())) {
662
5
      return kColumnNotFound;
663
22.8M
    } else {
664
22.8M
      return iter->second;
665
22.8M
    }
666
22.8M
  }
667
668
  Result<ColumnId> ColumnIdByName(const std::string& name) const;
669
670
  Result<ssize_t> ColumnIndexByName(GStringPiece col_name) const;
671
672
  // Returns true if the schema contains nullable columns
673
142
  bool has_nullables() const {
674
142
    return has_nullables_;
675
142
  }
676
677
  // Returns true if the schema contains static columns
678
133M
  bool has_statics() const {
679
133M
    return has_statics_;
680
133M
  }
681
682
  // Returns true if the specified column (by index) is a key
683
98.0M
  bool is_key_column(size_t idx) const {
684
98.0M
    return idx < num_key_columns_;
685
98.0M
  }
686
687
  // Returns true if the specified column (by column id) is a key
688
51.9M
  bool is_key_column(ColumnId column_id) const {
689
51.9M
    return is_key_column(find_column_by_id(column_id));
690
51.9M
  }
691
692
  // Returns true if the specified column (by name) is a key
693
232
  bool is_key_column(const GStringPiece col_name) const {
694
232
    return is_key_column(find_column(col_name));
695
232
  }
696
697
  // Returns true if the specified column (by index) is a hash key
698
5.05M
  bool is_hash_key_column(size_t idx) const {
699
5.05M
    return idx < num_hash_key_columns_;
700
5.05M
  }
701
702
  // Returns true if the specified column (by column id) is a hash key
703
0
  bool is_hash_key_column(ColumnId column_id) const {
704
0
    return is_hash_key_column(find_column_by_id(column_id));
705
0
  }
706
707
  // Returns true if the specified column (by name) is a hash key
708
0
  bool is_hash_key_column(const GStringPiece col_name) const {
709
0
    return is_hash_key_column(find_column(col_name));
710
0
  }
711
712
  // Returns true if the specified column (by index) is a range column
713
5.06M
  bool is_range_column(size_t idx) const {
714
5.06M
    return is_key_column(idx) && 
!is_hash_key_column(idx)5.05M
;
715
5.06M
  }
716
717
  // Returns true if the specified column (by column id) is a range column
718
4.73M
  bool is_range_column(ColumnId column_id) const {
719
4.73M
    return is_range_column(find_column_by_id(column_id));
720
4.73M
  }
721
722
  // Returns true if the specified column (by name) is a range column
723
0
  bool is_range_column(const GStringPiece col_name) const {
724
0
    return is_range_column(find_column(col_name));
725
0
  }
726
727
  // Return true if this Schema is initialized and valid.
728
12.3k
  bool initialized() const {
729
12.3k
    return !cols_.empty();
730
12.3k
  }
731
732
  // Returns the highest column id in this Schema.
733
56.3k
  ColumnId max_col_id() const {
734
56.3k
    return max_col_id_;
735
56.3k
  }
736
737
  // Gets and sets the uuid of the non-primary table this schema belongs to co-located in a tablet.
738
468M
  const Uuid& cotable_id() const {
739
468M
    return cotable_id_;
740
468M
  }
741
742
304M
  bool has_cotable_id() const {
743
304M
    return !cotable_id_.IsNil();
744
304M
  }
745
746
1.02M
  void set_cotable_id(const Uuid& cotable_id) {
747
1.02M
    if (!cotable_id.IsNil()) {
748
1.02M
      DCHECK_EQ(colocation_id_, kColocationIdNotSet);
749
1.02M
    }
750
1.02M
    cotable_id_ = cotable_id;
751
1.02M
  }
752
753
  // Gets the colocation ID of the non-primary table this schema belongs to in a
754
  // tablet with colocated tables.
755
80.4M
  ColocationId colocation_id() const {
756
80.4M
    return colocation_id_;
757
80.4M
  }
758
759
304M
  bool has_colocation_id() const {
760
304M
    return colocation_id_ != kColocationIdNotSet;
761
304M
  }
762
763
1.46k
  void set_colocation_id(const ColocationId colocation_id) {
764
1.46k
    if (colocation_id != kColocationIdNotSet) {
765
1.46k
      DCHECK(cotable_id_.IsNil());
766
1.46k
    }
767
1.46k
    colocation_id_ = colocation_id;
768
1.46k
  }
769
770
  // Extract a given column from a row where the type is
771
  // known at compile-time. The type is checked with a debug
772
  // assertion -- but if the wrong type is used and these assertions
773
  // are off, incorrect data may result.
774
  //
775
  // This is mostly useful for tests at this point.
776
  // TODO: consider removing it.
777
  template<DataType Type, class RowType>
778
  const typename DataTypeTraits<Type>::cpp_type *
779
  ExtractColumnFromRow(const RowType& row, size_t idx) const {
780
    DCHECK_SCHEMA_EQ(*this, *row.schema());
781
    const ColumnSchema& col_schema = cols_[idx];
782
    DCHECK_LT(idx, cols_.size());
783
    DCHECK_EQ(col_schema.type_info()->type, Type);
784
785
    const void *val;
786
    if (col_schema.is_nullable()) {
787
      val = row.nullable_cell_ptr(idx);
788
    } else {
789
      val = row.cell_ptr(idx);
790
    }
791
792
    return reinterpret_cast<const typename DataTypeTraits<Type>::cpp_type *>(val);
793
  }
794
795
  // Stringify the given row, which conforms to this schema,
796
  // in a way suitable for debugging. This isn't currently optimized
797
  // so should be avoided in hot paths.
798
  template<class RowType>
799
  std::string DebugRow(const RowType& row) const {
800
    DCHECK_SCHEMA_EQ(*this, *row.schema());
801
    return DebugRowColumns(row, num_columns());
802
  }
803
804
  // Compare two rows of this schema.
805
  template<class RowTypeA, class RowTypeB>
806
  int Compare(const RowTypeA& lhs, const RowTypeB& rhs) const {
807
    DCHECK(KeyEquals(*lhs.schema()) && KeyEquals(*rhs.schema()));
808
809
    for (size_t col = 0; col < num_key_columns_; col++) {
810
      int col_compare = column(col).Compare(lhs.cell_ptr(col), rhs.cell_ptr(col));
811
      if (col_compare != 0) {
812
        return col_compare;
813
      }
814
    }
815
    return 0;
816
  }
817
818
  // Return the projection of this schema which contains only
819
  // the key columns.
820
  // TODO: this should take a Schema* out-parameter to avoid an
821
  // extra copy of the ColumnSchemas.
822
  // TODO this should probably be cached since the key projection
823
  // is not supposed to change, for a single schema.
824
292k
  Schema CreateKeyProjection() const {
825
292k
    vector<ColumnSchema> key_cols(cols_.begin(),
826
292k
                                  cols_.begin() + num_key_columns_);
827
292k
    vector<ColumnId> col_ids;
828
292k
    if (!col_ids_.empty()) {
829
291k
      col_ids.assign(col_ids_.begin(), col_ids_.begin() + num_key_columns_);
830
291k
    }
831
832
292k
    return Schema(key_cols, col_ids, num_key_columns_);
833
292k
  }
834
835
  // Initialize column IDs by default values.
836
  // Requires that this schema has no column IDs.
837
  void InitColumnIdsByDefault();
838
839
  // Return a new Schema which is the same as this one, but without any column
840
  // IDs assigned.
841
  //
842
  // Requires that this schema has column IDs.
843
  Schema CopyWithoutColumnIds() const;
844
845
  // Create a new schema containing only the selected columns.
846
  // The resulting schema will have no key columns defined.
847
  // If this schema has IDs, the resulting schema will as well.
848
  CHECKED_STATUS CreateProjectionByNames(const std::vector<GStringPiece>& col_names,
849
                                         Schema* out, size_t num_key_columns = 0) const;
850
851
  // Create a new schema containing only the selected column IDs.
852
  //
853
  // If any column IDs are invalid, then they will be ignored and the
854
  // result will have fewer columns than requested.
855
  //
856
  // The resulting schema will have no key columns defined.
857
  CHECKED_STATUS CreateProjectionByIdsIgnoreMissing(const std::vector<ColumnId>& col_ids,
858
                                                    Schema* out) const;
859
860
  // Stringify this Schema. This is not particularly efficient,
861
  // so should only be used when necessary for output.
862
  std::string ToString() const;
863
864
  // Return true if the schemas have exactly the same set of columns
865
  // and respective types, and the same table properties.
866
  template <typename ColumnComparator>
867
21.9k
  bool Equals(const Schema &other, ColumnComparator comp) const {
868
21.9k
    if (this == &other) 
return true0
;
869
21.9k
    if (this->num_key_columns_ != other.num_key_columns_) 
return false4
;
870
21.9k
    if (this->table_properties_ != other.table_properties_) 
return false0
;
871
21.9k
    if (this->cols_.size() != other.cols_.size()) 
return false7
;
872
873
162k
    
for (size_t i = 0; 21.9k
i < other.cols_.size();
i++140k
) {
874
140k
      if (!this->cols_[i].Equals(other.cols_[i], comp)) 
return false0
;
875
140k
    }
876
877
21.9k
    return true;
878
21.9k
  }
bool yb::Schema::Equals<bool (*)(yb::ColumnSchema const&, yb::ColumnSchema const&)>(yb::Schema const&, bool (*)(yb::ColumnSchema const&, yb::ColumnSchema const&)) const
Line
Count
Source
867
21.9k
  bool Equals(const Schema &other, ColumnComparator comp) const {
868
21.9k
    if (this == &other) 
return true0
;
869
21.9k
    if (this->num_key_columns_ != other.num_key_columns_) 
return false4
;
870
21.9k
    if (this->table_properties_ != other.table_properties_) 
return false0
;
871
21.9k
    if (this->cols_.size() != other.cols_.size()) 
return false7
;
872
873
162k
    
for (size_t i = 0; 21.9k
i < other.cols_.size();
i++140k
) {
874
140k
      if (!this->cols_[i].Equals(other.cols_[i], comp)) 
return false0
;
875
140k
    }
876
877
21.9k
    return true;
878
21.9k
  }
Unexecuted instantiation: catalog_manager_ent.cc:bool yb::Schema::Equals<yb::master::enterprise::CatalogManager::ImportTableEntry(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::YQLDatabase>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::YQLDatabase> > > > const&, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData> > > const&, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData*)::CompareColumnsExceptNullable>(yb::Schema const&, yb::master::enterprise::CatalogManager::ImportTableEntry(std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::YQLDatabase>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::YQLDatabase> > > > const&, std::__1::map<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData> > > const&, yb::master::enterprise::CatalogManager::ExternalTableSnapshotData*)::CompareColumnsExceptNullable) const
879
880
21.9k
  bool Equals(const Schema &other) const {
881
21.9k
    return Equals(other, ColumnSchema::CompareByDefault);
882
21.9k
  }
883
884
  // Return true if the schemas have exactly the same set of columns
885
  // and respective types, and equivalent properties.
886
  // For example, one table property could have different properties for wal_retention_secs_ and
887
  // retain_delete_markers_ but still be equivalent.
888
0
  bool EquivalentForDataCopy(const Schema& other) const {
889
0
    if (this == &other) return true;
890
0
    if (this->num_key_columns_ != other.num_key_columns_) return false;
891
0
    if (!this->table_properties_.Equivalent(other.table_properties_)) return false;
892
0
    if (this->cols_.size() != other.cols_.size()) return false;
893
0
894
0
    for (size_t i = 0; i < other.cols_.size(); i++) {
895
0
      if (!this->cols_[i].Equals(other.cols_[i])) return false;
896
0
      if (this->column_id(i) != other.column_id(i)) return false;
897
0
    }
898
0
899
0
    return true;
900
0
  }
901
902
  // Return true if the key projection schemas have exactly the same set of
903
  // columns and respective types. Doesn't check column names.
904
141k
  bool KeyEquals(const Schema& other) const {
905
141k
    if (this->num_key_columns_ != other.num_key_columns_) 
return false0
;
906
451k
    
for (size_t i = 0; 141k
i < this->num_key_columns_;
i++309k
) {
907
309k
      if (!this->cols_[i].EqualsType(other.cols_[i])) 
return false0
;
908
309k
    }
909
141k
    return true;
910
141k
  }
911
912
  // Return a non-OK status if the project is not compatible with the current schema
913
  // - User columns non present in the tablet are considered errors
914
  // - Matching columns with different types, at the moment, are considered errors
915
  CHECKED_STATUS VerifyProjectionCompatibility(const Schema& projection) const;
916
917
  // Returns the projection schema mapped on the current one
918
  // If the project is invalid, return a non-OK status.
919
  CHECKED_STATUS GetMappedReadProjection(const Schema& projection,
920
                                 Schema *mapped_projection) const;
921
922
  // Loops through this schema (the projection) and calls the projector methods once for
923
  // each column.
924
  //
925
  // - CHECKED_STATUS ProjectBaseColumn(size_t proj_col_idx, size_t base_col_idx)
926
  //
927
  //     Called if the column in this schema matches one of the columns in 'base_schema'.
928
  //     The column type must match exactly.
929
  //
930
  // - CHECKED_STATUS ProjectDefaultColumn(size_t proj_idx)
931
  //
932
  //     Called if the column in this schema does not match any column in 'base_schema',
933
  //     but has a default or is nullable.
934
  //
935
  // - CHECKED_STATUS ProjectExtraColumn(size_t proj_idx, const ColumnSchema& col)
936
  //
937
  //     Called if the column in this schema does not match any column in 'base_schema',
938
  //     and does not have a default, and is not nullable.
939
  //
940
  // If both schemas have column IDs, then the matching is done by ID. Otherwise, it is
941
  // done by name.
942
  //
943
  // TODO(MAYBE): Pass the ColumnSchema and not only the column index?
944
  template <class Projector>
945
5
  CHECKED_STATUS GetProjectionMapping(const Schema& base_schema, Projector *projector) const {
946
5
    const bool use_column_ids = base_schema.has_column_ids() && 
has_column_ids()1
;
947
948
5
    int proj_idx = 0;
949
13
    for (size_t i = 0; i < cols_.size(); 
++i8
) {
950
10
      const ColumnSchema& col_schema = cols_[i];
951
952
      // try to lookup the column by ID if present or just by name.
953
      // Unit tests and Iter-Projections are probably always using the
954
      // lookup by name. The IDs are generally set by the server on AlterTable().
955
10
      ssize_t base_idx;
956
10
      if (use_column_ids) {
957
3
        base_idx = base_schema.find_column_by_id(col_ids_[i]);
958
7
      } else {
959
7
        base_idx = base_schema.find_column(col_schema.name());
960
7
      }
961
962
10
      if (base_idx >= 0) {
963
7
        const ColumnSchema& base_col_schema = base_schema.column(base_idx);
964
        // Column present in the Base Schema...
965
7
        if (!col_schema.EqualsType(base_col_schema)) {
966
          // ...but with a different type, (TODO: try with an adaptor)
967
1
          return STATUS(InvalidArgument, "The column '" + col_schema.name() +
968
1
                                         "' must have type " +
969
1
                                         base_col_schema.TypeToString() +
970
1
                                         " found " + col_schema.TypeToString());
971
6
        } else {
972
6
          RETURN_NOT_OK(projector->ProjectBaseColumn(proj_idx, base_idx));
973
6
        }
974
7
      } else {
975
3
        if (!col_schema.is_nullable()) {
976
1
          RETURN_NOT_OK(projector->ProjectExtraColumn(proj_idx));
977
1
        }
978
3
      }
979
8
      proj_idx++;
980
8
    }
981
3
    return Status::OK();
982
5
  }
983
984
  // Returns the column index given the column ID.
985
  // If no such column exists, returns kColumnNotFound.
986
178M
  int find_column_by_id(ColumnId id) const {
987
178M
    DCHECK(cols_.empty() || has_column_ids());
988
178M
    int ret = id_to_index_[id];
989
178M
    if (ret == -1) {
990
2.74k
      return kColumnNotFound;
991
2.74k
    }
992
178M
    return ret;
993
178M
  }
994
995
  // Returns the memory usage of this object without the object itself. Should
996
  // be used when embedded inside another object.
997
  size_t memory_footprint_excluding_this() const;
998
999
  // Returns the memory usage of this object including the object itself.
1000
  // Should be used when allocated on the heap.
1001
  size_t memory_footprint_including_this() const;
1002
1003
  static ColumnId first_column_id();
1004
1005
 private:
1006
1007
  void ResetColumnIds(const vector<ColumnId>& ids);
1008
1009
  // Return a stringified version of the first 'num_columns' columns of the
1010
  // row.
1011
  template<class RowType>
1012
  std::string DebugRowColumns(const RowType& row, size_t num_columns) const {
1013
    std::string ret;
1014
    ret.append("(");
1015
1016
    for (size_t col_idx = 0; col_idx < num_columns; col_idx++) {
1017
      if (col_idx > 0) {
1018
        ret.append(", ");
1019
      }
1020
      const ColumnSchema& col = cols_[col_idx];
1021
      col.DebugCellAppend(row.cell(col_idx), &ret);
1022
    }
1023
    ret.append(")");
1024
    return ret;
1025
  }
1026
1027
  friend class SchemaBuilder;
1028
1029
  vector<ColumnSchema> cols_;
1030
  size_t num_key_columns_;
1031
  size_t num_hash_key_columns_;
1032
  ColumnId max_col_id_;
1033
  vector<ColumnId> col_ids_;
1034
  vector<size_t> col_offsets_;
1035
1036
  // The keys of this map are GStringPiece references to the actual name members of the
1037
  // ColumnSchema objects inside cols_. This avoids an extra copy of those strings,
1038
  // and also allows us to do lookups on the map using GStringPiece keys, sometimes
1039
  // avoiding copies.
1040
  //
1041
  // The map is instrumented with a counting allocator so that we can accurately
1042
  // measure its memory footprint.
1043
  int64_t name_to_index_bytes_ = 0;
1044
  typedef STLCountingAllocator<std::pair<const GStringPiece, size_t>> NameToIndexMapAllocator;
1045
  typedef std::unordered_map<
1046
      GStringPiece,
1047
      size_t,
1048
      std::hash<GStringPiece>,
1049
      std::equal_to<GStringPiece>,
1050
      NameToIndexMapAllocator> NameToIndexMap;
1051
  NameToIndexMap name_to_index_;
1052
1053
  IdMapping id_to_index_;
1054
1055
  // Cached indicator whether any columns are nullable.
1056
  bool has_nullables_;
1057
1058
  // Cached indicator whether any columns are static.
1059
  bool has_statics_ = false;
1060
1061
  TableProperties table_properties_;
1062
1063
  // Uuid of the non-primary table this schema belongs to co-located in a tablet. Nil for the
1064
  // primary or single-tenant table.
1065
  Uuid cotable_id_;
1066
1067
  // Colocation ID used to distinguish a table within a colocation group.
1068
  // kColocationIdNotSet for a primary or single-tenant table.
1069
  ColocationId colocation_id_;
1070
1071
  PgSchemaName pgschema_name_;
1072
1073
  // NOTE: if you add more members, make sure to add the appropriate
1074
  // code to swap() and CopyFrom() as well to prevent subtle bugs.
1075
};
1076
1077
// Helper used for schema creation/editing.
1078
//
1079
// Example:
1080
//   Status s;
1081
//   SchemaBuilder builder(base_schema);
1082
//   s = builder.RemoveColumn("value");
1083
//   s = builder.AddKeyColumn("key2", STRING);
1084
//   s = builder.AddColumn("new_c1", UINT32);
1085
//   ...
1086
//   Schema new_schema = builder.Build();
1087
//
1088
// TODO(neil): Must introduce hash_key in this builder. Currently, only YBSchemaBuilder support
1089
// hash key, and YBSchemaBuilder don't use this builder.
1090
class SchemaBuilder {
1091
 public:
1092
64.1k
  SchemaBuilder() { Reset(); }
1093
1.50k
  explicit SchemaBuilder(const Schema& schema) { Reset(schema); }
1094
1095
  void Reset();
1096
  void Reset(const Schema& schema);
1097
1098
0
  bool is_valid() const { return cols_.size() > 0; }
1099
1100
  // Set the next column ID to be assigned to columns added with
1101
  // AddColumn.
1102
581
  void set_next_column_id(ColumnId next_id) {
1103
581
    DCHECK_GE(next_id, ColumnId(0));
1104
581
    next_id_ = next_id;
1105
581
  }
1106
1107
  // Return the next column ID that would be assigned with AddColumn.
1108
580
  ColumnId next_column_id() const {
1109
580
    return next_id_;
1110
580
  }
1111
1112
0
  void set_colocation_id(ColocationId colocation_id) {
1113
0
    colocation_id_ = colocation_id;
1114
0
  }
1115
1116
0
  ColocationId colocation_id() const {
1117
0
    return colocation_id_;
1118
0
  }
1119
1120
0
  void set_pgschema_name(PgSchemaName pgschema_name) {
1121
0
    pgschema_name_ = pgschema_name;
1122
0
  }
1123
1124
0
  PgSchemaName pgschema_name() const {
1125
0
    return pgschema_name_;
1126
0
  }
1127
1128
0
  void set_cotable_id(Uuid cotable_id) {
1129
0
    cotable_id_ = cotable_id;
1130
0
  }
1131
1132
0
  Uuid cotable_id() const {
1133
0
    return cotable_id_;
1134
0
  }
1135
1136
65.6k
  Schema Build() const {
1137
65.6k
    return Schema(cols_, col_ids_, num_key_columns_, table_properties_, cotable_id_,
1138
65.6k
                  colocation_id_, pgschema_name_);
1139
65.6k
  }
1140
  Schema BuildWithoutIds() const {
1141
    return Schema(cols_, num_key_columns_, table_properties_, cotable_id_,
1142
                  colocation_id_, pgschema_name_);
1143
  }
1144
1145
  // assumes type is allowed in primary key -- this should be checked before getting here
1146
  // using DataType (not QLType) since primary key columns only support elementary types
1147
  CHECKED_STATUS AddKeyColumn(const std::string& name, const std::shared_ptr<QLType>& type);
1148
  CHECKED_STATUS AddKeyColumn(const std::string& name, DataType type);
1149
1150
  // assumes type is allowed in hash key -- this should be checked before getting here
1151
  // using DataType (not QLType) since hash key columns only support elementary types
1152
  CHECKED_STATUS AddHashKeyColumn(const std::string& name, const std::shared_ptr<QLType>& type);
1153
  CHECKED_STATUS AddHashKeyColumn(const std::string& name, DataType type);
1154
1155
  CHECKED_STATUS AddColumn(const ColumnSchema& column, bool is_key);
1156
1157
331k
  CHECKED_STATUS AddColumn(const std::string& name, const std::shared_ptr<QLType>& type) {
1158
331k
    return AddColumn(name, type, false, false, false, false, 0,
1159
331k
                     SortingType::kNotSpecified);
1160
331k
  }
1161
1162
  // convenience function for adding columns with simple (non-parametric) data types
1163
  CHECKED_STATUS AddColumn(const std::string& name, DataType type);
1164
1165
2
  CHECKED_STATUS AddNullableColumn(const std::string& name, const std::shared_ptr<QLType>& type) {
1166
2
    return AddColumn(name, type, true, false, false, false, 0,
1167
2
                     SortingType::kNotSpecified);
1168
2
  }
1169
1170
  // convenience function for adding columns with simple (non-parametric) data types
1171
  CHECKED_STATUS AddNullableColumn(const std::string& name, DataType type);
1172
1173
  CHECKED_STATUS AddColumn(const std::string& name,
1174
                           const std::shared_ptr<QLType>& type,
1175
                           bool is_nullable,
1176
                           bool is_hash_key,
1177
                           bool is_static,
1178
                           bool is_counter,
1179
                           int32_t order,
1180
                           yb::SortingType sorting_type);
1181
1182
  // convenience function for adding columns with simple (non-parametric) data types
1183
  CHECKED_STATUS AddColumn(const std::string& name,
1184
                           DataType type,
1185
                           bool is_nullable,
1186
                           bool is_hash_key,
1187
                           bool is_static,
1188
                           bool is_counter,
1189
                           int32_t order,
1190
                           yb::SortingType sorting_type);
1191
1192
  CHECKED_STATUS RemoveColumn(const std::string& name);
1193
  CHECKED_STATUS RenameColumn(const std::string& old_name, const std::string& new_name);
1194
  CHECKED_STATUS AlterProperties(const TablePropertiesPB& pb);
1195
1196
 private:
1197
  ColumnId next_id_;
1198
  vector<ColumnId> col_ids_;
1199
  vector<ColumnSchema> cols_;
1200
  std::unordered_set<string> col_names_;
1201
  size_t num_key_columns_;
1202
  TableProperties table_properties_;
1203
  ColocationId colocation_id_ = kColocationIdNotSet;
1204
  PgSchemaName pgschema_name_ = "";
1205
  Uuid cotable_id_ = Uuid::Nil();
1206
1207
  DISALLOW_COPY_AND_ASSIGN(SchemaBuilder);
1208
};
1209
} // namespace yb
1210
1211
// Specialize std::hash for ColumnId
1212
namespace std {
1213
template<>
1214
struct hash<yb::ColumnId> {
1215
9.06M
  int operator()(const yb::ColumnId& col_id) const {
1216
9.06M
    return col_id;
1217
9.06M
  }
1218
};
1219
} // namespace std
1220
1221
#endif  // YB_COMMON_SCHEMA_H