1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2012, Facebook Inc.
5 Copyright (c) 2013, 2021, MariaDB Corporation.
6 
7 This program is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free Software
9 Foundation; version 2 of the License.
10 
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along with
16 this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
18 
19 *****************************************************************************/
20 
21 /******************************************************************//**
22 @file dict/dict0mem.cc
23 Data dictionary memory object creation
24 
25 Created 1/8/1996 Heikki Tuuri
26 ***********************************************************************/
27 
28 #include "ha_prototypes.h"
29 #include <mysql_com.h>
30 
31 #include "dict0mem.h"
32 #include "rem0rec.h"
33 #include "data0type.h"
34 #include "mach0data.h"
35 #include "dict0dict.h"
36 #include "fts0priv.h"
37 #include "lock0lock.h"
38 #include "sync0sync.h"
39 #include "row0row.h"
40 #include <iostream>
41 
42 #define	DICT_HEAP_SIZE		100	/*!< initial memory heap size when
43 					creating a table or index object */
44 
45 /** System databases */
46 static const char* innobase_system_databases[] = {
47 	"mysql/",
48 	"information_schema/",
49 	"performance_schema/",
50 	NullS
51 };
52 
53 /** Determine if a table belongs to innobase_system_databases[]
54 @param[in]	name	database_name/table_name
55 @return	whether the database_name is in innobase_system_databases[] */
dict_mem_table_is_system(const char * name)56 static bool dict_mem_table_is_system(const char *name)
57 {
58 	/* table has the following format: database/table
59 	and some system table are of the form SYS_* */
60 	if (!strchr(name, '/')) {
61 		return true;
62 	}
63 	size_t table_len = strlen(name);
64 	const char *system_db;
65 	int i = 0;
66 	while ((system_db = innobase_system_databases[i++])
67 	       && (system_db != NullS)) {
68 		size_t len = strlen(system_db);
69 		if (table_len > len && !strncmp(name, system_db, len)) {
70 			return true;
71 		}
72 	}
73 	return false;
74 }
75 
76 /** The start of the table basename suffix for partitioned tables */
77 const char table_name_t::part_suffix[4]
78 #ifdef _WIN32
79 = "#p#";
80 #else
81 = "#P#";
82 #endif
83 
84 /** Display an identifier.
85 @param[in,out]	s	output stream
86 @param[in]	id_name	SQL identifier (other than table name)
87 @return the output stream */
88 std::ostream&
operator <<(std::ostream & s,const id_name_t & id_name)89 operator<<(
90 	std::ostream&		s,
91 	const id_name_t&	id_name)
92 {
93 	const char	q	= '`';
94 	const char*	c	= id_name;
95 	s << q;
96 	for (; *c != 0; c++) {
97 		if (*c == q) {
98 			s << *c;
99 		}
100 		s << *c;
101 	}
102 	s << q;
103 	return(s);
104 }
105 
106 /** Display a table name.
107 @param[in,out]	s		output stream
108 @param[in]	table_name	table name
109 @return the output stream */
110 std::ostream&
operator <<(std::ostream & s,const table_name_t & table_name)111 operator<<(
112 	std::ostream&		s,
113 	const table_name_t&	table_name)
114 {
115 	return(s << ut_get_name(NULL, table_name.m_name));
116 }
117 
118 /** Create a table memory object.
119 @param name     table name
120 @param space    tablespace
121 @param n_cols   total number of columns (both virtual and non-virtual)
122 @param n_v_cols number of virtual columns
123 @param flags    table flags
124 @param flags2   table flags2
125 @return own: table object */
126 dict_table_t*
dict_mem_table_create(const char * name,fil_space_t * space,ulint n_cols,ulint n_v_cols,ulint flags,ulint flags2)127 dict_mem_table_create(
128 	const char*	name,
129 	fil_space_t*	space,
130 	ulint		n_cols,
131 	ulint		n_v_cols,
132 	ulint		flags,
133 	ulint		flags2)
134 {
135 	dict_table_t*	table;
136 	mem_heap_t*	heap;
137 
138 	ut_ad(name);
139 	ut_ad(!space
140 	      || space->purpose == FIL_TYPE_TABLESPACE
141 	      || space->purpose == FIL_TYPE_TEMPORARY
142 	      || space->purpose == FIL_TYPE_IMPORT);
143 	ut_a(dict_tf2_is_valid(flags, flags2));
144 	ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK));
145 
146 	heap = mem_heap_create(DICT_HEAP_SIZE);
147 
148 	table = static_cast<dict_table_t*>(
149 		mem_heap_zalloc(heap, sizeof(*table)));
150 
151 	lock_table_lock_list_init(&table->locks);
152 
153 	UT_LIST_INIT(table->indexes, &dict_index_t::indexes);
154 #ifdef BTR_CUR_HASH_ADAPT
155 	UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes);
156 #endif /* BTR_CUR_HASH_ADAPT */
157 
158 	table->heap = heap;
159 
160 	ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
161 
162 	table->flags = (unsigned int) flags;
163 	table->flags2 = (unsigned int) flags2;
164 	table->name.m_name = mem_strdup(name);
165 	table->is_system_db = dict_mem_table_is_system(table->name.m_name);
166 	table->space = space;
167 	table->space_id = space ? space->id : ULINT_UNDEFINED;
168 	table->n_t_cols = unsigned(n_cols + DATA_N_SYS_COLS);
169 	table->n_v_cols = (unsigned int) (n_v_cols);
170 	table->n_cols = unsigned(table->n_t_cols - table->n_v_cols);
171 
172 	table->cols = static_cast<dict_col_t*>(
173 		mem_heap_alloc(heap, table->n_cols * sizeof(dict_col_t)));
174 	table->v_cols = static_cast<dict_v_col_t*>(
175 		mem_heap_alloc(heap, n_v_cols * sizeof(*table->v_cols)));
176 
177 	table->autoinc_lock = static_cast<ib_lock_t*>(
178 		mem_heap_alloc(heap, lock_get_size()));
179 
180 	/* If the table has an FTS index or we are in the process
181 	of building one, create the table->fts */
182 	if (dict_table_has_fts_index(table)
183 	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
184 	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
185 		table->fts = fts_create(table);
186 		table->fts->cache = fts_cache_create(table);
187 	} else {
188 		table->fts = NULL;
189 	}
190 
191 	new(&table->foreign_set) dict_foreign_set();
192 	new(&table->referenced_set) dict_foreign_set();
193 
194 	return(table);
195 }
196 
197 /****************************************************************//**
198 Free a table memory object. */
199 void
dict_mem_table_free(dict_table_t * table)200 dict_mem_table_free(
201 /*================*/
202 	dict_table_t*	table)		/*!< in: table */
203 {
204 	ut_ad(table);
205 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
206 	ut_ad(UT_LIST_GET_LEN(table->indexes) == 0);
207 #ifdef BTR_CUR_HASH_ADAPT
208 	ut_ad(UT_LIST_GET_LEN(table->freed_indexes) == 0);
209 #endif /* BTR_CUR_HASH_ADAPT */
210 	ut_d(table->cached = FALSE);
211 
212 	if (dict_table_has_fts_index(table)
213 	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
214 	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
215 		if (table->fts) {
216 			fts_optimize_remove_table(table);
217 
218 			fts_free(table);
219 		}
220 	}
221 
222 	dict_mem_table_free_foreign_vcol_set(table);
223 
224 	table->foreign_set.~dict_foreign_set();
225 	table->referenced_set.~dict_foreign_set();
226 
227 	ut_free(table->name.m_name);
228 	table->name.m_name = NULL;
229 
230 	/* Clean up virtual index info structures that are registered
231 	with virtual columns */
232 	for (ulint i = 0; i < table->n_v_def; i++) {
233 		dict_v_col_t*	vcol
234 			= dict_table_get_nth_v_col(table, i);
235 
236 		UT_DELETE(vcol->v_indexes);
237 	}
238 
239 	if (table->s_cols != NULL) {
240 		UT_DELETE(table->s_cols);
241 	}
242 
243 	mem_heap_free(table->heap);
244 }
245 
246 /****************************************************************//**
247 Append 'name' to 'col_names'.  @see dict_table_t::col_names
248 @return new column names array */
249 static
250 const char*
dict_add_col_name(const char * col_names,ulint cols,const char * name,mem_heap_t * heap)251 dict_add_col_name(
252 /*==============*/
253 	const char*	col_names,	/*!< in: existing column names, or
254 					NULL */
255 	ulint		cols,		/*!< in: number of existing columns */
256 	const char*	name,		/*!< in: new column name */
257 	mem_heap_t*	heap)		/*!< in: heap */
258 {
259 	ulint	old_len;
260 	ulint	new_len;
261 	ulint	total_len;
262 	char*	res;
263 
264 	ut_ad(!cols == !col_names);
265 
266 	/* Find out length of existing array. */
267 	if (col_names) {
268 		const char*	s = col_names;
269 		ulint		i;
270 
271 		for (i = 0; i < cols; i++) {
272 			s += strlen(s) + 1;
273 		}
274 
275 		old_len = unsigned(s - col_names);
276 	} else {
277 		old_len = 0;
278 	}
279 
280 	new_len = strlen(name) + 1;
281 	total_len = old_len + new_len;
282 
283 	res = static_cast<char*>(mem_heap_alloc(heap, total_len));
284 
285 	if (old_len > 0) {
286 		memcpy(res, col_names, old_len);
287 	}
288 
289 	memcpy(res + old_len, name, new_len);
290 
291 	return(res);
292 }
293 
294 /**********************************************************************//**
295 Adds a column definition to a table. */
296 void
dict_mem_table_add_col(dict_table_t * table,mem_heap_t * heap,const char * name,ulint mtype,ulint prtype,ulint len)297 dict_mem_table_add_col(
298 /*===================*/
299 	dict_table_t*	table,	/*!< in: table */
300 	mem_heap_t*	heap,	/*!< in: temporary memory heap, or NULL */
301 	const char*	name,	/*!< in: column name, or NULL */
302 	ulint		mtype,	/*!< in: main datatype */
303 	ulint		prtype,	/*!< in: precise type */
304 	ulint		len)	/*!< in: precision */
305 {
306 	dict_col_t*	col;
307 	ulint		i;
308 
309 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
310 	ut_ad(!heap == !name);
311 
312 	ut_ad(!(prtype & DATA_VIRTUAL));
313 
314 	i = table->n_def++;
315 
316 	table->n_t_def++;
317 
318 	if (name) {
319 		if (table->n_def == table->n_cols) {
320 			heap = table->heap;
321 		}
322 		if (i && !table->col_names) {
323 			/* All preceding column names are empty. */
324 			char* s = static_cast<char*>(
325 				mem_heap_zalloc(heap, table->n_def));
326 
327 			table->col_names = s;
328 		}
329 
330 		table->col_names = dict_add_col_name(table->col_names,
331 						     i, name, heap);
332 	}
333 
334 	col = dict_table_get_nth_col(table, i);
335 
336 	dict_mem_fill_column_struct(col, i, mtype, prtype, len);
337 
338 	switch (prtype & DATA_VERSIONED) {
339 	case DATA_VERS_START:
340 		ut_ad(!table->vers_start);
341 		table->vers_start = i;
342 		break;
343 	case DATA_VERS_END:
344 		ut_ad(!table->vers_end);
345 		table->vers_end = i;
346 	}
347 }
348 
349 /** Adds a virtual column definition to a table.
350 @param[in,out]	table		table
351 @param[in,out]	heap		temporary memory heap, or NULL. It is
352 				used to store name when we have not finished
353 				adding all columns. When all columns are
354 				added, the whole name will copy to memory from
355 				table->heap
356 @param[in]	name		column name
357 @param[in]	mtype		main datatype
358 @param[in]	prtype		precise type
359 @param[in]	len		length
360 @param[in]	pos		position in a table
361 @param[in]	num_base	number of base columns
362 @return the virtual column definition */
363 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)364 dict_mem_table_add_v_col(
365 	dict_table_t*	table,
366 	mem_heap_t*	heap,
367 	const char*	name,
368 	ulint		mtype,
369 	ulint		prtype,
370 	ulint		len,
371 	ulint		pos,
372 	ulint		num_base)
373 {
374 	dict_v_col_t*	v_col;
375 	ulint		i;
376 
377 	ut_ad(table);
378 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
379 	ut_ad(!heap == !name);
380 
381 	ut_ad(prtype & DATA_VIRTUAL);
382 
383 	i = table->n_v_def++;
384 
385 	table->n_t_def++;
386 
387 	if (name != NULL) {
388 		if (table->n_v_def == table->n_v_cols) {
389 			heap = table->heap;
390 		}
391 
392 		if (i && !table->v_col_names) {
393 			/* All preceding column names are empty. */
394 			char* s = static_cast<char*>(
395 				mem_heap_zalloc(heap, table->n_v_def));
396 
397 			table->v_col_names = s;
398 		}
399 
400 		table->v_col_names = dict_add_col_name(table->v_col_names,
401 						       i, name, heap);
402 	}
403 
404 	v_col = &table->v_cols[i];
405 
406 	dict_mem_fill_column_struct(&v_col->m_col, pos, mtype, prtype, len);
407 	v_col->v_pos = i;
408 
409 	if (num_base != 0) {
410 		v_col->base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
411 					table->heap, num_base * sizeof(
412 						*v_col->base_col)));
413 	} else {
414 		v_col->base_col = NULL;
415 	}
416 
417 	v_col->num_base = num_base;
418 
419 	/* Initialize the index list for virtual columns */
420 	v_col->v_indexes = UT_NEW_NOKEY(dict_v_idx_list());
421 
422 	return(v_col);
423 }
424 
425 /** Adds a stored column definition to a table.
426 @param[in]	table		table
427 @param[in]	num_base	number of base columns. */
428 void
dict_mem_table_add_s_col(dict_table_t * table,ulint num_base)429 dict_mem_table_add_s_col(
430 	dict_table_t*	table,
431 	ulint		num_base)
432 {
433 	unsigned	i = unsigned(table->n_def) - 1;
434 	dict_col_t*	col = dict_table_get_nth_col(table, i);
435 	dict_s_col_t	s_col;
436 
437 	ut_ad(col != NULL);
438 
439 	if (table->s_cols == NULL) {
440 		table->s_cols = UT_NEW_NOKEY(dict_s_col_list());
441 	}
442 
443 	s_col.m_col = col;
444 	s_col.s_pos = i + table->n_v_def;
445 
446 	if (num_base != 0) {
447 		s_col.base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
448 			table->heap, num_base * sizeof(dict_col_t*)));
449 	} else {
450 		s_col.base_col = NULL;
451 	}
452 
453 	s_col.num_base = num_base;
454 	table->s_cols->push_back(s_col);
455 }
456 
457 /**********************************************************************//**
458 Renames a column of a table in the data dictionary cache. */
459 static MY_ATTRIBUTE((nonnull))
460 void
dict_mem_table_col_rename_low(dict_table_t * table,unsigned i,const char * to,const char * s,bool is_virtual)461 dict_mem_table_col_rename_low(
462 /*==========================*/
463 	dict_table_t*	table,	/*!< in/out: table */
464 	unsigned	i,	/*!< in: column offset corresponding to s */
465 	const char*	to,	/*!< in: new column name */
466 	const char*	s,	/*!< in: pointer to table->col_names */
467 	bool		is_virtual)
468 				/*!< in: if this is a virtual column */
469 {
470 	char*	t_col_names = const_cast<char*>(
471 		is_virtual ? table->v_col_names : table->col_names);
472 	ulint	n_col = is_virtual ? table->n_v_def : table->n_def;
473 
474 	size_t from_len = strlen(s), to_len = strlen(to);
475 
476 	ut_ad(i < table->n_def || is_virtual);
477 	ut_ad(i < table->n_v_def || !is_virtual);
478 
479 	ut_ad(from_len <= NAME_LEN);
480 	ut_ad(to_len <= NAME_LEN);
481 
482 	char from[NAME_LEN + 1];
483 	strncpy(from, s, sizeof from - 1);
484 	from[sizeof from - 1] = '\0';
485 
486 	if (from_len == to_len) {
487 		/* The easy case: simply replace the column name in
488 		table->col_names. */
489 		strcpy(const_cast<char*>(s), to);
490 	} else {
491 		/* We need to adjust all affected index->field
492 		pointers, as in dict_index_add_col(). First, copy
493 		table->col_names. */
494 		ulint	prefix_len	= ulint(s - t_col_names);
495 
496 		for (; i < n_col; i++) {
497 			s += strlen(s) + 1;
498 		}
499 
500 		ulint	full_len	= ulint(s - t_col_names);
501 		char*	col_names;
502 
503 		if (to_len > from_len) {
504 			col_names = static_cast<char*>(
505 				mem_heap_alloc(
506 					table->heap,
507 					full_len + to_len - from_len));
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 				    (!field->col->is_virtual())) {
534 					continue;
535 				}
536 
537 				ulint		name_ofs
538 					= ulint(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 		if (foreign->foreign_index == NULL) {
571 			/* We may go here when we set foreign_key_checks to 0,
572 			and then try to rename a column and modify the
573 			corresponding foreign key constraint. The index
574 			would have been dropped, we have to find an equivalent
575 			one */
576 			for (unsigned f = 0; f < foreign->n_fields; f++) {
577 				if (strcmp(foreign->foreign_col_names[f], from)
578 				    == 0) {
579 
580 					char** rc = const_cast<char**>(
581 						foreign->foreign_col_names
582 						+ f);
583 
584 					if (to_len <= strlen(*rc)) {
585 						memcpy(*rc, to, to_len + 1);
586 					} else {
587 						*rc = static_cast<char*>(
588 							mem_heap_dup(
589 								foreign->heap,
590 								to,
591 								to_len + 1));
592 					}
593 				}
594 			}
595 
596 			/* New index can be null if InnoDB already dropped
597 			the foreign index when FOREIGN_KEY_CHECKS is
598 			disabled */
599 			foreign->foreign_index = dict_foreign_find_index(
600 				foreign->foreign_table, NULL,
601 				foreign->foreign_col_names,
602 				foreign->n_fields, NULL, true, false,
603 				NULL, NULL, NULL);
604 
605 		} else {
606 
607 			for (unsigned f = 0; f < foreign->n_fields; f++) {
608 				/* These can point straight to
609 				table->col_names, because the foreign key
610 				constraints will be freed at the same time
611 				when the table object is freed. */
612 				foreign->foreign_col_names[f]
613 					= dict_index_get_nth_field(
614 						foreign->foreign_index,
615 						f)->name;
616 			}
617 		}
618 	}
619 
620 	for (dict_foreign_set::iterator it = table->referenced_set.begin();
621 	     it != table->referenced_set.end();
622 	     ++it) {
623 
624 		foreign = *it;
625 
626 		if (!foreign->referenced_index) {
627 			/* Referenced index could have been dropped
628 			when foreign_key_checks is disabled. In that case,
629 			rename the corresponding referenced_col_names and
630 			find the equivalent referenced index also */
631 			for (unsigned f = 0; f < foreign->n_fields; f++) {
632 
633 				const char*& rc =
634 					foreign->referenced_col_names[f];
635 				if (strcmp(rc, from)) {
636 					continue;
637 				}
638 
639 				if (to_len <= strlen(rc)) {
640 					memcpy(const_cast<char*>(rc), to,
641 					       to_len + 1);
642 				} else {
643 					rc = static_cast<char*>(
644 						mem_heap_dup(
645 							foreign->heap,
646 							to, to_len + 1));
647 				}
648 			}
649 
650 			/* New index can be null if InnoDB already dropped
651 			the referenced index when FOREIGN_KEY_CHECKS is
652 			disabled */
653 			foreign->referenced_index = dict_foreign_find_index(
654 				foreign->referenced_table, NULL,
655 				foreign->referenced_col_names,
656 				foreign->n_fields, NULL, true, false,
657 				NULL, NULL, NULL);
658 			return;
659 		}
660 
661 
662 		for (unsigned f = 0; f < foreign->n_fields; f++) {
663 			/* foreign->referenced_col_names[] need to be
664 			copies, because the constraint may become
665 			orphan when foreign_key_checks=0 and the
666 			parent table is dropped. */
667 
668 			const char* col_name = dict_index_get_nth_field(
669 				foreign->referenced_index, f)->name;
670 
671 			if (strcmp(foreign->referenced_col_names[f],
672 				   col_name)) {
673 				char**	rc = const_cast<char**>(
674 					foreign->referenced_col_names + f);
675 				size_t	col_name_len_1 = strlen(col_name) + 1;
676 
677 				if (col_name_len_1 <= strlen(*rc) + 1) {
678 					memcpy(*rc, col_name, col_name_len_1);
679 				} else {
680 					*rc = static_cast<char*>(
681 						mem_heap_dup(
682 							foreign->heap,
683 							col_name,
684 							col_name_len_1));
685 				}
686 			}
687 		}
688 	}
689 }
690 
691 /**********************************************************************//**
692 Renames a column of a table in the data dictionary cache. */
693 void
dict_mem_table_col_rename(dict_table_t * table,ulint nth_col,const char * from,const char * to,bool is_virtual)694 dict_mem_table_col_rename(
695 /*======================*/
696 	dict_table_t*	table,	/*!< in/out: table */
697 	ulint		nth_col,/*!< in: column index */
698 	const char*	from,	/*!< in: old column name */
699 	const char*	to,	/*!< in: new column name */
700 	bool		is_virtual)
701 				/*!< in: if this is a virtual column */
702 {
703 	const char*	s = is_virtual ? table->v_col_names : table->col_names;
704 
705 	ut_ad((!is_virtual && nth_col < table->n_def)
706 	       || (is_virtual && nth_col < table->n_v_def));
707 
708 	for (ulint i = 0; i < nth_col; i++) {
709 		size_t	len = strlen(s);
710 		ut_ad(len > 0);
711 		s += len + 1;
712 	}
713 
714 	ut_ad(!my_strcasecmp(system_charset_info, from, s));
715 
716 	dict_mem_table_col_rename_low(table, static_cast<unsigned>(nth_col),
717 				      to, s, is_virtual);
718 }
719 
720 /**********************************************************************//**
721 This function populates a dict_col_t memory structure with
722 supplied information. */
723 void
dict_mem_fill_column_struct(dict_col_t * column,ulint col_pos,ulint mtype,ulint prtype,ulint col_len)724 dict_mem_fill_column_struct(
725 /*========================*/
726 	dict_col_t*	column,		/*!< out: column struct to be
727 					filled */
728 	ulint		col_pos,	/*!< in: column position */
729 	ulint		mtype,		/*!< in: main data type */
730 	ulint		prtype,		/*!< in: precise type */
731 	ulint		col_len)	/*!< in: column length */
732 {
733 	ulint	mbminlen;
734 	ulint	mbmaxlen;
735 
736 	column->ind = (unsigned int) col_pos;
737 	column->ord_part = 0;
738 	column->max_prefix = 0;
739 	column->mtype = (unsigned int) mtype;
740 	column->prtype = (unsigned int) prtype;
741 	column->len = (unsigned int) col_len;
742 	dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
743 	column->mbminlen = mbminlen;
744 	column->mbmaxlen = mbmaxlen;
745 	column->def_val.data = NULL;
746 	column->def_val.len = UNIV_SQL_DEFAULT;
747 }
748 
749 /**********************************************************************//**
750 Creates an index memory object.
751 @return own: index object */
752 dict_index_t*
dict_mem_index_create(dict_table_t * table,const char * index_name,ulint type,ulint n_fields)753 dict_mem_index_create(
754 /*==================*/
755 	dict_table_t*	table,		/*!< in: table */
756 	const char*	index_name,	/*!< in: index name */
757 	ulint		type,		/*!< in: DICT_UNIQUE,
758 					DICT_CLUSTERED, ... ORed */
759 	ulint		n_fields)	/*!< in: number of fields */
760 {
761 	dict_index_t*	index;
762 	mem_heap_t*	heap;
763 
764 	ut_ad(!table || table->magic_n == DICT_TABLE_MAGIC_N);
765 	ut_ad(index_name);
766 
767 	heap = mem_heap_create(DICT_HEAP_SIZE);
768 
769 	index = static_cast<dict_index_t*>(
770 		mem_heap_zalloc(heap, sizeof(*index)));
771 	index->table = table;
772 
773 	dict_mem_fill_index_struct(index, heap, index_name, type, n_fields);
774 
775 	mysql_mutex_init(0, &index->zip_pad.mutex, NULL);
776 
777 	if (type & DICT_SPATIAL) {
778 		index->rtr_track = static_cast<rtr_info_track_t*>(
779 					mem_heap_alloc(
780 						heap,
781 						sizeof(*index->rtr_track)));
782 		mutex_create(LATCH_ID_RTR_ACTIVE_MUTEX,
783 			     &index->rtr_track->rtr_active_mutex);
784 		index->rtr_track->rtr_active = UT_NEW_NOKEY(rtr_info_active());
785 	}
786 
787 	return(index);
788 }
789 
790 /**********************************************************************//**
791 Creates and initializes a foreign constraint memory object.
792 @return own: foreign constraint struct */
793 dict_foreign_t*
dict_mem_foreign_create(void)794 dict_mem_foreign_create(void)
795 /*=========================*/
796 {
797 	dict_foreign_t*	foreign;
798 	mem_heap_t*	heap;
799 	DBUG_ENTER("dict_mem_foreign_create");
800 
801 	heap = mem_heap_create(100);
802 
803 	foreign = static_cast<dict_foreign_t*>(
804 		mem_heap_zalloc(heap, sizeof(dict_foreign_t)));
805 
806 	foreign->heap = heap;
807 
808 	foreign->v_cols = NULL;
809 
810 	DBUG_PRINT("dict_mem_foreign_create", ("heap: %p", heap));
811 
812 	DBUG_RETURN(foreign);
813 }
814 
815 /**********************************************************************//**
816 Sets the foreign_table_name_lookup pointer based on the value of
817 lower_case_table_names.  If that is 0 or 1, foreign_table_name_lookup
818 will point to foreign_table_name.  If 2, then another string is
819 allocated from foreign->heap and set to lower case. */
820 void
dict_mem_foreign_table_name_lookup_set(dict_foreign_t * foreign,ibool do_alloc)821 dict_mem_foreign_table_name_lookup_set(
822 /*===================================*/
823 	dict_foreign_t*	foreign,	/*!< in/out: foreign struct */
824 	ibool		do_alloc)	/*!< in: is an alloc needed */
825 {
826 	if (innobase_get_lower_case_table_names() == 2) {
827 		if (do_alloc) {
828 			ulint	len;
829 
830 			len = strlen(foreign->foreign_table_name) + 1;
831 
832 			foreign->foreign_table_name_lookup =
833 				static_cast<char*>(
834 					mem_heap_alloc(foreign->heap, len));
835 		}
836 		strcpy(foreign->foreign_table_name_lookup,
837 		       foreign->foreign_table_name);
838 		innobase_casedn_str(foreign->foreign_table_name_lookup);
839 	} else {
840 		foreign->foreign_table_name_lookup
841 			= foreign->foreign_table_name;
842 	}
843 }
844 
845 /**********************************************************************//**
846 Sets the referenced_table_name_lookup pointer based on the value of
847 lower_case_table_names.  If that is 0 or 1, referenced_table_name_lookup
848 will point to referenced_table_name.  If 2, then another string is
849 allocated from foreign->heap and set to lower case. */
850 void
dict_mem_referenced_table_name_lookup_set(dict_foreign_t * foreign,ibool do_alloc)851 dict_mem_referenced_table_name_lookup_set(
852 /*======================================*/
853 	dict_foreign_t*	foreign,	/*!< in/out: foreign struct */
854 	ibool		do_alloc)	/*!< in: is an alloc needed */
855 {
856 	if (innobase_get_lower_case_table_names() == 2) {
857 		if (do_alloc) {
858 			ulint	len;
859 
860 			len = strlen(foreign->referenced_table_name) + 1;
861 
862 			foreign->referenced_table_name_lookup =
863 				static_cast<char*>(
864 					mem_heap_alloc(foreign->heap, len));
865 		}
866 		strcpy(foreign->referenced_table_name_lookup,
867 		       foreign->referenced_table_name);
868 		innobase_casedn_str(foreign->referenced_table_name_lookup);
869 	} else {
870 		foreign->referenced_table_name_lookup
871 			= foreign->referenced_table_name;
872 	}
873 }
874 
875 /** Fill the virtual column set with virtual column information
876 present in the given virtual index.
877 @param[in]	index	virtual index
878 @param[out]	v_cols	virtual column set. */
879 static
880 void
dict_mem_fill_vcol_has_index(const dict_index_t * index,dict_vcol_set ** v_cols)881 dict_mem_fill_vcol_has_index(
882 	const dict_index_t*	index,
883 	dict_vcol_set**		v_cols)
884 {
885 	for (ulint i = 0; i < index->table->n_v_cols; i++) {
886 		dict_v_col_t*	v_col = dict_table_get_nth_v_col(
887 					index->table, i);
888 		if (!v_col->m_col.ord_part) {
889 			continue;
890 		}
891 
892 		dict_v_idx_list::iterator it;
893 		for (it = v_col->v_indexes->begin();
894 		     it != v_col->v_indexes->end(); ++it) {
895 			dict_v_idx_t	v_idx = *it;
896 
897 			if (v_idx.index != index) {
898 				continue;
899 			}
900 
901 			if (*v_cols == NULL) {
902 				*v_cols = UT_NEW_NOKEY(dict_vcol_set());
903 			}
904 
905 			(*v_cols)->insert(v_col);
906 		}
907 	}
908 }
909 
910 /** Fill the virtual column set with the virtual column of the index
911 if the index contains given column name.
912 @param[in]	col_name	column name
913 @param[in]	table		innodb table object
914 @param[out]	v_cols		set of virtual column information. */
915 static
916 void
dict_mem_fill_vcol_from_v_indexes(const char * col_name,const dict_table_t * table,dict_vcol_set ** v_cols)917 dict_mem_fill_vcol_from_v_indexes(
918 	const char*		col_name,
919 	const dict_table_t*	table,
920 	dict_vcol_set**		v_cols)
921 {
922 	/* virtual column can't be Primary Key, so start with
923 	secondary index */
924 	for (dict_index_t* index = dict_table_get_next_index(
925 			dict_table_get_first_index(table));
926 		index;
927 		index = dict_table_get_next_index(index)) {
928 
929 		/* Skip if the index have newly added
930 		virtual column because field name is NULL.
931 		Later virtual column set will be
932 		refreshed during loading of table. */
933 		if (!dict_index_has_virtual(index)
934 		    || index->has_new_v_col()) {
935 			continue;
936 		}
937 
938 		for (ulint i = 0; i < index->n_fields; i++) {
939 			dict_field_t*	field =
940 				dict_index_get_nth_field(index, i);
941 
942 			if (strcmp(field->name, col_name) == 0) {
943 				dict_mem_fill_vcol_has_index(
944 					index, v_cols);
945 			}
946 		}
947 	}
948 }
949 
950 /** Fill the virtual column set with virtual columns which have base columns
951 as the given col_name
952 @param[in]	col_name	column name
953 @param[in]	table		table object
954 @param[out]	v_cols		set of virtual columns. */
955 static
956 void
dict_mem_fill_vcol_set_for_base_col(const char * col_name,const dict_table_t * table,dict_vcol_set ** v_cols)957 dict_mem_fill_vcol_set_for_base_col(
958 	const char*		col_name,
959 	const dict_table_t*	table,
960 	dict_vcol_set**		v_cols)
961 {
962 	for (ulint i = 0; i < table->n_v_cols; i++) {
963 		dict_v_col_t*	v_col = dict_table_get_nth_v_col(table, i);
964 
965 		if (!v_col->m_col.ord_part) {
966 			continue;
967 		}
968 
969 		for (ulint j = 0; j < v_col->num_base; j++) {
970 			if (strcmp(col_name, dict_table_get_col_name(
971 					table,
972 					v_col->base_col[j]->ind)) == 0) {
973 
974 				if (*v_cols == NULL) {
975 					*v_cols = UT_NEW_NOKEY(dict_vcol_set());
976 				}
977 
978 				(*v_cols)->insert(v_col);
979 			}
980 		}
981 	}
982 }
983 
984 /** Fills the dependent virtual columns in a set.
985 Reason for being dependent are
986 1) FK can be present on base column of virtual columns
987 2) FK can be present on column which is a part of virtual index
988 @param[in,out]  foreign foreign key information. */
989 void
dict_mem_foreign_fill_vcol_set(dict_foreign_t * foreign)990 dict_mem_foreign_fill_vcol_set(
991         dict_foreign_t* foreign)
992 {
993 	ulint	type = foreign->type;
994 
995 	if (type == 0) {
996 		return;
997 	}
998 
999 	for (ulint i = 0; i < foreign->n_fields; i++) {
1000 		/** FK can be present on base columns
1001 		of virtual columns. */
1002 		dict_mem_fill_vcol_set_for_base_col(
1003 			foreign->foreign_col_names[i],
1004 			foreign->foreign_table,
1005 			&foreign->v_cols);
1006 
1007 		/** FK can be present on the columns
1008 		which can be a part of virtual index. */
1009 		dict_mem_fill_vcol_from_v_indexes(
1010 			foreign->foreign_col_names[i],
1011 			foreign->foreign_table,
1012 			&foreign->v_cols);
1013 	}
1014 }
1015 
1016 /** Fill virtual columns set in each fk constraint present in the table.
1017 @param[in,out]	table	innodb table object. */
1018 void
dict_mem_table_fill_foreign_vcol_set(dict_table_t * table)1019 dict_mem_table_fill_foreign_vcol_set(
1020 	dict_table_t*	table)
1021 {
1022 	dict_foreign_set	fk_set = table->foreign_set;
1023 	dict_foreign_t*		foreign;
1024 
1025 	dict_foreign_set::iterator it;
1026 	for (it = fk_set.begin(); it != fk_set.end(); ++it) {
1027 		foreign = *it;
1028 
1029 		dict_mem_foreign_fill_vcol_set(foreign);
1030 	}
1031 }
1032 
1033 /** Free the vcol_set from all foreign key constraint on the table.
1034 @param[in,out]	table	innodb table object. */
1035 void
dict_mem_table_free_foreign_vcol_set(dict_table_t * table)1036 dict_mem_table_free_foreign_vcol_set(
1037 	dict_table_t*	table)
1038 {
1039 	dict_foreign_set	fk_set = table->foreign_set;
1040 	dict_foreign_t*		foreign;
1041 
1042 	dict_foreign_set::iterator it;
1043 	for (it = fk_set.begin(); it != fk_set.end(); ++it) {
1044 
1045 		foreign = *it;
1046 
1047 		if (foreign->v_cols != NULL) {
1048 			UT_DELETE(foreign->v_cols);
1049 			foreign->v_cols = NULL;
1050 		}
1051 	}
1052 }
1053 
1054 /**********************************************************************//**
1055 Adds a field definition to an index. NOTE: does not take a copy
1056 of the column name if the field is a column. The memory occupied
1057 by the column name may be released only after publishing the index. */
1058 void
dict_mem_index_add_field(dict_index_t * index,const char * name,ulint prefix_len)1059 dict_mem_index_add_field(
1060 /*=====================*/
1061 	dict_index_t*	index,		/*!< in: index */
1062 	const char*	name,		/*!< in: column name */
1063 	ulint		prefix_len)	/*!< in: 0 or the column prefix length
1064 					in a MySQL index like
1065 					INDEX (textcol(25)) */
1066 {
1067 	dict_field_t*	field;
1068 
1069 	ut_ad(index);
1070 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1071 
1072 	index->n_def++;
1073 
1074 	field = dict_index_get_nth_field(index, unsigned(index->n_def) - 1);
1075 
1076 	field->name = name;
1077 	field->prefix_len = (unsigned int) prefix_len;
1078 }
1079 
1080 /**********************************************************************//**
1081 Frees an index memory object. */
1082 void
dict_mem_index_free(dict_index_t * index)1083 dict_mem_index_free(
1084 /*================*/
1085 	dict_index_t*	index)	/*!< in: index */
1086 {
1087 	ut_ad(index);
1088 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1089 
1090 	mysql_mutex_destroy(&index->zip_pad.mutex);
1091 
1092 	if (dict_index_is_spatial(index)) {
1093 		rtr_info_active::iterator	it;
1094 		rtr_info_t*			rtr_info;
1095 
1096 		for (it = index->rtr_track->rtr_active->begin();
1097 		     it != index->rtr_track->rtr_active->end(); ++it) {
1098 			rtr_info = *it;
1099 
1100 			rtr_info->index = NULL;
1101 		}
1102 
1103 		mutex_destroy(&index->rtr_track->rtr_active_mutex);
1104 		UT_DELETE(index->rtr_track->rtr_active);
1105 	}
1106 
1107 	dict_index_remove_from_v_col_list(index);
1108 	mem_heap_free(index->heap);
1109 }
1110 
1111 /** Create a temporary tablename like "#sql-ibNNN".
1112 @param[in]	heap	A memory heap
1113 @param[in]	dbtab	Table name in the form database/table name
1114 @param[in]	id	Table id
1115 @return A unique temporary tablename suitable for InnoDB use */
1116 char*
dict_mem_create_temporary_tablename(mem_heap_t * heap,const char * dbtab,table_id_t id)1117 dict_mem_create_temporary_tablename(
1118 	mem_heap_t*	heap,
1119 	const char*	dbtab,
1120 	table_id_t	id)
1121 {
1122 	size_t		size;
1123 	char*		name;
1124 	const char*	dbend   = strchr(dbtab, '/');
1125 	ut_ad(dbend);
1126 	size_t		dblen   = size_t(dbend - dbtab) + 1;
1127 
1128 	size = dblen + (sizeof(TEMP_FILE_PREFIX) + 3 + 20);
1129 	name = static_cast<char*>(mem_heap_alloc(heap, size));
1130 	memcpy(name, dbtab, dblen);
1131 	snprintf(name + dblen, size - dblen,
1132 		 TEMP_FILE_PREFIX_INNODB UINT64PF, id);
1133 
1134 	return(name);
1135 }
1136 
1137 /** Validate the search order in the foreign key set.
1138 @param[in]	fk_set	the foreign key set to be validated
1139 @return true if search order is fine in the set, false otherwise. */
1140 bool
dict_foreign_set_validate(const dict_foreign_set & fk_set)1141 dict_foreign_set_validate(
1142 	const dict_foreign_set&	fk_set)
1143 {
1144 	dict_foreign_not_exists	not_exists(fk_set);
1145 
1146 	dict_foreign_set::const_iterator it = std::find_if(
1147 		fk_set.begin(), fk_set.end(), not_exists);
1148 
1149 	if (it == fk_set.end()) {
1150 		return(true);
1151 	}
1152 
1153 	dict_foreign_t*	foreign = *it;
1154 	std::cerr << "Foreign key lookup failed: " << *foreign;
1155 	std::cerr << fk_set;
1156 	ut_ad(0);
1157 	return(false);
1158 }
1159 
1160 /** Validate the search order in the foreign key sets of the table
1161 (foreign_set and referenced_set).
1162 @param[in]	table	table whose foreign key sets are to be validated
1163 @return true if foreign key sets are fine, false otherwise. */
1164 bool
dict_foreign_set_validate(const dict_table_t & table)1165 dict_foreign_set_validate(
1166 	const dict_table_t&	table)
1167 {
1168 	return(dict_foreign_set_validate(table.foreign_set)
1169 	       && dict_foreign_set_validate(table.referenced_set));
1170 }
1171 
1172 std::ostream&
operator <<(std::ostream & out,const dict_foreign_t & foreign)1173 operator<< (std::ostream& out, const dict_foreign_t& foreign)
1174 {
1175 	out << "[dict_foreign_t: id='" << foreign.id << "'";
1176 
1177 	if (foreign.foreign_table_name != NULL) {
1178 		out << ",for: '" << foreign.foreign_table_name << "'";
1179 	}
1180 
1181 	out << "]";
1182 	return(out);
1183 }
1184 
1185 std::ostream&
operator <<(std::ostream & out,const dict_foreign_set & fk_set)1186 operator<< (std::ostream& out, const dict_foreign_set& fk_set)
1187 {
1188 	out << "[dict_foreign_set:";
1189 	std::for_each(fk_set.begin(), fk_set.end(), dict_foreign_print(out));
1190 	out << "]" << std::endl;
1191 	return(out);
1192 }
1193 
1194 /** Check whether fulltext index gets affected by foreign
1195 key constraint. */
affects_fulltext() const1196 bool dict_foreign_t::affects_fulltext() const
1197 {
1198   if (foreign_table == referenced_table || !foreign_table->fts)
1199     return false;
1200 
1201   for (ulint i= 0; i < n_fields; i++)
1202   {
1203     const dict_col_t *col= dict_index_get_nth_col(foreign_index, i);
1204     if (dict_table_is_fts_column(foreign_table->fts->indexes, col->ind,
1205                                  col->is_virtual()) != ULINT_UNDEFINED)
1206       return true;
1207   }
1208 
1209   return false;
1210 }
1211 
1212 /** Adjust clustered index metadata for instant ADD COLUMN.
1213 @param[in]	clustered index definition after instant ADD COLUMN */
instant_add_field(const dict_index_t & instant)1214 inline void dict_index_t::instant_add_field(const dict_index_t& instant)
1215 {
1216 	DBUG_ASSERT(is_primary());
1217 	DBUG_ASSERT(instant.is_primary());
1218 	DBUG_ASSERT(!instant.is_instant());
1219 	DBUG_ASSERT(n_def == n_fields);
1220 	DBUG_ASSERT(instant.n_def == instant.n_fields);
1221 
1222 	DBUG_ASSERT(type == instant.type);
1223 	DBUG_ASSERT(trx_id_offset == instant.trx_id_offset);
1224 	DBUG_ASSERT(n_user_defined_cols == instant.n_user_defined_cols);
1225 	DBUG_ASSERT(n_uniq == instant.n_uniq);
1226 	DBUG_ASSERT(instant.n_fields > n_fields);
1227 	DBUG_ASSERT(instant.n_def > n_def);
1228 	DBUG_ASSERT(instant.n_nullable >= n_nullable);
1229 	DBUG_ASSERT(instant.n_core_fields >= n_core_fields);
1230 	DBUG_ASSERT(instant.n_core_null_bytes >= n_core_null_bytes);
1231 
1232 	n_fields = instant.n_fields;
1233 	n_def = instant.n_def;
1234 	n_nullable = instant.n_nullable;
1235 	fields = static_cast<dict_field_t*>(
1236 		mem_heap_dup(heap, instant.fields, n_fields * sizeof *fields));
1237 
1238 	ut_d(unsigned n_null = 0);
1239 
1240 	for (unsigned i = 0; i < n_fields; i++) {
1241 		DBUG_ASSERT(fields[i].same(instant.fields[i]));
1242 		const dict_col_t* icol = instant.fields[i].col;
1243 		DBUG_ASSERT(!icol->is_virtual());
1244 		dict_col_t* col = fields[i].col = &table->cols[
1245 			icol - instant.table->cols];
1246 		fields[i].name = col->name(*table);
1247 		ut_d(n_null += col->is_nullable());
1248 	}
1249 
1250 	ut_ad(n_null == n_nullable);
1251 }
1252 
1253 /** Adjust metadata for instant ADD COLUMN.
1254 @param[in]	table	table definition after instant ADD COLUMN */
instant_add_column(const dict_table_t & table)1255 void dict_table_t::instant_add_column(const dict_table_t& table)
1256 {
1257 	DBUG_ASSERT(!table.cached);
1258 	DBUG_ASSERT(table.n_def == table.n_cols);
1259 	DBUG_ASSERT(table.n_t_def == table.n_t_cols);
1260 	DBUG_ASSERT(n_def == n_cols);
1261 	DBUG_ASSERT(n_t_def == n_t_cols);
1262 	DBUG_ASSERT(table.n_cols > n_cols);
1263 	ut_ad(mutex_own(&dict_sys->mutex));
1264 
1265 	const char* end = table.col_names;
1266 	for (unsigned i = table.n_cols; i--; ) end += strlen(end) + 1;
1267 
1268 	col_names = static_cast<char*>(
1269 		mem_heap_dup(heap, table.col_names,
1270 			     ulint(end - table.col_names)));
1271 	const dict_col_t* const old_cols = cols;
1272 	const dict_col_t* const old_cols_end = cols + n_cols;
1273 	cols = static_cast<dict_col_t*>(mem_heap_dup(heap, table.cols,
1274 						     table.n_cols
1275 						     * sizeof *cols));
1276 
1277 	/* Preserve the default values of previously instantly
1278 	added columns. */
1279 	for (unsigned i = unsigned(n_cols) - DATA_N_SYS_COLS; i--; ) {
1280 		cols[i].def_val = old_cols[i].def_val;
1281 	}
1282 
1283 	/* Copy the new default values to this->heap. */
1284 	for (unsigned i = n_cols; i < table.n_cols; i++) {
1285 		dict_col_t& c = cols[i - DATA_N_SYS_COLS];
1286 		DBUG_ASSERT(c.is_instant());
1287 		if (c.def_val.len == 0) {
1288 			c.def_val.data = field_ref_zero;
1289 		} else if (const void*& d = c.def_val.data) {
1290 			d = mem_heap_dup(heap, d, c.def_val.len);
1291 		} else {
1292 			DBUG_ASSERT(c.def_val.len == UNIV_SQL_NULL);
1293 		}
1294 	}
1295 
1296 	const unsigned old_n_cols = n_cols;
1297 	const unsigned n_add = unsigned(table.n_cols - n_cols);
1298 
1299 	n_t_def += n_add;
1300 	n_t_cols += n_add;
1301 	n_cols = table.n_cols;
1302 	n_def = n_cols;
1303 
1304 	for (unsigned i = n_v_def; i--; ) {
1305 		const dict_v_col_t& v = v_cols[i];
1306 		for (ulint n = v.num_base; n--; ) {
1307 			dict_col_t*& base = v.base_col[n];
1308 			if (!base->is_virtual()) {
1309 				DBUG_ASSERT(base >= old_cols);
1310 				size_t n = size_t(base - old_cols);
1311 				DBUG_ASSERT(n + DATA_N_SYS_COLS < old_n_cols);
1312 				base = &cols[n];
1313 			}
1314 		}
1315 	}
1316 
1317 	dict_index_t* index = dict_table_get_first_index(this);
1318 
1319 	index->instant_add_field(*dict_table_get_first_index(&table));
1320 
1321 	while ((index = dict_table_get_next_index(index)) != NULL) {
1322 		for (unsigned i = 0; i < index->n_fields; i++) {
1323 			dict_field_t& field = index->fields[i];
1324 			if (field.col < old_cols
1325 			    || field.col >= old_cols_end) {
1326 				DBUG_ASSERT(field.col->is_virtual());
1327 			} else {
1328 				/* Secondary indexes may contain user
1329 				columns and DB_ROW_ID (if there is
1330 				GEN_CLUST_INDEX instead of PRIMARY KEY),
1331 				but not DB_TRX_ID,DB_ROLL_PTR. */
1332 				DBUG_ASSERT(field.col >= old_cols);
1333 				size_t n = size_t(field.col - old_cols);
1334 				DBUG_ASSERT(n + DATA_N_SYS_COLS <= old_n_cols);
1335 				if (n + DATA_N_SYS_COLS >= old_n_cols) {
1336 					/* Replace DB_ROW_ID */
1337 					n += n_add;
1338 				}
1339 				field.col = &cols[n];
1340 				DBUG_ASSERT(!field.col->is_virtual());
1341 				field.name = field.col->name(*this);
1342 			}
1343 		}
1344 	}
1345 }
1346 
1347 /** Roll back instant_add_column().
1348 @param[in]	old_n_cols	original n_cols
1349 @param[in]	old_cols	original cols
1350 @param[in]	old_col_names	original col_names */
1351 void
rollback_instant(unsigned old_n_cols,dict_col_t * old_cols,const char * old_col_names)1352 dict_table_t::rollback_instant(
1353 	unsigned	old_n_cols,
1354 	dict_col_t*	old_cols,
1355 	const char*	old_col_names)
1356 {
1357 	ut_ad(mutex_own(&dict_sys->mutex));
1358 	dict_index_t* index = indexes.start;
1359 	/* index->is_instant() does not necessarily hold here, because
1360 	the table may have been emptied */
1361 	DBUG_ASSERT(old_n_cols >= DATA_N_SYS_COLS);
1362 	DBUG_ASSERT(n_cols >= old_n_cols);
1363 	DBUG_ASSERT(n_cols == n_def);
1364 	DBUG_ASSERT(index->n_def == index->n_fields);
1365 
1366 	const unsigned n_remove = n_cols - old_n_cols;
1367 
1368 	for (unsigned i = index->n_fields - n_remove; i < index->n_fields;
1369 	     i++) {
1370 		if (index->fields[i].col->is_nullable()) {
1371 			index->n_nullable--;
1372 		}
1373 	}
1374 
1375 	index->n_fields -= n_remove;
1376 	index->n_def = index->n_fields;
1377 	if (index->n_core_fields > index->n_fields) {
1378 		index->n_core_fields = index->n_fields;
1379 		index->n_core_null_bytes
1380 			= UT_BITS_IN_BYTES(unsigned(index->n_nullable));
1381 	}
1382 
1383 	const dict_col_t* const new_cols = cols;
1384 	const dict_col_t* const new_cols_end = cols + n_cols;
1385 
1386 	cols = old_cols;
1387 	col_names = old_col_names;
1388 	n_cols = old_n_cols;
1389 	n_def = old_n_cols;
1390 	n_t_def -= n_remove;
1391 	n_t_cols -= n_remove;
1392 
1393 	for (unsigned i = n_v_def; i--; ) {
1394 		const dict_v_col_t& v = v_cols[i];
1395 		for (ulint n = v.num_base; n--; ) {
1396 			dict_col_t*& base = v.base_col[n];
1397 			if (!base->is_virtual()) {
1398 				base = &cols[base - new_cols];
1399 			}
1400 		}
1401 	}
1402 
1403 	do {
1404 		for (unsigned i = 0; i < index->n_fields; i++) {
1405 			dict_field_t& field = index->fields[i];
1406 			if (field.col < new_cols
1407 			    || field.col >= new_cols_end) {
1408 				DBUG_ASSERT(field.col->is_virtual());
1409 			} else {
1410 				DBUG_ASSERT(field.col >= new_cols);
1411 				size_t n = size_t(field.col - new_cols);
1412 				DBUG_ASSERT(n <= n_cols);
1413 				if (n + DATA_N_SYS_COLS >= n_cols) {
1414 					n -= n_remove;
1415 				}
1416 				field.col = &cols[n];
1417 				DBUG_ASSERT(!field.col->is_virtual());
1418 				field.name = field.col->name(*this);
1419 			}
1420 		}
1421 	} while ((index = dict_table_get_next_index(index)) != NULL);
1422 }
1423 
1424 /** Trim the instantly added columns when an insert into SYS_COLUMNS
1425 is rolled back during ALTER TABLE or recovery.
1426 @param[in]	n	number of surviving non-system columns */
rollback_instant(unsigned n)1427 void dict_table_t::rollback_instant(unsigned n)
1428 {
1429 	ut_ad(mutex_own(&dict_sys->mutex));
1430 	dict_index_t* index = indexes.start;
1431 	DBUG_ASSERT(index->is_instant());
1432 	DBUG_ASSERT(index->n_def == index->n_fields);
1433 	DBUG_ASSERT(n_cols == n_def);
1434 	DBUG_ASSERT(n >= index->n_uniq);
1435 	DBUG_ASSERT(n_cols > n + DATA_N_SYS_COLS);
1436 	const unsigned n_remove = n_cols - n - DATA_N_SYS_COLS;
1437 
1438 	char* names = const_cast<char*>(dict_table_get_col_name(this, n));
1439 	const char* sys = names;
1440 	for (unsigned i = n_remove; i--; ) {
1441 		sys += strlen(sys) + 1;
1442 	}
1443 	static const char system[] = "DB_ROW_ID\0DB_TRX_ID\0DB_ROLL_PTR";
1444 	DBUG_ASSERT(!memcmp(sys, system, sizeof system));
1445 	for (unsigned i = index->n_fields - n_remove; i < index->n_fields;
1446 	     i++) {
1447 		if (index->fields[i].col->is_nullable()) {
1448 			index->n_nullable--;
1449 		}
1450 	}
1451 	index->n_fields -= n_remove;
1452 	index->n_def = index->n_fields;
1453 	memmove(names, sys, sizeof system);
1454 	memmove(cols + n, cols + n_cols - DATA_N_SYS_COLS,
1455 		DATA_N_SYS_COLS * sizeof *cols);
1456 	n_cols -= n_remove;
1457 	n_def = n_cols;
1458 	n_t_cols -= n_remove;
1459 	n_t_def -= n_remove;
1460 
1461 	for (unsigned i = DATA_N_SYS_COLS; i--; ) {
1462 		cols[n_cols - i].ind--;
1463 	}
1464 
1465 	if (dict_index_is_auto_gen_clust(index)) {
1466 		DBUG_ASSERT(index->n_uniq == 1);
1467 		dict_field_t* field = index->fields;
1468 		field->name = sys;
1469 		field->col = dict_table_get_sys_col(this, DATA_ROW_ID);
1470 		field++;
1471 		field->name = sys + sizeof "DB_ROW_ID";
1472 		field->col = dict_table_get_sys_col(this, DATA_TRX_ID);
1473 		field++;
1474 		field->name = sys + sizeof "DB_ROW_ID\0DB_TRX_ID";
1475 		field->col = dict_table_get_sys_col(this, DATA_ROLL_PTR);
1476 
1477 		/* Replace the DB_ROW_ID column in secondary indexes. */
1478 		while ((index = dict_table_get_next_index(index)) != NULL) {
1479 			field = &index->fields[index->n_fields - 1];
1480 			DBUG_ASSERT(field->col->mtype == DATA_SYS);
1481 			DBUG_ASSERT(field->col->prtype
1482 				    == DATA_NOT_NULL + DATA_TRX_ID);
1483 			field->col--;
1484 			field->name = sys;
1485 		}
1486 
1487 		return;
1488 	}
1489 
1490 	dict_field_t* field = &index->fields[index->n_uniq];
1491 	field->name = sys + sizeof "DB_ROW_ID";
1492 	field->col = dict_table_get_sys_col(this, DATA_TRX_ID);
1493 	field++;
1494 	field->name = sys + sizeof "DB_ROW_ID\0DB_TRX_ID";
1495 	field->col = dict_table_get_sys_col(this, DATA_ROLL_PTR);
1496 }
1497 
1498 
1499 /** Check if record in clustered index is historical row.
1500 @param[in]	rec	clustered row
1501 @param[in]	offsets	offsets
1502 @return true if row is historical */
1503 bool
vers_history_row(const rec_t * rec,const rec_offs * offsets)1504 dict_index_t::vers_history_row(
1505 	const rec_t*		rec,
1506 	const rec_offs*		offsets)
1507 {
1508 	ut_ad(is_primary());
1509 
1510 	ulint len;
1511 	dict_col_t& col= table->cols[table->vers_end];
1512 	ut_ad(col.vers_sys_end());
1513 	ulint nfield = dict_col_get_clust_pos(&col, this);
1514 	const byte *data = rec_get_nth_field(rec, offsets, nfield, &len);
1515 	if (col.vers_native()) {
1516 		ut_ad(len == sizeof trx_id_max_bytes);
1517 		return 0 != memcmp(data, trx_id_max_bytes, len);
1518 	}
1519 	ut_ad(len == sizeof timestamp_max_bytes);
1520 	return 0 != memcmp(data, timestamp_max_bytes, len);
1521 }
1522 
1523 /** Check if record in secondary index is historical row.
1524 @param[in]	rec	record in a secondary index
1525 @param[out]	history_row true if row is historical
1526 @return true on error */
1527 bool
vers_history_row(const rec_t * rec,bool & history_row)1528 dict_index_t::vers_history_row(
1529 	const rec_t* rec,
1530 	bool &history_row)
1531 {
1532 	ut_ad(!is_primary());
1533 
1534 	bool error = false;
1535 	mem_heap_t* heap = NULL;
1536 	dict_index_t* clust_index = NULL;
1537 	rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
1538 	rec_offs* offsets = offsets_;
1539 	rec_offs_init(offsets_);
1540 
1541 	mtr_t mtr;
1542 	mtr.start();
1543 
1544 	rec_t* clust_rec =
1545 	    row_get_clust_rec(BTR_SEARCH_LEAF, rec, this, &clust_index, &mtr);
1546 	if (clust_rec) {
1547 		offsets = rec_get_offsets(clust_rec, clust_index, offsets,
1548 					  clust_index->n_core_fields,
1549 					  ULINT_UNDEFINED, &heap);
1550 
1551 		history_row = clust_index->vers_history_row(clust_rec, offsets);
1552         } else {
1553 		ib::error() << "foreign constraints: secondary index is out of "
1554 			       "sync";
1555 		ut_ad(!"secondary index is out of sync");
1556 		error = true;
1557 	}
1558 	mtr.commit();
1559 	if (heap) {
1560 		mem_heap_free(heap);
1561 	}
1562 	return(error);
1563 }
1564