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