1 /*****************************************************************************
2
3 Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2012, Facebook Inc.
5 Copyright (c) 2013, 2021, MariaDB Corporation.
6
7 This program is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free Software
9 Foundation; version 2 of the License.
10
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along with
16 this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
18
19 *****************************************************************************/
20
21 /******************************************************************//**
22 @file dict/dict0mem.cc
23 Data dictionary memory object creation
24
25 Created 1/8/1996 Heikki Tuuri
26 ***********************************************************************/
27
28 #include "ha_prototypes.h"
29 #include <mysql_com.h>
30
31 #include "dict0mem.h"
32 #include "rem0rec.h"
33 #include "data0type.h"
34 #include "mach0data.h"
35 #include "dict0dict.h"
36 #include "fts0priv.h"
37 #include "lock0lock.h"
38 #include "sync0sync.h"
39 #include "row0row.h"
40 #include <iostream>
41
42 #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
43 creating a table or index object */
44
45 /** System databases */
46 static const char* innobase_system_databases[] = {
47 "mysql/",
48 "information_schema/",
49 "performance_schema/",
50 NullS
51 };
52
53 /** Determine if a table belongs to innobase_system_databases[]
54 @param[in] name database_name/table_name
55 @return whether the database_name is in innobase_system_databases[] */
dict_mem_table_is_system(const char * name)56 static bool dict_mem_table_is_system(const char *name)
57 {
58 /* table has the following format: database/table
59 and some system table are of the form SYS_* */
60 if (!strchr(name, '/')) {
61 return true;
62 }
63 size_t table_len = strlen(name);
64 const char *system_db;
65 int i = 0;
66 while ((system_db = innobase_system_databases[i++])
67 && (system_db != NullS)) {
68 size_t len = strlen(system_db);
69 if (table_len > len && !strncmp(name, system_db, len)) {
70 return true;
71 }
72 }
73 return false;
74 }
75
76 /** The start of the table basename suffix for partitioned tables */
77 const char table_name_t::part_suffix[4]
78 #ifdef _WIN32
79 = "#p#";
80 #else
81 = "#P#";
82 #endif
83
84 /** Display an identifier.
85 @param[in,out] s output stream
86 @param[in] id_name SQL identifier (other than table name)
87 @return the output stream */
88 std::ostream&
operator <<(std::ostream & s,const id_name_t & id_name)89 operator<<(
90 std::ostream& s,
91 const id_name_t& id_name)
92 {
93 const char q = '`';
94 const char* c = id_name;
95 s << q;
96 for (; *c != 0; c++) {
97 if (*c == q) {
98 s << *c;
99 }
100 s << *c;
101 }
102 s << q;
103 return(s);
104 }
105
106 /** Display a table name.
107 @param[in,out] s output stream
108 @param[in] table_name table name
109 @return the output stream */
110 std::ostream&
operator <<(std::ostream & s,const table_name_t & table_name)111 operator<<(
112 std::ostream& s,
113 const table_name_t& table_name)
114 {
115 return(s << ut_get_name(NULL, table_name.m_name));
116 }
117
118 /** Create a table memory object.
119 @param name table name
120 @param space tablespace
121 @param n_cols total number of columns (both virtual and non-virtual)
122 @param n_v_cols number of virtual columns
123 @param flags table flags
124 @param flags2 table flags2
125 @return own: table object */
126 dict_table_t*
dict_mem_table_create(const char * name,fil_space_t * space,ulint n_cols,ulint n_v_cols,ulint flags,ulint flags2)127 dict_mem_table_create(
128 const char* name,
129 fil_space_t* space,
130 ulint n_cols,
131 ulint n_v_cols,
132 ulint flags,
133 ulint flags2)
134 {
135 dict_table_t* table;
136 mem_heap_t* heap;
137
138 ut_ad(name);
139 ut_ad(!space
140 || space->purpose == FIL_TYPE_TABLESPACE
141 || space->purpose == FIL_TYPE_TEMPORARY
142 || space->purpose == FIL_TYPE_IMPORT);
143 ut_a(dict_tf2_is_valid(flags, flags2));
144 ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK));
145
146 heap = mem_heap_create(DICT_HEAP_SIZE);
147
148 table = static_cast<dict_table_t*>(
149 mem_heap_zalloc(heap, sizeof(*table)));
150
151 lock_table_lock_list_init(&table->locks);
152
153 UT_LIST_INIT(table->indexes, &dict_index_t::indexes);
154 #ifdef BTR_CUR_HASH_ADAPT
155 UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes);
156 #endif /* BTR_CUR_HASH_ADAPT */
157
158 table->heap = heap;
159
160 ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
161
162 table->flags = (unsigned int) flags;
163 table->flags2 = (unsigned int) flags2;
164 table->name.m_name = mem_strdup(name);
165 table->is_system_db = dict_mem_table_is_system(table->name.m_name);
166 table->space = space;
167 table->space_id = space ? space->id : ULINT_UNDEFINED;
168 table->n_t_cols = unsigned(n_cols + DATA_N_SYS_COLS);
169 table->n_v_cols = (unsigned int) (n_v_cols);
170 table->n_cols = unsigned(table->n_t_cols - table->n_v_cols);
171
172 table->cols = static_cast<dict_col_t*>(
173 mem_heap_alloc(heap, table->n_cols * sizeof(dict_col_t)));
174 table->v_cols = static_cast<dict_v_col_t*>(
175 mem_heap_alloc(heap, n_v_cols * sizeof(*table->v_cols)));
176
177 table->autoinc_lock = static_cast<ib_lock_t*>(
178 mem_heap_alloc(heap, lock_get_size()));
179
180 /* If the table has an FTS index or we are in the process
181 of building one, create the table->fts */
182 if (dict_table_has_fts_index(table)
183 || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
184 || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
185 table->fts = fts_create(table);
186 table->fts->cache = fts_cache_create(table);
187 } else {
188 table->fts = NULL;
189 }
190
191 new(&table->foreign_set) dict_foreign_set();
192 new(&table->referenced_set) dict_foreign_set();
193
194 return(table);
195 }
196
197 /****************************************************************//**
198 Free a table memory object. */
199 void
dict_mem_table_free(dict_table_t * table)200 dict_mem_table_free(
201 /*================*/
202 dict_table_t* table) /*!< in: table */
203 {
204 ut_ad(table);
205 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
206 ut_ad(UT_LIST_GET_LEN(table->indexes) == 0);
207 #ifdef BTR_CUR_HASH_ADAPT
208 ut_ad(UT_LIST_GET_LEN(table->freed_indexes) == 0);
209 #endif /* BTR_CUR_HASH_ADAPT */
210 ut_d(table->cached = FALSE);
211
212 if (dict_table_has_fts_index(table)
213 || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
214 || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
215 if (table->fts) {
216 fts_optimize_remove_table(table);
217
218 fts_free(table);
219 }
220 }
221
222 dict_mem_table_free_foreign_vcol_set(table);
223
224 table->foreign_set.~dict_foreign_set();
225 table->referenced_set.~dict_foreign_set();
226
227 ut_free(table->name.m_name);
228 table->name.m_name = NULL;
229
230 /* Clean up virtual index info structures that are registered
231 with virtual columns */
232 for (ulint i = 0; i < table->n_v_def; i++) {
233 dict_v_col_t* vcol
234 = dict_table_get_nth_v_col(table, i);
235
236 UT_DELETE(vcol->v_indexes);
237 }
238
239 if (table->s_cols != NULL) {
240 UT_DELETE(table->s_cols);
241 }
242
243 mem_heap_free(table->heap);
244 }
245
246 /****************************************************************//**
247 Append 'name' to 'col_names'. @see dict_table_t::col_names
248 @return new column names array */
249 static
250 const char*
dict_add_col_name(const char * col_names,ulint cols,const char * name,mem_heap_t * heap)251 dict_add_col_name(
252 /*==============*/
253 const char* col_names, /*!< in: existing column names, or
254 NULL */
255 ulint cols, /*!< in: number of existing columns */
256 const char* name, /*!< in: new column name */
257 mem_heap_t* heap) /*!< in: heap */
258 {
259 ulint old_len;
260 ulint new_len;
261 ulint total_len;
262 char* res;
263
264 ut_ad(!cols == !col_names);
265
266 /* Find out length of existing array. */
267 if (col_names) {
268 const char* s = col_names;
269 ulint i;
270
271 for (i = 0; i < cols; i++) {
272 s += strlen(s) + 1;
273 }
274
275 old_len = unsigned(s - col_names);
276 } else {
277 old_len = 0;
278 }
279
280 new_len = strlen(name) + 1;
281 total_len = old_len + new_len;
282
283 res = static_cast<char*>(mem_heap_alloc(heap, total_len));
284
285 if (old_len > 0) {
286 memcpy(res, col_names, old_len);
287 }
288
289 memcpy(res + old_len, name, new_len);
290
291 return(res);
292 }
293
294 /**********************************************************************//**
295 Adds a column definition to a table. */
296 void
dict_mem_table_add_col(dict_table_t * table,mem_heap_t * heap,const char * name,ulint mtype,ulint prtype,ulint len)297 dict_mem_table_add_col(
298 /*===================*/
299 dict_table_t* table, /*!< in: table */
300 mem_heap_t* heap, /*!< in: temporary memory heap, or NULL */
301 const char* name, /*!< in: column name, or NULL */
302 ulint mtype, /*!< in: main datatype */
303 ulint prtype, /*!< in: precise type */
304 ulint len) /*!< in: precision */
305 {
306 dict_col_t* col;
307 ulint i;
308
309 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
310 ut_ad(!heap == !name);
311
312 ut_ad(!(prtype & DATA_VIRTUAL));
313
314 i = table->n_def++;
315
316 table->n_t_def++;
317
318 if (name) {
319 if (table->n_def == table->n_cols) {
320 heap = table->heap;
321 }
322 if (i && !table->col_names) {
323 /* All preceding column names are empty. */
324 char* s = static_cast<char*>(
325 mem_heap_zalloc(heap, table->n_def));
326
327 table->col_names = s;
328 }
329
330 table->col_names = dict_add_col_name(table->col_names,
331 i, name, heap);
332 }
333
334 col = dict_table_get_nth_col(table, i);
335
336 dict_mem_fill_column_struct(col, i, mtype, prtype, len);
337
338 switch (prtype & DATA_VERSIONED) {
339 case DATA_VERS_START:
340 ut_ad(!table->vers_start);
341 table->vers_start = i;
342 break;
343 case DATA_VERS_END:
344 ut_ad(!table->vers_end);
345 table->vers_end = i;
346 }
347 }
348
349 /** Adds a virtual column definition to a table.
350 @param[in,out] table table
351 @param[in,out] heap temporary memory heap, or NULL. It is
352 used to store name when we have not finished
353 adding all columns. When all columns are
354 added, the whole name will copy to memory from
355 table->heap
356 @param[in] name column name
357 @param[in] mtype main datatype
358 @param[in] prtype precise type
359 @param[in] len length
360 @param[in] pos position in a table
361 @param[in] num_base number of base columns
362 @return the virtual column definition */
363 dict_v_col_t*
dict_mem_table_add_v_col(dict_table_t * table,mem_heap_t * heap,const char * name,ulint mtype,ulint prtype,ulint len,ulint pos,ulint num_base)364 dict_mem_table_add_v_col(
365 dict_table_t* table,
366 mem_heap_t* heap,
367 const char* name,
368 ulint mtype,
369 ulint prtype,
370 ulint len,
371 ulint pos,
372 ulint num_base)
373 {
374 dict_v_col_t* v_col;
375 ulint i;
376
377 ut_ad(table);
378 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
379 ut_ad(!heap == !name);
380
381 ut_ad(prtype & DATA_VIRTUAL);
382
383 i = table->n_v_def++;
384
385 table->n_t_def++;
386
387 if (name != NULL) {
388 if (table->n_v_def == table->n_v_cols) {
389 heap = table->heap;
390 }
391
392 if (i && !table->v_col_names) {
393 /* All preceding column names are empty. */
394 char* s = static_cast<char*>(
395 mem_heap_zalloc(heap, table->n_v_def));
396
397 table->v_col_names = s;
398 }
399
400 table->v_col_names = dict_add_col_name(table->v_col_names,
401 i, name, heap);
402 }
403
404 v_col = &table->v_cols[i];
405
406 dict_mem_fill_column_struct(&v_col->m_col, pos, mtype, prtype, len);
407 v_col->v_pos = i;
408
409 if (num_base != 0) {
410 v_col->base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
411 table->heap, num_base * sizeof(
412 *v_col->base_col)));
413 } else {
414 v_col->base_col = NULL;
415 }
416
417 v_col->num_base = num_base;
418
419 /* Initialize the index list for virtual columns */
420 v_col->v_indexes = UT_NEW_NOKEY(dict_v_idx_list());
421
422 return(v_col);
423 }
424
425 /** Adds a stored column definition to a table.
426 @param[in] table table
427 @param[in] num_base number of base columns. */
428 void
dict_mem_table_add_s_col(dict_table_t * table,ulint num_base)429 dict_mem_table_add_s_col(
430 dict_table_t* table,
431 ulint num_base)
432 {
433 unsigned i = unsigned(table->n_def) - 1;
434 dict_col_t* col = dict_table_get_nth_col(table, i);
435 dict_s_col_t s_col;
436
437 ut_ad(col != NULL);
438
439 if (table->s_cols == NULL) {
440 table->s_cols = UT_NEW_NOKEY(dict_s_col_list());
441 }
442
443 s_col.m_col = col;
444 s_col.s_pos = i + table->n_v_def;
445
446 if (num_base != 0) {
447 s_col.base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
448 table->heap, num_base * sizeof(dict_col_t*)));
449 } else {
450 s_col.base_col = NULL;
451 }
452
453 s_col.num_base = num_base;
454 table->s_cols->push_back(s_col);
455 }
456
457 /**********************************************************************//**
458 Renames a column of a table in the data dictionary cache. */
459 static MY_ATTRIBUTE((nonnull))
460 void
dict_mem_table_col_rename_low(dict_table_t * table,unsigned i,const char * to,const char * s,bool is_virtual)461 dict_mem_table_col_rename_low(
462 /*==========================*/
463 dict_table_t* table, /*!< in/out: table */
464 unsigned i, /*!< in: column offset corresponding to s */
465 const char* to, /*!< in: new column name */
466 const char* s, /*!< in: pointer to table->col_names */
467 bool is_virtual)
468 /*!< in: if this is a virtual column */
469 {
470 char* t_col_names = const_cast<char*>(
471 is_virtual ? table->v_col_names : table->col_names);
472 ulint n_col = is_virtual ? table->n_v_def : table->n_def;
473
474 size_t from_len = strlen(s), to_len = strlen(to);
475
476 ut_ad(i < table->n_def || is_virtual);
477 ut_ad(i < table->n_v_def || !is_virtual);
478
479 ut_ad(from_len <= NAME_LEN);
480 ut_ad(to_len <= NAME_LEN);
481
482 char from[NAME_LEN + 1];
483 strncpy(from, s, sizeof from - 1);
484 from[sizeof from - 1] = '\0';
485
486 if (from_len == to_len) {
487 /* The easy case: simply replace the column name in
488 table->col_names. */
489 strcpy(const_cast<char*>(s), to);
490 } else {
491 /* We need to adjust all affected index->field
492 pointers, as in dict_index_add_col(). First, copy
493 table->col_names. */
494 ulint prefix_len = ulint(s - t_col_names);
495
496 for (; i < n_col; i++) {
497 s += strlen(s) + 1;
498 }
499
500 ulint full_len = ulint(s - t_col_names);
501 char* col_names;
502
503 if (to_len > from_len) {
504 col_names = static_cast<char*>(
505 mem_heap_alloc(
506 table->heap,
507 full_len + to_len - from_len));
508
509 memcpy(col_names, t_col_names, prefix_len);
510 } else {
511 col_names = const_cast<char*>(t_col_names);
512 }
513
514 memcpy(col_names + prefix_len, to, to_len);
515 memmove(col_names + prefix_len + to_len,
516 t_col_names + (prefix_len + from_len),
517 full_len - (prefix_len + from_len));
518
519 /* Replace the field names in every index. */
520 for (dict_index_t* index = dict_table_get_first_index(table);
521 index != NULL;
522 index = dict_table_get_next_index(index)) {
523 ulint n_fields = dict_index_get_n_fields(index);
524
525 for (ulint i = 0; i < n_fields; i++) {
526 dict_field_t* field
527 = dict_index_get_nth_field(
528 index, i);
529
530 /* if is_virtual and that in field->col does
531 not match, continue */
532 if ((!is_virtual) !=
533 (!field->col->is_virtual())) {
534 continue;
535 }
536
537 ulint name_ofs
538 = ulint(field->name - t_col_names);
539 if (name_ofs <= prefix_len) {
540 field->name = col_names + name_ofs;
541 } else {
542 ut_a(name_ofs < full_len);
543 field->name = col_names
544 + name_ofs + to_len - from_len;
545 }
546 }
547 }
548
549 if (is_virtual) {
550 table->v_col_names = col_names;
551 } else {
552 table->col_names = col_names;
553 }
554 }
555
556 /* Virtual columns are not allowed for foreign key */
557 if (is_virtual) {
558 return;
559 }
560
561 dict_foreign_t* foreign;
562
563 /* Replace the field names in every foreign key constraint. */
564 for (dict_foreign_set::iterator it = table->foreign_set.begin();
565 it != table->foreign_set.end();
566 ++it) {
567
568 foreign = *it;
569
570 if (foreign->foreign_index == NULL) {
571 /* We may go here when we set foreign_key_checks to 0,
572 and then try to rename a column and modify the
573 corresponding foreign key constraint. The index
574 would have been dropped, we have to find an equivalent
575 one */
576 for (unsigned f = 0; f < foreign->n_fields; f++) {
577 if (strcmp(foreign->foreign_col_names[f], from)
578 == 0) {
579
580 char** rc = const_cast<char**>(
581 foreign->foreign_col_names
582 + f);
583
584 if (to_len <= strlen(*rc)) {
585 memcpy(*rc, to, to_len + 1);
586 } else {
587 *rc = static_cast<char*>(
588 mem_heap_dup(
589 foreign->heap,
590 to,
591 to_len + 1));
592 }
593 }
594 }
595
596 /* New index can be null if InnoDB already dropped
597 the foreign index when FOREIGN_KEY_CHECKS is
598 disabled */
599 foreign->foreign_index = dict_foreign_find_index(
600 foreign->foreign_table, NULL,
601 foreign->foreign_col_names,
602 foreign->n_fields, NULL, true, false,
603 NULL, NULL, NULL);
604
605 } else {
606
607 for (unsigned f = 0; f < foreign->n_fields; f++) {
608 /* These can point straight to
609 table->col_names, because the foreign key
610 constraints will be freed at the same time
611 when the table object is freed. */
612 foreign->foreign_col_names[f]
613 = dict_index_get_nth_field(
614 foreign->foreign_index,
615 f)->name;
616 }
617 }
618 }
619
620 for (dict_foreign_set::iterator it = table->referenced_set.begin();
621 it != table->referenced_set.end();
622 ++it) {
623
624 foreign = *it;
625
626 if (!foreign->referenced_index) {
627 /* Referenced index could have been dropped
628 when foreign_key_checks is disabled. In that case,
629 rename the corresponding referenced_col_names and
630 find the equivalent referenced index also */
631 for (unsigned f = 0; f < foreign->n_fields; f++) {
632
633 const char*& rc =
634 foreign->referenced_col_names[f];
635 if (strcmp(rc, from)) {
636 continue;
637 }
638
639 if (to_len <= strlen(rc)) {
640 memcpy(const_cast<char*>(rc), to,
641 to_len + 1);
642 } else {
643 rc = static_cast<char*>(
644 mem_heap_dup(
645 foreign->heap,
646 to, to_len + 1));
647 }
648 }
649
650 /* New index can be null if InnoDB already dropped
651 the referenced index when FOREIGN_KEY_CHECKS is
652 disabled */
653 foreign->referenced_index = dict_foreign_find_index(
654 foreign->referenced_table, NULL,
655 foreign->referenced_col_names,
656 foreign->n_fields, NULL, true, false,
657 NULL, NULL, NULL);
658 return;
659 }
660
661
662 for (unsigned f = 0; f < foreign->n_fields; f++) {
663 /* foreign->referenced_col_names[] need to be
664 copies, because the constraint may become
665 orphan when foreign_key_checks=0 and the
666 parent table is dropped. */
667
668 const char* col_name = dict_index_get_nth_field(
669 foreign->referenced_index, f)->name;
670
671 if (strcmp(foreign->referenced_col_names[f],
672 col_name)) {
673 char** rc = const_cast<char**>(
674 foreign->referenced_col_names + f);
675 size_t col_name_len_1 = strlen(col_name) + 1;
676
677 if (col_name_len_1 <= strlen(*rc) + 1) {
678 memcpy(*rc, col_name, col_name_len_1);
679 } else {
680 *rc = static_cast<char*>(
681 mem_heap_dup(
682 foreign->heap,
683 col_name,
684 col_name_len_1));
685 }
686 }
687 }
688 }
689 }
690
691 /**********************************************************************//**
692 Renames a column of a table in the data dictionary cache. */
693 void
dict_mem_table_col_rename(dict_table_t * table,ulint nth_col,const char * from,const char * to,bool is_virtual)694 dict_mem_table_col_rename(
695 /*======================*/
696 dict_table_t* table, /*!< in/out: table */
697 ulint nth_col,/*!< in: column index */
698 const char* from, /*!< in: old column name */
699 const char* to, /*!< in: new column name */
700 bool is_virtual)
701 /*!< in: if this is a virtual column */
702 {
703 const char* s = is_virtual ? table->v_col_names : table->col_names;
704
705 ut_ad((!is_virtual && nth_col < table->n_def)
706 || (is_virtual && nth_col < table->n_v_def));
707
708 for (ulint i = 0; i < nth_col; i++) {
709 size_t len = strlen(s);
710 ut_ad(len > 0);
711 s += len + 1;
712 }
713
714 ut_ad(!my_strcasecmp(system_charset_info, from, s));
715
716 dict_mem_table_col_rename_low(table, static_cast<unsigned>(nth_col),
717 to, s, is_virtual);
718 }
719
720 /**********************************************************************//**
721 This function populates a dict_col_t memory structure with
722 supplied information. */
723 void
dict_mem_fill_column_struct(dict_col_t * column,ulint col_pos,ulint mtype,ulint prtype,ulint col_len)724 dict_mem_fill_column_struct(
725 /*========================*/
726 dict_col_t* column, /*!< out: column struct to be
727 filled */
728 ulint col_pos, /*!< in: column position */
729 ulint mtype, /*!< in: main data type */
730 ulint prtype, /*!< in: precise type */
731 ulint col_len) /*!< in: column length */
732 {
733 ulint mbminlen;
734 ulint mbmaxlen;
735
736 column->ind = (unsigned int) col_pos;
737 column->ord_part = 0;
738 column->max_prefix = 0;
739 column->mtype = (unsigned int) mtype;
740 column->prtype = (unsigned int) prtype;
741 column->len = (unsigned int) col_len;
742 dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
743 column->mbminlen = mbminlen;
744 column->mbmaxlen = mbmaxlen;
745 column->def_val.data = NULL;
746 column->def_val.len = UNIV_SQL_DEFAULT;
747 }
748
749 /**********************************************************************//**
750 Creates an index memory object.
751 @return own: index object */
752 dict_index_t*
dict_mem_index_create(dict_table_t * table,const char * index_name,ulint type,ulint n_fields)753 dict_mem_index_create(
754 /*==================*/
755 dict_table_t* table, /*!< in: table */
756 const char* index_name, /*!< in: index name */
757 ulint type, /*!< in: DICT_UNIQUE,
758 DICT_CLUSTERED, ... ORed */
759 ulint n_fields) /*!< in: number of fields */
760 {
761 dict_index_t* index;
762 mem_heap_t* heap;
763
764 ut_ad(!table || table->magic_n == DICT_TABLE_MAGIC_N);
765 ut_ad(index_name);
766
767 heap = mem_heap_create(DICT_HEAP_SIZE);
768
769 index = static_cast<dict_index_t*>(
770 mem_heap_zalloc(heap, sizeof(*index)));
771 index->table = table;
772
773 dict_mem_fill_index_struct(index, heap, index_name, type, n_fields);
774
775 mysql_mutex_init(0, &index->zip_pad.mutex, NULL);
776
777 if (type & DICT_SPATIAL) {
778 index->rtr_track = static_cast<rtr_info_track_t*>(
779 mem_heap_alloc(
780 heap,
781 sizeof(*index->rtr_track)));
782 mutex_create(LATCH_ID_RTR_ACTIVE_MUTEX,
783 &index->rtr_track->rtr_active_mutex);
784 index->rtr_track->rtr_active = UT_NEW_NOKEY(rtr_info_active());
785 }
786
787 return(index);
788 }
789
790 /**********************************************************************//**
791 Creates and initializes a foreign constraint memory object.
792 @return own: foreign constraint struct */
793 dict_foreign_t*
dict_mem_foreign_create(void)794 dict_mem_foreign_create(void)
795 /*=========================*/
796 {
797 dict_foreign_t* foreign;
798 mem_heap_t* heap;
799 DBUG_ENTER("dict_mem_foreign_create");
800
801 heap = mem_heap_create(100);
802
803 foreign = static_cast<dict_foreign_t*>(
804 mem_heap_zalloc(heap, sizeof(dict_foreign_t)));
805
806 foreign->heap = heap;
807
808 foreign->v_cols = NULL;
809
810 DBUG_PRINT("dict_mem_foreign_create", ("heap: %p", heap));
811
812 DBUG_RETURN(foreign);
813 }
814
815 /**********************************************************************//**
816 Sets the foreign_table_name_lookup pointer based on the value of
817 lower_case_table_names. If that is 0 or 1, foreign_table_name_lookup
818 will point to foreign_table_name. If 2, then another string is
819 allocated from foreign->heap and set to lower case. */
820 void
dict_mem_foreign_table_name_lookup_set(dict_foreign_t * foreign,ibool do_alloc)821 dict_mem_foreign_table_name_lookup_set(
822 /*===================================*/
823 dict_foreign_t* foreign, /*!< in/out: foreign struct */
824 ibool do_alloc) /*!< in: is an alloc needed */
825 {
826 if (innobase_get_lower_case_table_names() == 2) {
827 if (do_alloc) {
828 ulint len;
829
830 len = strlen(foreign->foreign_table_name) + 1;
831
832 foreign->foreign_table_name_lookup =
833 static_cast<char*>(
834 mem_heap_alloc(foreign->heap, len));
835 }
836 strcpy(foreign->foreign_table_name_lookup,
837 foreign->foreign_table_name);
838 innobase_casedn_str(foreign->foreign_table_name_lookup);
839 } else {
840 foreign->foreign_table_name_lookup
841 = foreign->foreign_table_name;
842 }
843 }
844
845 /**********************************************************************//**
846 Sets the referenced_table_name_lookup pointer based on the value of
847 lower_case_table_names. If that is 0 or 1, referenced_table_name_lookup
848 will point to referenced_table_name. If 2, then another string is
849 allocated from foreign->heap and set to lower case. */
850 void
dict_mem_referenced_table_name_lookup_set(dict_foreign_t * foreign,ibool do_alloc)851 dict_mem_referenced_table_name_lookup_set(
852 /*======================================*/
853 dict_foreign_t* foreign, /*!< in/out: foreign struct */
854 ibool do_alloc) /*!< in: is an alloc needed */
855 {
856 if (innobase_get_lower_case_table_names() == 2) {
857 if (do_alloc) {
858 ulint len;
859
860 len = strlen(foreign->referenced_table_name) + 1;
861
862 foreign->referenced_table_name_lookup =
863 static_cast<char*>(
864 mem_heap_alloc(foreign->heap, len));
865 }
866 strcpy(foreign->referenced_table_name_lookup,
867 foreign->referenced_table_name);
868 innobase_casedn_str(foreign->referenced_table_name_lookup);
869 } else {
870 foreign->referenced_table_name_lookup
871 = foreign->referenced_table_name;
872 }
873 }
874
875 /** Fill the virtual column set with virtual column information
876 present in the given virtual index.
877 @param[in] index virtual index
878 @param[out] v_cols virtual column set. */
879 static
880 void
dict_mem_fill_vcol_has_index(const dict_index_t * index,dict_vcol_set ** v_cols)881 dict_mem_fill_vcol_has_index(
882 const dict_index_t* index,
883 dict_vcol_set** v_cols)
884 {
885 for (ulint i = 0; i < index->table->n_v_cols; i++) {
886 dict_v_col_t* v_col = dict_table_get_nth_v_col(
887 index->table, i);
888 if (!v_col->m_col.ord_part) {
889 continue;
890 }
891
892 dict_v_idx_list::iterator it;
893 for (it = v_col->v_indexes->begin();
894 it != v_col->v_indexes->end(); ++it) {
895 dict_v_idx_t v_idx = *it;
896
897 if (v_idx.index != index) {
898 continue;
899 }
900
901 if (*v_cols == NULL) {
902 *v_cols = UT_NEW_NOKEY(dict_vcol_set());
903 }
904
905 (*v_cols)->insert(v_col);
906 }
907 }
908 }
909
910 /** Fill the virtual column set with the virtual column of the index
911 if the index contains given column name.
912 @param[in] col_name column name
913 @param[in] table innodb table object
914 @param[out] v_cols set of virtual column information. */
915 static
916 void
dict_mem_fill_vcol_from_v_indexes(const char * col_name,const dict_table_t * table,dict_vcol_set ** v_cols)917 dict_mem_fill_vcol_from_v_indexes(
918 const char* col_name,
919 const dict_table_t* table,
920 dict_vcol_set** v_cols)
921 {
922 /* virtual column can't be Primary Key, so start with
923 secondary index */
924 for (dict_index_t* index = dict_table_get_next_index(
925 dict_table_get_first_index(table));
926 index;
927 index = dict_table_get_next_index(index)) {
928
929 /* Skip if the index have newly added
930 virtual column because field name is NULL.
931 Later virtual column set will be
932 refreshed during loading of table. */
933 if (!dict_index_has_virtual(index)
934 || index->has_new_v_col()) {
935 continue;
936 }
937
938 for (ulint i = 0; i < index->n_fields; i++) {
939 dict_field_t* field =
940 dict_index_get_nth_field(index, i);
941
942 if (strcmp(field->name, col_name) == 0) {
943 dict_mem_fill_vcol_has_index(
944 index, v_cols);
945 }
946 }
947 }
948 }
949
950 /** Fill the virtual column set with virtual columns which have base columns
951 as the given col_name
952 @param[in] col_name column name
953 @param[in] table table object
954 @param[out] v_cols set of virtual columns. */
955 static
956 void
dict_mem_fill_vcol_set_for_base_col(const char * col_name,const dict_table_t * table,dict_vcol_set ** v_cols)957 dict_mem_fill_vcol_set_for_base_col(
958 const char* col_name,
959 const dict_table_t* table,
960 dict_vcol_set** v_cols)
961 {
962 for (ulint i = 0; i < table->n_v_cols; i++) {
963 dict_v_col_t* v_col = dict_table_get_nth_v_col(table, i);
964
965 if (!v_col->m_col.ord_part) {
966 continue;
967 }
968
969 for (ulint j = 0; j < v_col->num_base; j++) {
970 if (strcmp(col_name, dict_table_get_col_name(
971 table,
972 v_col->base_col[j]->ind)) == 0) {
973
974 if (*v_cols == NULL) {
975 *v_cols = UT_NEW_NOKEY(dict_vcol_set());
976 }
977
978 (*v_cols)->insert(v_col);
979 }
980 }
981 }
982 }
983
984 /** Fills the dependent virtual columns in a set.
985 Reason for being dependent are
986 1) FK can be present on base column of virtual columns
987 2) FK can be present on column which is a part of virtual index
988 @param[in,out] foreign foreign key information. */
989 void
dict_mem_foreign_fill_vcol_set(dict_foreign_t * foreign)990 dict_mem_foreign_fill_vcol_set(
991 dict_foreign_t* foreign)
992 {
993 ulint type = foreign->type;
994
995 if (type == 0) {
996 return;
997 }
998
999 for (ulint i = 0; i < foreign->n_fields; i++) {
1000 /** FK can be present on base columns
1001 of virtual columns. */
1002 dict_mem_fill_vcol_set_for_base_col(
1003 foreign->foreign_col_names[i],
1004 foreign->foreign_table,
1005 &foreign->v_cols);
1006
1007 /** FK can be present on the columns
1008 which can be a part of virtual index. */
1009 dict_mem_fill_vcol_from_v_indexes(
1010 foreign->foreign_col_names[i],
1011 foreign->foreign_table,
1012 &foreign->v_cols);
1013 }
1014 }
1015
1016 /** Fill virtual columns set in each fk constraint present in the table.
1017 @param[in,out] table innodb table object. */
1018 void
dict_mem_table_fill_foreign_vcol_set(dict_table_t * table)1019 dict_mem_table_fill_foreign_vcol_set(
1020 dict_table_t* table)
1021 {
1022 dict_foreign_set fk_set = table->foreign_set;
1023 dict_foreign_t* foreign;
1024
1025 dict_foreign_set::iterator it;
1026 for (it = fk_set.begin(); it != fk_set.end(); ++it) {
1027 foreign = *it;
1028
1029 dict_mem_foreign_fill_vcol_set(foreign);
1030 }
1031 }
1032
1033 /** Free the vcol_set from all foreign key constraint on the table.
1034 @param[in,out] table innodb table object. */
1035 void
dict_mem_table_free_foreign_vcol_set(dict_table_t * table)1036 dict_mem_table_free_foreign_vcol_set(
1037 dict_table_t* table)
1038 {
1039 dict_foreign_set fk_set = table->foreign_set;
1040 dict_foreign_t* foreign;
1041
1042 dict_foreign_set::iterator it;
1043 for (it = fk_set.begin(); it != fk_set.end(); ++it) {
1044
1045 foreign = *it;
1046
1047 if (foreign->v_cols != NULL) {
1048 UT_DELETE(foreign->v_cols);
1049 foreign->v_cols = NULL;
1050 }
1051 }
1052 }
1053
1054 /**********************************************************************//**
1055 Adds a field definition to an index. NOTE: does not take a copy
1056 of the column name if the field is a column. The memory occupied
1057 by the column name may be released only after publishing the index. */
1058 void
dict_mem_index_add_field(dict_index_t * index,const char * name,ulint prefix_len)1059 dict_mem_index_add_field(
1060 /*=====================*/
1061 dict_index_t* index, /*!< in: index */
1062 const char* name, /*!< in: column name */
1063 ulint prefix_len) /*!< in: 0 or the column prefix length
1064 in a MySQL index like
1065 INDEX (textcol(25)) */
1066 {
1067 dict_field_t* field;
1068
1069 ut_ad(index);
1070 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1071
1072 index->n_def++;
1073
1074 field = dict_index_get_nth_field(index, unsigned(index->n_def) - 1);
1075
1076 field->name = name;
1077 field->prefix_len = (unsigned int) prefix_len;
1078 }
1079
1080 /**********************************************************************//**
1081 Frees an index memory object. */
1082 void
dict_mem_index_free(dict_index_t * index)1083 dict_mem_index_free(
1084 /*================*/
1085 dict_index_t* index) /*!< in: index */
1086 {
1087 ut_ad(index);
1088 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1089
1090 mysql_mutex_destroy(&index->zip_pad.mutex);
1091
1092 if (dict_index_is_spatial(index)) {
1093 rtr_info_active::iterator it;
1094 rtr_info_t* rtr_info;
1095
1096 for (it = index->rtr_track->rtr_active->begin();
1097 it != index->rtr_track->rtr_active->end(); ++it) {
1098 rtr_info = *it;
1099
1100 rtr_info->index = NULL;
1101 }
1102
1103 mutex_destroy(&index->rtr_track->rtr_active_mutex);
1104 UT_DELETE(index->rtr_track->rtr_active);
1105 }
1106
1107 dict_index_remove_from_v_col_list(index);
1108 mem_heap_free(index->heap);
1109 }
1110
1111 /** Create a temporary tablename like "#sql-ibNNN".
1112 @param[in] heap A memory heap
1113 @param[in] dbtab Table name in the form database/table name
1114 @param[in] id Table id
1115 @return A unique temporary tablename suitable for InnoDB use */
1116 char*
dict_mem_create_temporary_tablename(mem_heap_t * heap,const char * dbtab,table_id_t id)1117 dict_mem_create_temporary_tablename(
1118 mem_heap_t* heap,
1119 const char* dbtab,
1120 table_id_t id)
1121 {
1122 size_t size;
1123 char* name;
1124 const char* dbend = strchr(dbtab, '/');
1125 ut_ad(dbend);
1126 size_t dblen = size_t(dbend - dbtab) + 1;
1127
1128 size = dblen + (sizeof(TEMP_FILE_PREFIX) + 3 + 20);
1129 name = static_cast<char*>(mem_heap_alloc(heap, size));
1130 memcpy(name, dbtab, dblen);
1131 snprintf(name + dblen, size - dblen,
1132 TEMP_FILE_PREFIX_INNODB UINT64PF, id);
1133
1134 return(name);
1135 }
1136
1137 /** Validate the search order in the foreign key set.
1138 @param[in] fk_set the foreign key set to be validated
1139 @return true if search order is fine in the set, false otherwise. */
1140 bool
dict_foreign_set_validate(const dict_foreign_set & fk_set)1141 dict_foreign_set_validate(
1142 const dict_foreign_set& fk_set)
1143 {
1144 dict_foreign_not_exists not_exists(fk_set);
1145
1146 dict_foreign_set::const_iterator it = std::find_if(
1147 fk_set.begin(), fk_set.end(), not_exists);
1148
1149 if (it == fk_set.end()) {
1150 return(true);
1151 }
1152
1153 dict_foreign_t* foreign = *it;
1154 std::cerr << "Foreign key lookup failed: " << *foreign;
1155 std::cerr << fk_set;
1156 ut_ad(0);
1157 return(false);
1158 }
1159
1160 /** Validate the search order in the foreign key sets of the table
1161 (foreign_set and referenced_set).
1162 @param[in] table table whose foreign key sets are to be validated
1163 @return true if foreign key sets are fine, false otherwise. */
1164 bool
dict_foreign_set_validate(const dict_table_t & table)1165 dict_foreign_set_validate(
1166 const dict_table_t& table)
1167 {
1168 return(dict_foreign_set_validate(table.foreign_set)
1169 && dict_foreign_set_validate(table.referenced_set));
1170 }
1171
1172 std::ostream&
operator <<(std::ostream & out,const dict_foreign_t & foreign)1173 operator<< (std::ostream& out, const dict_foreign_t& foreign)
1174 {
1175 out << "[dict_foreign_t: id='" << foreign.id << "'";
1176
1177 if (foreign.foreign_table_name != NULL) {
1178 out << ",for: '" << foreign.foreign_table_name << "'";
1179 }
1180
1181 out << "]";
1182 return(out);
1183 }
1184
1185 std::ostream&
operator <<(std::ostream & out,const dict_foreign_set & fk_set)1186 operator<< (std::ostream& out, const dict_foreign_set& fk_set)
1187 {
1188 out << "[dict_foreign_set:";
1189 std::for_each(fk_set.begin(), fk_set.end(), dict_foreign_print(out));
1190 out << "]" << std::endl;
1191 return(out);
1192 }
1193
1194 /** Check whether fulltext index gets affected by foreign
1195 key constraint. */
affects_fulltext() const1196 bool dict_foreign_t::affects_fulltext() const
1197 {
1198 if (foreign_table == referenced_table || !foreign_table->fts)
1199 return false;
1200
1201 for (ulint i= 0; i < n_fields; i++)
1202 {
1203 const dict_col_t *col= dict_index_get_nth_col(foreign_index, i);
1204 if (dict_table_is_fts_column(foreign_table->fts->indexes, col->ind,
1205 col->is_virtual()) != ULINT_UNDEFINED)
1206 return true;
1207 }
1208
1209 return false;
1210 }
1211
1212 /** Adjust clustered index metadata for instant ADD COLUMN.
1213 @param[in] clustered index definition after instant ADD COLUMN */
instant_add_field(const dict_index_t & instant)1214 inline void dict_index_t::instant_add_field(const dict_index_t& instant)
1215 {
1216 DBUG_ASSERT(is_primary());
1217 DBUG_ASSERT(instant.is_primary());
1218 DBUG_ASSERT(!instant.is_instant());
1219 DBUG_ASSERT(n_def == n_fields);
1220 DBUG_ASSERT(instant.n_def == instant.n_fields);
1221
1222 DBUG_ASSERT(type == instant.type);
1223 DBUG_ASSERT(trx_id_offset == instant.trx_id_offset);
1224 DBUG_ASSERT(n_user_defined_cols == instant.n_user_defined_cols);
1225 DBUG_ASSERT(n_uniq == instant.n_uniq);
1226 DBUG_ASSERT(instant.n_fields > n_fields);
1227 DBUG_ASSERT(instant.n_def > n_def);
1228 DBUG_ASSERT(instant.n_nullable >= n_nullable);
1229 DBUG_ASSERT(instant.n_core_fields >= n_core_fields);
1230 DBUG_ASSERT(instant.n_core_null_bytes >= n_core_null_bytes);
1231
1232 n_fields = instant.n_fields;
1233 n_def = instant.n_def;
1234 n_nullable = instant.n_nullable;
1235 fields = static_cast<dict_field_t*>(
1236 mem_heap_dup(heap, instant.fields, n_fields * sizeof *fields));
1237
1238 ut_d(unsigned n_null = 0);
1239
1240 for (unsigned i = 0; i < n_fields; i++) {
1241 DBUG_ASSERT(fields[i].same(instant.fields[i]));
1242 const dict_col_t* icol = instant.fields[i].col;
1243 DBUG_ASSERT(!icol->is_virtual());
1244 dict_col_t* col = fields[i].col = &table->cols[
1245 icol - instant.table->cols];
1246 fields[i].name = col->name(*table);
1247 ut_d(n_null += col->is_nullable());
1248 }
1249
1250 ut_ad(n_null == n_nullable);
1251 }
1252
1253 /** Adjust metadata for instant ADD COLUMN.
1254 @param[in] table table definition after instant ADD COLUMN */
instant_add_column(const dict_table_t & table)1255 void dict_table_t::instant_add_column(const dict_table_t& table)
1256 {
1257 DBUG_ASSERT(!table.cached);
1258 DBUG_ASSERT(table.n_def == table.n_cols);
1259 DBUG_ASSERT(table.n_t_def == table.n_t_cols);
1260 DBUG_ASSERT(n_def == n_cols);
1261 DBUG_ASSERT(n_t_def == n_t_cols);
1262 DBUG_ASSERT(table.n_cols > n_cols);
1263 ut_ad(mutex_own(&dict_sys->mutex));
1264
1265 const char* end = table.col_names;
1266 for (unsigned i = table.n_cols; i--; ) end += strlen(end) + 1;
1267
1268 col_names = static_cast<char*>(
1269 mem_heap_dup(heap, table.col_names,
1270 ulint(end - table.col_names)));
1271 const dict_col_t* const old_cols = cols;
1272 const dict_col_t* const old_cols_end = cols + n_cols;
1273 cols = static_cast<dict_col_t*>(mem_heap_dup(heap, table.cols,
1274 table.n_cols
1275 * sizeof *cols));
1276
1277 /* Preserve the default values of previously instantly
1278 added columns. */
1279 for (unsigned i = unsigned(n_cols) - DATA_N_SYS_COLS; i--; ) {
1280 cols[i].def_val = old_cols[i].def_val;
1281 }
1282
1283 /* Copy the new default values to this->heap. */
1284 for (unsigned i = n_cols; i < table.n_cols; i++) {
1285 dict_col_t& c = cols[i - DATA_N_SYS_COLS];
1286 DBUG_ASSERT(c.is_instant());
1287 if (c.def_val.len == 0) {
1288 c.def_val.data = field_ref_zero;
1289 } else if (const void*& d = c.def_val.data) {
1290 d = mem_heap_dup(heap, d, c.def_val.len);
1291 } else {
1292 DBUG_ASSERT(c.def_val.len == UNIV_SQL_NULL);
1293 }
1294 }
1295
1296 const unsigned old_n_cols = n_cols;
1297 const unsigned n_add = unsigned(table.n_cols - n_cols);
1298
1299 n_t_def += n_add;
1300 n_t_cols += n_add;
1301 n_cols = table.n_cols;
1302 n_def = n_cols;
1303
1304 for (unsigned i = n_v_def; i--; ) {
1305 const dict_v_col_t& v = v_cols[i];
1306 for (ulint n = v.num_base; n--; ) {
1307 dict_col_t*& base = v.base_col[n];
1308 if (!base->is_virtual()) {
1309 DBUG_ASSERT(base >= old_cols);
1310 size_t n = size_t(base - old_cols);
1311 DBUG_ASSERT(n + DATA_N_SYS_COLS < old_n_cols);
1312 base = &cols[n];
1313 }
1314 }
1315 }
1316
1317 dict_index_t* index = dict_table_get_first_index(this);
1318
1319 index->instant_add_field(*dict_table_get_first_index(&table));
1320
1321 while ((index = dict_table_get_next_index(index)) != NULL) {
1322 for (unsigned i = 0; i < index->n_fields; i++) {
1323 dict_field_t& field = index->fields[i];
1324 if (field.col < old_cols
1325 || field.col >= old_cols_end) {
1326 DBUG_ASSERT(field.col->is_virtual());
1327 } else {
1328 /* Secondary indexes may contain user
1329 columns and DB_ROW_ID (if there is
1330 GEN_CLUST_INDEX instead of PRIMARY KEY),
1331 but not DB_TRX_ID,DB_ROLL_PTR. */
1332 DBUG_ASSERT(field.col >= old_cols);
1333 size_t n = size_t(field.col - old_cols);
1334 DBUG_ASSERT(n + DATA_N_SYS_COLS <= old_n_cols);
1335 if (n + DATA_N_SYS_COLS >= old_n_cols) {
1336 /* Replace DB_ROW_ID */
1337 n += n_add;
1338 }
1339 field.col = &cols[n];
1340 DBUG_ASSERT(!field.col->is_virtual());
1341 field.name = field.col->name(*this);
1342 }
1343 }
1344 }
1345 }
1346
1347 /** Roll back instant_add_column().
1348 @param[in] old_n_cols original n_cols
1349 @param[in] old_cols original cols
1350 @param[in] old_col_names original col_names */
1351 void
rollback_instant(unsigned old_n_cols,dict_col_t * old_cols,const char * old_col_names)1352 dict_table_t::rollback_instant(
1353 unsigned old_n_cols,
1354 dict_col_t* old_cols,
1355 const char* old_col_names)
1356 {
1357 ut_ad(mutex_own(&dict_sys->mutex));
1358 dict_index_t* index = indexes.start;
1359 /* index->is_instant() does not necessarily hold here, because
1360 the table may have been emptied */
1361 DBUG_ASSERT(old_n_cols >= DATA_N_SYS_COLS);
1362 DBUG_ASSERT(n_cols >= old_n_cols);
1363 DBUG_ASSERT(n_cols == n_def);
1364 DBUG_ASSERT(index->n_def == index->n_fields);
1365
1366 const unsigned n_remove = n_cols - old_n_cols;
1367
1368 for (unsigned i = index->n_fields - n_remove; i < index->n_fields;
1369 i++) {
1370 if (index->fields[i].col->is_nullable()) {
1371 index->n_nullable--;
1372 }
1373 }
1374
1375 index->n_fields -= n_remove;
1376 index->n_def = index->n_fields;
1377 if (index->n_core_fields > index->n_fields) {
1378 index->n_core_fields = index->n_fields;
1379 index->n_core_null_bytes
1380 = UT_BITS_IN_BYTES(unsigned(index->n_nullable));
1381 }
1382
1383 const dict_col_t* const new_cols = cols;
1384 const dict_col_t* const new_cols_end = cols + n_cols;
1385
1386 cols = old_cols;
1387 col_names = old_col_names;
1388 n_cols = old_n_cols;
1389 n_def = old_n_cols;
1390 n_t_def -= n_remove;
1391 n_t_cols -= n_remove;
1392
1393 for (unsigned i = n_v_def; i--; ) {
1394 const dict_v_col_t& v = v_cols[i];
1395 for (ulint n = v.num_base; n--; ) {
1396 dict_col_t*& base = v.base_col[n];
1397 if (!base->is_virtual()) {
1398 base = &cols[base - new_cols];
1399 }
1400 }
1401 }
1402
1403 do {
1404 for (unsigned i = 0; i < index->n_fields; i++) {
1405 dict_field_t& field = index->fields[i];
1406 if (field.col < new_cols
1407 || field.col >= new_cols_end) {
1408 DBUG_ASSERT(field.col->is_virtual());
1409 } else {
1410 DBUG_ASSERT(field.col >= new_cols);
1411 size_t n = size_t(field.col - new_cols);
1412 DBUG_ASSERT(n <= n_cols);
1413 if (n + DATA_N_SYS_COLS >= n_cols) {
1414 n -= n_remove;
1415 }
1416 field.col = &cols[n];
1417 DBUG_ASSERT(!field.col->is_virtual());
1418 field.name = field.col->name(*this);
1419 }
1420 }
1421 } while ((index = dict_table_get_next_index(index)) != NULL);
1422 }
1423
1424 /** Trim the instantly added columns when an insert into SYS_COLUMNS
1425 is rolled back during ALTER TABLE or recovery.
1426 @param[in] n number of surviving non-system columns */
rollback_instant(unsigned n)1427 void dict_table_t::rollback_instant(unsigned n)
1428 {
1429 ut_ad(mutex_own(&dict_sys->mutex));
1430 dict_index_t* index = indexes.start;
1431 DBUG_ASSERT(index->is_instant());
1432 DBUG_ASSERT(index->n_def == index->n_fields);
1433 DBUG_ASSERT(n_cols == n_def);
1434 DBUG_ASSERT(n >= index->n_uniq);
1435 DBUG_ASSERT(n_cols > n + DATA_N_SYS_COLS);
1436 const unsigned n_remove = n_cols - n - DATA_N_SYS_COLS;
1437
1438 char* names = const_cast<char*>(dict_table_get_col_name(this, n));
1439 const char* sys = names;
1440 for (unsigned i = n_remove; i--; ) {
1441 sys += strlen(sys) + 1;
1442 }
1443 static const char system[] = "DB_ROW_ID\0DB_TRX_ID\0DB_ROLL_PTR";
1444 DBUG_ASSERT(!memcmp(sys, system, sizeof system));
1445 for (unsigned i = index->n_fields - n_remove; i < index->n_fields;
1446 i++) {
1447 if (index->fields[i].col->is_nullable()) {
1448 index->n_nullable--;
1449 }
1450 }
1451 index->n_fields -= n_remove;
1452 index->n_def = index->n_fields;
1453 memmove(names, sys, sizeof system);
1454 memmove(cols + n, cols + n_cols - DATA_N_SYS_COLS,
1455 DATA_N_SYS_COLS * sizeof *cols);
1456 n_cols -= n_remove;
1457 n_def = n_cols;
1458 n_t_cols -= n_remove;
1459 n_t_def -= n_remove;
1460
1461 for (unsigned i = DATA_N_SYS_COLS; i--; ) {
1462 cols[n_cols - i].ind--;
1463 }
1464
1465 if (dict_index_is_auto_gen_clust(index)) {
1466 DBUG_ASSERT(index->n_uniq == 1);
1467 dict_field_t* field = index->fields;
1468 field->name = sys;
1469 field->col = dict_table_get_sys_col(this, DATA_ROW_ID);
1470 field++;
1471 field->name = sys + sizeof "DB_ROW_ID";
1472 field->col = dict_table_get_sys_col(this, DATA_TRX_ID);
1473 field++;
1474 field->name = sys + sizeof "DB_ROW_ID\0DB_TRX_ID";
1475 field->col = dict_table_get_sys_col(this, DATA_ROLL_PTR);
1476
1477 /* Replace the DB_ROW_ID column in secondary indexes. */
1478 while ((index = dict_table_get_next_index(index)) != NULL) {
1479 field = &index->fields[index->n_fields - 1];
1480 DBUG_ASSERT(field->col->mtype == DATA_SYS);
1481 DBUG_ASSERT(field->col->prtype
1482 == DATA_NOT_NULL + DATA_TRX_ID);
1483 field->col--;
1484 field->name = sys;
1485 }
1486
1487 return;
1488 }
1489
1490 dict_field_t* field = &index->fields[index->n_uniq];
1491 field->name = sys + sizeof "DB_ROW_ID";
1492 field->col = dict_table_get_sys_col(this, DATA_TRX_ID);
1493 field++;
1494 field->name = sys + sizeof "DB_ROW_ID\0DB_TRX_ID";
1495 field->col = dict_table_get_sys_col(this, DATA_ROLL_PTR);
1496 }
1497
1498
1499 /** Check if record in clustered index is historical row.
1500 @param[in] rec clustered row
1501 @param[in] offsets offsets
1502 @return true if row is historical */
1503 bool
vers_history_row(const rec_t * rec,const rec_offs * offsets)1504 dict_index_t::vers_history_row(
1505 const rec_t* rec,
1506 const rec_offs* offsets)
1507 {
1508 ut_ad(is_primary());
1509
1510 ulint len;
1511 dict_col_t& col= table->cols[table->vers_end];
1512 ut_ad(col.vers_sys_end());
1513 ulint nfield = dict_col_get_clust_pos(&col, this);
1514 const byte *data = rec_get_nth_field(rec, offsets, nfield, &len);
1515 if (col.vers_native()) {
1516 ut_ad(len == sizeof trx_id_max_bytes);
1517 return 0 != memcmp(data, trx_id_max_bytes, len);
1518 }
1519 ut_ad(len == sizeof timestamp_max_bytes);
1520 return 0 != memcmp(data, timestamp_max_bytes, len);
1521 }
1522
1523 /** Check if record in secondary index is historical row.
1524 @param[in] rec record in a secondary index
1525 @param[out] history_row true if row is historical
1526 @return true on error */
1527 bool
vers_history_row(const rec_t * rec,bool & history_row)1528 dict_index_t::vers_history_row(
1529 const rec_t* rec,
1530 bool &history_row)
1531 {
1532 ut_ad(!is_primary());
1533
1534 bool error = false;
1535 mem_heap_t* heap = NULL;
1536 dict_index_t* clust_index = NULL;
1537 rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
1538 rec_offs* offsets = offsets_;
1539 rec_offs_init(offsets_);
1540
1541 mtr_t mtr;
1542 mtr.start();
1543
1544 rec_t* clust_rec =
1545 row_get_clust_rec(BTR_SEARCH_LEAF, rec, this, &clust_index, &mtr);
1546 if (clust_rec) {
1547 offsets = rec_get_offsets(clust_rec, clust_index, offsets,
1548 clust_index->n_core_fields,
1549 ULINT_UNDEFINED, &heap);
1550
1551 history_row = clust_index->vers_history_row(clust_rec, offsets);
1552 } else {
1553 ib::error() << "foreign constraints: secondary index is out of "
1554 "sync";
1555 ut_ad(!"secondary index is out of sync");
1556 error = true;
1557 }
1558 mtr.commit();
1559 if (heap) {
1560 mem_heap_free(heap);
1561 }
1562 return(error);
1563 }
1564