1 /*****************************************************************************
2
3 Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25 *****************************************************************************/
26
27 /**************************************************//**
28 @file dict/dict0crea.cc
29 Database object creation
30
31 Created 1/8/1996 Heikki Tuuri
32 *******************************************************/
33
34 #include "dict0crea.h"
35
36 #ifdef UNIV_NONINL
37 #include "dict0crea.ic"
38 #endif
39
40 #include "btr0pcur.h"
41 #include "btr0btr.h"
42 #include "page0page.h"
43 #include "mach0data.h"
44 #include "dict0boot.h"
45 #include "dict0dict.h"
46 #include "que0que.h"
47 #include "row0ins.h"
48 #include "row0mysql.h"
49 #include "pars0pars.h"
50 #include "trx0roll.h"
51 #include "usr0sess.h"
52 #include "ut0vec.h"
53 #include "dict0priv.h"
54 #include "fts0priv.h"
55 #include "ha_prototypes.h"
56
57 /*****************************************************************//**
58 Based on a table object, this function builds the entry to be inserted
59 in the SYS_TABLES system table.
60 @return the tuple which should be inserted */
61 static
62 dtuple_t*
dict_create_sys_tables_tuple(const dict_table_t * table,mem_heap_t * heap)63 dict_create_sys_tables_tuple(
64 /*=========================*/
65 const dict_table_t* table, /*!< in: table */
66 mem_heap_t* heap) /*!< in: memory heap from
67 which the memory for the built
68 tuple is allocated */
69 {
70 dict_table_t* sys_tables;
71 dtuple_t* entry;
72 dfield_t* dfield;
73 byte* ptr;
74 ulint type;
75
76 ut_ad(table);
77 ut_ad(heap);
78
79 sys_tables = dict_sys->sys_tables;
80
81 entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS);
82
83 dict_table_copy_types(entry, sys_tables);
84
85 /* 0: NAME -----------------------------*/
86 dfield = dtuple_get_nth_field(
87 entry, DICT_COL__SYS_TABLES__NAME);
88
89 dfield_set_data(dfield, table->name, ut_strlen(table->name));
90
91 /* 1: DB_TRX_ID added later */
92 /* 2: DB_ROLL_PTR added later */
93 /* 3: ID -------------------------------*/
94 dfield = dtuple_get_nth_field(
95 entry, DICT_COL__SYS_TABLES__ID);
96
97 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
98 mach_write_to_8(ptr, table->id);
99
100 dfield_set_data(dfield, ptr, 8);
101
102 /* 4: N_COLS ---------------------------*/
103 dfield = dtuple_get_nth_field(
104 entry, DICT_COL__SYS_TABLES__N_COLS);
105
106 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
107 mach_write_to_4(ptr, table->n_def
108 | ((table->flags & DICT_TF_COMPACT) << 31));
109 dfield_set_data(dfield, ptr, 4);
110
111 /* 5: TYPE (table flags) -----------------------------*/
112 dfield = dtuple_get_nth_field(
113 entry, DICT_COL__SYS_TABLES__TYPE);
114
115 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
116
117 /* Validate the table flags and convert them to what is saved in
118 SYS_TABLES.TYPE. Table flag values 0 and 1 are both written to
119 SYS_TABLES.TYPE as 1. */
120 type = dict_tf_to_sys_tables_type(table->flags);
121 mach_write_to_4(ptr, type);
122
123 dfield_set_data(dfield, ptr, 4);
124
125 /* 6: MIX_ID (obsolete) ---------------------------*/
126 dfield = dtuple_get_nth_field(
127 entry, DICT_COL__SYS_TABLES__MIX_ID);
128
129 ptr = static_cast<byte*>(mem_heap_zalloc(heap, 8));
130
131 dfield_set_data(dfield, ptr, 8);
132
133 /* 7: MIX_LEN (additional flags) --------------------------*/
134 dfield = dtuple_get_nth_field(
135 entry, DICT_COL__SYS_TABLES__MIX_LEN);
136
137 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
138 /* Be sure all non-used bits are zero. */
139 ut_a(!(table->flags2 & ~DICT_TF2_BIT_MASK));
140 mach_write_to_4(ptr, table->flags2);
141
142 dfield_set_data(dfield, ptr, 4);
143
144 /* 8: CLUSTER_NAME ---------------------*/
145 dfield = dtuple_get_nth_field(
146 entry, DICT_COL__SYS_TABLES__CLUSTER_ID);
147 dfield_set_null(dfield); /* not supported */
148
149 /* 9: SPACE ----------------------------*/
150 dfield = dtuple_get_nth_field(
151 entry, DICT_COL__SYS_TABLES__SPACE);
152
153 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
154 mach_write_to_4(ptr, table->space);
155
156 dfield_set_data(dfield, ptr, 4);
157 /*----------------------------------*/
158
159 return(entry);
160 }
161
162 /*****************************************************************//**
163 Based on a table object, this function builds the entry to be inserted
164 in the SYS_COLUMNS system table.
165 @return the tuple which should be inserted */
166 static
167 dtuple_t*
dict_create_sys_columns_tuple(const dict_table_t * table,ulint i,mem_heap_t * heap)168 dict_create_sys_columns_tuple(
169 /*==========================*/
170 const dict_table_t* table, /*!< in: table */
171 ulint i, /*!< in: column number */
172 mem_heap_t* heap) /*!< in: memory heap from
173 which the memory for the built
174 tuple is allocated */
175 {
176 dict_table_t* sys_columns;
177 dtuple_t* entry;
178 const dict_col_t* column;
179 dfield_t* dfield;
180 byte* ptr;
181 const char* col_name;
182
183 ut_ad(table);
184 ut_ad(heap);
185
186 column = dict_table_get_nth_col(table, i);
187
188 sys_columns = dict_sys->sys_columns;
189
190 entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
191
192 dict_table_copy_types(entry, sys_columns);
193
194 /* 0: TABLE_ID -----------------------*/
195 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__TABLE_ID);
196
197 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
198 mach_write_to_8(ptr, table->id);
199
200 dfield_set_data(dfield, ptr, 8);
201
202 /* 1: POS ----------------------------*/
203 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__POS);
204
205 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
206 mach_write_to_4(ptr, i);
207
208 dfield_set_data(dfield, ptr, 4);
209
210 /* 2: DB_TRX_ID added later */
211 /* 3: DB_ROLL_PTR added later */
212 /* 4: NAME ---------------------------*/
213 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__NAME);
214
215 col_name = dict_table_get_col_name(table, i);
216 dfield_set_data(dfield, col_name, ut_strlen(col_name));
217
218 /* 5: MTYPE --------------------------*/
219 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__MTYPE);
220
221 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
222 mach_write_to_4(ptr, column->mtype);
223
224 dfield_set_data(dfield, ptr, 4);
225
226 /* 6: PRTYPE -------------------------*/
227 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__PRTYPE);
228
229 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
230 mach_write_to_4(ptr, column->prtype);
231
232 dfield_set_data(dfield, ptr, 4);
233
234 /* 7: LEN ----------------------------*/
235 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__LEN);
236
237 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
238 mach_write_to_4(ptr, column->len);
239
240 dfield_set_data(dfield, ptr, 4);
241
242 /* 8: PREC ---------------------------*/
243 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_COLUMNS__PREC);
244
245 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
246 mach_write_to_4(ptr, 0/* unused */);
247
248 dfield_set_data(dfield, ptr, 4);
249 /*---------------------------------*/
250
251 return(entry);
252 }
253
254 /***************************************************************//**
255 Builds a table definition to insert.
256 @return DB_SUCCESS or error code */
257 static MY_ATTRIBUTE((nonnull, warn_unused_result))
258 dberr_t
dict_build_table_def_step(que_thr_t * thr,tab_node_t * node)259 dict_build_table_def_step(
260 /*======================*/
261 que_thr_t* thr, /*!< in: query thread */
262 tab_node_t* node) /*!< in: table create node */
263 {
264 dict_table_t* table;
265 dtuple_t* row;
266 dberr_t error;
267 const char* path;
268 mtr_t mtr;
269 ulint space = 0;
270 bool use_tablespace;
271
272 ut_ad(mutex_own(&(dict_sys->mutex)));
273
274 table = node->table;
275 use_tablespace = DICT_TF2_FLAG_IS_SET(table, DICT_TF2_USE_TABLESPACE);
276
277 dict_hdr_get_new_id(&table->id, NULL, NULL);
278
279 thr_get_trx(thr)->table_id = table->id;
280
281 /* Always set this bit for all new created tables */
282 DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME);
283 DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
284 DICT_TF2_FLAG_UNSET(table,
285 DICT_TF2_FTS_AUX_HEX_NAME););
286
287 if (use_tablespace) {
288 /* This table will not use the system tablespace.
289 Get a new space id. */
290 dict_hdr_get_new_id(NULL, NULL, &space);
291
292 DBUG_EXECUTE_IF(
293 "ib_create_table_fail_out_of_space_ids",
294 space = ULINT_UNDEFINED;
295 );
296
297 if (UNIV_UNLIKELY(space == ULINT_UNDEFINED)) {
298 return(DB_ERROR);
299 }
300
301 /* We create a new single-table tablespace for the table.
302 We initially let it be 4 pages:
303 - page 0 is the fsp header and an extent descriptor page,
304 - page 1 is an ibuf bitmap page,
305 - page 2 is the first inode page,
306 - page 3 will contain the root of the clustered index of the
307 table we create here. */
308
309 path = table->data_dir_path ? table->data_dir_path
310 : table->dir_path_of_temp_table;
311
312 ut_ad(dict_table_get_format(table) <= UNIV_FORMAT_MAX);
313 ut_ad(!dict_table_zip_size(table)
314 || dict_table_get_format(table) >= UNIV_FORMAT_B);
315
316 error = fil_create_new_single_table_tablespace(
317 space, table->name, path,
318 dict_tf_to_fsp_flags(table->flags),
319 table->flags2,
320 FIL_IBD_FILE_INITIAL_SIZE);
321
322 table->space = (unsigned int) space;
323
324 if (error != DB_SUCCESS) {
325
326 return(error);
327 }
328
329 mtr_start(&mtr);
330
331 fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
332
333 mtr_commit(&mtr);
334 } else {
335 /* Create in the system tablespace: disallow Barracuda
336 features by keeping only the first bit which says whether
337 the row format is redundant or compact */
338 table->flags &= DICT_TF_COMPACT;
339 }
340
341 row = dict_create_sys_tables_tuple(table, node->heap);
342
343 ins_node_set_new_row(node->tab_def, row);
344
345 return(DB_SUCCESS);
346 }
347
348 /***************************************************************//**
349 Builds a column definition to insert. */
350 static
351 void
dict_build_col_def_step(tab_node_t * node)352 dict_build_col_def_step(
353 /*====================*/
354 tab_node_t* node) /*!< in: table create node */
355 {
356 dtuple_t* row;
357
358 row = dict_create_sys_columns_tuple(node->table, node->col_no,
359 node->heap);
360 ins_node_set_new_row(node->col_def, row);
361 }
362
363 /*****************************************************************//**
364 Based on an index object, this function builds the entry to be inserted
365 in the SYS_INDEXES system table.
366 @return the tuple which should be inserted */
367 static
368 dtuple_t*
dict_create_sys_indexes_tuple(const dict_index_t * index,mem_heap_t * heap)369 dict_create_sys_indexes_tuple(
370 /*==========================*/
371 const dict_index_t* index, /*!< in: index */
372 mem_heap_t* heap) /*!< in: memory heap from
373 which the memory for the built
374 tuple is allocated */
375 {
376 dict_table_t* sys_indexes;
377 dict_table_t* table;
378 dtuple_t* entry;
379 dfield_t* dfield;
380 byte* ptr;
381
382 ut_ad(mutex_own(&(dict_sys->mutex)));
383 ut_ad(index);
384 ut_ad(heap);
385
386 sys_indexes = dict_sys->sys_indexes;
387
388 table = dict_table_get_low(index->table_name);
389
390 entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
391
392 dict_table_copy_types(entry, sys_indexes);
393
394 /* 0: TABLE_ID -----------------------*/
395 dfield = dtuple_get_nth_field(
396 entry, DICT_COL__SYS_INDEXES__TABLE_ID);
397
398 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
399 mach_write_to_8(ptr, table->id);
400
401 dfield_set_data(dfield, ptr, 8);
402
403 /* 1: ID ----------------------------*/
404 dfield = dtuple_get_nth_field(
405 entry, DICT_COL__SYS_INDEXES__ID);
406
407 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
408 mach_write_to_8(ptr, index->id);
409
410 dfield_set_data(dfield, ptr, 8);
411
412 /* 2: DB_TRX_ID added later */
413 /* 3: DB_ROLL_PTR added later */
414 /* 4: NAME --------------------------*/
415 dfield = dtuple_get_nth_field(
416 entry, DICT_COL__SYS_INDEXES__NAME);
417
418 dfield_set_data(dfield, index->name, ut_strlen(index->name));
419
420 /* 5: N_FIELDS ----------------------*/
421 dfield = dtuple_get_nth_field(
422 entry, DICT_COL__SYS_INDEXES__N_FIELDS);
423
424 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
425 mach_write_to_4(ptr, index->n_fields);
426
427 dfield_set_data(dfield, ptr, 4);
428
429 /* 6: TYPE --------------------------*/
430 dfield = dtuple_get_nth_field(
431 entry, DICT_COL__SYS_INDEXES__TYPE);
432
433 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
434 mach_write_to_4(ptr, index->type);
435
436 dfield_set_data(dfield, ptr, 4);
437
438 /* 7: SPACE --------------------------*/
439
440 dfield = dtuple_get_nth_field(
441 entry, DICT_COL__SYS_INDEXES__SPACE);
442
443 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
444 mach_write_to_4(ptr, index->space);
445
446 dfield_set_data(dfield, ptr, 4);
447
448 /* 8: PAGE_NO --------------------------*/
449
450 dfield = dtuple_get_nth_field(
451 entry, DICT_COL__SYS_INDEXES__PAGE_NO);
452
453 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
454 mach_write_to_4(ptr, FIL_NULL);
455
456 dfield_set_data(dfield, ptr, 4);
457
458 /*--------------------------------*/
459
460 return(entry);
461 }
462
463 /*****************************************************************//**
464 Based on an index object, this function builds the entry to be inserted
465 in the SYS_FIELDS system table.
466 @return the tuple which should be inserted */
467 static
468 dtuple_t*
dict_create_sys_fields_tuple(const dict_index_t * index,ulint fld_no,mem_heap_t * heap)469 dict_create_sys_fields_tuple(
470 /*=========================*/
471 const dict_index_t* index, /*!< in: index */
472 ulint fld_no, /*!< in: field number */
473 mem_heap_t* heap) /*!< in: memory heap from
474 which the memory for the built
475 tuple is allocated */
476 {
477 dict_table_t* sys_fields;
478 dtuple_t* entry;
479 dict_field_t* field;
480 dfield_t* dfield;
481 byte* ptr;
482 ibool index_contains_column_prefix_field = FALSE;
483 ulint j;
484
485 ut_ad(index);
486 ut_ad(heap);
487
488 for (j = 0; j < index->n_fields; j++) {
489 if (dict_index_get_nth_field(index, j)->prefix_len > 0) {
490 index_contains_column_prefix_field = TRUE;
491 break;
492 }
493 }
494
495 field = dict_index_get_nth_field(index, fld_no);
496
497 sys_fields = dict_sys->sys_fields;
498
499 entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
500
501 dict_table_copy_types(entry, sys_fields);
502
503 /* 0: INDEX_ID -----------------------*/
504 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__INDEX_ID);
505
506 ptr = static_cast<byte*>(mem_heap_alloc(heap, 8));
507 mach_write_to_8(ptr, index->id);
508
509 dfield_set_data(dfield, ptr, 8);
510
511 /* 1: POS; FIELD NUMBER & PREFIX LENGTH -----------------------*/
512
513 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__POS);
514
515 ptr = static_cast<byte*>(mem_heap_alloc(heap, 4));
516
517 if (index_contains_column_prefix_field) {
518 /* If there are column prefix fields in the index, then
519 we store the number of the field to the 2 HIGH bytes
520 and the prefix length to the 2 low bytes, */
521
522 mach_write_to_4(ptr, (fld_no << 16) + field->prefix_len);
523 } else {
524 /* Else we store the number of the field to the 2 LOW bytes.
525 This is to keep the storage format compatible with
526 InnoDB versions < 4.0.14. */
527
528 mach_write_to_4(ptr, fld_no);
529 }
530
531 dfield_set_data(dfield, ptr, 4);
532
533 /* 2: DB_TRX_ID added later */
534 /* 3: DB_ROLL_PTR added later */
535 /* 4: COL_NAME -------------------------*/
536 dfield = dtuple_get_nth_field(entry, DICT_COL__SYS_FIELDS__COL_NAME);
537
538 dfield_set_data(dfield, field->name,
539 ut_strlen(field->name));
540 /*---------------------------------*/
541
542 return(entry);
543 }
544
545 /*****************************************************************//**
546 Creates the tuple with which the index entry is searched for writing the index
547 tree root page number, if such a tree is created.
548 @return the tuple for search */
549 static
550 dtuple_t*
dict_create_search_tuple(const dtuple_t * tuple,mem_heap_t * heap)551 dict_create_search_tuple(
552 /*=====================*/
553 const dtuple_t* tuple, /*!< in: the tuple inserted in the SYS_INDEXES
554 table */
555 mem_heap_t* heap) /*!< in: memory heap from which the memory for
556 the built tuple is allocated */
557 {
558 dtuple_t* search_tuple;
559 const dfield_t* field1;
560 dfield_t* field2;
561
562 ut_ad(tuple && heap);
563
564 search_tuple = dtuple_create(heap, 2);
565
566 field1 = dtuple_get_nth_field(tuple, 0);
567 field2 = dtuple_get_nth_field(search_tuple, 0);
568
569 dfield_copy(field2, field1);
570
571 field1 = dtuple_get_nth_field(tuple, 1);
572 field2 = dtuple_get_nth_field(search_tuple, 1);
573
574 dfield_copy(field2, field1);
575
576 ut_ad(dtuple_validate(search_tuple));
577
578 return(search_tuple);
579 }
580
581 /***************************************************************//**
582 Builds an index definition row to insert.
583 @return DB_SUCCESS or error code */
584 static MY_ATTRIBUTE((nonnull, warn_unused_result))
585 dberr_t
dict_build_index_def_step(que_thr_t * thr,ind_node_t * node)586 dict_build_index_def_step(
587 /*======================*/
588 que_thr_t* thr, /*!< in: query thread */
589 ind_node_t* node) /*!< in: index create node */
590 {
591 dict_table_t* table;
592 dict_index_t* index;
593 dtuple_t* row;
594 trx_t* trx;
595
596 ut_ad(mutex_own(&(dict_sys->mutex)));
597
598 trx = thr_get_trx(thr);
599
600 index = node->index;
601
602 table = dict_table_get_low(index->table_name);
603
604 if (table == NULL) {
605 return(DB_TABLE_NOT_FOUND);
606 }
607
608 if (!trx->table_id) {
609 /* Record only the first table id. */
610 trx->table_id = table->id;
611 }
612
613 node->table = table;
614
615 ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
616 || dict_index_is_clust(index));
617
618 dict_hdr_get_new_id(NULL, &index->id, NULL);
619
620 /* Inherit the space id from the table; we store all indexes of a
621 table in the same tablespace */
622
623 index->space = table->space;
624 node->page_no = FIL_NULL;
625 row = dict_create_sys_indexes_tuple(index, node->heap);
626 node->ind_row = row;
627
628 ins_node_set_new_row(node->ind_def, row);
629
630 /* Note that the index was created by this transaction. */
631 index->trx_id = trx->id;
632 ut_ad(table->def_trx_id <= trx->id);
633 table->def_trx_id = trx->id;
634
635 return(DB_SUCCESS);
636 }
637
638 /***************************************************************//**
639 Builds a field definition row to insert. */
640 static
641 void
dict_build_field_def_step(ind_node_t * node)642 dict_build_field_def_step(
643 /*======================*/
644 ind_node_t* node) /*!< in: index create node */
645 {
646 dict_index_t* index;
647 dtuple_t* row;
648
649 index = node->index;
650
651 row = dict_create_sys_fields_tuple(index, node->field_no, node->heap);
652
653 ins_node_set_new_row(node->field_def, row);
654 }
655
656 /***************************************************************//**
657 Creates an index tree for the index if it is not a member of a cluster.
658 @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
659 static MY_ATTRIBUTE((nonnull, warn_unused_result))
660 dberr_t
dict_create_index_tree_step(ind_node_t * node)661 dict_create_index_tree_step(
662 /*========================*/
663 ind_node_t* node) /*!< in: index create node */
664 {
665 dict_index_t* index;
666 dict_table_t* sys_indexes;
667 dtuple_t* search_tuple;
668 btr_pcur_t pcur;
669 mtr_t mtr;
670
671 ut_ad(mutex_own(&(dict_sys->mutex)));
672
673 index = node->index;
674
675 sys_indexes = dict_sys->sys_indexes;
676
677 if (index->type == DICT_FTS) {
678 /* FTS index does not need an index tree */
679 return(DB_SUCCESS);
680 }
681
682 /* Run a mini-transaction in which the index tree is allocated for
683 the index and its root address is written to the index entry in
684 sys_indexes */
685
686 mtr_start(&mtr);
687
688 search_tuple = dict_create_search_tuple(node->ind_row, node->heap);
689
690 btr_pcur_open(UT_LIST_GET_FIRST(sys_indexes->indexes),
691 search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
692 &pcur, &mtr);
693
694 btr_pcur_move_to_next_user_rec(&pcur, &mtr);
695
696
697 dberr_t err = DB_SUCCESS;
698 ulint zip_size = dict_table_zip_size(index->table);
699
700 if (node->index->table->ibd_file_missing
701 || dict_table_is_discarded(node->index->table)) {
702
703 node->page_no = FIL_NULL;
704 } else {
705 node->page_no = btr_create(
706 index->type, index->space, zip_size,
707 index->id, index, &mtr);
708
709 if (node->page_no == FIL_NULL) {
710 err = DB_OUT_OF_FILE_SPACE;
711 }
712
713 DBUG_EXECUTE_IF("ib_import_create_index_failure_1",
714 node->page_no = FIL_NULL;
715 err = DB_OUT_OF_FILE_SPACE; );
716 }
717
718 page_rec_write_field(
719 btr_pcur_get_rec(&pcur), DICT_FLD__SYS_INDEXES__PAGE_NO,
720 node->page_no, &mtr);
721
722 btr_pcur_close(&pcur);
723
724 mtr_commit(&mtr);
725
726 return(err);
727 }
728
729 /*******************************************************************//**
730 Drops the index tree associated with a row in SYS_INDEXES table. */
731 UNIV_INTERN
732 void
dict_drop_index_tree(rec_t * rec,mtr_t * mtr)733 dict_drop_index_tree(
734 /*=================*/
735 rec_t* rec, /*!< in/out: record in the clustered index
736 of SYS_INDEXES table */
737 mtr_t* mtr) /*!< in: mtr having the latch on the record page */
738 {
739 ulint root_page_no;
740 ulint space;
741 ulint zip_size;
742 const byte* ptr;
743 ulint len;
744
745 ut_ad(mutex_own(&(dict_sys->mutex)));
746 ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
747 ptr = rec_get_nth_field_old(
748 rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
749
750 ut_ad(len == 4);
751
752 root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
753
754 if (root_page_no == FIL_NULL) {
755 /* The tree has already been freed */
756
757 return;
758 }
759
760 ptr = rec_get_nth_field_old(
761 rec, DICT_FLD__SYS_INDEXES__SPACE, &len);
762
763 ut_ad(len == 4);
764
765 space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
766 zip_size = fil_space_get_zip_size(space);
767
768 if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
769 /* It is a single table tablespace and the .ibd file is
770 missing: do nothing */
771
772 return;
773 }
774
775 /* We free all the pages but the root page first; this operation
776 may span several mini-transactions */
777
778 btr_free_but_not_root(space, zip_size, root_page_no);
779
780 /* Then we free the root page in the same mini-transaction where
781 we write FIL_NULL to the appropriate field in the SYS_INDEXES
782 record: this mini-transaction marks the B-tree totally freed */
783
784 /* printf("Dropping index tree in space %lu root page %lu\n", space,
785 root_page_no); */
786 btr_free_root(space, zip_size, root_page_no, mtr);
787
788 page_rec_write_field(rec, DICT_FLD__SYS_INDEXES__PAGE_NO,
789 FIL_NULL, mtr);
790 }
791
792 /*******************************************************************//**
793 Truncates the index tree associated with a row in SYS_INDEXES table.
794 @return new root page number, or FIL_NULL on failure */
795 UNIV_INTERN
796 ulint
dict_truncate_index_tree(dict_table_t * table,ulint space,btr_pcur_t * pcur,mtr_t * mtr)797 dict_truncate_index_tree(
798 /*=====================*/
799 dict_table_t* table, /*!< in: the table the index belongs to */
800 ulint space, /*!< in: 0=truncate,
801 nonzero=create the index tree in the
802 given tablespace */
803 btr_pcur_t* pcur, /*!< in/out: persistent cursor pointing to
804 record in the clustered index of
805 SYS_INDEXES table. The cursor may be
806 repositioned in this call. */
807 mtr_t* mtr) /*!< in: mtr having the latch
808 on the record page. The mtr may be
809 committed and restarted in this call. */
810 {
811 ulint root_page_no;
812 ibool drop = !space;
813 ulint zip_size;
814 ulint type;
815 index_id_t index_id;
816 rec_t* rec;
817 const byte* ptr;
818 ulint len;
819 dict_index_t* index;
820 bool has_been_dropped = false;
821
822 ut_ad(mutex_own(&(dict_sys->mutex)));
823 ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
824 rec = btr_pcur_get_rec(pcur);
825 ptr = rec_get_nth_field_old(
826 rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
827
828 ut_ad(len == 4);
829
830 root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
831
832 if (drop && root_page_no == FIL_NULL) {
833 has_been_dropped = true;
834 drop = FALSE;
835 }
836
837 ptr = rec_get_nth_field_old(
838 rec, DICT_FLD__SYS_INDEXES__SPACE, &len);
839
840 ut_ad(len == 4);
841
842 if (drop) {
843 space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
844 }
845
846 zip_size = fil_space_get_zip_size(space);
847
848 if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
849 /* It is a single table tablespace and the .ibd file is
850 missing: do nothing */
851
852 ut_print_timestamp(stderr);
853 fprintf(stderr, " InnoDB: Trying to TRUNCATE"
854 " a missing .ibd file of table %s!\n", table->name);
855 return(FIL_NULL);
856 }
857
858 ptr = rec_get_nth_field_old(
859 rec, DICT_FLD__SYS_INDEXES__TYPE, &len);
860 ut_ad(len == 4);
861 type = mach_read_from_4(ptr);
862
863 ptr = rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__ID, &len);
864 ut_ad(len == 8);
865 index_id = mach_read_from_8(ptr);
866
867 if (!drop) {
868
869 goto create;
870 }
871
872 /* We free all the pages but the root page first; this operation
873 may span several mini-transactions */
874
875 btr_free_but_not_root(space, zip_size, root_page_no);
876
877 /* Then we free the root page in the same mini-transaction where
878 we create the b-tree and write its new root page number to the
879 appropriate field in the SYS_INDEXES record: this mini-transaction
880 marks the B-tree totally truncated */
881
882 btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, NULL, mtr);
883
884 btr_free_root(space, zip_size, root_page_no, mtr);
885 create:
886 /* We will temporarily write FIL_NULL to the PAGE_NO field
887 in SYS_INDEXES, so that the database will not get into an
888 inconsistent state in case it crashes between the mtr_commit()
889 below and the following mtr_commit() call. */
890 page_rec_write_field(rec, DICT_FLD__SYS_INDEXES__PAGE_NO,
891 FIL_NULL, mtr);
892
893 /* We will need to commit the mini-transaction in order to avoid
894 deadlocks in the btr_create() call, because otherwise we would
895 be freeing and allocating pages in the same mini-transaction. */
896 btr_pcur_store_position(pcur, mtr);
897 mtr_commit(mtr);
898
899 mtr_start(mtr);
900 btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
901
902 /* Find the index corresponding to this SYS_INDEXES record. */
903 for (index = UT_LIST_GET_FIRST(table->indexes);
904 index;
905 index = UT_LIST_GET_NEXT(indexes, index)) {
906 if (index->id == index_id) {
907 if (index->type & DICT_FTS) {
908 return(FIL_NULL);
909 } else {
910 if (has_been_dropped) {
911 fprintf(stderr, " InnoDB: Trying to"
912 " TRUNCATE a missing index of"
913 " table %s!\n",
914 index->table->name);
915 }
916
917 root_page_no = btr_create(type, space, zip_size,
918 index_id, index, mtr);
919 index->page = (unsigned int) root_page_no;
920 return(root_page_no);
921 }
922 }
923 }
924
925 ut_print_timestamp(stderr);
926 fprintf(stderr,
927 " InnoDB: Index %llu of table %s is missing\n"
928 "InnoDB: from the data dictionary during TRUNCATE!\n",
929 (ullint) index_id,
930 table->name);
931
932 return(FIL_NULL);
933 }
934
935 /*********************************************************************//**
936 Creates a table create graph.
937 @return own: table create node */
938 UNIV_INTERN
939 tab_node_t*
tab_create_graph_create(dict_table_t * table,mem_heap_t * heap,bool commit)940 tab_create_graph_create(
941 /*====================*/
942 dict_table_t* table, /*!< in: table to create, built as a memory data
943 structure */
944 mem_heap_t* heap, /*!< in: heap where created */
945 bool commit) /*!< in: true if the commit node should be
946 added to the query graph */
947 {
948 tab_node_t* node;
949
950 node = static_cast<tab_node_t*>(
951 mem_heap_alloc(heap, sizeof(tab_node_t)));
952
953 node->common.type = QUE_NODE_CREATE_TABLE;
954
955 node->table = table;
956
957 node->state = TABLE_BUILD_TABLE_DEF;
958 node->heap = mem_heap_create(256);
959
960 node->tab_def = ins_node_create(INS_DIRECT, dict_sys->sys_tables,
961 heap);
962 node->tab_def->common.parent = node;
963
964 node->col_def = ins_node_create(INS_DIRECT, dict_sys->sys_columns,
965 heap);
966 node->col_def->common.parent = node;
967
968 if (commit) {
969 node->commit_node = trx_commit_node_create(heap);
970 node->commit_node->common.parent = node;
971 } else {
972 node->commit_node = 0;
973 }
974
975 return(node);
976 }
977
978 /*********************************************************************//**
979 Creates an index create graph.
980 @return own: index create node */
981 UNIV_INTERN
982 ind_node_t*
ind_create_graph_create(dict_index_t * index,mem_heap_t * heap,bool commit)983 ind_create_graph_create(
984 /*====================*/
985 dict_index_t* index, /*!< in: index to create, built as a memory data
986 structure */
987 mem_heap_t* heap, /*!< in: heap where created */
988 bool commit) /*!< in: true if the commit node should be
989 added to the query graph */
990 {
991 ind_node_t* node;
992
993 node = static_cast<ind_node_t*>(
994 mem_heap_alloc(heap, sizeof(ind_node_t)));
995
996 node->common.type = QUE_NODE_CREATE_INDEX;
997
998 node->index = index;
999
1000 node->state = INDEX_BUILD_INDEX_DEF;
1001 node->page_no = FIL_NULL;
1002 node->heap = mem_heap_create(256);
1003
1004 node->ind_def = ins_node_create(INS_DIRECT,
1005 dict_sys->sys_indexes, heap);
1006 node->ind_def->common.parent = node;
1007
1008 node->field_def = ins_node_create(INS_DIRECT,
1009 dict_sys->sys_fields, heap);
1010 node->field_def->common.parent = node;
1011
1012 if (commit) {
1013 node->commit_node = trx_commit_node_create(heap);
1014 node->commit_node->common.parent = node;
1015 } else {
1016 node->commit_node = 0;
1017 }
1018
1019 return(node);
1020 }
1021
1022 /***********************************************************//**
1023 Creates a table. This is a high-level function used in SQL execution graphs.
1024 @return query thread to run next or NULL */
1025 UNIV_INTERN
1026 que_thr_t*
dict_create_table_step(que_thr_t * thr)1027 dict_create_table_step(
1028 /*===================*/
1029 que_thr_t* thr) /*!< in: query thread */
1030 {
1031 tab_node_t* node;
1032 dberr_t err = DB_ERROR;
1033 trx_t* trx;
1034
1035 ut_ad(thr);
1036 ut_ad(mutex_own(&(dict_sys->mutex)));
1037
1038 trx = thr_get_trx(thr);
1039
1040 node = static_cast<tab_node_t*>(thr->run_node);
1041
1042 ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_TABLE);
1043
1044 if (thr->prev_node == que_node_get_parent(node)) {
1045 node->state = TABLE_BUILD_TABLE_DEF;
1046 }
1047
1048 if (node->state == TABLE_BUILD_TABLE_DEF) {
1049
1050 /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
1051
1052 err = dict_build_table_def_step(thr, node);
1053
1054 if (err != DB_SUCCESS) {
1055
1056 goto function_exit;
1057 }
1058
1059 node->state = TABLE_BUILD_COL_DEF;
1060 node->col_no = 0;
1061
1062 thr->run_node = node->tab_def;
1063
1064 return(thr);
1065 }
1066
1067 if (node->state == TABLE_BUILD_COL_DEF) {
1068
1069 if (node->col_no < (node->table)->n_def) {
1070
1071 dict_build_col_def_step(node);
1072
1073 node->col_no++;
1074
1075 thr->run_node = node->col_def;
1076
1077 return(thr);
1078 } else {
1079 node->state = TABLE_COMMIT_WORK;
1080 }
1081 }
1082
1083 if (node->state == TABLE_COMMIT_WORK) {
1084
1085 /* Table was correctly defined: do NOT commit the transaction
1086 (CREATE TABLE does NOT do an implicit commit of the current
1087 transaction) */
1088
1089 node->state = TABLE_ADD_TO_CACHE;
1090
1091 /* thr->run_node = node->commit_node;
1092
1093 return(thr); */
1094 }
1095
1096 if (node->state == TABLE_ADD_TO_CACHE) {
1097
1098 dict_table_add_to_cache(node->table, TRUE, node->heap);
1099
1100 err = DB_SUCCESS;
1101 }
1102
1103 function_exit:
1104 trx->error_state = err;
1105
1106 if (err == DB_SUCCESS) {
1107 /* Ok: do nothing */
1108
1109 } else if (err == DB_LOCK_WAIT) {
1110
1111 return(NULL);
1112 } else {
1113 /* SQL error detected */
1114
1115 return(NULL);
1116 }
1117
1118 thr->run_node = que_node_get_parent(node);
1119
1120 return(thr);
1121 }
1122
1123 /***********************************************************//**
1124 Creates an index. This is a high-level function used in SQL execution
1125 graphs.
1126 @return query thread to run next or NULL */
1127 UNIV_INTERN
1128 que_thr_t*
dict_create_index_step(que_thr_t * thr)1129 dict_create_index_step(
1130 /*===================*/
1131 que_thr_t* thr) /*!< in: query thread */
1132 {
1133 ind_node_t* node;
1134 dberr_t err = DB_ERROR;
1135 trx_t* trx;
1136
1137 ut_ad(thr);
1138 ut_ad(mutex_own(&(dict_sys->mutex)));
1139
1140 trx = thr_get_trx(thr);
1141
1142 node = static_cast<ind_node_t*>(thr->run_node);
1143
1144 ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_INDEX);
1145
1146 if (thr->prev_node == que_node_get_parent(node)) {
1147 node->state = INDEX_BUILD_INDEX_DEF;
1148 }
1149
1150 if (node->state == INDEX_BUILD_INDEX_DEF) {
1151 /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
1152 err = dict_build_index_def_step(thr, node);
1153
1154 if (err != DB_SUCCESS) {
1155
1156 goto function_exit;
1157 }
1158
1159 node->state = INDEX_BUILD_FIELD_DEF;
1160 node->field_no = 0;
1161
1162 thr->run_node = node->ind_def;
1163
1164 return(thr);
1165 }
1166
1167 if (node->state == INDEX_BUILD_FIELD_DEF) {
1168
1169 if (node->field_no < (node->index)->n_fields) {
1170
1171 dict_build_field_def_step(node);
1172
1173 node->field_no++;
1174
1175 thr->run_node = node->field_def;
1176
1177 return(thr);
1178 } else {
1179 node->state = INDEX_ADD_TO_CACHE;
1180 }
1181 }
1182
1183 if (node->state == INDEX_ADD_TO_CACHE) {
1184
1185 index_id_t index_id = node->index->id;
1186
1187 err = dict_index_add_to_cache(
1188 node->table, node->index, FIL_NULL,
1189 trx_is_strict(trx)
1190 || dict_table_get_format(node->table)
1191 >= UNIV_FORMAT_B);
1192
1193 node->index = dict_index_get_if_in_cache_low(index_id);
1194 ut_a(!node->index == (err != DB_SUCCESS));
1195
1196 if (err != DB_SUCCESS) {
1197
1198 goto function_exit;
1199 }
1200
1201 node->state = INDEX_CREATE_INDEX_TREE;
1202 }
1203
1204 if (node->state == INDEX_CREATE_INDEX_TREE) {
1205
1206 err = dict_create_index_tree_step(node);
1207
1208 DBUG_EXECUTE_IF("ib_dict_create_index_tree_fail",
1209 err = DB_OUT_OF_MEMORY;);
1210
1211 if (err != DB_SUCCESS) {
1212 /* If this is a FTS index, we will need to remove
1213 it from fts->cache->indexes list as well */
1214 if ((node->index->type & DICT_FTS)
1215 && node->table->fts) {
1216 fts_index_cache_t* index_cache;
1217
1218 rw_lock_x_lock(
1219 &node->table->fts->cache->init_lock);
1220
1221 index_cache = (fts_index_cache_t*)
1222 fts_find_index_cache(
1223 node->table->fts->cache,
1224 node->index);
1225
1226 if (index_cache->words) {
1227 rbt_free(index_cache->words);
1228 index_cache->words = 0;
1229 }
1230
1231 ib_vector_remove(
1232 node->table->fts->cache->indexes,
1233 *reinterpret_cast<void**>(index_cache));
1234
1235 rw_lock_x_unlock(
1236 &node->table->fts->cache->init_lock);
1237 }
1238
1239 dict_index_remove_from_cache(node->table, node->index);
1240 node->index = NULL;
1241
1242 goto function_exit;
1243 }
1244
1245 node->index->page = node->page_no;
1246 /* These should have been set in
1247 dict_build_index_def_step() and
1248 dict_index_add_to_cache(). */
1249 ut_ad(node->index->trx_id == trx->id);
1250 ut_ad(node->index->table->def_trx_id == trx->id);
1251 node->state = INDEX_COMMIT_WORK;
1252 }
1253
1254 if (node->state == INDEX_COMMIT_WORK) {
1255
1256 /* Index was correctly defined: do NOT commit the transaction
1257 (CREATE INDEX does NOT currently do an implicit commit of
1258 the current transaction) */
1259
1260 node->state = INDEX_CREATE_INDEX_TREE;
1261
1262 /* thr->run_node = node->commit_node;
1263
1264 return(thr); */
1265 }
1266
1267 function_exit:
1268 trx->error_state = err;
1269
1270 if (err == DB_SUCCESS) {
1271 /* Ok: do nothing */
1272
1273 } else if (err == DB_LOCK_WAIT) {
1274
1275 return(NULL);
1276 } else {
1277 /* SQL error detected */
1278
1279 return(NULL);
1280 }
1281
1282 thr->run_node = que_node_get_parent(node);
1283
1284 return(thr);
1285 }
1286
1287 /****************************************************************//**
1288 Check whether a system table exists. Additionally, if it exists,
1289 move it to the non-LRU end of the table LRU list. This is oly used
1290 for system tables that can be upgraded or added to an older database,
1291 which include SYS_FOREIGN, SYS_FOREIGN_COLS, SYS_TABLESPACES and
1292 SYS_DATAFILES.
1293 @return DB_SUCCESS if the sys table exists, DB_CORRUPTION if it exists
1294 but is not current, DB_TABLE_NOT_FOUND if it does not exist*/
1295 static
1296 dberr_t
dict_check_if_system_table_exists(const char * tablename,ulint num_fields,ulint num_indexes)1297 dict_check_if_system_table_exists(
1298 /*==============================*/
1299 const char* tablename, /*!< in: name of table */
1300 ulint num_fields, /*!< in: number of fields */
1301 ulint num_indexes) /*!< in: number of indexes */
1302 {
1303 dict_table_t* sys_table;
1304 dberr_t error = DB_SUCCESS;
1305
1306 ut_a(srv_get_active_thread_type() == SRV_NONE);
1307
1308 mutex_enter(&dict_sys->mutex);
1309
1310 sys_table = dict_table_get_low(tablename);
1311
1312 if (sys_table == NULL) {
1313 error = DB_TABLE_NOT_FOUND;
1314
1315 } else if (UT_LIST_GET_LEN(sys_table->indexes) != num_indexes
1316 || sys_table->n_cols != num_fields) {
1317 error = DB_CORRUPTION;
1318
1319 } else {
1320 /* This table has already been created, and it is OK.
1321 Ensure that it can't be evicted from the table LRU cache. */
1322
1323 dict_table_move_from_lru_to_non_lru(sys_table);
1324 }
1325
1326 mutex_exit(&dict_sys->mutex);
1327
1328 return(error);
1329 }
1330
1331 /****************************************************************//**
1332 Creates the foreign key constraints system tables inside InnoDB
1333 at server bootstrap or server start if they are not found or are
1334 not of the right form.
1335 @return DB_SUCCESS or error code */
1336 UNIV_INTERN
1337 dberr_t
dict_create_or_check_foreign_constraint_tables(void)1338 dict_create_or_check_foreign_constraint_tables(void)
1339 /*================================================*/
1340 {
1341 trx_t* trx;
1342 my_bool srv_file_per_table_backup;
1343 dberr_t err;
1344 dberr_t sys_foreign_err;
1345 dberr_t sys_foreign_cols_err;
1346
1347 ut_a(srv_get_active_thread_type() == SRV_NONE);
1348
1349 /* Note: The master thread has not been started at this point. */
1350
1351
1352 sys_foreign_err = dict_check_if_system_table_exists(
1353 "SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3);
1354 sys_foreign_cols_err = dict_check_if_system_table_exists(
1355 "SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1);
1356
1357 if (sys_foreign_err == DB_SUCCESS
1358 && sys_foreign_cols_err == DB_SUCCESS) {
1359 return(DB_SUCCESS);
1360 }
1361
1362 trx = trx_allocate_for_mysql();
1363
1364 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1365
1366 trx->op_info = "creating foreign key sys tables";
1367
1368 row_mysql_lock_data_dictionary(trx);
1369
1370 /* Check which incomplete table definition to drop. */
1371
1372 if (sys_foreign_err == DB_CORRUPTION) {
1373 ib_logf(IB_LOG_LEVEL_WARN,
1374 "Dropping incompletely created "
1375 "SYS_FOREIGN table.");
1376 row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
1377 }
1378
1379 if (sys_foreign_cols_err == DB_CORRUPTION) {
1380 ib_logf(IB_LOG_LEVEL_WARN,
1381 "Dropping incompletely created "
1382 "SYS_FOREIGN_COLS table.");
1383
1384 row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
1385 }
1386
1387 ib_logf(IB_LOG_LEVEL_WARN,
1388 "Creating foreign key constraint system tables.");
1389
1390 /* NOTE: in dict_load_foreigns we use the fact that
1391 there are 2 secondary indexes on SYS_FOREIGN, and they
1392 are defined just like below */
1393
1394 /* NOTE: when designing InnoDB's foreign key support in 2001, we made
1395 an error and made the table names and the foreign key id of type
1396 'CHAR' (internally, really a VARCHAR). We should have made the type
1397 VARBINARY, like in other InnoDB system tables, to get a clean
1398 design. */
1399
1400 srv_file_per_table_backup = srv_file_per_table;
1401
1402 /* We always want SYSTEM tables to be created inside the system
1403 tablespace. */
1404
1405 srv_file_per_table = 0;
1406
1407 err = que_eval_sql(
1408 NULL,
1409 "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
1410 "BEGIN\n"
1411 "CREATE TABLE\n"
1412 "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
1413 " REF_NAME CHAR, N_COLS INT);\n"
1414 "CREATE UNIQUE CLUSTERED INDEX ID_IND"
1415 " ON SYS_FOREIGN (ID);\n"
1416 "CREATE INDEX FOR_IND"
1417 " ON SYS_FOREIGN (FOR_NAME);\n"
1418 "CREATE INDEX REF_IND"
1419 " ON SYS_FOREIGN (REF_NAME);\n"
1420 "CREATE TABLE\n"
1421 "SYS_FOREIGN_COLS(ID CHAR, POS INT,"
1422 " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
1423 "CREATE UNIQUE CLUSTERED INDEX ID_IND"
1424 " ON SYS_FOREIGN_COLS (ID, POS);\n"
1425 "END;\n",
1426 FALSE, trx);
1427
1428 if (err != DB_SUCCESS) {
1429 ib_logf(IB_LOG_LEVEL_ERROR,
1430 "Creation of SYS_FOREIGN and SYS_FOREIGN_COLS "
1431 "has failed with error %lu. Tablespace is full. "
1432 "Dropping incompletely created tables.",
1433 (ulong) err);
1434
1435 ut_ad(err == DB_OUT_OF_FILE_SPACE
1436 || err == DB_TOO_MANY_CONCURRENT_TRXS);
1437
1438 row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
1439 row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
1440
1441 if (err == DB_OUT_OF_FILE_SPACE) {
1442 err = DB_MUST_GET_MORE_FILE_SPACE;
1443 }
1444 }
1445
1446 trx_commit_for_mysql(trx);
1447
1448 row_mysql_unlock_data_dictionary(trx);
1449
1450 trx_free_for_mysql(trx);
1451
1452 srv_file_per_table = srv_file_per_table_backup;
1453
1454 if (err == DB_SUCCESS) {
1455 ib_logf(IB_LOG_LEVEL_INFO,
1456 "Foreign key constraint system tables created");
1457 }
1458
1459 /* Note: The master thread has not been started at this point. */
1460 /* Confirm and move to the non-LRU part of the table LRU list. */
1461 sys_foreign_err = dict_check_if_system_table_exists(
1462 "SYS_FOREIGN", DICT_NUM_FIELDS__SYS_FOREIGN + 1, 3);
1463 ut_a(sys_foreign_err == DB_SUCCESS);
1464
1465 sys_foreign_cols_err = dict_check_if_system_table_exists(
1466 "SYS_FOREIGN_COLS", DICT_NUM_FIELDS__SYS_FOREIGN_COLS + 1, 1);
1467 ut_a(sys_foreign_cols_err == DB_SUCCESS);
1468
1469 return(err);
1470 }
1471
1472 /****************************************************************//**
1473 Evaluate the given foreign key SQL statement.
1474 @return error code or DB_SUCCESS */
1475 static MY_ATTRIBUTE((nonnull, warn_unused_result))
1476 dberr_t
dict_foreign_eval_sql(pars_info_t * info,const char * sql,const char * name,const char * id,trx_t * trx)1477 dict_foreign_eval_sql(
1478 /*==================*/
1479 pars_info_t* info, /*!< in: info struct */
1480 const char* sql, /*!< in: SQL string to evaluate */
1481 const char* name, /*!< in: table name (for diagnostics) */
1482 const char* id, /*!< in: foreign key id */
1483 trx_t* trx) /*!< in/out: transaction */
1484 {
1485 dberr_t error;
1486 FILE* ef = dict_foreign_err_file;
1487
1488 error = que_eval_sql(info, sql, FALSE, trx);
1489
1490 if (error == DB_DUPLICATE_KEY) {
1491 mutex_enter(&dict_foreign_err_mutex);
1492 rewind(ef);
1493 ut_print_timestamp(ef);
1494 fputs(" Error in foreign key constraint creation for table ",
1495 ef);
1496 ut_print_name(ef, trx, TRUE, name);
1497 fputs(".\nA foreign key constraint of name ", ef);
1498 ut_print_name(ef, trx, TRUE, id);
1499 fputs("\nalready exists."
1500 " (Note that internally InnoDB adds 'databasename'\n"
1501 "in front of the user-defined constraint name.)\n"
1502 "Note that InnoDB's FOREIGN KEY system tables store\n"
1503 "constraint names as case-insensitive, with the\n"
1504 "MySQL standard latin1_swedish_ci collation. If you\n"
1505 "create tables or databases whose names differ only in\n"
1506 "the character case, then collisions in constraint\n"
1507 "names can occur. Workaround: name your constraints\n"
1508 "explicitly with unique names.\n",
1509 ef);
1510
1511 mutex_exit(&dict_foreign_err_mutex);
1512
1513 return(error);
1514 }
1515
1516 if (error != DB_SUCCESS) {
1517 fprintf(stderr,
1518 "InnoDB: Foreign key constraint creation failed:\n"
1519 "InnoDB: internal error number %lu\n", (ulong) error);
1520
1521 mutex_enter(&dict_foreign_err_mutex);
1522 ut_print_timestamp(ef);
1523 fputs(" Internal error in foreign key constraint creation"
1524 " for table ", ef);
1525 ut_print_name(ef, trx, TRUE, name);
1526 fputs(".\n"
1527 "See the MySQL .err log in the datadir"
1528 " for more information.\n", ef);
1529 mutex_exit(&dict_foreign_err_mutex);
1530
1531 return(error);
1532 }
1533
1534 return(DB_SUCCESS);
1535 }
1536
1537 /********************************************************************//**
1538 Add a single foreign key field definition to the data dictionary tables in
1539 the database.
1540 @return error code or DB_SUCCESS */
1541 static MY_ATTRIBUTE((nonnull, warn_unused_result))
1542 dberr_t
dict_create_add_foreign_field_to_dictionary(ulint field_nr,const char * table_name,const dict_foreign_t * foreign,trx_t * trx)1543 dict_create_add_foreign_field_to_dictionary(
1544 /*========================================*/
1545 ulint field_nr, /*!< in: field number */
1546 const char* table_name, /*!< in: table name */
1547 const dict_foreign_t* foreign, /*!< in: foreign */
1548 trx_t* trx) /*!< in/out: transaction */
1549 {
1550 pars_info_t* info = pars_info_create();
1551
1552 pars_info_add_str_literal(info, "id", foreign->id);
1553
1554 pars_info_add_int4_literal(info, "pos", field_nr);
1555
1556 pars_info_add_str_literal(info, "for_col_name",
1557 foreign->foreign_col_names[field_nr]);
1558
1559 pars_info_add_str_literal(info, "ref_col_name",
1560 foreign->referenced_col_names[field_nr]);
1561
1562 return(dict_foreign_eval_sql(
1563 info,
1564 "PROCEDURE P () IS\n"
1565 "BEGIN\n"
1566 "INSERT INTO SYS_FOREIGN_COLS VALUES"
1567 "(:id, :pos, :for_col_name, :ref_col_name);\n"
1568 "END;\n",
1569 table_name, foreign->id, trx));
1570 }
1571
1572 /********************************************************************//**
1573 Add a foreign key definition to the data dictionary tables.
1574 @return error code or DB_SUCCESS */
1575 UNIV_INTERN
1576 dberr_t
dict_create_add_foreign_to_dictionary(const char * name,const dict_foreign_t * foreign,trx_t * trx)1577 dict_create_add_foreign_to_dictionary(
1578 /*==================================*/
1579 const char* name, /*!< in: table name */
1580 const dict_foreign_t* foreign,/*!< in: foreign key */
1581 trx_t* trx) /*!< in/out: dictionary transaction */
1582 {
1583 dberr_t error;
1584 pars_info_t* info = pars_info_create();
1585
1586 pars_info_add_str_literal(info, "id", foreign->id);
1587
1588 pars_info_add_str_literal(info, "for_name", name);
1589
1590 pars_info_add_str_literal(info, "ref_name",
1591 foreign->referenced_table_name);
1592
1593 pars_info_add_int4_literal(info, "n_cols",
1594 foreign->n_fields + (foreign->type << 24));
1595
1596 error = dict_foreign_eval_sql(info,
1597 "PROCEDURE P () IS\n"
1598 "BEGIN\n"
1599 "INSERT INTO SYS_FOREIGN VALUES"
1600 "(:id, :for_name, :ref_name, :n_cols);\n"
1601 "END;\n"
1602 , name, foreign->id, trx);
1603
1604 if (error != DB_SUCCESS) {
1605
1606 return(error);
1607 }
1608
1609 for (ulint i = 0; i < foreign->n_fields; i++) {
1610 error = dict_create_add_foreign_field_to_dictionary(
1611 i, name, foreign, trx);
1612
1613 if (error != DB_SUCCESS) {
1614
1615 return(error);
1616 }
1617 }
1618
1619 return(error);
1620 }
1621
1622 /** Adds the given set of foreign key objects to the dictionary tables
1623 in the database. This function does not modify the dictionary cache. The
1624 caller must ensure that all foreign key objects contain a valid constraint
1625 name in foreign->id.
1626 @param[in] local_fk_set set of foreign key objects, to be added to
1627 the dictionary tables
1628 @param[in] table table to which the foreign key objects in
1629 local_fk_set belong to
1630 @param[in,out] trx transaction
1631 @return error code or DB_SUCCESS */
1632 UNIV_INTERN
1633 dberr_t
dict_create_add_foreigns_to_dictionary(const dict_foreign_set & local_fk_set,const dict_table_t * table,trx_t * trx)1634 dict_create_add_foreigns_to_dictionary(
1635 /*===================================*/
1636 const dict_foreign_set& local_fk_set,
1637 const dict_table_t* table,
1638 trx_t* trx)
1639 {
1640 dict_foreign_t* foreign;
1641 dberr_t error;
1642
1643 ut_ad(mutex_own(&(dict_sys->mutex)));
1644
1645 if (NULL == dict_table_get_low("SYS_FOREIGN")) {
1646 fprintf(stderr,
1647 "InnoDB: table SYS_FOREIGN not found"
1648 " in internal data dictionary\n");
1649
1650 return(DB_ERROR);
1651 }
1652
1653 for (dict_foreign_set::const_iterator it = local_fk_set.begin();
1654 it != local_fk_set.end();
1655 ++it) {
1656
1657 foreign = *it;
1658 ut_ad(foreign->id != NULL);
1659
1660 error = dict_create_add_foreign_to_dictionary(table->name,
1661 foreign, trx);
1662
1663 if (error != DB_SUCCESS) {
1664
1665 return(error);
1666 }
1667 }
1668
1669 trx->op_info = "committing foreign key definitions";
1670
1671 trx_commit(trx);
1672
1673 trx->op_info = "";
1674
1675 return(DB_SUCCESS);
1676 }
1677
1678 /****************************************************************//**
1679 Creates the tablespaces and datafiles system tables inside InnoDB
1680 at server bootstrap or server start if they are not found or are
1681 not of the right form.
1682 @return DB_SUCCESS or error code */
1683 UNIV_INTERN
1684 dberr_t
dict_create_or_check_sys_tablespace(void)1685 dict_create_or_check_sys_tablespace(void)
1686 /*=====================================*/
1687 {
1688 trx_t* trx;
1689 my_bool srv_file_per_table_backup;
1690 dberr_t err;
1691 dberr_t sys_tablespaces_err;
1692 dberr_t sys_datafiles_err;
1693
1694 ut_a(srv_get_active_thread_type() == SRV_NONE);
1695
1696 /* Note: The master thread has not been started at this point. */
1697
1698 sys_tablespaces_err = dict_check_if_system_table_exists(
1699 "SYS_TABLESPACES", DICT_NUM_FIELDS__SYS_TABLESPACES + 1, 1);
1700 sys_datafiles_err = dict_check_if_system_table_exists(
1701 "SYS_DATAFILES", DICT_NUM_FIELDS__SYS_DATAFILES + 1, 1);
1702
1703 if (sys_tablespaces_err == DB_SUCCESS
1704 && sys_datafiles_err == DB_SUCCESS) {
1705 return(DB_SUCCESS);
1706 }
1707
1708 trx = trx_allocate_for_mysql();
1709
1710 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1711
1712 trx->op_info = "creating tablepace and datafile sys tables";
1713
1714 row_mysql_lock_data_dictionary(trx);
1715
1716 /* Check which incomplete table definition to drop. */
1717
1718 if (sys_tablespaces_err == DB_CORRUPTION) {
1719 ib_logf(IB_LOG_LEVEL_WARN,
1720 "Dropping incompletely created "
1721 "SYS_TABLESPACES table.");
1722 row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE);
1723 }
1724
1725 if (sys_datafiles_err == DB_CORRUPTION) {
1726 ib_logf(IB_LOG_LEVEL_WARN,
1727 "Dropping incompletely created "
1728 "SYS_DATAFILES table.");
1729
1730 row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE);
1731 }
1732
1733 ib_logf(IB_LOG_LEVEL_INFO,
1734 "Creating tablespace and datafile system tables.");
1735
1736 /* We always want SYSTEM tables to be created inside the system
1737 tablespace. */
1738 srv_file_per_table_backup = srv_file_per_table;
1739 srv_file_per_table = 0;
1740
1741 err = que_eval_sql(
1742 NULL,
1743 "PROCEDURE CREATE_SYS_TABLESPACE_PROC () IS\n"
1744 "BEGIN\n"
1745 "CREATE TABLE SYS_TABLESPACES(\n"
1746 " SPACE INT, NAME CHAR, FLAGS INT);\n"
1747 "CREATE UNIQUE CLUSTERED INDEX SYS_TABLESPACES_SPACE"
1748 " ON SYS_TABLESPACES (SPACE);\n"
1749 "CREATE TABLE SYS_DATAFILES(\n"
1750 " SPACE INT, PATH CHAR);\n"
1751 "CREATE UNIQUE CLUSTERED INDEX SYS_DATAFILES_SPACE"
1752 " ON SYS_DATAFILES (SPACE);\n"
1753 "END;\n",
1754 FALSE, trx);
1755
1756 if (err != DB_SUCCESS) {
1757 ib_logf(IB_LOG_LEVEL_ERROR,
1758 "Creation of SYS_TABLESPACES and SYS_DATAFILES "
1759 "has failed with error %lu. Tablespace is full. "
1760 "Dropping incompletely created tables.",
1761 (ulong) err);
1762
1763 ut_a(err == DB_OUT_OF_FILE_SPACE
1764 || err == DB_TOO_MANY_CONCURRENT_TRXS);
1765
1766 row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE);
1767 row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE);
1768
1769 if (err == DB_OUT_OF_FILE_SPACE) {
1770 err = DB_MUST_GET_MORE_FILE_SPACE;
1771 }
1772 }
1773
1774 trx_commit_for_mysql(trx);
1775
1776 row_mysql_unlock_data_dictionary(trx);
1777
1778 trx_free_for_mysql(trx);
1779
1780 srv_file_per_table = srv_file_per_table_backup;
1781
1782 if (err == DB_SUCCESS) {
1783 ib_logf(IB_LOG_LEVEL_INFO,
1784 "Tablespace and datafile system tables created.");
1785 }
1786
1787 /* Note: The master thread has not been started at this point. */
1788 /* Confirm and move to the non-LRU part of the table LRU list. */
1789
1790 sys_tablespaces_err = dict_check_if_system_table_exists(
1791 "SYS_TABLESPACES", DICT_NUM_FIELDS__SYS_TABLESPACES + 1, 1);
1792 ut_a(sys_tablespaces_err == DB_SUCCESS);
1793
1794 sys_datafiles_err = dict_check_if_system_table_exists(
1795 "SYS_DATAFILES", DICT_NUM_FIELDS__SYS_DATAFILES + 1, 1);
1796 ut_a(sys_datafiles_err == DB_SUCCESS);
1797
1798 return(err);
1799 }
1800
1801 /********************************************************************//**
1802 Add a single tablespace definition to the data dictionary tables in the
1803 database.
1804 @return error code or DB_SUCCESS */
1805 UNIV_INTERN
1806 dberr_t
dict_create_add_tablespace_to_dictionary(ulint space,const char * name,ulint flags,const char * path,trx_t * trx,bool commit)1807 dict_create_add_tablespace_to_dictionary(
1808 /*=====================================*/
1809 ulint space, /*!< in: tablespace id */
1810 const char* name, /*!< in: tablespace name */
1811 ulint flags, /*!< in: tablespace flags */
1812 const char* path, /*!< in: tablespace path */
1813 trx_t* trx, /*!< in/out: transaction */
1814 bool commit) /*!< in: if true then commit the
1815 transaction */
1816 {
1817 dberr_t error;
1818
1819 pars_info_t* info = pars_info_create();
1820
1821 ut_a(space > TRX_SYS_SPACE);
1822
1823 pars_info_add_int4_literal(info, "space", space);
1824
1825 pars_info_add_str_literal(info, "name", name);
1826
1827 pars_info_add_int4_literal(info, "flags", flags);
1828
1829 pars_info_add_str_literal(info, "path", path);
1830
1831 error = que_eval_sql(info,
1832 "PROCEDURE P () IS\n"
1833 "BEGIN\n"
1834 "INSERT INTO SYS_TABLESPACES VALUES"
1835 "(:space, :name, :flags);\n"
1836 "INSERT INTO SYS_DATAFILES VALUES"
1837 "(:space, :path);\n"
1838 "END;\n",
1839 FALSE, trx);
1840
1841 if (error != DB_SUCCESS) {
1842 return(error);
1843 }
1844
1845 if (commit) {
1846 trx->op_info = "committing tablespace and datafile definition";
1847 trx_commit(trx);
1848 }
1849
1850 trx->op_info = "";
1851
1852 return(error);
1853 }
1854