1/*****************************************************************************
2
3Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, 2018, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/**************************************************//**
21@file dict/dict0crea.cc
22Database object creation
23
24Created 1/8/1996 Heikki Tuuri
25*******************************************************/
26
27#include "ha_prototypes.h"
28
29#include "dict0crea.h"
30#include "btr0pcur.h"
31#include "btr0btr.h"
32#include "page0page.h"
33#include "mach0data.h"
34#include "dict0boot.h"
35#include "dict0dict.h"
36#include "que0que.h"
37#include "row0ins.h"
38#include "row0mysql.h"
39#include "pars0pars.h"
40#include "trx0roll.h"
41#include "ut0vec.h"
42#include "dict0priv.h"
43#include "fts0priv.h"
44#include "fsp0space.h"
45#include "fsp0sysspace.h"
46#include "srv0start.h"
47
48/*****************************************************************//**
49Based on a table object, this function builds the entry to be inserted
50in the SYS_TABLES system table.
51@return the tuple which should be inserted */
52static
53dtuple_t*
54dict_create_sys_tables_tuple(
55/*=========================*/
56 const dict_table_t* table, /*!< in: table */
57 mem_heap_t* heap) /*!< in: memory heap from
58 which the memory for the built
59 tuple is allocated */
60{
61 dict_table_t* sys_tables;
62 dtuple_t* entry;
63 dfield_t* dfield;
64 byte* ptr;
65 ulint type;
66
67 ut_ad(table);
68 ut_ad(!table->space || table->space->id == table->space_id);
69 ut_ad(heap);
70 ut_ad(table->n_cols >= DATA_N_SYS_COLS);
71
72 sys_tables = dict_sys->sys_tables;
73
74 entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS);
75
76 dict_table_copy_types(entry, sys_tables);
77
78 /* 0: NAME -----------------------------*/
79 dfield = dtuple_get_nth_field(
80 entry, DICT_COL__SYS_TABLES__NAME);
81
82 dfield_set_data(dfield,
83 table->name.m_name, strlen(table->name.m_name));
84
85 /* 1: DB_TRX_ID added later */
86 /* 2: DB_ROLL_PTR added later */
87 /* 3: ID -------------------------------*/
88 dfield = dtuple_get_nth_field(
89 entry, DICT_COL__SYS_TABLES__ID);
90
91 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
92 mach_write_to_8(ptr, table->id);
93
94 dfield_set_data(dfield, ptr, 8);
95
96 /* 4: N_COLS ---------------------------*/
97 dfield = dtuple_get_nth_field(
98 entry, DICT_COL__SYS_TABLES__N_COLS);
99
100 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
101
102 /* If there is any virtual column, encode it in N_COLS */
103 mach_write_to_4(ptr, dict_table_encode_n_col(
104 ulint(table->n_cols - DATA_N_SYS_COLS),
105 ulint(table->n_v_def))
106 | (ulint(table->flags & DICT_TF_COMPACT) << 31));
107 dfield_set_data(dfield, ptr, 4);
108
109 /* 5: TYPE (table flags) -----------------------------*/
110 dfield = dtuple_get_nth_field(
111 entry, DICT_COL__SYS_TABLES__TYPE);
112
113 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
114
115 /* Validate the table flags and convert them to what is saved in
116 SYS_TABLES.TYPE. Table flag values 0 and 1 are both written to
117 SYS_TABLES.TYPE as 1. */
118 type = dict_tf_to_sys_tables_type(table->flags);
119 mach_write_to_4(ptr, type);
120
121 dfield_set_data(dfield, ptr, 4);
122
123 /* 6: MIX_ID (obsolete) ---------------------------*/
124 dfield = dtuple_get_nth_field(
125 entry, DICT_COL__SYS_TABLES__MIX_ID);
126
127 ptr = static_cast<byte*>(mem_heap_zalloc(heap, 8));
128
129 dfield_set_data(dfield, ptr, 8);
130
131 /* 7: MIX_LEN (additional flags) --------------------------*/
132 dfield = dtuple_get_nth_field(
133 entry, DICT_COL__SYS_TABLES__MIX_LEN);
134
135 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
136 /* Be sure all non-used bits are zero. */
137 ut_a(!(table->flags2 & DICT_TF2_UNUSED_BIT_MASK));
138 mach_write_to_4(ptr, table->flags2);
139
140 dfield_set_data(dfield, ptr, 4);
141
142 /* 8: CLUSTER_NAME ---------------------*/
143 dfield = dtuple_get_nth_field(
144 entry, DICT_COL__SYS_TABLES__CLUSTER_ID);
145 dfield_set_null(dfield); /* not supported */
146
147 /* 9: SPACE ----------------------------*/
148 dfield = dtuple_get_nth_field(
149 entry, DICT_COL__SYS_TABLES__SPACE);
150
151 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
152 mach_write_to_4(ptr, table->space_id);
153
154 dfield_set_data(dfield, ptr, 4);
155 /*----------------------------------*/
156
157 return(entry);
158}
159
160/*****************************************************************//**
161Based on a table object, this function builds the entry to be inserted
162in the SYS_COLUMNS system table.
163@return the tuple which should be inserted */
164static
165dtuple_t*
166dict_create_sys_columns_tuple(
167/*==========================*/
168 const dict_table_t* table, /*!< in: table */
169 ulint i, /*!< in: column number */
170 mem_heap_t* heap) /*!< in: memory heap from
171 which the memory for the built
172 tuple is allocated */
173{
174 dict_table_t* sys_columns;
175 dtuple_t* entry;
176 const dict_col_t* column;
177 dfield_t* dfield;
178 byte* ptr;
179 const char* col_name;
180 ulint num_base = 0;
181 ulint v_col_no = ULINT_UNDEFINED;
182
183 ut_ad(table);
184 ut_ad(heap);
185
186 /* Any column beyond table->n_def would be virtual columns */
187 if (i >= table->n_def) {
188 dict_v_col_t* v_col = dict_table_get_nth_v_col(
189 table, i - table->n_def);
190 column = &v_col->m_col;
191 num_base = v_col->num_base;
192 v_col_no = column->ind;
193 } else {
194 column = dict_table_get_nth_col(table, i);
195 ut_ad(!column->is_virtual());
196 }
197
198 sys_columns = dict_sys->sys_columns;
199
200 entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
201
202 dict_table_copy_types(entry, sys_columns);
203
204 /* 0: TABLE_ID -----------------------*/
205 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__TABLE_ID);
206
207 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
208 mach_write_to_8(ptr, table->id);
209
210 dfield_set_data(dfield, ptr, 8);
211
212 /* 1: POS ----------------------------*/
213 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__POS);
214
215 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
216
217 if (v_col_no != ULINT_UNDEFINED) {
218 /* encode virtual column's position in MySQL table and InnoDB
219 table in "POS" */
220 mach_write_to_4(ptr, dict_create_v_col_pos(
221 i - table->n_def, v_col_no));
222 } else {
223 mach_write_to_4(ptr, i);
224 }
225
226 dfield_set_data(dfield, ptr, 4);
227
228 /* 2: DB_TRX_ID added later */
229 /* 3: DB_ROLL_PTR added later */
230 /* 4: NAME ---------------------------*/
231 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__NAME);
232
233 if (i >= table->n_def) {
234 col_name = dict_table_get_v_col_name(table, i - table->n_def);
235 } else {
236 col_name = dict_table_get_col_name(table, i);
237 }
238
239 dfield_set_data(dfield, col_name, ut_strlen(col_name));
240
241 /* 5: MTYPE --------------------------*/
242 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__MTYPE);
243
244 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
245 mach_write_to_4(ptr, column->mtype);
246
247 dfield_set_data(dfield, ptr, 4);
248
249 /* 6: PRTYPE -------------------------*/
250 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__PRTYPE);
251
252 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
253 mach_write_to_4(ptr, column->prtype);
254
255 dfield_set_data(dfield, ptr, 4);
256
257 /* 7: LEN ----------------------------*/
258 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__LEN);
259
260 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
261 mach_write_to_4(ptr, column->len);
262
263 dfield_set_data(dfield, ptr, 4);
264
265 /* 8: PREC ---------------------------*/
266 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__PREC);
267
268 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
269 mach_write_to_4(ptr, num_base);
270
271 dfield_set_data(dfield, ptr, 4);
272 /*---------------------------------*/
273
274 return(entry);
275}
276
277/** Based on a table object, this function builds the entry to be inserted
278in the SYS_VIRTUAL system table. Each row maps a virtual column to one of
279its base column.
280@param[in] table table
281@param[in] v_col_n virtual column number
282@param[in] b_col_n base column sequence num
283@param[in] heap memory heap
284@return the tuple which should be inserted */
285static
286dtuple_t*
287dict_create_sys_virtual_tuple(
288 const dict_table_t* table,
289 ulint v_col_n,
290 ulint b_col_n,
291 mem_heap_t* heap)
292{
293 dict_table_t* sys_virtual;
294 dtuple_t* entry;
295 const dict_col_t* base_column;
296 dfield_t* dfield;
297 byte* ptr;
298
299 ut_ad(table);
300 ut_ad(heap);
301
302 ut_ad(v_col_n < table->n_v_def);
303 dict_v_col_t* v_col = dict_table_get_nth_v_col(table, v_col_n);
304 base_column = v_col->base_col[b_col_n];
305
306 sys_virtual = dict_sys->sys_virtual;
307
308 entry = dtuple_create(heap, DICT_NUM_COLS__SYS_VIRTUAL
309 + DATA_N_SYS_COLS);
310
311 dict_table_copy_types(entry, sys_virtual);
312
313 /* 0: TABLE_ID -----------------------*/
314 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_VIRTUAL__TABLE_ID);
315
316 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
317 mach_write_to_8(ptr, table->id);
318
319 dfield_set_data(dfield, ptr, 8);
320
321 /* 1: POS ---------------------------*/
322 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_VIRTUAL__POS);
323
324 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
325 ulint v_col_no = dict_create_v_col_pos(v_col_n, v_col->m_col.ind);
326 mach_write_to_4(ptr, v_col_no);
327
328 dfield_set_data(dfield, ptr, 4);
329
330 /* 2: BASE_POS ----------------------------*/
331 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_VIRTUAL__BASE_POS);
332
333 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
334 mach_write_to_4(ptr, base_column->ind);
335
336 dfield_set_data(dfield, ptr, 4);
337
338 /* 3: DB_TRX_ID added later */
339 /* 4: DB_ROLL_PTR added later */
340
341 /*---------------------------------*/
342 return(entry);
343}
344
345/***************************************************************//**
346Builds a table definition to insert.
347@return DB_SUCCESS or error code */
348static MY_ATTRIBUTE((nonnull, warn_unused_result))
349dberr_t
350dict_build_table_def_step(
351/*======================*/
352 que_thr_t* thr, /*!< in: query thread */
353 tab_node_t* node) /*!< in: table create node */
354{
355 ut_ad(mutex_own(&dict_sys->mutex));
356 dict_table_t* table = node->table;
357 ut_ad(!table->is_temporary());
358 ut_ad(!table->space);
359 ut_ad(table->space_id == ULINT_UNDEFINED);
360 dict_table_assign_new_id(table, thr_get_trx(thr));
361
362 /* Always set this bit for all new created tables */
363 DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME);
364 DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
365 DICT_TF2_FLAG_UNSET(table,
366 DICT_TF2_FTS_AUX_HEX_NAME););
367
368 if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_USE_FILE_PER_TABLE)) {
369 /* This table will need a new tablespace. */
370
371 ut_ad(DICT_TF_GET_ZIP_SSIZE(table->flags) == 0
372 || dict_table_has_atomic_blobs(table));
373
374 /* Get a new tablespace ID */
375 ulint space_id;
376 dict_hdr_get_new_id(NULL, NULL, &space_id, table, false);
377
378 DBUG_EXECUTE_IF(
379 "ib_create_table_fail_out_of_space_ids",
380 space_id = ULINT_UNDEFINED;
381 );
382
383 if (space_id == ULINT_UNDEFINED) {
384 return(DB_ERROR);
385 }
386
387 /* Determine the tablespace flags. */
388 bool has_data_dir = DICT_TF_HAS_DATA_DIR(table->flags);
389 ulint fsp_flags = dict_tf_to_fsp_flags(table->flags);
390 ut_ad(!has_data_dir || table->data_dir_path);
391 char* filepath = has_data_dir
392 ? fil_make_filepath(table->data_dir_path,
393 table->name.m_name, IBD, true)
394 : fil_make_filepath(NULL,
395 table->name.m_name, IBD, false);
396
397 /* We create a new single-table tablespace for the table.
398 We initially let it be 4 pages:
399 - page 0 is the fsp header and an extent descriptor page,
400 - page 1 is an ibuf bitmap page,
401 - page 2 is the first inode page,
402 - page 3 will contain the root of the clustered index of
403 the table we create here. */
404
405 dberr_t err;
406 table->space = fil_ibd_create(
407 space_id, table->name.m_name, filepath, fsp_flags,
408 FIL_IBD_FILE_INITIAL_SIZE,
409 node->mode, node->key_id, &err);
410
411 ut_free(filepath);
412
413 if (!table->space) {
414 ut_ad(err != DB_SUCCESS);
415 return err;
416 }
417
418 table->space_id = space_id;
419 mtr_t mtr;
420 mtr.start();
421 mtr.set_named_space(table->space);
422 fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
423 mtr.commit();
424 } else {
425 ut_ad(dict_tf_get_rec_format(table->flags)
426 != REC_FORMAT_COMPRESSED);
427 table->space = fil_system.sys_space;
428 table->space_id = TRX_SYS_SPACE;
429 DBUG_EXECUTE_IF("ib_ddl_crash_during_tablespace_alloc",
430 DBUG_SUICIDE(););
431 }
432
433 ins_node_set_new_row(node->tab_def,
434 dict_create_sys_tables_tuple(table, node->heap));
435 return DB_SUCCESS;
436}
437
438/** Builds a SYS_VIRTUAL row definition to insert.
439@param[in] node table create node */
440static
441void
442dict_build_v_col_def_step(
443 tab_node_t* node)
444{
445 dtuple_t* row;
446
447 row = dict_create_sys_virtual_tuple(node->table, node->col_no,
448 node->base_col_no,
449 node->heap);
450 ins_node_set_new_row(node->v_col_def, row);
451}
452
453/*****************************************************************//**
454Based on an index object, this function builds the entry to be inserted
455in the SYS_INDEXES system table.
456@return the tuple which should be inserted */
457static
458dtuple_t*
459dict_create_sys_indexes_tuple(
460/*==========================*/
461 const dict_index_t* index, /*!< in: index */
462 mem_heap_t* heap) /*!< in: memory heap from
463 which the memory for the built
464 tuple is allocated */
465{
466 dict_table_t* sys_indexes;
467 dtuple_t* entry;
468 dfield_t* dfield;
469 byte* ptr;
470
471 ut_ad(mutex_own(&dict_sys->mutex));
472 ut_ad(index);
473 ut_ad(index->table->space || index->table->file_unreadable);
474 ut_ad(!index->table->space
475 || index->table->space->id == index->table->space_id);
476 ut_ad(heap);
477
478 sys_indexes = dict_sys->sys_indexes;
479
480 entry = dtuple_create(
481 heap, DICT_NUM_COLS__SYS_INDEXES + DATA_N_SYS_COLS);
482
483 dict_table_copy_types(entry, sys_indexes);
484
485 /* 0: TABLE_ID -----------------------*/
486 dfield = dtuple_get_nth_field(
487 entry, DICT_COL__SYS_INDEXES__TABLE_ID);
488
489 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
490 mach_write_to_8(ptr, index->table->id);
491
492 dfield_set_data(dfield, ptr, 8);
493
494 /* 1: ID ----------------------------*/
495 dfield = dtuple_get_nth_field(
496 entry, DICT_COL__SYS_INDEXES__ID);
497
498 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
499 mach_write_to_8(ptr, index->id);
500
501 dfield_set_data(dfield, ptr, 8);
502
503 /* 2: DB_TRX_ID added later */
504 /* 3: DB_ROLL_PTR added later */
505 /* 4: NAME --------------------------*/
506 dfield = dtuple_get_nth_field(
507 entry, DICT_COL__SYS_INDEXES__NAME);
508
509 if (!index->is_committed()) {
510 ulint len = strlen(index->name) + 1;
511 char* name = static_cast<char*>(
512 mem_heap_alloc(heap, len));
513 *name = *TEMP_INDEX_PREFIX_STR;
514 memcpy(name + 1, index->name, len - 1);
515 dfield_set_data(dfield, name, len);
516 } else {
517 dfield_set_data(dfield, index->name, strlen(index->name));
518 }
519
520 /* 5: N_FIELDS ----------------------*/
521 dfield = dtuple_get_nth_field(
522 entry, DICT_COL__SYS_INDEXES__N_FIELDS);
523
524 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
525 mach_write_to_4(ptr, index->n_fields);
526
527 dfield_set_data(dfield, ptr, 4);
528
529 /* 6: TYPE --------------------------*/
530 dfield = dtuple_get_nth_field(
531 entry, DICT_COL__SYS_INDEXES__TYPE);
532
533 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
534 mach_write_to_4(ptr, index->type);
535
536 dfield_set_data(dfield, ptr, 4);
537
538 /* 7: SPACE --------------------------*/
539
540 dfield = dtuple_get_nth_field(
541 entry, DICT_COL__SYS_INDEXES__SPACE);
542
543 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
544 mach_write_to_4(ptr, index->table->space_id);
545
546 dfield_set_data(dfield, ptr, 4);
547
548 /* 8: PAGE_NO --------------------------*/
549
550 dfield = dtuple_get_nth_field(
551 entry, DICT_COL__SYS_INDEXES__PAGE_NO);
552
553 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
554 mach_write_to_4(ptr, FIL_NULL);
555
556 dfield_set_data(dfield, ptr, 4);
557
558 /* 9: MERGE_THRESHOLD ----------------*/
559
560 dfield = dtuple_get_nth_field(
561 entry, DICT_COL__SYS_INDEXES__MERGE_THRESHOLD);
562
563 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
564 mach_write_to_4(ptr, DICT_INDEX_MERGE_THRESHOLD_DEFAULT);
565
566 dfield_set_data(dfield, ptr, 4);
567
568 /*--------------------------------*/
569
570 return(entry);
571}
572
573/*****************************************************************//**
574Based on an index object, this function builds the entry to be inserted
575in the SYS_FIELDS system table.
576@return the tuple which should be inserted */
577static
578dtuple_t*
579dict_create_sys_fields_tuple(
580/*=========================*/
581 const dict_index_t* index, /*!< in: index */
582 ulint fld_no, /*!< in: field number */
583 mem_heap_t* heap) /*!< in: memory heap from
584 which the memory for the built
585 tuple is allocated */
586{
587 dict_table_t* sys_fields;
588 dtuple_t* entry;
589 dict_field_t* field;
590 dfield_t* dfield;
591 byte* ptr;
592 ibool index_contains_column_prefix_field = FALSE;
593 ulint j;
594
595 ut_ad(index);
596 ut_ad(heap);
597
598 for (j = 0; j < index->n_fields; j++) {
599 if (dict_index_get_nth_field(index, j)->prefix_len > 0) {
600 index_contains_column_prefix_field = TRUE;
601 break;
602 }
603 }
604
605 field = dict_index_get_nth_field(index, fld_no);
606
607 sys_fields = dict_sys->sys_fields;
608
609 entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
610
611 dict_table_copy_types(entry, sys_fields);
612
613 /* 0: INDEX_ID -----------------------*/
614 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__INDEX_ID);
615
616 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
617 mach_write_to_8(ptr, index->id);
618
619 dfield_set_data(dfield, ptr, 8);
620
621 /* 1: POS; FIELD NUMBER & PREFIX LENGTH -----------------------*/
622
623 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__POS);
624
625 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
626
627 if (index_contains_column_prefix_field) {
628 /* If there are column prefix fields in the index, then
629 we store the number of the field to the 2 HIGH bytes
630 and the prefix length to the 2 low bytes, */
631
632 mach_write_to_4(ptr, (fld_no << 16) + field->prefix_len);
633 } else {
634 /* Else we store the number of the field to the 2 LOW bytes.
635 This is to keep the storage format compatible with
636 InnoDB versions < 4.0.14. */
637
638 mach_write_to_4(ptr, fld_no);
639 }
640
641 dfield_set_data(dfield, ptr, 4);
642
643 /* 2: DB_TRX_ID added later */
644 /* 3: DB_ROLL_PTR added later */
645 /* 4: COL_NAME -------------------------*/
646 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__COL_NAME);
647
648 dfield_set_data(dfield, field->name,
649 ut_strlen(field->name));
650 /*---------------------------------*/
651
652 return(entry);
653}
654
655/*****************************************************************//**
656Creates the tuple with which the index entry is searched for writing the index
657tree root page number, if such a tree is created.
658@return the tuple for search */
659static
660dtuple_t*
661dict_create_search_tuple(
662/*=====================*/
663 const dtuple_t* tuple, /*!< in: the tuple inserted in the SYS_INDEXES
664 table */
665 mem_heap_t* heap) /*!< in: memory heap from which the memory for
666 the built tuple is allocated */
667{
668 dtuple_t* search_tuple;
669 const dfield_t* field1;
670 dfield_t* field2;
671
672 ut_ad(tuple && heap);
673
674 search_tuple = dtuple_create(heap, 2);
675
676 field1 = dtuple_get_nth_field(tuple, 0);
677 field2 = dtuple_get_nth_field(search_tuple, 0);
678
679 dfield_copy(field2, field1);
680
681 field1 = dtuple_get_nth_field(tuple, 1);
682 field2 = dtuple_get_nth_field(search_tuple, 1);
683
684 dfield_copy(field2, field1);
685
686 ut_ad(dtuple_validate(search_tuple));
687
688 return(search_tuple);
689}
690
691/***************************************************************//**
692Builds an index definition row to insert.
693@return DB_SUCCESS or error code */
694static MY_ATTRIBUTE((nonnull, warn_unused_result))
695dberr_t
696dict_build_index_def_step(
697/*======================*/
698 que_thr_t* thr, /*!< in: query thread */
699 ind_node_t* node) /*!< in: index create node */
700{
701 dict_table_t* table;
702 dict_index_t* index;
703 dtuple_t* row;
704 trx_t* trx;
705
706 ut_ad(mutex_own(&dict_sys->mutex));
707
708 trx = thr_get_trx(thr);
709
710 index = node->index;
711
712 table = index->table = node->table = dict_table_open_on_name(
713 node->table_name, TRUE, FALSE, DICT_ERR_IGNORE_NONE);
714
715 if (table == NULL) {
716 return(DB_TABLE_NOT_FOUND);
717 }
718
719 if (!trx->table_id) {
720 /* Record only the first table id. */
721 trx->table_id = table->id;
722 }
723
724 ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
725 || dict_index_is_clust(index));
726
727 dict_hdr_get_new_id(NULL, &index->id, NULL, table, false);
728
729 /* Inherit the space id from the table; we store all indexes of a
730 table in the same tablespace */
731
732 node->page_no = FIL_NULL;
733 row = dict_create_sys_indexes_tuple(index, node->heap);
734 node->ind_row = row;
735
736 ins_node_set_new_row(node->ind_def, row);
737
738 /* Note that the index was created by this transaction. */
739 index->trx_id = trx->id;
740 ut_ad(table->def_trx_id <= trx->id);
741 table->def_trx_id = trx->id;
742 dict_table_close(table, true, false);
743
744 return(DB_SUCCESS);
745}
746
747/***************************************************************//**
748Builds an index definition without updating SYSTEM TABLES.
749@return DB_SUCCESS or error code */
750void
751dict_build_index_def(
752/*=================*/
753 const dict_table_t* table, /*!< in: table */
754 dict_index_t* index, /*!< in/out: index */
755 trx_t* trx) /*!< in/out: InnoDB transaction handle */
756{
757 ut_ad(mutex_own(&dict_sys->mutex));
758
759 if (trx->table_id == 0) {
760 /* Record only the first table id. */
761 trx->table_id = table->id;
762 }
763
764 ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
765 || dict_index_is_clust(index));
766
767 dict_hdr_get_new_id(NULL, &index->id, NULL, table, false);
768
769 /* Note that the index was created by this transaction. */
770 index->trx_id = trx->id;
771}
772
773/***************************************************************//**
774Builds a field definition row to insert. */
775static
776void
777dict_build_field_def_step(
778/*======================*/
779 ind_node_t* node) /*!< in: index create node */
780{
781 dict_index_t* index;
782 dtuple_t* row;
783
784 index = node->index;
785
786 row = dict_create_sys_fields_tuple(index, node->field_no, node->heap);
787
788 ins_node_set_new_row(node->field_def, row);
789}
790
791/***************************************************************//**
792Creates an index tree for the index if it is not a member of a cluster.
793@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
794static MY_ATTRIBUTE((nonnull, warn_unused_result))
795dberr_t
796dict_create_index_tree_step(
797/*========================*/
798 ind_node_t* node) /*!< in: index create node */
799{
800 mtr_t mtr;
801 btr_pcur_t pcur;
802 dict_index_t* index;
803 dict_table_t* sys_indexes;
804 dtuple_t* search_tuple;
805
806 ut_ad(mutex_own(&dict_sys->mutex));
807
808 index = node->index;
809
810 sys_indexes = dict_sys->sys_indexes;
811
812 if (index->type == DICT_FTS) {
813 /* FTS index does not need an index tree */
814 return(DB_SUCCESS);
815 }
816
817 /* Run a mini-transaction in which the index tree is allocated for
818 the index and its root address is written to the index entry in
819 sys_indexes */
820
821 mtr.start();
822
823 search_tuple = dict_create_search_tuple(node->ind_row, node->heap);
824
825 btr_pcur_open(UT_LIST_GET_FIRST(sys_indexes->indexes),
826 search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
827 &pcur, &mtr);
828
829 btr_pcur_move_to_next_user_rec(&pcur, &mtr);
830
831
832 dberr_t err = DB_SUCCESS;
833
834 if (!index->is_readable()) {
835 node->page_no = FIL_NULL;
836 } else {
837 index->set_modified(mtr);
838
839 node->page_no = btr_create(
840 index->type, index->table->space,
841 index->id, index, NULL, &mtr);
842
843 if (node->page_no == FIL_NULL) {
844 err = DB_OUT_OF_FILE_SPACE;
845 }
846
847 DBUG_EXECUTE_IF("ib_import_create_index_failure_1",
848 node->page_no = FIL_NULL;
849 err = DB_OUT_OF_FILE_SPACE; );
850 }
851
852 page_rec_write_field(
853 btr_pcur_get_rec(&pcur), DICT_FLD__SYS_INDEXES__PAGE_NO,
854 node->page_no, &mtr);
855
856 btr_pcur_close(&pcur);
857
858 mtr.commit();
859
860 return(err);
861}
862
863/***************************************************************//**
864Creates an index tree for the index if it is not a member of a cluster.
865Don't update SYSTEM TABLES.
866@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
867dberr_t
868dict_create_index_tree_in_mem(
869/*==========================*/
870 dict_index_t* index, /*!< in/out: index */
871 const trx_t* trx) /*!< in: InnoDB transaction handle */
872{
873 mtr_t mtr;
874
875 ut_ad(mutex_own(&dict_sys->mutex));
876 ut_ad(!(index->type & DICT_FTS));
877
878 mtr_start(&mtr);
879 mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
880
881 /* Currently this function is being used by temp-tables only.
882 Import/Discard of temp-table is blocked and so this assert. */
883 ut_ad(index->is_readable());
884 ut_ad(!(index->table->flags2 & DICT_TF2_DISCARDED));
885
886 index->page = btr_create(index->type, index->table->space,
887 index->id, index, NULL, &mtr);
888 mtr_commit(&mtr);
889
890 index->trx_id = trx->id;
891
892 return index->page == FIL_NULL ? DB_OUT_OF_FILE_SPACE : DB_SUCCESS;
893}
894
895/** Drop the index tree associated with a row in SYS_INDEXES table.
896@param[in,out] rec SYS_INDEXES record
897@param[in,out] pcur persistent cursor on rec
898@param[in,out] mtr mini-transaction
899@return whether freeing the B-tree was attempted */
900bool
901dict_drop_index_tree(
902 rec_t* rec,
903 btr_pcur_t* pcur,
904 mtr_t* mtr)
905{
906 const byte* ptr;
907 ulint len;
908 ulint space;
909 ulint root_page_no;
910
911 ut_ad(mutex_own(&dict_sys->mutex));
912 ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
913
914 ptr = rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
915
916 ut_ad(len == 4);
917
918 btr_pcur_store_position(pcur, mtr);
919
920 root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
921
922 if (root_page_no == FIL_NULL) {
923 /* The tree has already been freed */
924
925 return(false);
926 }
927
928 mlog_write_ulint(const_cast<byte*>(ptr), FIL_NULL, MLOG_4BYTES, mtr);
929
930 ptr = rec_get_nth_field_old(
931 rec, DICT_FLD__SYS_INDEXES__SPACE, &len);
932
933 ut_ad(len == 4);
934
935 space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
936
937 ptr = rec_get_nth_field_old(
938 rec, DICT_FLD__SYS_INDEXES__ID, &len);
939
940 ut_ad(len == 8);
941
942 bool found;
943 const page_size_t page_size(fil_space_get_page_size(space,
944 &found));
945
946 if (!found) {
947 /* It is a single table tablespace and the .ibd file is
948 missing: do nothing */
949
950 return(false);
951 }
952
953 /* If tablespace is scheduled for truncate, do not try to drop
954 the indexes in that tablespace. There is a truncate fixup action
955 which will take care of it. */
956 if (srv_is_tablespace_truncated(space)) {
957 return(false);
958 }
959
960 btr_free_if_exists(page_id_t(space, root_page_no), page_size,
961 mach_read_from_8(ptr), mtr);
962
963 return(true);
964}
965
966/*******************************************************************//**
967Recreate the index tree associated with a row in SYS_INDEXES table.
968@return new root page number, or FIL_NULL on failure */
969ulint
970dict_recreate_index_tree(
971/*=====================*/
972 const dict_table_t*
973 table, /*!< in/out: the table the index belongs to */
974 btr_pcur_t* pcur, /*!< in/out: persistent cursor pointing to
975 record in the clustered index of
976 SYS_INDEXES table. The cursor may be
977 repositioned in this call. */
978 mtr_t* mtr) /*!< in/out: mtr having the latch
979 on the record page. */
980{
981 ut_ad(mutex_own(&dict_sys->mutex));
982 ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
983 ut_ad(!table->space || table->space->id == table->space_id);
984
985 ulint len;
986 const rec_t* rec = btr_pcur_get_rec(pcur);
987
988 const byte* ptr = rec_get_nth_field_old(
989 rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
990
991 ut_ad(len == 4);
992
993 ut_ad(table->space_id == mach_read_from_4(
994 rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__SPACE,
995 &len)));
996 ut_ad(len == 4);
997
998 if (!table->space) {
999 /* It is a single table tablespae and the .ibd file is
1000 missing: do nothing. */
1001
1002 ib::warn()
1003 << "Trying to TRUNCATE a missing .ibd file of table "
1004 << table->name << "!";
1005
1006 return(FIL_NULL);
1007 }
1008
1009 ptr = rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__TYPE, &len);
1010 ut_ad(len == 4);
1011 ulint type = mach_read_from_4(ptr);
1012
1013 ptr = rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__ID, &len);
1014 ut_ad(len == 8);
1015 index_id_t index_id = mach_read_from_8(ptr);
1016
1017 /* We will need to commit the mini-transaction in order to avoid
1018 deadlocks in the btr_create() call, because otherwise we would
1019 be freeing and allocating pages in the same mini-transaction. */
1020 btr_pcur_store_position(pcur, mtr);
1021 mtr_commit(mtr);
1022
1023 mtr_start(mtr);
1024 mtr->set_named_space(table->space);
1025 btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
1026
1027 /* Find the index corresponding to this SYS_INDEXES record. */
1028 for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
1029 index != NULL;
1030 index = UT_LIST_GET_NEXT(indexes, index)) {
1031 if (index->id == index_id) {
1032 ulint root_page_no = (index->type & DICT_FTS)
1033 ? FIL_NULL
1034 : btr_create(type, table->space,
1035 index_id, index, NULL, mtr);
1036 index->page = unsigned(root_page_no);
1037 return root_page_no;
1038 }
1039 }
1040
1041 ib::error() << "Failed to create index with index id " << index_id
1042 << " of table " << table->name;
1043
1044 return(FIL_NULL);
1045}
1046
1047/*********************************************************************//**
1048Creates a table create graph.
1049@return own: table create node */
1050tab_node_t*
1051tab_create_graph_create(
1052/*====================*/
1053 dict_table_t* table, /*!< in: table to create, built as a memory data
1054 structure */
1055 mem_heap_t* heap, /*!< in: heap where created */
1056 fil_encryption_t mode, /*!< in: encryption mode */
1057 uint32_t key_id) /*!< in: encryption key_id */
1058{
1059 tab_node_t* node;
1060
1061 node = static_cast<tab_node_t*>(
1062 mem_heap_alloc(heap, sizeof(tab_node_t)));
1063
1064 node->common.type = QUE_NODE_CREATE_TABLE;
1065
1066 node->table = table;
1067
1068 node->state = TABLE_BUILD_TABLE_DEF;
1069 node->heap = mem_heap_create(256);
1070 node->mode = mode;
1071 node->key_id = key_id;
1072
1073 node->tab_def = ins_node_create(INS_DIRECT, dict_sys->sys_tables,
1074 heap);
1075 node->tab_def->common.parent = node;
1076
1077 node->col_def = ins_node_create(INS_DIRECT, dict_sys->sys_columns,
1078 heap);
1079 node->col_def->common.parent = node;
1080
1081 node->v_col_def = ins_node_create(INS_DIRECT, dict_sys->sys_virtual,
1082 heap);
1083 node->v_col_def->common.parent = node;
1084
1085 return(node);
1086}
1087
1088/** Creates an index create graph.
1089@param[in] index index to create, built as a memory data structure
1090@param[in] table table name
1091@param[in,out] heap heap where created
1092@param[in] add_v new virtual columns added in the same clause with
1093 add index
1094@return own: index create node */
1095ind_node_t*
1096ind_create_graph_create(
1097 dict_index_t* index,
1098 const char* table,
1099 mem_heap_t* heap,
1100 const dict_add_v_col_t* add_v)
1101{
1102 ind_node_t* node;
1103
1104 node = static_cast<ind_node_t*>(
1105 mem_heap_alloc(heap, sizeof(ind_node_t)));
1106
1107 node->common.type = QUE_NODE_CREATE_INDEX;
1108
1109 node->index = index;
1110
1111 node->table_name = table;
1112
1113 node->add_v = add_v;
1114
1115 node->state = INDEX_BUILD_INDEX_DEF;
1116 node->page_no = FIL_NULL;
1117 node->heap = mem_heap_create(256);
1118
1119 node->ind_def = ins_node_create(INS_DIRECT,
1120 dict_sys->sys_indexes, heap);
1121 node->ind_def->common.parent = node;
1122
1123 node->field_def = ins_node_create(INS_DIRECT,
1124 dict_sys->sys_fields, heap);
1125 node->field_def->common.parent = node;
1126
1127 return(node);
1128}
1129
1130/***********************************************************//**
1131Creates a table. This is a high-level function used in SQL execution graphs.
1132@return query thread to run next or NULL */
1133que_thr_t*
1134dict_create_table_step(
1135/*===================*/
1136 que_thr_t* thr) /*!< in: query thread */
1137{
1138 tab_node_t* node;
1139 dberr_t err = DB_ERROR;
1140 trx_t* trx;
1141
1142 ut_ad(thr);
1143 ut_ad(mutex_own(&dict_sys->mutex));
1144
1145 trx = thr_get_trx(thr);
1146
1147 node = static_cast<tab_node_t*>(thr->run_node);
1148
1149 ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_TABLE);
1150
1151 if (thr->prev_node == que_node_get_parent(node)) {
1152 node->state = TABLE_BUILD_TABLE_DEF;
1153 }
1154
1155 if (node->state == TABLE_BUILD_TABLE_DEF) {
1156
1157 /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
1158
1159 err = dict_build_table_def_step(thr, node);
1160 if (err != DB_SUCCESS) {
1161
1162 goto function_exit;
1163 }
1164
1165 node->state = TABLE_BUILD_COL_DEF;
1166 node->col_no = 0;
1167
1168 thr->run_node = node->tab_def;
1169
1170 return(thr);
1171 }
1172
1173 if (node->state == TABLE_BUILD_COL_DEF) {
1174
1175 if (node->col_no + DATA_N_SYS_COLS
1176 < (static_cast<ulint>(node->table->n_def)
1177 + static_cast<ulint>(node->table->n_v_def))) {
1178
1179 ulint i = node->col_no++;
1180 if (i + DATA_N_SYS_COLS >= node->table->n_def) {
1181 i += DATA_N_SYS_COLS;
1182 }
1183
1184 ins_node_set_new_row(
1185 node->col_def,
1186 dict_create_sys_columns_tuple(node->table, i,
1187 node->heap));
1188
1189 thr->run_node = node->col_def;
1190
1191 return(thr);
1192 } else {
1193 /* Move on to SYS_VIRTUAL table */
1194 node->col_no = 0;
1195 node->base_col_no = 0;
1196 node->state = TABLE_BUILD_V_COL_DEF;
1197 }
1198 }
1199
1200 if (node->state == TABLE_BUILD_V_COL_DEF) {
1201
1202 if (node->col_no < static_cast<ulint>(node->table->n_v_def)) {
1203 dict_v_col_t* v_col = dict_table_get_nth_v_col(
1204 node->table, node->col_no);
1205
1206 /* If no base column */
1207 while (v_col->num_base == 0) {
1208 node->col_no++;
1209 if (node->col_no == static_cast<ulint>(
1210 (node->table)->n_v_def)) {
1211 node->state = TABLE_ADD_TO_CACHE;
1212 break;
1213 }
1214
1215 v_col = dict_table_get_nth_v_col(
1216 node->table, node->col_no);
1217 node->base_col_no = 0;
1218 }
1219
1220 if (node->state != TABLE_ADD_TO_CACHE) {
1221 ut_ad(node->col_no == v_col->v_pos);
1222 dict_build_v_col_def_step(node);
1223
1224 if (node->base_col_no < v_col->num_base - 1) {
1225 /* move on to next base column */
1226 node->base_col_no++;
1227 } else {
1228 /* move on to next virtual column */
1229 node->col_no++;
1230 node->base_col_no = 0;
1231 }
1232
1233 thr->run_node = node->v_col_def;
1234
1235 return(thr);
1236 }
1237 } else {
1238 node->state = TABLE_ADD_TO_CACHE;
1239 }
1240 }
1241
1242 if (node->state == TABLE_ADD_TO_CACHE) {
1243 DBUG_EXECUTE_IF("ib_ddl_crash_during_create", DBUG_SUICIDE(););
1244
1245 node->table->can_be_evicted = true;
1246 node->table->add_to_cache();
1247
1248 err = DB_SUCCESS;
1249 }
1250
1251function_exit:
1252 trx->error_state = err;
1253
1254 if (err == DB_SUCCESS) {
1255 /* Ok: do nothing */
1256
1257 } else if (err == DB_LOCK_WAIT) {
1258
1259 return(NULL);
1260 } else {
1261 /* SQL error detected */
1262
1263 return(NULL);
1264 }
1265
1266 thr->run_node = que_node_get_parent(node);
1267
1268 return(thr);
1269}
1270
1271/***********************************************************//**
1272Creates an index. This is a high-level function used in SQL execution
1273graphs.
1274@return query thread to run next or NULL */
1275que_thr_t*
1276dict_create_index_step(
1277/*===================*/
1278 que_thr_t* thr) /*!< in: query thread */
1279{
1280 ind_node_t* node;
1281 dberr_t err = DB_ERROR;
1282 trx_t* trx;
1283
1284 ut_ad(thr);
1285 ut_ad(mutex_own(&dict_sys->mutex));
1286
1287 trx = thr_get_trx(thr);
1288
1289 node = static_cast<ind_node_t*>(thr->run_node);
1290
1291 ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_INDEX);
1292
1293 if (thr->prev_node == que_node_get_parent(node)) {
1294 node->state = INDEX_BUILD_INDEX_DEF;
1295 }
1296
1297 if (node->state == INDEX_BUILD_INDEX_DEF) {
1298 /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
1299 err = dict_build_index_def_step(thr, node);
1300
1301 if (err != DB_SUCCESS) {
1302
1303 goto function_exit;
1304 }
1305
1306 node->state = INDEX_BUILD_FIELD_DEF;
1307 node->field_no = 0;
1308
1309 thr->run_node = node->ind_def;
1310
1311 return(thr);
1312 }
1313
1314 if (node->state == INDEX_BUILD_FIELD_DEF) {
1315
1316 if (node->field_no < (node->index)->n_fields) {
1317
1318 dict_build_field_def_step(node);
1319
1320 node->field_no++;
1321
1322 thr->run_node = node->field_def;
1323
1324 return(thr);
1325 } else {
1326 node->state = INDEX_ADD_TO_CACHE;
1327 }
1328 }
1329
1330 if (node->state == INDEX_ADD_TO_CACHE) {
1331 ut_ad(node->index->table == node->table);
1332 node->index = dict_index_add_to_cache(
1333 node->index, FIL_NULL, trx_is_strict(trx),
1334 &err, node->add_v);
1335
1336 ut_ad((node->index == NULL) == (err != DB_SUCCESS));
1337
1338 if (!node->index) {
1339 goto function_exit;
1340 }
1341
1342 ut_ad(!node->index->is_instant());
1343 ut_ad(node->index->n_core_null_bytes
1344 == ((dict_index_is_clust(node->index)
1345 && node->table->supports_instant())
1346 ? dict_index_t::NO_CORE_NULL_BYTES
1347 : UT_BITS_IN_BYTES(
1348 unsigned(node->index->n_nullable))));
1349 node->index->n_core_null_bytes = UT_BITS_IN_BYTES(
1350 unsigned(node->index->n_nullable));
1351 node->state = INDEX_CREATE_INDEX_TREE;
1352 }
1353
1354 if (node->state == INDEX_CREATE_INDEX_TREE) {
1355
1356 err = dict_create_index_tree_step(node);
1357
1358 DBUG_EXECUTE_IF("ib_dict_create_index_tree_fail",
1359 err = DB_OUT_OF_MEMORY;);
1360
1361 if (err != DB_SUCCESS) {
1362 /* If this is a FTS index, we will need to remove
1363 it from fts->cache->indexes list as well */
1364 if ((node->index->type & DICT_FTS)
1365 && node->table->fts) {
1366 fts_index_cache_t* index_cache;
1367
1368 rw_lock_x_lock(
1369 &node->table->fts->cache->init_lock);
1370
1371 index_cache = (fts_index_cache_t*)
1372 fts_find_index_cache(
1373 node->table->fts->cache,
1374 node->index);
1375
1376 if (index_cache->words) {
1377 rbt_free(index_cache->words);
1378 index_cache->words = 0;
1379 }
1380
1381 ib_vector_remove(
1382 node->table->fts->cache->indexes,
1383 *reinterpret_cast<void**>(index_cache));
1384
1385 rw_lock_x_unlock(
1386 &node->table->fts->cache->init_lock);
1387 }
1388
1389 dict_index_remove_from_cache(node->table, node->index);
1390 node->index = NULL;
1391
1392 goto function_exit;
1393 }
1394
1395 node->index->page = node->page_no;
1396 /* These should have been set in
1397 dict_build_index_def_step() and
1398 dict_index_add_to_cache(). */
1399 ut_ad(node->index->trx_id == trx->id);
1400 ut_ad(node->index->table->def_trx_id == trx->id);
1401 }
1402
1403function_exit:
1404 trx->error_state = err;
1405
1406 if (err == DB_SUCCESS) {
1407 /* Ok: do nothing */
1408
1409 } else if (err == DB_LOCK_WAIT) {
1410
1411 return(NULL);
1412 } else {
1413 /* SQL error detected */
1414
1415 return(NULL);
1416 }
1417
1418 thr->run_node = que_node_get_parent(node);
1419
1420 return(thr);
1421}
1422
1423/****************************************************************//**
1424Check whether a system table exists. Additionally, if it exists,
1425move it to the non-LRU end of the table LRU list. This is oly used
1426for system tables that can be upgraded or added to an older database,
1427which include SYS_FOREIGN, SYS_FOREIGN_COLS, SYS_TABLESPACES and
1428SYS_DATAFILES.
1429@return DB_SUCCESS if the sys table exists, DB_CORRUPTION if it exists
1430but is not current, DB_TABLE_NOT_FOUND if it does not exist*/
1431static
1432dberr_t
1433dict_check_if_system_table_exists(
1434/*==============================*/
1435 const char* tablename, /*!< in: name of table */
1436 ulint num_fields, /*!< in: number of fields */
1437 ulint num_indexes) /*!< in: number of indexes */
1438{
1439 dict_table_t* sys_table;
1440 dberr_t error = DB_SUCCESS;
1441
1442 ut_a(srv_get_active_thread_type() == SRV_NONE);
1443
1444 mutex_enter(&dict_sys->mutex);
1445
1446 sys_table = dict_table_get_low(tablename);
1447
1448 if (sys_table == NULL) {
1449 error = DB_TABLE_NOT_FOUND;
1450
1451 } else if (UT_LIST_GET_LEN(sys_table->indexes) != num_indexes
1452 || sys_table->n_cols != num_fields) {
1453 error = DB_CORRUPTION;
1454
1455 } else {
1456 /* This table has already been created, and it is OK.
1457 Ensure that it can't be evicted from the table LRU cache. */
1458
1459 dict_table_prevent_eviction(sys_table);
1460 }
1461
1462 mutex_exit(&dict_sys->mutex);
1463
1464 return(error);
1465}
1466
1467/****************************************************************//**
1468Creates the foreign key constraints system tables inside InnoDB
1469at server bootstrap or server start if they are not found or are
1470not of the right form.
1471@return DB_SUCCESS or error code */
1472dberr_t
1473dict_create_or_check_foreign_constraint_tables(void)
1474/*================================================*/
1475{
1476 trx_t* trx;
1477 my_bool srv_file_per_table_backup;
1478 dberr_t err;
1479 dberr_t sys_foreign_err;
1480 dberr_t sys_foreign_cols_err;
1481
1482 ut_a(srv_get_active_thread_type() == SRV_NONE);
1483
1484 /* Note: The master thread has not been started at this point. */
1485
1486
1487 sys_foreign_err = dict_check_if_system_table_exists(
1488 "SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3);
1489 sys_foreign_cols_err = dict_check_if_system_table_exists(
1490 "SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1);
1491
1492 if (sys_foreign_err == DB_SUCCESS
1493 && sys_foreign_cols_err == DB_SUCCESS) {
1494 return(DB_SUCCESS);
1495 }
1496
1497 if (srv_read_only_mode
1498 || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) {
1499 return(DB_READ_ONLY);
1500 }
1501
1502 trx = trx_create();
1503
1504 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1505
1506 trx->op_info = "creating foreign key sys tables";
1507
1508 row_mysql_lock_data_dictionary(trx);
1509
1510 /* Check which incomplete table definition to drop. */
1511
1512 if (sys_foreign_err == DB_CORRUPTION) {
1513 ib::warn() << "Dropping incompletely created"
1514 " SYS_FOREIGN table.";
1515 row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE);
1516 }
1517
1518 if (sys_foreign_cols_err == DB_CORRUPTION) {
1519 ib::warn() << "Dropping incompletely created"
1520 " SYS_FOREIGN_COLS table.";
1521
1522 row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE);
1523 }
1524
1525 ib::info() << "Creating foreign key constraint system tables.";
1526
1527 /* NOTE: in dict_load_foreigns we use the fact that
1528 there are 2 secondary indexes on SYS_FOREIGN, and they
1529 are defined just like below */
1530
1531 /* NOTE: when designing InnoDB's foreign key support in 2001, we made
1532 an error and made the table names and the foreign key id of type
1533 'CHAR' (internally, really a VARCHAR). We should have made the type
1534 VARBINARY, like in other InnoDB system tables, to get a clean
1535 design. */
1536
1537 srv_file_per_table_backup = srv_file_per_table;
1538
1539 /* We always want SYSTEM tables to be created inside the system
1540 tablespace. */
1541
1542 srv_file_per_table = 0;
1543
1544 err = que_eval_sql(
1545 NULL,
1546 "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
1547 "BEGIN\n"
1548 "CREATE TABLE\n"
1549 "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
1550 " REF_NAME CHAR, N_COLS INT);\n"
1551 "CREATE UNIQUE CLUSTERED INDEX ID_IND"
1552 " ON SYS_FOREIGN (ID);\n"
1553 "CREATE INDEX FOR_IND"
1554 " ON SYS_FOREIGN (FOR_NAME);\n"
1555 "CREATE INDEX REF_IND"
1556 " ON SYS_FOREIGN (REF_NAME);\n"
1557 "CREATE TABLE\n"
1558 "SYS_FOREIGN_COLS(ID CHAR, POS INT,"
1559 " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
1560 "CREATE UNIQUE CLUSTERED INDEX ID_IND"
1561 " ON SYS_FOREIGN_COLS (ID, POS);\n"
1562 "END;\n",
1563 FALSE, trx);
1564
1565 if (err != DB_SUCCESS) {
1566
1567 ib::error() << "Creation of SYS_FOREIGN and SYS_FOREIGN_COLS"
1568 " failed: " << ut_strerr(err) << ". Tablespace is"
1569 " full. Dropping incompletely created tables.";
1570
1571 ut_ad(err == DB_OUT_OF_FILE_SPACE
1572 || err == DB_TOO_MANY_CONCURRENT_TRXS);
1573
1574 row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE);
1575 row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE);
1576
1577 if (err == DB_OUT_OF_FILE_SPACE) {
1578 err = DB_MUST_GET_MORE_FILE_SPACE;
1579 }
1580 }
1581
1582 trx_commit_for_mysql(trx);
1583
1584 row_mysql_unlock_data_dictionary(trx);
1585
1586 trx_free(trx);
1587
1588 srv_file_per_table = srv_file_per_table_backup;
1589
1590 /* Note: The master thread has not been started at this point. */
1591 /* Confirm and move to the non-LRU part of the table LRU list. */
1592 sys_foreign_err = dict_check_if_system_table_exists(
1593 "SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3);
1594 ut_a(sys_foreign_err == DB_SUCCESS);
1595
1596 sys_foreign_cols_err = dict_check_if_system_table_exists(
1597 "SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1);
1598 ut_a(sys_foreign_cols_err == DB_SUCCESS);
1599
1600 return(err);
1601}
1602
1603/** Creates the virtual column system table (SYS_VIRTUAL) inside InnoDB
1604at server bootstrap or server start if the table is not found or is
1605not of the right form.
1606@return DB_SUCCESS or error code */
1607dberr_t
1608dict_create_or_check_sys_virtual()
1609{
1610 trx_t* trx;
1611 my_bool srv_file_per_table_backup;
1612 dberr_t err;
1613
1614 ut_a(srv_get_active_thread_type() == SRV_NONE);
1615
1616 /* Note: The master thread has not been started at this point. */
1617 err = dict_check_if_system_table_exists(
1618 "SYS_VIRTUAL", DICT_NUM_FIELDS__SYS_VIRTUAL + 1, 1);
1619
1620 if (err == DB_SUCCESS) {
1621 mutex_enter(&dict_sys->mutex);
1622 dict_sys->sys_virtual = dict_table_get_low("SYS_VIRTUAL");
1623 mutex_exit(&dict_sys->mutex);
1624 return(DB_SUCCESS);
1625 }
1626
1627 if (srv_read_only_mode
1628 || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) {
1629 return(DB_READ_ONLY);
1630 }
1631
1632 trx = trx_create();
1633
1634 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1635
1636 trx->op_info = "creating sys_virtual tables";
1637
1638 row_mysql_lock_data_dictionary(trx);
1639
1640 /* Check which incomplete table definition to drop. */
1641
1642 if (err == DB_CORRUPTION) {
1643 ib::warn() << "Dropping incompletely created"
1644 " SYS_VIRTUAL table.";
1645 row_drop_table_for_mysql("SYS_VIRTUAL", trx, false, TRUE);
1646 }
1647
1648 ib::info() << "Creating sys_virtual system tables.";
1649
1650 srv_file_per_table_backup = srv_file_per_table;
1651
1652 /* We always want SYSTEM tables to be created inside the system
1653 tablespace. */
1654
1655 srv_file_per_table = 0;
1656
1657 err = que_eval_sql(
1658 NULL,
1659 "PROCEDURE CREATE_SYS_VIRTUAL_TABLES_PROC () IS\n"
1660 "BEGIN\n"
1661 "CREATE TABLE\n"
1662 "SYS_VIRTUAL(TABLE_ID BIGINT, POS INT,"
1663 " BASE_POS INT);\n"
1664 "CREATE UNIQUE CLUSTERED INDEX BASE_IDX"
1665 " ON SYS_VIRTUAL(TABLE_ID, POS, BASE_POS);\n"
1666 "END;\n",
1667 FALSE, trx);
1668
1669 if (err != DB_SUCCESS) {
1670
1671 ib::error() << "Creation of SYS_VIRTUAL"
1672 " failed: " << ut_strerr(err) << ". Tablespace is"
1673 " full or too many transactions."
1674 " Dropping incompletely created tables.";
1675
1676 ut_ad(err == DB_OUT_OF_FILE_SPACE
1677 || err == DB_TOO_MANY_CONCURRENT_TRXS);
1678
1679 row_drop_table_for_mysql("SYS_VIRTUAL", trx, false, TRUE);
1680
1681 if (err == DB_OUT_OF_FILE_SPACE) {
1682 err = DB_MUST_GET_MORE_FILE_SPACE;
1683 }
1684 }
1685
1686 trx_commit_for_mysql(trx);
1687
1688 row_mysql_unlock_data_dictionary(trx);
1689
1690 trx_free(trx);
1691
1692 srv_file_per_table = srv_file_per_table_backup;
1693
1694 /* Note: The master thread has not been started at this point. */
1695 /* Confirm and move to the non-LRU part of the table LRU list. */
1696 dberr_t sys_virtual_err = dict_check_if_system_table_exists(
1697 "SYS_VIRTUAL", DICT_NUM_FIELDS__SYS_VIRTUAL + 1, 1);
1698 ut_a(sys_virtual_err == DB_SUCCESS);
1699 mutex_enter(&dict_sys->mutex);
1700 dict_sys->sys_virtual = dict_table_get_low("SYS_VIRTUAL");
1701 mutex_exit(&dict_sys->mutex);
1702
1703 return(err);
1704}
1705
1706/****************************************************************//**
1707Evaluate the given foreign key SQL statement.
1708@return error code or DB_SUCCESS */
1709static MY_ATTRIBUTE((nonnull, warn_unused_result))
1710dberr_t
1711dict_foreign_eval_sql(
1712/*==================*/
1713 pars_info_t* info, /*!< in: info struct */
1714 const char* sql, /*!< in: SQL string to evaluate */
1715 const char* name, /*!< in: table name (for diagnostics) */
1716 const char* id, /*!< in: foreign key id */
1717 trx_t* trx) /*!< in/out: transaction */
1718{
1719 dberr_t error;
1720 FILE* ef = dict_foreign_err_file;
1721
1722 error = que_eval_sql(info, sql, FALSE, trx);
1723
1724 if (error == DB_DUPLICATE_KEY) {
1725 mutex_enter(&dict_foreign_err_mutex);
1726 rewind(ef);
1727 ut_print_timestamp(ef);
1728 fputs(" Error in foreign key constraint creation for table ",
1729 ef);
1730 ut_print_name(ef, trx, name);
1731 fputs(".\nA foreign key constraint of name ", ef);
1732 ut_print_name(ef, trx, id);
1733 fputs("\nalready exists."
1734 " (Note that internally InnoDB adds 'databasename'\n"
1735 "in front of the user-defined constraint name.)\n"
1736 "Note that InnoDB's FOREIGN KEY system tables store\n"
1737 "constraint names as case-insensitive, with the\n"
1738 "MySQL standard latin1_swedish_ci collation. If you\n"
1739 "create tables or databases whose names differ only in\n"
1740 "the character case, then collisions in constraint\n"
1741 "names can occur. Workaround: name your constraints\n"
1742 "explicitly with unique names.\n",
1743 ef);
1744
1745 mutex_exit(&dict_foreign_err_mutex);
1746
1747 return(error);
1748 }
1749
1750 if (error != DB_SUCCESS) {
1751 ib::error() << "Foreign key constraint creation failed: "
1752 << ut_strerr(error);
1753
1754 mutex_enter(&dict_foreign_err_mutex);
1755 ut_print_timestamp(ef);
1756 fputs(" Internal error in foreign key constraint creation"
1757 " for table ", ef);
1758 ut_print_name(ef, trx, name);
1759 fputs(".\n"
1760 "See the MySQL .err log in the datadir"
1761 " for more information.\n", ef);
1762 mutex_exit(&dict_foreign_err_mutex);
1763
1764 return(error);
1765 }
1766
1767 return(DB_SUCCESS);
1768}
1769
1770/********************************************************************//**
1771Add a single foreign key field definition to the data dictionary tables in
1772the database.
1773@return error code or DB_SUCCESS */
1774static MY_ATTRIBUTE((nonnull, warn_unused_result))
1775dberr_t
1776dict_create_add_foreign_field_to_dictionary(
1777/*========================================*/
1778 ulint field_nr, /*!< in: field number */
1779 const char* table_name, /*!< in: table name */
1780 const dict_foreign_t* foreign, /*!< in: foreign */
1781 trx_t* trx) /*!< in/out: transaction */
1782{
1783 DBUG_ENTER("dict_create_add_foreign_field_to_dictionary");
1784
1785 pars_info_t* info = pars_info_create();
1786
1787 pars_info_add_str_literal(info, "id", foreign->id);
1788
1789 pars_info_add_int4_literal(info, "pos", field_nr);
1790
1791 pars_info_add_str_literal(info, "for_col_name",
1792 foreign->foreign_col_names[field_nr]);
1793
1794 pars_info_add_str_literal(info, "ref_col_name",
1795 foreign->referenced_col_names[field_nr]);
1796
1797 DBUG_RETURN(dict_foreign_eval_sql(
1798 info,
1799 "PROCEDURE P () IS\n"
1800 "BEGIN\n"
1801 "INSERT INTO SYS_FOREIGN_COLS VALUES"
1802 "(:id, :pos, :for_col_name, :ref_col_name);\n"
1803 "END;\n",
1804 table_name, foreign->id, trx));
1805}
1806
1807/********************************************************************//**
1808Construct foreign key constraint defintion from data dictionary information.
1809*/
1810UNIV_INTERN
1811char*
1812dict_foreign_def_get(
1813/*=================*/
1814 dict_foreign_t* foreign,/*!< in: foreign */
1815 trx_t* trx) /*!< in: trx */
1816{
1817 char* fk_def = (char *)mem_heap_alloc(foreign->heap, 4*1024);
1818 const char* tbname;
1819 char tablebuf[MAX_TABLE_NAME_LEN + 1] = "";
1820 unsigned i;
1821 char* bufend;
1822
1823 tbname = dict_remove_db_name(foreign->id);
1824 bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
1825 tbname, strlen(tbname), trx->mysql_thd);
1826 tablebuf[bufend - tablebuf] = '\0';
1827
1828 sprintf(fk_def,
1829 (char *)"CONSTRAINT %s FOREIGN KEY (", (char *)tablebuf);
1830
1831 for(i = 0; i < foreign->n_fields; i++) {
1832 char buf[MAX_TABLE_NAME_LEN + 1] = "";
1833 innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
1834 foreign->foreign_col_names[i],
1835 strlen(foreign->foreign_col_names[i]),
1836 trx->mysql_thd);
1837 strcat(fk_def, buf);
1838 if (i < static_cast<unsigned>(foreign->n_fields-1)) {
1839 strcat(fk_def, (char *)",");
1840 }
1841 }
1842
1843 strcat(fk_def,(char *)") REFERENCES ");
1844
1845 bufend = innobase_convert_name(tablebuf, MAX_TABLE_NAME_LEN,
1846 foreign->referenced_table_name,
1847 strlen(foreign->referenced_table_name),
1848 trx->mysql_thd);
1849 tablebuf[bufend - tablebuf] = '\0';
1850
1851 strcat(fk_def, tablebuf);
1852 strcat(fk_def, " (");
1853
1854 for(i = 0; i < foreign->n_fields; i++) {
1855 char buf[MAX_TABLE_NAME_LEN + 1] = "";
1856 bufend = innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
1857 foreign->referenced_col_names[i],
1858 strlen(foreign->referenced_col_names[i]),
1859 trx->mysql_thd);
1860 buf[bufend - buf] = '\0';
1861 strcat(fk_def, buf);
1862 if (i < (uint)foreign->n_fields-1) {
1863 strcat(fk_def, (char *)",");
1864 }
1865 }
1866 strcat(fk_def, (char *)")");
1867
1868 return fk_def;
1869}
1870
1871/********************************************************************//**
1872Convert foreign key column names from data dictionary to SQL-layer.
1873*/
1874static
1875void
1876dict_foreign_def_get_fields(
1877/*========================*/
1878 dict_foreign_t* foreign,/*!< in: foreign */
1879 trx_t* trx, /*!< in: trx */
1880 char** field, /*!< out: foreign column */
1881 char** field2, /*!< out: referenced column */
1882 ulint col_no) /*!< in: column number */
1883{
1884 char* bufend;
1885 char* fieldbuf = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
1886 char* fieldbuf2 = (char *)mem_heap_alloc(foreign->heap, MAX_TABLE_NAME_LEN+1);
1887
1888 bufend = innobase_convert_name(fieldbuf, MAX_TABLE_NAME_LEN,
1889 foreign->foreign_col_names[col_no],
1890 strlen(foreign->foreign_col_names[col_no]),
1891 trx->mysql_thd);
1892
1893 fieldbuf[bufend - fieldbuf] = '\0';
1894
1895 bufend = innobase_convert_name(fieldbuf2, MAX_TABLE_NAME_LEN,
1896 foreign->referenced_col_names[col_no],
1897 strlen(foreign->referenced_col_names[col_no]),
1898 trx->mysql_thd);
1899
1900 fieldbuf2[bufend - fieldbuf2] = '\0';
1901 *field = fieldbuf;
1902 *field2 = fieldbuf2;
1903}
1904
1905/********************************************************************//**
1906Add a foreign key definition to the data dictionary tables.
1907@return error code or DB_SUCCESS */
1908dberr_t
1909dict_create_add_foreign_to_dictionary(
1910/*==================================*/
1911 const char* name, /*!< in: table name */
1912 const dict_foreign_t* foreign,/*!< in: foreign key */
1913 trx_t* trx) /*!< in/out: dictionary transaction */
1914{
1915 dberr_t error;
1916
1917 DBUG_ENTER("dict_create_add_foreign_to_dictionary");
1918
1919 pars_info_t* info = pars_info_create();
1920
1921 pars_info_add_str_literal(info, "id", foreign->id);
1922
1923 pars_info_add_str_literal(info, "for_name", name);
1924
1925 pars_info_add_str_literal(info, "ref_name",
1926 foreign->referenced_table_name);
1927
1928 pars_info_add_int4_literal(info, "n_cols",
1929 ulint(foreign->n_fields)
1930 | (ulint(foreign->type) << 24));
1931
1932 DBUG_PRINT("dict_create_add_foreign_to_dictionary",
1933 ("'%s', '%s', '%s', %d", foreign->id, name,
1934 foreign->referenced_table_name,
1935 foreign->n_fields + (foreign->type << 24)));
1936
1937 error = dict_foreign_eval_sql(info,
1938 "PROCEDURE P () IS\n"
1939 "BEGIN\n"
1940 "INSERT INTO SYS_FOREIGN VALUES"
1941 "(:id, :for_name, :ref_name, :n_cols);\n"
1942 "END;\n"
1943 , name, foreign->id, trx);
1944
1945 if (error != DB_SUCCESS) {
1946
1947 if (error == DB_DUPLICATE_KEY) {
1948 char buf[MAX_TABLE_NAME_LEN + 1] = "";
1949 char tablename[MAX_TABLE_NAME_LEN + 1] = "";
1950 char* fk_def;
1951
1952 innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
1953 name, strlen(name), trx->mysql_thd);
1954
1955 innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
1956 foreign->id, strlen(foreign->id), trx->mysql_thd);
1957
1958 fk_def = dict_foreign_def_get((dict_foreign_t*)foreign, trx);
1959
1960 ib_push_warning(trx, error,
1961 "Create or Alter table %s with foreign key constraint"
1962 " failed. Foreign key constraint %s"
1963 " already exists on data dictionary."
1964 " Foreign key constraint names need to be unique in database."
1965 " Error in foreign key definition: %s.",
1966 tablename, buf, fk_def);
1967 }
1968
1969 DBUG_RETURN(error);
1970 }
1971
1972 for (ulint i = 0; i < foreign->n_fields; i++) {
1973 error = dict_create_add_foreign_field_to_dictionary(
1974 i, name, foreign, trx);
1975
1976 if (error != DB_SUCCESS) {
1977 char buf[MAX_TABLE_NAME_LEN + 1] = "";
1978 char tablename[MAX_TABLE_NAME_LEN + 1] = "";
1979 char* field=NULL;
1980 char* field2=NULL;
1981 char* fk_def;
1982
1983 innobase_convert_name(tablename, MAX_TABLE_NAME_LEN,
1984 name, strlen(name), trx->mysql_thd);
1985 innobase_convert_name(buf, MAX_TABLE_NAME_LEN,
1986 foreign->id, strlen(foreign->id), trx->mysql_thd);
1987 fk_def = dict_foreign_def_get((dict_foreign_t*)foreign, trx);
1988 dict_foreign_def_get_fields((dict_foreign_t*)foreign, trx, &field, &field2, i);
1989
1990 ib_push_warning(trx, error,
1991 "Create or Alter table %s with foreign key constraint"
1992 " failed. Error adding foreign key constraint name %s"
1993 " fields %s or %s to the dictionary."
1994 " Error in foreign key definition: %s.",
1995 tablename, buf, i+1, fk_def);
1996
1997 DBUG_RETURN(error);
1998 }
1999 }
2000
2001 DBUG_RETURN(error);
2002}
2003
2004/** Check whether a column is in an index by the column name
2005@param[in] col_name column name for the column to be checked
2006@param[in] index the index to be searched
2007@return true if this column is in the index, otherwise, false */
2008static
2009bool
2010dict_index_has_col_by_name(
2011/*=======================*/
2012 const char* col_name,
2013 const dict_index_t* index)
2014{
2015 for (ulint i = 0; i < index->n_fields; i++) {
2016 dict_field_t* field = dict_index_get_nth_field(index, i);
2017
2018 if (strcmp(field->name, col_name) == 0) {
2019 return(true);
2020 }
2021 }
2022 return(false);
2023}
2024
2025/** Check whether the foreign constraint could be on a column that is
2026part of a virtual index (index contains virtual column) in the table
2027@param[in] fk_col_name FK column name to be checked
2028@param[in] table the table
2029@return true if this column is indexed with other virtual columns */
2030bool
2031dict_foreign_has_col_in_v_index(
2032 const char* fk_col_name,
2033 const dict_table_t* table)
2034{
2035 /* virtual column can't be Primary Key, so start with secondary index */
2036 for (dict_index_t* index = dict_table_get_next_index(
2037 dict_table_get_first_index(table));
2038 index;
2039 index = dict_table_get_next_index(index)) {
2040
2041 if (dict_index_has_virtual(index)) {
2042 if (dict_index_has_col_by_name(fk_col_name, index)) {
2043 return(true);
2044 }
2045 }
2046 }
2047
2048 return(false);
2049}
2050
2051
2052/** Check whether the foreign constraint could be on a column that is
2053a base column of some indexed virtual columns.
2054@param[in] col_name column name for the column to be checked
2055@param[in] table the table
2056@return true if this column is a base column, otherwise, false */
2057bool
2058dict_foreign_has_col_as_base_col(
2059 const char* col_name,
2060 const dict_table_t* table)
2061{
2062 /* Loop through each virtual column and check if its base column has
2063 the same name as the column name being checked */
2064 for (ulint i = 0; i < table->n_v_cols; i++) {
2065 dict_v_col_t* v_col = dict_table_get_nth_v_col(table, i);
2066
2067 /* Only check if the virtual column is indexed */
2068 if (!v_col->m_col.ord_part) {
2069 continue;
2070 }
2071
2072 for (ulint j = 0; j < v_col->num_base; j++) {
2073 if (strcmp(col_name, dict_table_get_col_name(
2074 table,
2075 v_col->base_col[j]->ind)) == 0) {
2076 return(true);
2077 }
2078 }
2079 }
2080
2081 return(false);
2082}
2083
2084/** Check if a foreign constraint is on the given column name.
2085@param[in] col_name column name to be searched for fk constraint
2086@param[in] table table to which foreign key constraint belongs
2087@return true if fk constraint is present on the table, false otherwise. */
2088static
2089bool
2090dict_foreign_base_for_stored(
2091 const char* col_name,
2092 const dict_table_t* table)
2093{
2094 /* Loop through each stored column and check if its base column has
2095 the same name as the column name being checked */
2096 dict_s_col_list::const_iterator it;
2097 for (it = table->s_cols->begin();
2098 it != table->s_cols->end(); ++it) {
2099 dict_s_col_t s_col = *it;
2100
2101 for (ulint j = 0; j < s_col.num_base; j++) {
2102 if (strcmp(col_name, dict_table_get_col_name(
2103 table,
2104 s_col.base_col[j]->ind)) == 0) {
2105 return(true);
2106 }
2107 }
2108 }
2109
2110 return(false);
2111}
2112
2113/** Check if a foreign constraint is on columns served as base columns
2114of any stored column. This is to prevent creating SET NULL or CASCADE
2115constraint on such columns
2116@param[in] local_fk_set set of foreign key objects, to be added to
2117the dictionary tables
2118@param[in] table table to which the foreign key objects in
2119local_fk_set belong to
2120@return true if yes, otherwise, false */
2121bool
2122dict_foreigns_has_s_base_col(
2123 const dict_foreign_set& local_fk_set,
2124 const dict_table_t* table)
2125{
2126 dict_foreign_t* foreign;
2127
2128 if (table->s_cols == NULL) {
2129 return (false);
2130 }
2131
2132 for (dict_foreign_set::const_iterator it = local_fk_set.begin();
2133 it != local_fk_set.end(); ++it) {
2134
2135 foreign = *it;
2136 ulint type = foreign->type;
2137
2138 type &= ~(DICT_FOREIGN_ON_DELETE_NO_ACTION
2139 | DICT_FOREIGN_ON_UPDATE_NO_ACTION);
2140
2141 if (type == 0) {
2142 continue;
2143 }
2144
2145 for (ulint i = 0; i < foreign->n_fields; i++) {
2146 /* Check if the constraint is on a column that
2147 is a base column of any stored column */
2148 if (dict_foreign_base_for_stored(
2149 foreign->foreign_col_names[i], table)) {
2150 return(true);
2151 }
2152 }
2153 }
2154
2155 return(false);
2156}
2157
2158/** Check if a column is in foreign constraint with CASCADE properties or
2159SET NULL
2160@param[in] table table
2161@param[in] fk_col_name name for the column to be checked
2162@return true if the column is in foreign constraint, otherwise, false */
2163bool
2164dict_foreigns_has_this_col(
2165 const dict_table_t* table,
2166 const char* col_name)
2167{
2168 dict_foreign_t* foreign;
2169 const dict_foreign_set* local_fk_set = &table->foreign_set;
2170
2171 for (dict_foreign_set::const_iterator it = local_fk_set->begin();
2172 it != local_fk_set->end();
2173 ++it) {
2174 foreign = *it;
2175 ut_ad(foreign->id != NULL);
2176 ulint type = foreign->type;
2177
2178 type &= ~(DICT_FOREIGN_ON_DELETE_NO_ACTION
2179 | DICT_FOREIGN_ON_UPDATE_NO_ACTION);
2180
2181 if (type == 0) {
2182 continue;
2183 }
2184
2185 for (ulint i = 0; i < foreign->n_fields; i++) {
2186 if (strcmp(foreign->foreign_col_names[i],
2187 col_name) == 0) {
2188 return(true);
2189 }
2190 }
2191 }
2192 return(false);
2193}
2194
2195/** Adds the given set of foreign key objects to the dictionary tables
2196in the database. This function does not modify the dictionary cache. The
2197caller must ensure that all foreign key objects contain a valid constraint
2198name in foreign->id.
2199@param[in] local_fk_set set of foreign key objects, to be added to
2200the dictionary tables
2201@param[in] table table to which the foreign key objects in
2202local_fk_set belong to
2203@param[in,out] trx transaction
2204@return error code or DB_SUCCESS */
2205dberr_t
2206dict_create_add_foreigns_to_dictionary(
2207/*===================================*/
2208 const dict_foreign_set& local_fk_set,
2209 const dict_table_t* table,
2210 trx_t* trx)
2211{
2212 dict_foreign_t* foreign;
2213 dberr_t error;
2214
2215 ut_ad(mutex_own(&dict_sys->mutex));
2216
2217 if (NULL == dict_table_get_low("SYS_FOREIGN")) {
2218
2219 ib::error() << "Table SYS_FOREIGN not found"
2220 " in internal data dictionary";
2221
2222 return(DB_ERROR);
2223 }
2224
2225 for (dict_foreign_set::const_iterator it = local_fk_set.begin();
2226 it != local_fk_set.end();
2227 ++it) {
2228
2229 foreign = *it;
2230 ut_ad(foreign->id != NULL);
2231
2232 error = dict_create_add_foreign_to_dictionary(
2233 table->name.m_name, foreign, trx);
2234
2235 if (error != DB_SUCCESS) {
2236
2237 return(error);
2238 }
2239 }
2240
2241 trx->op_info = "committing foreign key definitions";
2242
2243 if (trx_is_started(trx)) {
2244
2245 trx_commit(trx);
2246 }
2247
2248 trx->op_info = "";
2249
2250 return(DB_SUCCESS);
2251}
2252
2253/****************************************************************//**
2254Creates the tablespaces and datafiles system tables inside InnoDB
2255at server bootstrap or server start if they are not found or are
2256not of the right form.
2257@return DB_SUCCESS or error code */
2258dberr_t
2259dict_create_or_check_sys_tablespace(void)
2260/*=====================================*/
2261{
2262 trx_t* trx;
2263 my_bool srv_file_per_table_backup;
2264 dberr_t err;
2265 dberr_t sys_tablespaces_err;
2266 dberr_t sys_datafiles_err;
2267
2268 ut_a(srv_get_active_thread_type() == SRV_NONE);
2269
2270 /* Note: The master thread has not been started at this point. */
2271
2272 sys_tablespaces_err = dict_check_if_system_table_exists(
2273 "SYS_TABLESPACES", DICT_NUM_FIELDS__SYS_TABLESPACES + 1, 1);
2274 sys_datafiles_err = dict_check_if_system_table_exists(
2275 "SYS_DATAFILES", DICT_NUM_FIELDS__SYS_DATAFILES + 1, 1);
2276
2277 if (sys_tablespaces_err == DB_SUCCESS
2278 && sys_datafiles_err == DB_SUCCESS) {
2279 srv_sys_tablespaces_open = true;
2280 return(DB_SUCCESS);
2281 }
2282
2283 if (srv_read_only_mode
2284 || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO) {
2285 return(DB_READ_ONLY);
2286 }
2287
2288 trx = trx_create();
2289
2290 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2291
2292 trx->op_info = "creating tablepace and datafile sys tables";
2293
2294 row_mysql_lock_data_dictionary(trx);
2295
2296 /* Check which incomplete table definition to drop. */
2297
2298 if (sys_tablespaces_err == DB_CORRUPTION) {
2299 ib::warn() << "Dropping incompletely created"
2300 " SYS_TABLESPACES table.";
2301 row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE, TRUE);
2302 }
2303
2304 if (sys_datafiles_err == DB_CORRUPTION) {
2305 ib::warn() << "Dropping incompletely created"
2306 " SYS_DATAFILES table.";
2307
2308 row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE, TRUE);
2309 }
2310
2311 ib::info() << "Creating tablespace and datafile system tables.";
2312
2313 /* We always want SYSTEM tables to be created inside the system
2314 tablespace. */
2315 srv_file_per_table_backup = srv_file_per_table;
2316 srv_file_per_table = 0;
2317
2318 err = que_eval_sql(
2319 NULL,
2320 "PROCEDURE CREATE_SYS_TABLESPACE_PROC () IS\n"
2321 "BEGIN\n"
2322 "CREATE TABLE SYS_TABLESPACES(\n"
2323 " SPACE INT, NAME CHAR, FLAGS INT);\n"
2324 "CREATE UNIQUE CLUSTERED INDEX SYS_TABLESPACES_SPACE"
2325 " ON SYS_TABLESPACES (SPACE);\n"
2326 "CREATE TABLE SYS_DATAFILES(\n"
2327 " SPACE INT, PATH CHAR);\n"
2328 "CREATE UNIQUE CLUSTERED INDEX SYS_DATAFILES_SPACE"
2329 " ON SYS_DATAFILES (SPACE);\n"
2330 "END;\n",
2331 FALSE, trx);
2332
2333 if (err != DB_SUCCESS) {
2334
2335 ib::error() << "Creation of SYS_TABLESPACES and SYS_DATAFILES"
2336 " has failed with error " << ut_strerr(err)
2337 << ". Dropping incompletely created tables.";
2338
2339 ut_a(err == DB_OUT_OF_FILE_SPACE
2340 || err == DB_DUPLICATE_KEY
2341 || err == DB_TOO_MANY_CONCURRENT_TRXS);
2342
2343 row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE, TRUE);
2344 row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE, TRUE);
2345
2346 if (err == DB_OUT_OF_FILE_SPACE) {
2347 err = DB_MUST_GET_MORE_FILE_SPACE;
2348 }
2349 }
2350
2351 trx_commit_for_mysql(trx);
2352
2353 row_mysql_unlock_data_dictionary(trx);
2354
2355 trx_free(trx);
2356
2357 srv_file_per_table = srv_file_per_table_backup;
2358
2359 if (err == DB_SUCCESS) {
2360 srv_sys_tablespaces_open = true;
2361 }
2362
2363 /* Note: The master thread has not been started at this point. */
2364 /* Confirm and move to the non-LRU part of the table LRU list. */
2365
2366 sys_tablespaces_err = dict_check_if_system_table_exists(
2367 "SYS_TABLESPACES", DICT_NUM_FIELDS__SYS_TABLESPACES + 1, 1);
2368 ut_a(sys_tablespaces_err == DB_SUCCESS || err != DB_SUCCESS);
2369
2370 sys_datafiles_err = dict_check_if_system_table_exists(
2371 "SYS_DATAFILES", DICT_NUM_FIELDS__SYS_DATAFILES + 1, 1);
2372 ut_a(sys_datafiles_err == DB_SUCCESS || err != DB_SUCCESS);
2373
2374 return(err);
2375}
2376
2377/** Put a tablespace definition into the data dictionary,
2378replacing what was there previously.
2379@param[in] space Tablespace id
2380@param[in] name Tablespace name
2381@param[in] flags Tablespace flags
2382@param[in] path Tablespace path
2383@param[in] trx Transaction
2384@return error code or DB_SUCCESS */
2385dberr_t
2386dict_replace_tablespace_in_dictionary(
2387 ulint space_id,
2388 const char* name,
2389 ulint flags,
2390 const char* path,
2391 trx_t* trx)
2392{
2393 if (!srv_sys_tablespaces_open) {
2394 /* Startup procedure is not yet ready for updates. */
2395 return(DB_SUCCESS);
2396 }
2397
2398 dberr_t error;
2399
2400 pars_info_t* info = pars_info_create();
2401
2402 pars_info_add_int4_literal(info, "space", space_id);
2403
2404 pars_info_add_str_literal(info, "name", name);
2405
2406 pars_info_add_int4_literal(info, "flags", flags);
2407
2408 pars_info_add_str_literal(info, "path", path);
2409
2410 error = que_eval_sql(info,
2411 "PROCEDURE P () IS\n"
2412 "p CHAR;\n"
2413
2414 "DECLARE CURSOR c IS\n"
2415 " SELECT PATH FROM SYS_DATAFILES\n"
2416 " WHERE SPACE=:space FOR UPDATE;\n"
2417
2418 "BEGIN\n"
2419 "OPEN c;\n"
2420 "FETCH c INTO p;\n"
2421
2422 "IF (SQL % NOTFOUND) THEN"
2423 " DELETE FROM SYS_TABLESPACES "
2424 "WHERE SPACE=:space;\n"
2425 " INSERT INTO SYS_TABLESPACES VALUES"
2426 "(:space, :name, :flags);\n"
2427 " INSERT INTO SYS_DATAFILES VALUES"
2428 "(:space, :path);\n"
2429 "ELSIF p <> :path THEN\n"
2430 " UPDATE SYS_DATAFILES SET PATH=:path"
2431 " WHERE CURRENT OF c;\n"
2432 "END IF;\n"
2433 "END;\n",
2434 FALSE, trx);
2435
2436 if (error != DB_SUCCESS) {
2437 return(error);
2438 }
2439
2440 trx->op_info = "";
2441
2442 return(error);
2443}
2444
2445/** Delete records from SYS_TABLESPACES and SYS_DATAFILES associated
2446with a particular tablespace ID.
2447@param[in] space Tablespace ID
2448@param[in,out] trx Current transaction
2449@return DB_SUCCESS if OK, dberr_t if the operation failed */
2450
2451dberr_t
2452dict_delete_tablespace_and_datafiles(
2453 ulint space,
2454 trx_t* trx)
2455{
2456 dberr_t err = DB_SUCCESS;
2457
2458 ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
2459 ut_ad(mutex_own(&dict_sys->mutex));
2460 ut_ad(srv_sys_tablespaces_open);
2461
2462 trx->op_info = "delete tablespace and datafiles from dictionary";
2463
2464 pars_info_t* info = pars_info_create();
2465 ut_a(!is_system_tablespace(space));
2466 pars_info_add_int4_literal(info, "space", space);
2467
2468 err = que_eval_sql(info,
2469 "PROCEDURE P () IS\n"
2470 "BEGIN\n"
2471 "DELETE FROM SYS_TABLESPACES\n"
2472 "WHERE SPACE = :space;\n"
2473 "DELETE FROM SYS_DATAFILES\n"
2474 "WHERE SPACE = :space;\n"
2475 "END;\n",
2476 FALSE, trx);
2477
2478 if (err != DB_SUCCESS) {
2479 ib::warn() << "Could not delete space_id "
2480 << space << " from data dictionary";
2481 }
2482
2483 trx->op_info = "";
2484
2485 return(err);
2486}
2487
2488/** Assign a new table ID and put it into the table cache and the transaction.
2489@param[in,out] table Table that needs an ID
2490@param[in,out] trx Transaction */
2491void
2492dict_table_assign_new_id(
2493 dict_table_t* table,
2494 trx_t* trx)
2495{
2496 dict_hdr_get_new_id(&table->id, NULL, NULL, table, false);
2497 trx->table_id = table->id;
2498}
2499