/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 |