1 /* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "sql/dd/impl/types/table_impl.h"
24
25 #include <string.h>
26 #include <set>
27 #include <sstream>
28 #include <string>
29
30 #include "my_rapidjson_size_t.h" // IWYU pragma: keep
31
32 #include <rapidjson/document.h>
33 #include <rapidjson/prettywriter.h>
34
35 #include "m_string.h"
36 #include "my_dbug.h"
37 #include "my_sys.h"
38 #include "mysqld_error.h" // ER_*
39 #include "sql/current_thd.h" // current_thd
40 #include "sql/dd/impl/bootstrap/bootstrap_ctx.h" // dd::bootstrap::DD_bootstrap_ctx
41 #include "sql/dd/impl/dictionary_impl.h" // Dictionary_impl
42 #include "sql/dd/impl/properties_impl.h" // Properties_impl
43 #include "sql/dd/impl/raw/raw_record.h" // Raw_record
44 #include "sql/dd/impl/raw/raw_record_set.h" // Raw_record_set
45 #include "sql/dd/impl/raw/raw_table.h" // Raw_table
46 #include "sql/dd/impl/sdi_impl.h" // sdi read/write functions
47 #include "sql/dd/impl/tables/check_constraints.h" // Check_constraints
48 #include "sql/dd/impl/tables/columns.h" // Columns
49 #include "sql/dd/impl/tables/foreign_keys.h" // Foreign_keys
50 #include "sql/dd/impl/tables/indexes.h" // Indexes
51 #include "sql/dd/impl/tables/schemata.h" // Schemata
52 #include "sql/dd/impl/tables/table_partitions.h" // Table_partitions
53 #include "sql/dd/impl/tables/tables.h" // Tables
54 #include "sql/dd/impl/tables/triggers.h" // Triggers
55 #include "sql/dd/impl/transaction_impl.h" // Open_dictionary_tables_ctx
56 #include "sql/dd/impl/types/check_constraint_impl.h" // Check_constraint_impl
57 #include "sql/dd/impl/types/foreign_key_impl.h" // Foreign_key_impl
58 #include "sql/dd/impl/types/index_impl.h" // Index_impl
59 #include "sql/dd/impl/types/partition_impl.h" // Partition_impl
60 #include "sql/dd/impl/types/trigger_impl.h" // Trigger_impl
61 #include "sql/dd/properties.h"
62 #include "sql/dd/string_type.h" // dd::String_type
63 #include "sql/dd/types/column.h" // Column
64 #include "sql/dd/types/foreign_key.h"
65 #include "sql/dd/types/index.h"
66 #include "sql/dd/types/partition.h"
67 #include "sql/dd/types/weak_object.h"
68 #include "sql/sql_class.h"
69
70 using dd::tables::Check_constraints;
71 using dd::tables::Foreign_keys;
72 using dd::tables::Indexes;
73 using dd::tables::Table_partitions;
74 using dd::tables::Tables;
75 using dd::tables::Triggers;
76
77 namespace dd {
78
79 class Sdi_rcontext;
80 class Sdi_wcontext;
81
82 ///////////////////////////////////////////////////////////////////////////
83 // Table_impl implementation.
84 ///////////////////////////////////////////////////////////////////////////
85
Table_impl()86 Table_impl::Table_impl()
87 : m_se_private_id(INVALID_OBJECT_ID),
88 m_se_private_data(),
89 m_row_format(RF_FIXED),
90 m_is_temporary(false),
91 m_partition_type(PT_NONE),
92 m_default_partitioning(DP_NONE),
93 m_subpartition_type(ST_NONE),
94 m_default_subpartitioning(DP_NONE),
95 m_indexes(),
96 m_foreign_keys(),
97 m_partitions(),
98 m_triggers(),
99 m_check_constraints(),
100 m_collation_id(INVALID_OBJECT_ID),
101 m_tablespace_id(INVALID_OBJECT_ID) {}
102
~Table_impl()103 Table_impl::~Table_impl() { delete_container_pointers(m_foreign_key_parents); }
104
105 ///////////////////////////////////////////////////////////////////////////
106
validate() const107 bool Table_impl::validate() const {
108 if (Abstract_table_impl::validate()) return true;
109
110 if (m_collation_id == INVALID_OBJECT_ID) {
111 my_error(ER_INVALID_DD_OBJECT, MYF(0), DD_table::instance().name().c_str(),
112 "Collation ID not set.");
113 return true;
114 }
115
116 if (m_engine.empty()) {
117 my_error(ER_INVALID_DD_OBJECT, MYF(0), DD_table::instance().name().c_str(),
118 "Engine name is not set.");
119 return true;
120 }
121
122 return false;
123 }
124
125 ///////////////////////////////////////////////////////////////////////////
126
load_foreign_key_parents(Open_dictionary_tables_ctx * otx)127 bool Table_impl::load_foreign_key_parents(Open_dictionary_tables_ctx *otx) {
128 /*
129 Read information about FKs where this table is the parent.
130 The relevant tables are already opened.
131 */
132
133 // 1. Read the parent's schema name based on schema_id.
134 Raw_table *schema_table = otx->get_table<dd::Schema>();
135 DBUG_ASSERT(schema_table);
136 Primary_id_key schema_pk(schema_id());
137
138 std::unique_ptr<Raw_record_set> schema_rs;
139 if (schema_table->open_record_set(&schema_pk, schema_rs)) return true;
140
141 Raw_record *schema_rec = schema_rs->current_record();
142 DBUG_ASSERT(schema_rec);
143 if (schema_rec == nullptr) return true;
144
145 // 2. Build a key for searching the FK table.
146 Table_reference_range_key parent_ref_key(
147 tables::Foreign_keys::INDEX_K_REF_CATALOG_REF_SCHEMA_REF_TABLE,
148 tables::Foreign_keys::FIELD_REFERENCED_TABLE_CATALOG,
149 String_type(Dictionary_impl::default_catalog_name()),
150 tables::Foreign_keys::FIELD_REFERENCED_TABLE_SCHEMA,
151 schema_rec->read_str(tables::Schemata::FIELD_NAME),
152 tables::Foreign_keys::FIELD_REFERENCED_TABLE, name());
153
154 // 3. Get the FK record set where this table is parent.
155 Raw_table *foreign_key_table = otx->get_table<dd::Foreign_key>();
156 DBUG_ASSERT(foreign_key_table);
157
158 std::unique_ptr<Raw_record_set> child_fk_rs;
159 if (foreign_key_table->open_record_set(&parent_ref_key, child_fk_rs))
160 return true;
161
162 Raw_record *child_fk_rec = child_fk_rs->current_record();
163 while (child_fk_rec) {
164 // 4.1 Get the child table record based on the child table id.
165 Primary_id_key child_pk(
166 child_fk_rec->read_int(tables::Foreign_keys::FIELD_TABLE_ID));
167 Raw_table *tables_table = otx->get_table<dd::Table>();
168 DBUG_ASSERT(tables_table);
169
170 std::unique_ptr<Raw_record_set> child_table_rs;
171 if (tables_table->open_record_set(&child_pk, child_table_rs)) return true;
172
173 Raw_record *child_table = child_table_rs->current_record();
174 DBUG_ASSERT(child_table);
175 if (child_table == nullptr) return true;
176
177 /*
178 4.2 Filter out child tables belonging to different SEs.
179 This is not supported at the moment and we don't want
180 such FKs to show up as Foreign_key_parent objects.
181 */
182 if (my_strcasecmp(
183 system_charset_info,
184 child_table->read_str(tables::Tables::FIELD_ENGINE).c_str(),
185 m_engine.c_str()) != 0) {
186 if (child_fk_rs->next(child_fk_rec)) return true;
187 continue;
188 }
189
190 // 5. Get the child schema record based on schema id from the table record.
191 schema_pk.update(child_table->read_int(tables::Tables::FIELD_SCHEMA_ID));
192 schema_rs.reset(nullptr); // Must end index read to allow new index read.
193 if (schema_table->open_record_set(&schema_pk, schema_rs)) return true;
194
195 schema_rec = schema_rs->current_record();
196 DBUG_ASSERT(schema_rec);
197 if (schema_rec == nullptr) return true;
198
199 // 6. Collect the relevant information.
200 Foreign_key_parent *fk_parent = add_foreign_key_parent();
201 fk_parent->set_child_schema_name(
202 schema_rec->read_str(tables::Schemata::FIELD_NAME));
203 fk_parent->set_child_table_name(
204 child_table->read_str(tables::Tables::FIELD_NAME));
205 fk_parent->set_fk_name(
206 child_fk_rec->read_str(tables::Foreign_keys::FIELD_NAME));
207
208 Foreign_key::enum_rule update_rule = static_cast<Foreign_key::enum_rule>(
209 child_fk_rec->read_int(tables::Foreign_keys::FIELD_UPDATE_RULE));
210
211 fk_parent->set_update_rule(update_rule);
212
213 Foreign_key::enum_rule delete_rule = static_cast<Foreign_key::enum_rule>(
214 child_fk_rec->read_int(tables::Foreign_keys::FIELD_DELETE_RULE));
215
216 fk_parent->set_delete_rule(delete_rule);
217
218 // 7. Get next child record.
219 if (child_fk_rs->next(child_fk_rec)) return true;
220 }
221
222 return false;
223 }
224
225 ///////////////////////////////////////////////////////////////////////////
226
reload_foreign_key_parents(THD * thd)227 bool Table_impl::reload_foreign_key_parents(THD *thd) {
228 /*
229 Use READ UNCOMMITTED isolation, so this method works correctly when
230 called from the middle of atomic DDL statements.
231 */
232 dd::Transaction_ro trx(thd, ISO_READ_UNCOMMITTED);
233
234 // Register and open tables.
235 trx.otx.register_tables<dd::Table>();
236 if (trx.otx.open_tables()) {
237 DBUG_ASSERT(thd->is_system_thread() || thd->killed || thd->is_error());
238 return true;
239 }
240
241 // Delete and reload the foreign key parents.
242 delete_container_pointers(m_foreign_key_parents);
243
244 return load_foreign_key_parents(&trx.otx);
245 }
246
247 ///////////////////////////////////////////////////////////////////////////
248
restore_children(Open_dictionary_tables_ctx * otx)249 bool Table_impl::restore_children(Open_dictionary_tables_ctx *otx) {
250 // NOTE: the order of restoring collections is important because:
251 // - Index-objects reference Column-objects
252 // (thus, Column-objects must be loaded before Index-objects).
253 // - Foreign_key-objects reference both Index-objects and Column-objects.
254 // (thus, both Indexes and Columns must be loaded before FKs).
255 // - Partitions should be loaded at the end, as it refers to
256 // indexes.
257
258 /*
259 Do not load check constraints if upgrade is from the DD version before
260 check constraints support. Check constraint support is introduced in 80016.
261 */
262 bool skip_check_constraints =
263 (bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade_from_before(
264 bootstrap::DD_VERSION_80016));
265
266 return (
267 Abstract_table_impl::restore_children(otx) ||
268 m_indexes.restore_items(this, otx, otx->get_table<Index>(),
269 Indexes::create_key_by_table_id(this->id())) ||
270 m_foreign_keys.restore_items(
271 this, otx, otx->get_table<Foreign_key>(),
272 Foreign_keys::create_key_by_table_id(this->id()),
273 Foreign_key_order_comparator()) ||
274 m_partitions.restore_items(
275 this, otx, otx->get_table<Partition>(),
276 Table_partitions::create_key_by_parent_partition_id(
277 this->id(), dd::INVALID_OBJECT_ID),
278 // Sort partitions first on level and then on number.
279 Partition_order_comparator()) ||
280 m_triggers.restore_items(this, otx, otx->get_table<Trigger>(),
281 Triggers::create_key_by_table_id(this->id()),
282 Trigger_order_comparator()) ||
283 load_foreign_key_parents(otx) ||
284 (!skip_check_constraints &&
285 m_check_constraints.restore_items(
286 this, otx, otx->get_table<Check_constraint>(),
287 Check_constraints::create_key_by_table_id(this->id()),
288 Check_constraint_order_comparator())));
289 }
290
291 ///////////////////////////////////////////////////////////////////////////
292
store_triggers(Open_dictionary_tables_ctx * otx)293 bool Table_impl::store_triggers(Open_dictionary_tables_ctx *otx) {
294 /*
295 There is a requirement to keep the collection items in
296 following order. The reason is,
297
298 Suppose we are updating a dd::Table object with,
299 a) We already have a trigger 't1' with ID 1.
300 b) We added a new trigger 't2' added preceding to 't1'.
301 We have a row for a) in (DD) disk with action_order=1.
302
303 The expectation is that row b) should have action_order=1
304 and row a) should have action_order=2.
305
306 If we try to store row b) first with action_order=1, then
307 there is possibility violating the constraint
308 "UNIQUE KEY (table_id, event_type,
309 action_timing, action_order)"
310 because row a) might also contain the same event_type and
311 action_timing as that of b). And we would fail inserting
312 row b).
313
314 This demands us to drop all the triggers which are already
315 present on disk and then store any new triggers. This
316 would not violate the above unique constraint.
317
318 However we should avoid trying to drop triggers if no triggers
319 existed before. Such an attempt will lead to index lookup which
320 might cause acquisition of gap lock on index supremum in InnoDB.
321 This might lead to deadlock if two independent CREATE TRIGGER
322 are executed concurrently and both acquire gap locks on index
323 supremum first and then try to insert their records into this gap.
324 */
325 bool needs_delete = m_triggers.has_removed_items();
326
327 if (!needs_delete) {
328 /* Check if there are any non-new Trigger objects. */
329 for (const Trigger *trigger : *triggers()) {
330 if (trigger->id() != INVALID_OBJECT_ID) {
331 needs_delete = true;
332 break;
333 }
334 }
335 }
336
337 if (needs_delete) {
338 if (m_triggers.drop_items(otx, otx->get_table<Trigger>(),
339 Triggers::create_key_by_table_id(this->id())))
340 return true;
341
342 /*
343 In-case a trigger is dropped, we need to avoid dropping it
344 second time. So clear all the removed items.
345 */
346 m_triggers.clear_removed_items();
347 }
348
349 // Store the items.
350 return m_triggers.store_items(otx);
351 }
352
353 ///////////////////////////////////////////////////////////////////////////
354
store_children(Open_dictionary_tables_ctx * otx)355 bool Table_impl::store_children(Open_dictionary_tables_ctx *otx) {
356 /*
357 Do not store check constraints if upgrade is from the DD version before
358 check constraints support. Check constraint support is introduced in 80016.
359 */
360 bool skip_check_constraints =
361 (bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade_from_before(
362 bootstrap::DD_VERSION_80016));
363
364 return Abstract_table_impl::store_children(otx) ||
365 // Note that indexes has to be stored first, as
366 // partitions refer indexes.
367 m_indexes.store_items(otx) || m_foreign_keys.store_items(otx) ||
368 m_partitions.store_items(otx) || store_triggers(otx) ||
369 (!skip_check_constraints && m_check_constraints.store_items(otx));
370 }
371
372 ///////////////////////////////////////////////////////////////////////////
373
drop_children(Open_dictionary_tables_ctx * otx) const374 bool Table_impl::drop_children(Open_dictionary_tables_ctx *otx) const {
375 // Note that partition collection has to be dropped first
376 // as it has foreign key to indexes.
377
378 return m_check_constraints.drop_items(
379 otx, otx->get_table<Check_constraint>(),
380 Check_constraints::create_key_by_table_id(this->id())) ||
381 m_triggers.drop_items(otx, otx->get_table<Trigger>(),
382 Triggers::create_key_by_table_id(this->id())) ||
383 m_partitions.drop_items(
384 otx, otx->get_table<Partition>(),
385 Table_partitions::create_key_by_table_id(this->id())) ||
386 m_foreign_keys.drop_items(
387 otx, otx->get_table<Foreign_key>(),
388 Foreign_keys::create_key_by_table_id(this->id())) ||
389 m_indexes.drop_items(otx, otx->get_table<Index>(),
390 Indexes::create_key_by_table_id(this->id())) ||
391 Abstract_table_impl::drop_children(otx);
392 }
393
394 /////////////////////////////////////////////////////////////////////////
395
restore_attributes(const Raw_record & r)396 bool Table_impl::restore_attributes(const Raw_record &r) {
397 {
398 enum_table_type table_type =
399 static_cast<enum_table_type>(r.read_int(Tables::FIELD_TYPE));
400
401 if (table_type != enum_table_type::BASE_TABLE) return true;
402 }
403
404 if (Abstract_table_impl::restore_attributes(r)) return true;
405
406 m_comment = r.read_str(Tables::FIELD_COMMENT);
407 m_row_format = (enum_row_format)r.read_int(Tables::FIELD_ROW_FORMAT);
408
409 // Partitioning related fields (NULL -> enum value 0!)
410
411 m_partition_type =
412 (enum_partition_type)r.read_int(Tables::FIELD_PARTITION_TYPE, 0);
413
414 m_default_partitioning = (enum_default_partitioning)r.read_int(
415 Tables::FIELD_DEFAULT_PARTITIONING, 0);
416
417 m_subpartition_type =
418 (enum_subpartition_type)r.read_int(Tables::FIELD_SUBPARTITION_TYPE, 0);
419
420 m_default_subpartitioning = (enum_default_partitioning)r.read_int(
421 Tables::FIELD_DEFAULT_SUBPARTITIONING, 0);
422
423 // Special cases dealing with NULL values for nullable fields
424
425 m_se_private_id = dd::tables::Tables::read_se_private_id(r);
426
427 m_collation_id = r.read_ref_id(Tables::FIELD_COLLATION_ID);
428 m_tablespace_id = r.read_ref_id(Tables::FIELD_TABLESPACE_ID);
429
430 set_se_private_data(r.read_str(Tables::FIELD_SE_PRIVATE_DATA, ""));
431
432 // m_engine_attribute and m_secondary_engine_attribute added in 80021
433 if (!bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade_from_before(
434 bootstrap::DD_VERSION_80021)) {
435 m_engine_attribute = r.read_str(Tables::FIELD_ENGINE_ATTRIBUTE, "");
436 m_secondary_engine_attribute =
437 r.read_str(Tables::FIELD_SECONDARY_ENGINE_ATTRIBUTE, "");
438 }
439
440 m_engine = r.read_str(Tables::FIELD_ENGINE);
441
442 // m_last_checked_for_upgrade_version added in 80012
443 if (bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade_from_before(
444 bootstrap::DD_VERSION_80013)) {
445 m_last_checked_for_upgrade_version_id = 0;
446 } else {
447 m_last_checked_for_upgrade_version_id =
448 r.read_int(Tables::FIELD_LAST_CHECKED_FOR_UPGRADE_VERSION_ID, 0);
449 }
450 m_partition_expression = r.read_str(Tables::FIELD_PARTITION_EXPRESSION, "");
451 m_partition_expression_utf8 =
452 r.read_str(Tables::FIELD_PARTITION_EXPRESSION_UTF8, "");
453 m_subpartition_expression =
454 r.read_str(Tables::FIELD_SUBPARTITION_EXPRESSION, "");
455 m_subpartition_expression_utf8 =
456 r.read_str(Tables::FIELD_SUBPARTITION_EXPRESSION_UTF8, "");
457
458 return false;
459 }
460
461 ///////////////////////////////////////////////////////////////////////////
462
store_attributes(Raw_record * r)463 bool Table_impl::store_attributes(Raw_record *r) {
464 //
465 // Special cases dealing with NULL values for nullable fields
466 // - Store NULL if version is not set
467 // Eg: USER_VIEW or SYSTEM_VIEW may not have version set
468 // - Store NULL if se_private_id is not set
469 // Eg: A non-innodb table may not have se_private_id
470 // - Store NULL if collation id is not set
471 // Eg: USER_VIEW will not have collation id set.
472 // - Store NULL if tablespace id is not set
473 // Eg: A non-innodb table may not have tablespace
474 // - Store NULL in options if there are no key=value pairs
475 // - Store NULL in se_private_data if there are no key=value pairs
476 // - Store NULL in partition type if not set.
477 // - Store NULL in partition expression if not set.
478 // - Store NULL in default partitioning if not set.
479 // - Store NULL in subpartition type if not set.
480 // - Store NULL in subpartition expression if not set.
481 // - Store NULL in default subpartitioning if not set.
482 //
483
484 // Temporary table definitions are never persisted.
485 DBUG_ASSERT(!m_is_temporary);
486
487 // Store last_checked_for_upgrade_version_id only if we're not upgrading
488 if (!bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade_from_before(
489 bootstrap::DD_VERSION_80013) &&
490 r->store(Tables::FIELD_LAST_CHECKED_FOR_UPGRADE_VERSION_ID,
491 m_last_checked_for_upgrade_version_id)) {
492 return true;
493 }
494
495 // Store engine_attribute and secondary_engine_attribute only if
496 // we're not upgrading
497 if (!bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade_from_before(
498 bootstrap::DD_VERSION_80021) &&
499 (r->store(Tables::FIELD_ENGINE_ATTRIBUTE, m_engine_attribute,
500 m_engine_attribute.empty()) ||
501 r->store(Tables::FIELD_SECONDARY_ENGINE_ATTRIBUTE,
502 m_secondary_engine_attribute,
503 m_secondary_engine_attribute.empty()))) {
504 return true;
505 }
506
507 // Store field values
508 return Abstract_table_impl::store_attributes(r) ||
509 r->store(Tables::FIELD_ENGINE, m_engine) ||
510 r->store_ref_id(Tables::FIELD_COLLATION_ID, m_collation_id) ||
511 r->store(Tables::FIELD_COMMENT, m_comment) ||
512 r->store(Tables::FIELD_SE_PRIVATE_DATA, m_se_private_data) ||
513 r->store(Tables::FIELD_SE_PRIVATE_ID, m_se_private_id,
514 m_se_private_id == (Object_id)-1) ||
515 r->store(Tables::FIELD_ROW_FORMAT, m_row_format) ||
516 r->store_ref_id(Tables::FIELD_TABLESPACE_ID, m_tablespace_id) ||
517 r->store(Tables::FIELD_PARTITION_TYPE, m_partition_type,
518 m_partition_type == PT_NONE) ||
519 r->store(Tables::FIELD_PARTITION_EXPRESSION, m_partition_expression,
520 m_partition_expression.empty()) ||
521 r->store(Tables::FIELD_PARTITION_EXPRESSION_UTF8,
522 m_partition_expression_utf8,
523 m_partition_expression_utf8.empty()) ||
524 r->store(Tables::FIELD_DEFAULT_PARTITIONING, m_default_partitioning,
525 m_default_partitioning == DP_NONE) ||
526 r->store(Tables::FIELD_SUBPARTITION_TYPE, m_subpartition_type,
527 m_subpartition_type == ST_NONE) ||
528 r->store(Tables::FIELD_SUBPARTITION_EXPRESSION,
529 m_subpartition_expression,
530 m_subpartition_expression.empty()) ||
531 r->store(Tables::FIELD_SUBPARTITION_EXPRESSION_UTF8,
532 m_subpartition_expression_utf8,
533 m_subpartition_expression_utf8.empty()) ||
534 r->store(Tables::FIELD_DEFAULT_SUBPARTITIONING,
535 m_default_subpartitioning,
536 m_default_subpartitioning == DP_NONE);
537 }
538
539 ///////////////////////////////////////////////////////////////////////////
540 static_assert(Tables::NUMBER_OF_FIELDS == 37,
541 "Tables definition has changed, check if serialize() and "
542 "deserialize() need to be updated!");
serialize(Sdi_wcontext * wctx,Sdi_writer * w) const543 void Table_impl::serialize(Sdi_wcontext *wctx, Sdi_writer *w) const {
544 // Temporary table definitions are never persisted.
545 DBUG_ASSERT(!m_is_temporary);
546
547 w->StartObject();
548 Abstract_table_impl::serialize(wctx, w);
549 write(w, m_se_private_id, STRING_WITH_LEN("se_private_id"));
550 write(w, m_engine, STRING_WITH_LEN("engine"));
551 write(w, m_last_checked_for_upgrade_version_id,
552 STRING_WITH_LEN("last_checked_for_upgrade_version_id"));
553 write(w, m_comment, STRING_WITH_LEN("comment"));
554 write_properties(w, m_se_private_data, STRING_WITH_LEN("se_private_data"));
555 write(w, m_engine_attribute, STRING_WITH_LEN("engine_attribute"));
556 write(w, m_secondary_engine_attribute,
557 STRING_WITH_LEN("secondary_engine_attribute"));
558 write_enum(w, m_row_format, STRING_WITH_LEN("row_format"));
559 write_enum(w, m_partition_type, STRING_WITH_LEN("partition_type"));
560 write(w, m_partition_expression, STRING_WITH_LEN("partition_expression"));
561 write(w, m_partition_expression_utf8,
562 STRING_WITH_LEN("partition_expression_utf8"));
563 write_enum(w, m_default_partitioning,
564 STRING_WITH_LEN("default_partitioning"));
565 write_enum(w, m_subpartition_type, STRING_WITH_LEN("subpartition_type"));
566 write(w, m_subpartition_expression,
567 STRING_WITH_LEN("subpartition_expression"));
568 write(w, m_subpartition_expression_utf8,
569 STRING_WITH_LEN("subpartition_expression_utf8"));
570 write_enum(w, m_default_subpartitioning,
571 STRING_WITH_LEN("default_subpartitioning"));
572 serialize_each(wctx, w, m_indexes, STRING_WITH_LEN("indexes"));
573 serialize_each(wctx, w, m_foreign_keys, STRING_WITH_LEN("foreign_keys"));
574 serialize_each(wctx, w, m_check_constraints,
575 STRING_WITH_LEN("check_constraints"));
576 serialize_each(wctx, w, m_partitions, STRING_WITH_LEN("partitions"));
577 write(w, m_collation_id, STRING_WITH_LEN("collation_id"));
578 serialize_tablespace_ref(wctx, w, m_tablespace_id,
579 STRING_WITH_LEN("tablespace_ref"));
580 w->EndObject();
581 }
582
583 ///////////////////////////////////////////////////////////////////////////
584
deserialize(Sdi_rcontext * rctx,const RJ_Value & val)585 bool Table_impl::deserialize(Sdi_rcontext *rctx, const RJ_Value &val) {
586 Abstract_table_impl::deserialize(rctx, val);
587 read(&m_se_private_id, val, "se_private_id");
588 read(&m_engine, val, "engine");
589 read(&m_last_checked_for_upgrade_version_id, val,
590 "last_checked_for_upgrade_version_id");
591 read(&m_comment, val, "comment");
592 read_properties(&m_se_private_data, val, "se_private_data");
593 read(&m_engine_attribute, val, "engine_attribute");
594 read(&m_secondary_engine_attribute, val, "secondary_engine_attribute");
595 read_enum(&m_row_format, val, "row_format");
596 read_enum(&m_partition_type, val, "partition_type");
597 read(&m_partition_expression, val, "partition_expression");
598 read(&m_partition_expression_utf8, val, "partition_expression_utf8");
599 read_enum(&m_default_partitioning, val, "default_partitioning");
600 read_enum(&m_subpartition_type, val, "subpartition_type");
601 read(&m_subpartition_expression, val, "subpartition_expression");
602 read(&m_subpartition_expression_utf8, val, "subpartition_expression_utf8");
603 read_enum(&m_default_subpartitioning, val, "default_subpartitioning");
604
605 // Note! Deserialization of ordinal position cross-referenced
606 // objects (i.e. Index and Column) must happen before deserializing
607 // objects which refrence these objects:
608 // Foreign_key_element -> Column,
609 // Foreign_key -> Index,
610 // Index_element -> Column,
611 // Partition_index -> Index
612 // Otherwise the cross-references will not be deserialized correctly
613 // (as we don't know the address of the referenced Column or Index
614 // object).
615
616 deserialize_each(
617 rctx, [this]() { return add_index(); }, val, "indexes");
618
619 deserialize_each(
620 rctx, [this]() { return add_foreign_key(); }, val, "foreign_keys");
621 deserialize_each(
622 rctx, [this]() { return add_check_constraint(); }, val,
623 "check_constraints");
624 deserialize_each(
625 rctx, [this]() { return add_partition(); }, val, "partitions");
626 read(&m_collation_id, val, "collation_id");
627 #ifndef XTRABACKUP
628 return deserialize_tablespace_ref(rctx, &m_tablespace_id, val,
629 "tablespace_id");
630 #else
631 return false;
632 #endif
633 }
634
635 ///////////////////////////////////////////////////////////////////////////
636
debug_print(String_type & outb) const637 void Table_impl::debug_print(String_type &outb) const {
638 String_type s;
639 Abstract_table_impl::debug_print(s);
640
641 dd::Stringstream_type ss;
642 ss << "TABLE OBJECT: { " << s << "m_engine: " << m_engine << "; "
643 << "m_last_checked_for_upgrade_version_id: "
644 << m_last_checked_for_upgrade_version_id << "; "
645 << "m_collation: {OID: " << m_collation_id << "}; "
646 << "m_comment: " << m_comment << "; "
647 << "m_se_private_data " << m_se_private_data.raw_string() << "; "
648 << "m_se_private_id: {OID: " << m_se_private_id << "}; "
649 << "m_engine_attribute: " << m_engine_attribute << "; "
650 << "m_secondary_engine_attribute: " << m_secondary_engine_attribute << "; "
651 << "m_row_format: " << m_row_format << "; "
652 << "m_is_temporary: " << m_is_temporary << "; "
653 << "m_tablespace: {OID: " << m_tablespace_id << "}; "
654 << "m_partition_type " << m_partition_type << "; "
655 << "m_default_partitioning " << m_default_partitioning << "; "
656 << "m_partition_expression " << m_partition_expression << "; "
657 << "m_partition_expression_utf8 " << m_partition_expression_utf8 << "; "
658 << "m_subpartition_type " << m_subpartition_type << "; "
659 << "m_default_subpartitioning " << m_default_subpartitioning << "; "
660 << "m_subpartition_expression " << m_subpartition_expression << "; "
661 << "m_subpartition_expression_utf8 " << m_subpartition_expression_utf8
662 << "; "
663 << "m_partitions: " << m_partitions.size() << " [ ";
664
665 {
666 for (const Partition *i : partitions()) {
667 String_type sp;
668 i->debug_print(sp);
669 ss << sp << " | ";
670 }
671 }
672
673 ss << "] m_indexes: " << m_indexes.size() << " [ ";
674
675 {
676 for (const Index *i : indexes()) {
677 String_type si;
678 i->debug_print(si);
679 ss << si << " | ";
680 }
681 }
682
683 ss << "] m_foreign_keys: " << m_foreign_keys.size() << " [ ";
684
685 {
686 for (const Foreign_key *fk : foreign_keys()) {
687 String_type sfk;
688 fk->debug_print(sfk);
689 ss << sfk << " | ";
690 }
691 }
692
693 ss << "] m_check_constraints: " << m_check_constraints.size() << " [ ";
694
695 {
696 for (const Check_constraint *cc : check_constraints()) {
697 String_type scc;
698 cc->debug_print(scc);
699 ss << scc << " | ";
700 }
701 }
702
703 ss << "] m_triggers: " << m_triggers.size() << " [ ";
704
705 {
706 for (const Trigger *trig : triggers()) {
707 String_type st;
708 trig->debug_print(st);
709 ss << st << " | ";
710 }
711 }
712 ss << "] ";
713
714 ss << " }";
715
716 outb = ss.str();
717 }
718
719 ///////////////////////////////////////////////////////////////////////////
720 // Index collection.
721 ///////////////////////////////////////////////////////////////////////////
722
add_index()723 Index *Table_impl::add_index() {
724 Index_impl *i = new (std::nothrow) Index_impl(this);
725 m_indexes.push_back(i);
726 return i;
727 }
728
729 ///////////////////////////////////////////////////////////////////////////
730
add_first_index()731 Index *Table_impl::add_first_index() {
732 Index_impl *i = new (std::nothrow) Index_impl(this);
733 m_indexes.push_front(i);
734 return i;
735 }
736
737 ///////////////////////////////////////////////////////////////////////////
738
get_index(Object_id index_id)739 Index *Table_impl::get_index(Object_id index_id) {
740 for (Index *i : m_indexes) {
741 if (i->id() == index_id) return i;
742 }
743
744 return nullptr;
745 }
746
747 ///////////////////////////////////////////////////////////////////////////
748 // Foreign key collection.
749 ///////////////////////////////////////////////////////////////////////////
750
add_foreign_key()751 Foreign_key *Table_impl::add_foreign_key() {
752 Foreign_key_impl *fk = new (std::nothrow) Foreign_key_impl(this);
753 m_foreign_keys.push_back(fk);
754 return fk;
755 }
756
757 ///////////////////////////////////////////////////////////////////////////
758 // Foreign key parent collection.
759 ///////////////////////////////////////////////////////////////////////////
760
add_foreign_key_parent()761 Foreign_key_parent *Table_impl::add_foreign_key_parent() {
762 Foreign_key_parent *fk_parent = new (std::nothrow) Foreign_key_parent();
763 m_foreign_key_parents.push_back(fk_parent);
764 return fk_parent;
765 }
766
767 ///////////////////////////////////////////////////////////////////////////
768 // Partition collection.
769 ///////////////////////////////////////////////////////////////////////////
770
add_partition()771 Partition *Table_impl::add_partition() {
772 Partition_impl *i = new (std::nothrow) Partition_impl(this);
773 m_partitions.push_back(i);
774
775 return i;
776 }
777
778 ///////////////////////////////////////////////////////////////////////////
779
get_partition(Object_id partition_id)780 Partition *Table_impl::get_partition(Object_id partition_id) {
781 for (Partition *i : m_partitions) {
782 if (i->id() == partition_id) return i;
783 }
784
785 return nullptr;
786 }
787
788 ///////////////////////////////////////////////////////////////////////////
789 // Trigger collection.
790 ///////////////////////////////////////////////////////////////////////////
791
get_max_action_order(Trigger::enum_action_timing at,Trigger::enum_event_type et) const792 uint Table_impl::get_max_action_order(Trigger::enum_action_timing at,
793 Trigger::enum_event_type et) const {
794 uint max_order = 0;
795 for (const Trigger *trig : triggers()) {
796 if (trig->action_timing() == at && trig->event_type() == et) max_order++;
797 }
798
799 return max_order;
800 }
801
802 ///////////////////////////////////////////////////////////////////////////
803
reorder_action_order(Trigger::enum_action_timing at,Trigger::enum_event_type et)804 void Table_impl::reorder_action_order(Trigger::enum_action_timing at,
805 Trigger::enum_event_type et) {
806 uint new_order = 1;
807 for (Trigger *trigger : *triggers()) {
808 if (trigger->action_timing() == at && trigger->event_type() == et)
809 trigger->set_action_order(new_order++);
810 }
811 }
812
813 ///////////////////////////////////////////////////////////////////////////
814
create_trigger()815 Trigger_impl *Table_impl::create_trigger() {
816 Trigger_impl *trigger = new (std::nothrow) Trigger_impl(this);
817 if (trigger == nullptr) return nullptr;
818
819 THD *thd = current_thd;
820 trigger->set_created(thd->query_start_timeval_trunc(2));
821 trigger->set_last_altered(thd->query_start_timeval_trunc(2));
822
823 return trigger;
824 }
825
826 ///////////////////////////////////////////////////////////////////////////
827
add_trigger(Trigger::enum_action_timing at,Trigger::enum_event_type et)828 Trigger *Table_impl::add_trigger(Trigger::enum_action_timing at,
829 Trigger::enum_event_type et) {
830 Trigger_impl *trigger = create_trigger();
831 if (trigger == nullptr) return nullptr;
832
833 m_triggers.push_back(trigger);
834 trigger->set_action_timing(at);
835 trigger->set_event_type(et);
836 trigger->set_action_order(get_max_action_order(at, et));
837
838 return trigger;
839 }
840
841 ///////////////////////////////////////////////////////////////////////////
842
get_trigger(const char * name) const843 const Trigger *Table_impl::get_trigger(const char *name) const {
844 const uchar *src_trg_name = pointer_cast<const uchar *>(name);
845 size_t src_trg_name_len = strlen(name);
846 for (const Trigger *trigger : triggers()) {
847 if (!my_strnncoll(dd::tables::Triggers::name_collation(), src_trg_name,
848 src_trg_name_len,
849 pointer_cast<const uchar *>(trigger->name().c_str()),
850 trigger->name().length()))
851 return trigger;
852 }
853
854 return nullptr;
855 }
856
857 ///////////////////////////////////////////////////////////////////////////
858
add_trigger_following(const Trigger * trigger,Trigger::enum_action_timing at,Trigger::enum_event_type et)859 Trigger *Table_impl::add_trigger_following(const Trigger *trigger,
860 Trigger::enum_action_timing at,
861 Trigger::enum_event_type et) {
862 DBUG_ASSERT(trigger != nullptr && trigger->action_timing() == at &&
863 trigger->event_type() == et);
864
865 // Allocate new Trigger object.
866 Trigger_impl *new_trigger = create_trigger();
867 if (new_trigger == nullptr) return nullptr;
868
869 Trigger_collection::iterator it =
870 m_triggers.find(dynamic_cast<const Trigger_impl *>(trigger));
871
872 if (++it != m_triggers.end())
873 m_triggers.insert(it, new_trigger);
874 else
875 m_triggers.push_back(new_trigger);
876
877 new_trigger->set_action_timing(at);
878 new_trigger->set_event_type(et);
879
880 reorder_action_order(at, et);
881 return new_trigger;
882 }
883
884 ///////////////////////////////////////////////////////////////////////////
885
add_trigger_preceding(const Trigger * trigger,Trigger::enum_action_timing at,Trigger::enum_event_type et)886 Trigger *Table_impl::add_trigger_preceding(const Trigger *trigger,
887 Trigger::enum_action_timing at,
888 Trigger::enum_event_type et) {
889 DBUG_ASSERT(trigger != nullptr && trigger->action_timing() == at &&
890 trigger->event_type() == et);
891
892 Trigger_impl *new_trigger = create_trigger();
893 if (new_trigger == nullptr) return nullptr;
894
895 new_trigger->set_action_timing(at);
896 new_trigger->set_event_type(et);
897
898 Trigger_collection::iterator it =
899 m_triggers.find(dynamic_cast<const Trigger_impl *>(trigger));
900 m_triggers.insert(it, new_trigger);
901
902 reorder_action_order(at, et);
903
904 return new_trigger;
905 }
906
907 ///////////////////////////////////////////////////////////////////////////
908
copy_triggers(const Table * tab_obj)909 void Table_impl::copy_triggers(const Table *tab_obj) {
910 DBUG_ASSERT(tab_obj != nullptr);
911
912 for (const Trigger *trig : tab_obj->triggers()) {
913 /*
914 Reset the trigger primary key ID, so that a new row is
915 created for them, when the object is stored. Following is
916 the issue if we don't do that.
917
918 * When the triggers are copied by dd::Table::copy_triggers(),
919 it retained the old trigger ID's. This is fine in theory
920 to re-use ID. But see below points.
921
922 * thd->dd_client()->update() updates the dd::Table object which
923 contains the moved triggers. The DD framework would insert
924 these triggers with same old trigger ID in mysql.triggers.id.
925 This too is fine.
926
927 * After inserting a row, we set dd::Trigger_impl::m_id
928 only if a new id m_table->file->insert_id_for_cur_row was
929 generated. The problem here is that there was no new row ID
930 generated as we did retain old mysql.triggers.id. Hence we
931 end-up marking the dd::Trigger_impl::m_id as INVALID_OBJECT_ID.
932 Note that the value stored in DD is now difference than the
933 value in in-memory dd::Trigger_impl object.
934
935 * Later if the same object is updated (may be rename operation)
936 then as the dd::Trigger_impl::m_id is INVALID_OBJECT_ID, we
937 end-up creating a duplicate row which already exists.
938
939 So, It is not necessary to retain the old trigger ID's, the
940 dd::Table::copy_triggers() API now sets the ID's of cloned
941 trigger objects to INVALID_OBJECT_ID. This will work fine as the
942 m_table->file->insert_id_for_cur_row gets generated as expected
943 and the trigger metadata on DD table mysql.triggers and in-memory
944 DD object dd::Trigger_impl would both be same.
945 */
946 Trigger_impl *new_trigger =
947 new Trigger_impl(*dynamic_cast<const Trigger_impl *>(trig), this);
948 DBUG_ASSERT(new_trigger != nullptr);
949
950 new_trigger->set_id(INVALID_OBJECT_ID);
951
952 m_triggers.push_back(new_trigger);
953 }
954 }
955
956 ///////////////////////////////////////////////////////////////////////////
957
drop_all_triggers()958 void Table_impl::drop_all_triggers() { m_triggers.remove_all(); }
959
960 ///////////////////////////////////////////////////////////////////////////
961
drop_trigger(const Trigger * trigger)962 void Table_impl::drop_trigger(const Trigger *trigger) {
963 DBUG_ASSERT(trigger != nullptr);
964 dd::Trigger::enum_action_timing at = trigger->action_timing();
965 dd::Trigger::enum_event_type et = trigger->event_type();
966
967 m_triggers.remove(
968 dynamic_cast<Trigger_impl *>(const_cast<Trigger *>(trigger)));
969
970 reorder_action_order(at, et);
971 }
972
973 ///////////////////////////////////////////////////////////////////////////
974 // Check constraint collection.
975 ///////////////////////////////////////////////////////////////////////////
976
add_check_constraint()977 Check_constraint *Table_impl::add_check_constraint() {
978 Check_constraint_impl *cc = new (std::nothrow) Check_constraint_impl(this);
979 if (cc != nullptr) m_check_constraints.push_back(cc);
980 return cc;
981 }
982
983 ///////////////////////////////////////////////////////////////////////////
984
get_partition(const String_type & name)985 Partition *Table_impl::get_partition(const String_type &name) {
986 for (Partition *i : m_partitions) {
987 if (i->name() == name) return i;
988 }
989
990 return nullptr;
991 }
992
993 ///////////////////////////////////////////////////////////////////////////
994
update_aux_key(Aux_key * key,const String_type & engine,Object_id se_private_id)995 bool Table::update_aux_key(Aux_key *key, const String_type &engine,
996 Object_id se_private_id) {
997 if (se_private_id != INVALID_OBJECT_ID)
998 return Tables::update_aux_key(key, engine, se_private_id);
999
1000 return true;
1001 }
1002
1003 ///////////////////////////////////////////////////////////////////////////
1004
register_tables(Open_dictionary_tables_ctx * otx)1005 void Table_impl::register_tables(Open_dictionary_tables_ctx *otx) {
1006 otx->add_table<Tables>();
1007
1008 otx->register_tables<Schema>();
1009 otx->register_tables<Column>();
1010 otx->register_tables<Index>();
1011 otx->register_tables<Foreign_key>();
1012 otx->register_tables<Partition>();
1013 otx->register_tables<Trigger>();
1014 /*
1015 Do not register check constraint table if upgrade is from the DD version
1016 before check constraints support. Check constraint is introduced in 8.0.15.
1017 */
1018 if (!bootstrap::DD_bootstrap_ctx::instance().is_dd_upgrade_from_before(
1019 bootstrap::DD_VERSION_80016))
1020 otx->register_tables<Check_constraint>();
1021 }
1022
1023 ///////////////////////////////////////////////////////////////////////////
1024
Table_impl(const Table_impl & src)1025 Table_impl::Table_impl(const Table_impl &src)
1026 : Weak_object(src),
1027 Abstract_table_impl(src),
1028 m_se_private_id(src.m_se_private_id),
1029 m_engine(src.m_engine),
1030 m_comment(src.m_comment),
1031 m_last_checked_for_upgrade_version_id{
1032 src.m_last_checked_for_upgrade_version_id},
1033 m_se_private_data(src.m_se_private_data),
1034 m_engine_attribute(src.m_engine_attribute),
1035 m_secondary_engine_attribute(src.m_secondary_engine_attribute),
1036 m_row_format(src.m_row_format),
1037 m_is_temporary(src.m_is_temporary),
1038 m_partition_type(src.m_partition_type),
1039 m_partition_expression(src.m_partition_expression),
1040 m_partition_expression_utf8(src.m_partition_expression_utf8),
1041 m_default_partitioning(src.m_default_partitioning),
1042 m_subpartition_type(src.m_subpartition_type),
1043 m_subpartition_expression(src.m_subpartition_expression),
1044 m_subpartition_expression_utf8(src.m_subpartition_expression_utf8),
1045 m_default_subpartitioning(src.m_default_subpartitioning),
1046 m_indexes(),
1047 m_foreign_keys(),
1048 m_partitions(),
1049 m_triggers(),
1050 m_check_constraints(),
1051 m_collation_id(src.m_collation_id),
1052 m_tablespace_id(src.m_tablespace_id) {
1053 m_indexes.deep_copy(src.m_indexes, this);
1054 m_foreign_keys.deep_copy(src.m_foreign_keys, this);
1055 for (auto fk_parent : src.m_foreign_key_parents)
1056 m_foreign_key_parents.push_back(new (std::nothrow)
1057 Foreign_key_parent(*fk_parent));
1058 m_partitions.deep_copy(src.m_partitions, this);
1059 m_triggers.deep_copy(src.m_triggers, this);
1060 m_check_constraints.deep_copy(src.m_check_constraints, this);
1061 }
1062 } // namespace dd
1063