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