1 /*****************************************************************************
2
3 Copyright (c) 1996, 2021, Oracle and/or its affiliates.
4 Copyright (c) 2012, Facebook Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2.0,
8 as published by the Free Software Foundation.
9
10 This program is also distributed with certain software (including
11 but not limited to OpenSSL) that is licensed under separate terms,
12 as designated in a particular file or component or in included license
13 documentation. The authors of MySQL hereby grant you an additional
14 permission to link the program and your derivative works with the
15 separately licensed software that they have included with MySQL.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License, version 2.0, for more details.
21
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
25
26 *****************************************************************************/
27
28 /******************************************************************//**
29 @file dict/dict0mem.cc
30 Data dictionary memory object creation
31
32 Created 1/8/1996 Heikki Tuuri
33 ***********************************************************************/
34
35 #ifndef UNIV_HOTBACKUP
36 #include "ha_prototypes.h"
37 #include <mysql_com.h>
38 #endif /* !UNIV_HOTBACKUP */
39
40 #include "dict0mem.h"
41
42 #ifdef UNIV_NONINL
43 #include "dict0mem.ic"
44 #endif
45
46 #include "rem0rec.h"
47 #include "data0type.h"
48 #include "mach0data.h"
49 #include "dict0dict.h"
50 #include "fts0priv.h"
51 #include "ut0crc32.h"
52
53 #ifndef UNIV_HOTBACKUP
54 # include "lock0lock.h"
55 #endif /* !UNIV_HOTBACKUP */
56
57 #include "sync0sync.h"
58 #include <iostream>
59
60 #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
61 creating a table or index object */
62
63 /** An interger randomly initialized at startup used to make a temporary
64 table name as unuique as possible. */
65 static ib_uint32_t dict_temp_file_num;
66
67 /** Display an identifier.
68 @param[in,out] s output stream
69 @param[in] id_name SQL identifier (other than table name)
70 @return the output stream */
71 std::ostream&
operator <<(std::ostream & s,const id_name_t & id_name)72 operator<<(
73 std::ostream& s,
74 const id_name_t& id_name)
75 {
76 const char q = '`';
77 const char* c = id_name;
78 s << q;
79 for (; *c != 0; c++) {
80 if (*c == q) {
81 s << *c;
82 }
83 s << *c;
84 }
85 s << q;
86 return(s);
87 }
88
89 /** Display a table name.
90 @param[in,out] s output stream
91 @param[in] table_name table name
92 @return the output stream */
93 std::ostream&
operator <<(std::ostream & s,const table_name_t & table_name)94 operator<<(
95 std::ostream& s,
96 const table_name_t& table_name)
97 {
98 return(s << ut_get_name(NULL, table_name.m_name));
99 }
100
101 /**********************************************************************//**
102 Creates a table memory object.
103 @return own: table object */
104 dict_table_t*
dict_mem_table_create(const char * name,ulint space,ulint n_cols,ulint n_v_cols,ulint flags,ulint flags2)105 dict_mem_table_create(
106 /*==================*/
107 const char* name, /*!< in: table name */
108 ulint space, /*!< in: space where the clustered index of
109 the table is placed */
110 ulint n_cols, /*!< in: total number of columns including
111 virtual and non-virtual columns */
112 ulint n_v_cols,/*!< in: number of virtual columns */
113 ulint flags, /*!< in: table flags */
114 ulint flags2) /*!< in: table flags2 */
115 {
116 dict_table_t* table;
117 mem_heap_t* heap;
118
119 ut_ad(name);
120 ut_a(dict_tf2_is_valid(flags, flags2));
121 ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK));
122
123 heap = mem_heap_create(DICT_HEAP_SIZE);
124
125 table = static_cast<dict_table_t*>(
126 mem_heap_zalloc(heap, sizeof(*table)));
127
128 lock_table_lock_list_init(&table->locks);
129
130 UT_LIST_INIT(table->indexes, &dict_index_t::indexes);
131
132 table->heap = heap;
133
134 ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
135
136 table->flags = (unsigned int) flags;
137 table->flags2 = (unsigned int) flags2;
138 table->name.m_name = mem_strdup(name);
139 table->space = (unsigned int) space;
140 table->n_t_cols = (unsigned int) (n_cols +
141 dict_table_get_n_sys_cols(table));
142 table->n_v_cols = (unsigned int) (n_v_cols);
143 table->n_cols = table->n_t_cols - table->n_v_cols;
144
145 table->cols = static_cast<dict_col_t*>(
146 mem_heap_alloc(heap, table->n_cols * sizeof(dict_col_t)));
147 table->v_cols = static_cast<dict_v_col_t*>(
148 mem_heap_alloc(heap, n_v_cols * sizeof(*table->v_cols)));
149
150 /* true means that the stats latch will be enabled -
151 dict_table_stats_lock() will not be noop. */
152 dict_table_stats_latch_create(table, true);
153
154 #ifndef UNIV_HOTBACKUP
155 table->autoinc_lock = static_cast<ib_lock_t*>(
156 mem_heap_alloc(heap, lock_get_size()));
157
158 /* lazy creation of table autoinc latch */
159 dict_table_autoinc_create_lazy(table);
160
161 dict_table_analyze_index_create_lazy(table);
162
163 table->autoinc = 0;
164 table->sess_row_id = 0;
165 table->sess_trx_id = 0;
166
167 /* The number of transactions that are either waiting on the
168 AUTOINC lock or have been granted the lock. */
169 table->n_waiting_or_granted_auto_inc_locks = 0;
170
171 /* If the table has an FTS index or we are in the process
172 of building one, create the table->fts */
173 if (dict_table_has_fts_index(table)
174 || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
175 || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
176 table->fts = fts_create(table);
177 table->fts->cache = fts_cache_create(table);
178 } else {
179 table->fts = NULL;
180 }
181
182 table->is_corrupt = false;
183
184 table->file_unreadable = false;
185
186 #endif /* !UNIV_HOTBACKUP */
187
188 if (DICT_TF_HAS_SHARED_SPACE(table->flags)) {
189 dict_get_and_save_space_name(table, true);
190 }
191
192 new(&table->foreign_set) dict_foreign_set();
193 new(&table->referenced_set) dict_foreign_set();
194
195 return(table);
196 }
197
198 /****************************************************************//**
199 Free a table memory object. */
200 void
dict_mem_table_free(dict_table_t * table)201 dict_mem_table_free(
202 /*================*/
203 dict_table_t* table) /*!< in: table */
204 {
205 ut_ad(table);
206 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
207 ut_d(table->cached = FALSE);
208
209 if (dict_table_has_fts_index(table)
210 || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
211 || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
212 if (table->fts) {
213 fts_optimize_remove_table(table);
214
215 fts_free(table);
216 }
217 }
218 #ifndef UNIV_HOTBACKUP
219 dict_table_analyze_index_destroy(table);
220 dict_table_autoinc_destroy(table);
221 #endif /* UNIV_HOTBACKUP */
222
223 dict_mem_table_free_foreign_vcol_set(table);
224 dict_table_stats_latch_destroy(table);
225
226 table->foreign_set.~dict_foreign_set();
227 table->referenced_set.~dict_foreign_set();
228
229 ut_free(table->name.m_name);
230 table->name.m_name = NULL;
231
232 /* Clean up virtual index info structures that are registered
233 with virtual columns */
234 for (ulint i = 0; i < table->n_v_def; i++) {
235 dict_v_col_t* vcol
236 = dict_table_get_nth_v_col(table, i);
237
238 UT_DELETE(vcol->v_indexes);
239 }
240
241 if (table->s_cols != NULL) {
242 UT_DELETE(table->s_cols);
243 }
244
245 mem_heap_free(table->heap);
246 table = NULL;
247 }
248
249 /****************************************************************//**
250 Append 'name' to 'col_names'. @see dict_table_t::col_names
251 @return new column names array */
252 static
253 const char*
dict_add_col_name(const char * col_names,ulint cols,const char * name,mem_heap_t * heap)254 dict_add_col_name(
255 /*==============*/
256 const char* col_names, /*!< in: existing column names, or
257 NULL */
258 ulint cols, /*!< in: number of existing columns */
259 const char* name, /*!< in: new column name */
260 mem_heap_t* heap) /*!< in: heap */
261 {
262 ulint old_len;
263 ulint new_len;
264 ulint total_len;
265 char* res;
266
267 ut_ad(!cols == !col_names);
268
269 /* Find out length of existing array. */
270 if (col_names) {
271 const char* s = col_names;
272 ulint i;
273
274 for (i = 0; i < cols; i++) {
275 s += strlen(s) + 1;
276 }
277
278 old_len = s - col_names;
279 } else {
280 old_len = 0;
281 }
282
283 new_len = strlen(name) + 1;
284 total_len = old_len + new_len;
285
286 res = static_cast<char*>(mem_heap_alloc(heap, total_len));
287
288 if (old_len > 0) {
289 memcpy(res, col_names, old_len);
290 }
291
292 memcpy(res + old_len, name, new_len);
293
294 return(res);
295 }
296
297 /**********************************************************************//**
298 Adds a column definition to a table. */
299 void
dict_mem_table_add_col(dict_table_t * table,mem_heap_t * heap,const char * name,ulint mtype,ulint prtype,ulint len)300 dict_mem_table_add_col(
301 /*===================*/
302 dict_table_t* table, /*!< in: table */
303 mem_heap_t* heap, /*!< in: temporary memory heap, or NULL */
304 const char* name, /*!< in: column name, or NULL */
305 ulint mtype, /*!< in: main datatype */
306 ulint prtype, /*!< in: precise type */
307 ulint len) /*!< in: precision */
308 {
309 dict_col_t* col;
310 ulint i;
311
312 ut_ad(table);
313 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
314 ut_ad(!heap == !name);
315
316 ut_ad(!(prtype & DATA_VIRTUAL));
317
318 i = table->n_def++;
319
320 table->n_t_def++;
321
322 if (name) {
323 if (table->n_def == table->n_cols) {
324 heap = table->heap;
325 }
326 if (i && !table->col_names) {
327 /* All preceding column names are empty. */
328 char* s = static_cast<char*>(
329 mem_heap_zalloc(heap, table->n_def));
330
331 table->col_names = s;
332 }
333
334 table->col_names = dict_add_col_name(table->col_names,
335 i, name, heap);
336 }
337
338 col = dict_table_get_nth_col(table, i);
339
340 dict_mem_fill_column_struct(col, i, mtype, prtype, len);
341 }
342
343 /** Adds a virtual column definition to a table.
344 @param[in,out] table table
345 @param[in,out] heap temporary memory heap, or NULL. It is
346 used to store name when we have not finished
347 adding all columns. When all columns are
348 added, the whole name will copy to memory from
349 table->heap
350 @param[in] name column name
351 @param[in] mtype main datatype
352 @param[in] prtype precise type
353 @param[in] len length
354 @param[in] pos position in a table
355 @param[in] num_base number of base columns
356 @return the virtual column definition */
357 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)358 dict_mem_table_add_v_col(
359 dict_table_t* table,
360 mem_heap_t* heap,
361 const char* name,
362 ulint mtype,
363 ulint prtype,
364 ulint len,
365 ulint pos,
366 ulint num_base)
367 {
368 dict_v_col_t* v_col;
369 ulint i;
370
371 ut_ad(table);
372 ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
373 ut_ad(!heap == !name);
374
375 ut_ad(prtype & DATA_VIRTUAL);
376
377 i = table->n_v_def++;
378
379 table->n_t_def++;
380
381 if (name != NULL) {
382 if (table->n_v_def == table->n_v_cols) {
383 heap = table->heap;
384 }
385
386 if (i && !table->v_col_names) {
387 /* All preceding column names are empty. */
388 char* s = static_cast<char*>(
389 mem_heap_zalloc(heap, table->n_v_def));
390
391 table->v_col_names = s;
392 }
393
394 table->v_col_names = dict_add_col_name(table->v_col_names,
395 i, name, heap);
396 }
397
398 v_col = dict_table_get_nth_v_col(table, i);
399
400 dict_mem_fill_column_struct(&v_col->m_col, pos, mtype, prtype, len);
401 v_col->v_pos = i;
402
403 if (num_base != 0) {
404 v_col->base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
405 table->heap, num_base * sizeof(
406 *v_col->base_col)));
407 } else {
408 v_col->base_col = NULL;
409 }
410
411 v_col->num_base = num_base;
412
413 /* Initialize the index list for virtual columns */
414 v_col->v_indexes = UT_NEW_NOKEY(dict_v_idx_list());
415
416 return(v_col);
417 }
418
419 /** Adds a stored column definition to a table.
420 @param[in] table table
421 @param[in] num_base number of base columns. */
422 void
dict_mem_table_add_s_col(dict_table_t * table,ulint num_base)423 dict_mem_table_add_s_col(
424 dict_table_t* table,
425 ulint num_base)
426 {
427 ulint i = table->n_def - 1;
428 dict_col_t* col = dict_table_get_nth_col(table, i);
429 dict_s_col_t s_col;
430
431 ut_ad(col != NULL);
432
433 if (table->s_cols == NULL) {
434 table->s_cols = UT_NEW_NOKEY(dict_s_col_list());
435 }
436
437 s_col.m_col = col;
438 s_col.s_pos = i + table->n_v_def;
439
440 if (num_base != 0) {
441 s_col.base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
442 table->heap, num_base * sizeof(dict_col_t*)));
443 } else {
444 s_col.base_col = NULL;
445 }
446
447 s_col.num_base = num_base;
448 table->s_cols->push_back(s_col);
449 }
450
451
452 /**********************************************************************//**
453 Renames a column of a table in the data dictionary cache. */
454 static MY_ATTRIBUTE((nonnull))
455 void
dict_mem_table_col_rename_low(dict_table_t * table,unsigned i,const char * to,const char * s,bool is_virtual)456 dict_mem_table_col_rename_low(
457 /*==========================*/
458 dict_table_t* table, /*!< in/out: table */
459 unsigned i, /*!< in: column offset corresponding to s */
460 const char* to, /*!< in: new column name */
461 const char* s, /*!< in: pointer to table->col_names */
462 bool is_virtual)
463 /*!< in: if this is a virtual column */
464 {
465 char* t_col_names = const_cast<char*>(
466 is_virtual ? table->v_col_names : table->col_names);
467 ulint n_col = is_virtual ? table->n_v_def : table->n_def;
468
469 size_t from_len = strlen(s), to_len = strlen(to);
470
471 ut_ad(i < table->n_def || is_virtual);
472 ut_ad(i < table->n_v_def || !is_virtual);
473
474 ut_ad(from_len <= NAME_LEN);
475 ut_ad(to_len <= NAME_LEN);
476
477 if (from_len == to_len) {
478 /* The easy case: simply replace the column name in
479 table->col_names. */
480 strcpy(const_cast<char*>(s), to);
481 } else {
482 /* We need to adjust all affected index->field
483 pointers, as in dict_index_add_col(). First, copy
484 table->col_names. */
485 ulint prefix_len = s - t_col_names;
486
487 for (; i < n_col; i++) {
488 s += strlen(s) + 1;
489 }
490
491 ulint full_len = s - t_col_names;
492 char* col_names;
493
494 if (to_len > from_len) {
495 ulint table_size_before_rename_col
496 = mem_heap_get_size(table->heap);
497 col_names = static_cast<char*>(
498 mem_heap_alloc(
499 table->heap,
500 full_len + to_len - from_len));
501 ulint table_size_after_rename_col
502 = mem_heap_get_size(table->heap);
503 if (table_size_before_rename_col
504 != table_size_after_rename_col) {
505 dict_sys->size +=
506 table_size_after_rename_col
507 - table_size_before_rename_col;
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 (!dict_col_is_virtual(field->col))) {
534 continue;
535 }
536
537 ulint name_ofs
538 = 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 for (unsigned f = 0; f < foreign->n_fields; f++) {
571 /* These can point straight to
572 table->col_names, because the foreign key
573 constraints will be freed at the same time
574 when the table object is freed. */
575 foreign->foreign_col_names[f]
576 = dict_index_get_nth_field(
577 foreign->foreign_index, f)->name;
578 }
579 }
580
581 for (dict_foreign_set::iterator it = table->referenced_set.begin();
582 it != table->referenced_set.end();
583 ++it) {
584
585 foreign = *it;
586
587 for (unsigned f = 0; f < foreign->n_fields; f++) {
588 /* foreign->referenced_col_names[] need to be
589 copies, because the constraint may become
590 orphan when foreign_key_checks=0 and the
591 parent table is dropped. */
592
593 const char* col_name = dict_index_get_nth_field(
594 foreign->referenced_index, f)->name;
595
596 if (strcmp(foreign->referenced_col_names[f],
597 col_name)) {
598 char** rc = const_cast<char**>(
599 foreign->referenced_col_names + f);
600 size_t col_name_len_1 = strlen(col_name) + 1;
601
602 if (col_name_len_1 <= strlen(*rc) + 1) {
603 memcpy(*rc, col_name, col_name_len_1);
604 } else {
605 *rc = static_cast<char*>(
606 mem_heap_dup(
607 foreign->heap,
608 col_name,
609 col_name_len_1));
610 }
611 }
612 }
613 }
614 }
615
616 /**********************************************************************//**
617 Renames a column of a table in the data dictionary cache. */
618 void
dict_mem_table_col_rename(dict_table_t * table,ulint nth_col,const char * from,const char * to,bool is_virtual)619 dict_mem_table_col_rename(
620 /*======================*/
621 dict_table_t* table, /*!< in/out: table */
622 ulint nth_col,/*!< in: column index */
623 const char* from, /*!< in: old column name */
624 const char* to, /*!< in: new column name */
625 bool is_virtual)
626 /*!< in: if this is a virtual column */
627 {
628 const char* s = is_virtual ? table->v_col_names : table->col_names;
629
630 ut_ad((!is_virtual && nth_col < table->n_def)
631 || (is_virtual && nth_col < table->n_v_def));
632
633 for (ulint i = 0; i < nth_col; i++) {
634 size_t len = strlen(s);
635 ut_ad(len > 0);
636 s += len + 1;
637 }
638
639 /* This could fail if the data dictionaries are out of sync.
640 Proceed with the renaming anyway. */
641 ut_ad(!strcmp(from, s));
642
643
644 dict_mem_table_col_rename_low(table, static_cast<unsigned>(nth_col),
645 to, s, is_virtual);
646 }
647
648 /**********************************************************************//**
649 This function populates a dict_col_t memory structure with
650 supplied information. */
651 void
dict_mem_fill_column_struct(dict_col_t * column,ulint col_pos,ulint mtype,ulint prtype,ulint col_len)652 dict_mem_fill_column_struct(
653 /*========================*/
654 dict_col_t* column, /*!< out: column struct to be
655 filled */
656 ulint col_pos, /*!< in: column position */
657 ulint mtype, /*!< in: main data type */
658 ulint prtype, /*!< in: precise type */
659 ulint col_len) /*!< in: column length */
660 {
661 #ifndef UNIV_HOTBACKUP
662 ulint mbminlen;
663 ulint mbmaxlen;
664 #endif /* !UNIV_HOTBACKUP */
665
666 column->ind = (unsigned int) col_pos;
667 column->ord_part = 0;
668 column->max_prefix = 0;
669 column->mtype = (unsigned int) mtype;
670 column->prtype = (unsigned int) prtype;
671 column->len = (unsigned int) col_len;
672 #ifndef UNIV_HOTBACKUP
673 dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
674 dict_col_set_mbminmaxlen(column, mbminlen, mbmaxlen);
675 #endif /* !UNIV_HOTBACKUP */
676 }
677
678 /**********************************************************************//**
679 Creates an index memory object.
680 @return own: index object */
681 dict_index_t*
dict_mem_index_create(const char * table_name,const char * index_name,ulint space,ulint type,ulint n_fields)682 dict_mem_index_create(
683 /*==================*/
684 const char* table_name, /*!< in: table name */
685 const char* index_name, /*!< in: index name */
686 ulint space, /*!< in: space where the index tree is
687 placed, ignored if the index is of
688 the clustered type */
689 ulint type, /*!< in: DICT_UNIQUE,
690 DICT_CLUSTERED, ... ORed */
691 ulint n_fields) /*!< in: number of fields */
692 {
693 dict_index_t* index;
694 mem_heap_t* heap;
695
696 ut_ad(table_name && index_name);
697
698 heap = mem_heap_create(DICT_HEAP_SIZE);
699
700 index = static_cast<dict_index_t*>(
701 mem_heap_zalloc(heap, sizeof(*index)));
702
703 dict_mem_fill_index_struct(index, heap, table_name, index_name,
704 space, type, n_fields);
705
706 dict_index_zip_pad_mutex_create_lazy(index);
707
708 if (type & DICT_SPATIAL) {
709 mutex_create(LATCH_ID_RTR_SSN_MUTEX, &index->rtr_ssn.mutex);
710 index->rtr_track = static_cast<rtr_info_track_t*>(
711 mem_heap_alloc(
712 heap,
713 sizeof(*index->rtr_track)));
714 mutex_create(LATCH_ID_RTR_ACTIVE_MUTEX,
715 &index->rtr_track->rtr_active_mutex);
716 index->rtr_track->rtr_active = UT_NEW_NOKEY(rtr_info_active());
717 }
718
719 return(index);
720 }
721
722 #ifndef UNIV_HOTBACKUP
723 /**********************************************************************//**
724 Creates and initializes a foreign constraint memory object.
725 @return own: foreign constraint struct */
726 dict_foreign_t*
dict_mem_foreign_create(void)727 dict_mem_foreign_create(void)
728 /*=========================*/
729 {
730 dict_foreign_t* foreign;
731 mem_heap_t* heap;
732 DBUG_ENTER("dict_mem_foreign_create");
733
734 heap = mem_heap_create(100);
735
736 foreign = static_cast<dict_foreign_t*>(
737 mem_heap_zalloc(heap, sizeof(dict_foreign_t)));
738
739 foreign->heap = heap;
740
741 foreign->v_cols = NULL;
742
743 DBUG_PRINT("dict_mem_foreign_create", ("heap: %p", heap));
744
745 DBUG_RETURN(foreign);
746 }
747
748 /**********************************************************************//**
749 Sets the foreign_table_name_lookup pointer based on the value of
750 lower_case_table_names. If that is 0 or 1, foreign_table_name_lookup
751 will point to foreign_table_name. If 2, then another string is
752 allocated from foreign->heap and set to lower case. */
753 void
dict_mem_foreign_table_name_lookup_set(dict_foreign_t * foreign,ibool do_alloc)754 dict_mem_foreign_table_name_lookup_set(
755 /*===================================*/
756 dict_foreign_t* foreign, /*!< in/out: foreign struct */
757 ibool do_alloc) /*!< in: is an alloc needed */
758 {
759 if (innobase_get_lower_case_table_names() == 2) {
760 if (do_alloc) {
761 ulint len;
762
763 len = strlen(foreign->foreign_table_name) + 1;
764
765 foreign->foreign_table_name_lookup =
766 static_cast<char*>(
767 mem_heap_alloc(foreign->heap, len));
768 }
769 strcpy(foreign->foreign_table_name_lookup,
770 foreign->foreign_table_name);
771 innobase_casedn_str(foreign->foreign_table_name_lookup);
772 } else {
773 foreign->foreign_table_name_lookup
774 = foreign->foreign_table_name;
775 }
776 }
777
778 /**********************************************************************//**
779 Sets the referenced_table_name_lookup pointer based on the value of
780 lower_case_table_names. If that is 0 or 1, referenced_table_name_lookup
781 will point to referenced_table_name. If 2, then another string is
782 allocated from foreign->heap and set to lower case. */
783 void
dict_mem_referenced_table_name_lookup_set(dict_foreign_t * foreign,ibool do_alloc)784 dict_mem_referenced_table_name_lookup_set(
785 /*======================================*/
786 dict_foreign_t* foreign, /*!< in/out: foreign struct */
787 ibool do_alloc) /*!< in: is an alloc needed */
788 {
789 if (innobase_get_lower_case_table_names() == 2) {
790 if (do_alloc) {
791 ulint len;
792
793 len = strlen(foreign->referenced_table_name) + 1;
794
795 foreign->referenced_table_name_lookup =
796 static_cast<char*>(
797 mem_heap_alloc(foreign->heap, len));
798 }
799 strcpy(foreign->referenced_table_name_lookup,
800 foreign->referenced_table_name);
801 innobase_casedn_str(foreign->referenced_table_name_lookup);
802 } else {
803 foreign->referenced_table_name_lookup
804 = foreign->referenced_table_name;
805 }
806 }
807
808 /** Fill the virtual column set with virtual column information
809 present in the given virtual index.
810 @param[in] index virtual index
811 @param[out] v_cols virtual column set. */
812 static
813 void
dict_mem_fill_vcol_has_index(const dict_index_t * index,dict_vcol_set ** v_cols)814 dict_mem_fill_vcol_has_index(
815 const dict_index_t* index,
816 dict_vcol_set** v_cols)
817 {
818 for (ulint i = 0; i < index->table->n_v_cols; i++) {
819 dict_v_col_t* v_col = dict_table_get_nth_v_col(
820 index->table, i);
821 if (!v_col->m_col.ord_part) {
822 continue;
823 }
824
825 dict_v_idx_list::iterator it;
826 for (it = v_col->v_indexes->begin();
827 it != v_col->v_indexes->end(); ++it) {
828 dict_v_idx_t v_idx = *it;
829
830 if (v_idx.index != index) {
831 continue;
832 }
833
834 if (*v_cols == NULL) {
835 *v_cols = UT_NEW_NOKEY(dict_vcol_set());
836 }
837
838 (*v_cols)->insert(v_col);
839 }
840 }
841 }
842
843 /** Fill the virtual column set with the virtual column of the index
844 if the index contains given column name.
845 @param[in] col_name column name
846 @param[in] table innodb table object
847 @param[out] v_cols set of virtual column information. */
848 static
849 void
dict_mem_fill_vcol_from_v_indexes(const char * col_name,const dict_table_t * table,dict_vcol_set ** v_cols)850 dict_mem_fill_vcol_from_v_indexes(
851 const char* col_name,
852 const dict_table_t* table,
853 dict_vcol_set** v_cols)
854 {
855 /* virtual column can't be Primary Key, so start with
856 secondary index */
857 for (dict_index_t* index = dict_table_get_next_index(
858 dict_table_get_first_index(table));
859 index;
860 index = dict_table_get_next_index(index)) {
861
862 /* Skip if the index have newly added
863 virtual column because field name is NULL.
864 Later virtual column set will be
865 refreshed during loading of table. */
866 if (!dict_index_has_virtual(index)
867 || index->has_new_v_col) {
868 continue;
869 }
870
871 for (ulint i = 0; i < index->n_fields; i++) {
872 dict_field_t* field =
873 dict_index_get_nth_field(index, i);
874
875 if (strcmp(field->name, col_name) == 0) {
876 dict_mem_fill_vcol_has_index(
877 index, v_cols);
878 }
879 }
880 }
881 }
882
883 /** Fill the virtual column set with virtual columns which have base columns
884 as the given col_name
885 @param[in] col_name column name
886 @param[in] table table object
887 @param[out] v_cols set of virtual columns. */
888 static
889 void
dict_mem_fill_vcol_set_for_base_col(const char * col_name,const dict_table_t * table,dict_vcol_set ** v_cols)890 dict_mem_fill_vcol_set_for_base_col(
891 const char* col_name,
892 const dict_table_t* table,
893 dict_vcol_set** v_cols)
894 {
895 for (ulint i = 0; i < table->n_v_cols; i++) {
896 dict_v_col_t* v_col = dict_table_get_nth_v_col(table, i);
897
898 if (!v_col->m_col.ord_part) {
899 continue;
900 }
901
902 for (ulint j = 0; j < v_col->num_base; j++) {
903 if (strcmp(col_name, dict_table_get_col_name(
904 table,
905 v_col->base_col[j]->ind)) == 0) {
906
907 if (*v_cols == NULL) {
908 *v_cols = UT_NEW_NOKEY(dict_vcol_set());
909 }
910
911 (*v_cols)->insert(v_col);
912 }
913 }
914 }
915 }
916
917 /** Fills the dependent virtual columns in a set.
918 Reason for being dependent are
919 1) FK can be present on base column of virtual columns
920 2) FK can be present on column which is a part of virtual index
921 @param[in,out] foreign foreign key information. */
922 void
dict_mem_foreign_fill_vcol_set(dict_foreign_t * foreign)923 dict_mem_foreign_fill_vcol_set(
924 dict_foreign_t* foreign)
925 {
926 ulint type = foreign->type;
927
928 if (type == 0) {
929 return;
930 }
931
932 for (ulint i = 0; i < foreign->n_fields; i++) {
933 /** FK can be present on base columns
934 of virtual columns. */
935 dict_mem_fill_vcol_set_for_base_col(
936 foreign->foreign_col_names[i],
937 foreign->foreign_table,
938 &foreign->v_cols);
939
940 /** FK can be present on the columns
941 which can be a part of virtual index. */
942 dict_mem_fill_vcol_from_v_indexes(
943 foreign->foreign_col_names[i],
944 foreign->foreign_table,
945 &foreign->v_cols);
946 }
947 }
948
949 /** Fill virtual columns set in each fk constraint present in the table.
950 @param[in,out] table innodb table object. */
951 void
dict_mem_table_fill_foreign_vcol_set(dict_table_t * table)952 dict_mem_table_fill_foreign_vcol_set(
953 dict_table_t* table)
954 {
955 dict_foreign_set fk_set = table->foreign_set;
956 dict_foreign_t* foreign;
957
958 dict_foreign_set::iterator it;
959 for (it = fk_set.begin(); it != fk_set.end(); ++it) {
960 foreign = *it;
961
962 dict_mem_foreign_fill_vcol_set(foreign);
963 }
964 }
965
966 /** Free the vcol_set from all foreign key constraint on the table.
967 @param[in,out] table innodb table object. */
968 void
dict_mem_table_free_foreign_vcol_set(dict_table_t * table)969 dict_mem_table_free_foreign_vcol_set(
970 dict_table_t* table)
971 {
972 dict_foreign_set fk_set = table->foreign_set;
973 dict_foreign_t* foreign;
974
975 dict_foreign_set::iterator it;
976 for (it = fk_set.begin(); it != fk_set.end(); ++it) {
977
978 foreign = *it;
979
980 if (foreign->v_cols != NULL) {
981 UT_DELETE(foreign->v_cols);
982 foreign->v_cols = NULL;
983 }
984 }
985 }
986
987 #endif /* !UNIV_HOTBACKUP */
988
989 /**********************************************************************//**
990 Adds a field definition to an index. NOTE: does not take a copy
991 of the column name if the field is a column. The memory occupied
992 by the column name may be released only after publishing the index. */
993 void
dict_mem_index_add_field(dict_index_t * index,const char * name,ulint prefix_len)994 dict_mem_index_add_field(
995 /*=====================*/
996 dict_index_t* index, /*!< in: index */
997 const char* name, /*!< in: column name */
998 ulint prefix_len) /*!< in: 0 or the column prefix length
999 in a MySQL index like
1000 INDEX (textcol(25)) */
1001 {
1002 dict_field_t* field;
1003
1004 ut_ad(index);
1005 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1006
1007 index->n_def++;
1008
1009 field = dict_index_get_nth_field(index, index->n_def - 1);
1010
1011 field->name = name;
1012 field->prefix_len = (unsigned int) prefix_len;
1013 }
1014
1015 /**********************************************************************//**
1016 Frees an index memory object. */
1017 void
dict_mem_index_free(dict_index_t * index)1018 dict_mem_index_free(
1019 /*================*/
1020 dict_index_t* index) /*!< in: index */
1021 {
1022 ut_ad(index);
1023 ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1024
1025 dict_index_zip_pad_mutex_destroy(index);
1026
1027 if (dict_index_is_spatial(index)) {
1028 rtr_info_active::iterator it;
1029 rtr_info_t* rtr_info;
1030
1031 for (it = index->rtr_track->rtr_active->begin();
1032 it != index->rtr_track->rtr_active->end(); ++it) {
1033 rtr_info = *it;
1034
1035 rtr_info->index = NULL;
1036 }
1037
1038 mutex_destroy(&index->rtr_ssn.mutex);
1039 mutex_destroy(&index->rtr_track->rtr_active_mutex);
1040 UT_DELETE(index->rtr_track->rtr_active);
1041 }
1042
1043 dict_index_remove_from_v_col_list(index);
1044 mem_heap_free(index->heap);
1045 }
1046
1047 /** Create a temporary tablename like "#sql-ibtid-inc where
1048 tid = the Table ID
1049 inc = a randomly initialized number that is incremented for each file
1050 The table ID is a 64 bit integer, can use up to 20 digits, and is
1051 initialized at bootstrap. The second number is 32 bits, can use up to 10
1052 digits, and is initialized at startup to a randomly distributed number.
1053 It is hoped that the combination of these two numbers will provide a
1054 reasonably unique temporary file name.
1055 @param[in] heap A memory heap
1056 @param[in] dbtab Table name in the form database/table name
1057 @param[in] id Table id
1058 @return A unique temporary tablename suitable for InnoDB use */
1059 char*
dict_mem_create_temporary_tablename(mem_heap_t * heap,const char * dbtab,table_id_t id)1060 dict_mem_create_temporary_tablename(
1061 mem_heap_t* heap,
1062 const char* dbtab,
1063 table_id_t id)
1064 {
1065 size_t size;
1066 char* name;
1067 const char* dbend = strchr(dbtab, '/');
1068 ut_ad(dbend);
1069 size_t dblen = dbend - dbtab + 1;
1070
1071 /* Increment a randomly initialized number for each temp file. */
1072 os_atomic_increment_uint32(&dict_temp_file_num, 1);
1073
1074 size = dblen + (sizeof(TEMP_FILE_PREFIX) + 3 + 20 + 1 + 10);
1075 name = static_cast<char*>(mem_heap_alloc(heap, size));
1076 memcpy(name, dbtab, dblen);
1077 ut_snprintf(name + dblen, size - dblen,
1078 TEMP_FILE_PREFIX_INNODB UINT64PF "-" UINT32PF,
1079 id, dict_temp_file_num);
1080
1081 return(name);
1082 }
1083
1084 /** Initialize dict memory variables */
1085 void
dict_mem_init(void)1086 dict_mem_init(void)
1087 {
1088 /* Initialize a randomly distributed temporary file number */
1089 ib_uint32_t now = static_cast<ib_uint32_t>(ut_time());
1090
1091 const byte* buf = reinterpret_cast<const byte*>(&now);
1092
1093 dict_temp_file_num = ut_crc32(buf, sizeof(now));
1094
1095 DBUG_PRINT("dict_mem_init",
1096 ("Starting Temporary file number is " UINT32PF,
1097 dict_temp_file_num));
1098 }
1099
1100 /** Validate the search order in the foreign key set.
1101 @param[in] fk_set the foreign key set to be validated
1102 @return true if search order is fine in the set, false otherwise. */
1103 bool
dict_foreign_set_validate(const dict_foreign_set & fk_set)1104 dict_foreign_set_validate(
1105 const dict_foreign_set& fk_set)
1106 {
1107 dict_foreign_not_exists not_exists(fk_set);
1108
1109 dict_foreign_set::iterator it = std::find_if(
1110 fk_set.begin(), fk_set.end(), not_exists);
1111
1112 if (it == fk_set.end()) {
1113 return(true);
1114 }
1115
1116 dict_foreign_t* foreign = *it;
1117 std::cerr << "Foreign key lookup failed: " << *foreign;
1118 std::cerr << fk_set;
1119 ut_ad(0);
1120 return(false);
1121 }
1122
1123 /** Validate the search order in the foreign key sets of the table
1124 (foreign_set and referenced_set).
1125 @param[in] table table whose foreign key sets are to be validated
1126 @return true if foreign key sets are fine, false otherwise. */
1127 bool
dict_foreign_set_validate(const dict_table_t & table)1128 dict_foreign_set_validate(
1129 const dict_table_t& table)
1130 {
1131 return(dict_foreign_set_validate(table.foreign_set)
1132 && dict_foreign_set_validate(table.referenced_set));
1133 }
1134
1135 std::ostream&
operator <<(std::ostream & out,const dict_foreign_t & foreign)1136 operator<< (std::ostream& out, const dict_foreign_t& foreign)
1137 {
1138 out << "[dict_foreign_t: id='" << foreign.id << "'";
1139
1140 if (foreign.foreign_table_name != NULL) {
1141 out << ",for: '" << foreign.foreign_table_name << "'";
1142 }
1143
1144 out << "]";
1145 return(out);
1146 }
1147
1148 std::ostream&
operator <<(std::ostream & out,const dict_foreign_set & fk_set)1149 operator<< (std::ostream& out, const dict_foreign_set& fk_set)
1150 {
1151 out << "[dict_foreign_set:";
1152 std::for_each(fk_set.begin(), fk_set.end(), dict_foreign_print(out));
1153 out << "]" << std::endl;
1154 return(out);
1155 }
1156
1157