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