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