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