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 "sql_string.h"
41 #include <iostream>
42 
43 #define	DICT_HEAP_SIZE		100	/*!< initial memory heap size when
44 					creating a table or index object */
45 
46 /** System databases */
47 static const char* innobase_system_databases[] = {
48 	"mysql/",
49 	"information_schema/",
50 	"performance_schema/",
51 	NullS
52 };
53 
54 /** Determine if a table belongs to innobase_system_databases[]
55 @param[in]	name	database_name/table_name
56 @return	whether the database_name is in innobase_system_databases[] */
dict_mem_table_is_system(const char * name)57 static bool dict_mem_table_is_system(const char *name)
58 {
59 	/* table has the following format: database/table
60 	and some system table are of the form SYS_* */
61 	if (!strchr(name, '/')) {
62 		return true;
63 	}
64 	size_t table_len = strlen(name);
65 	const char *system_db;
66 	int i = 0;
67 	while ((system_db = innobase_system_databases[i++])
68 	       && (system_db != NullS)) {
69 		size_t len = strlen(system_db);
70 		if (table_len > len && !strncmp(name, system_db, len)) {
71 			return true;
72 		}
73 	}
74 	return false;
75 }
76 
77 /** The start of the table basename suffix for partitioned tables */
78 const char table_name_t::part_suffix[4]
79 #ifdef _WIN32
80 = "#p#";
81 #else
82 = "#P#";
83 #endif
84 
85 /** Display an identifier.
86 @param[in,out]	s	output stream
87 @param[in]	id_name	SQL identifier (other than table name)
88 @return the output stream */
89 std::ostream&
operator <<(std::ostream & s,const id_name_t & id_name)90 operator<<(
91 	std::ostream&		s,
92 	const id_name_t&	id_name)
93 {
94 	const char	q	= '`';
95 	const char*	c	= id_name;
96 	s << q;
97 	for (; *c != 0; c++) {
98 		if (*c == q) {
99 			s << *c;
100 		}
101 		s << *c;
102 	}
103 	s << q;
104 	return(s);
105 }
106 
107 /** Display a table name.
108 @param[in,out]	s		output stream
109 @param[in]	table_name	table name
110 @return the output stream */
111 std::ostream&
operator <<(std::ostream & s,const table_name_t & table_name)112 operator<<(
113 	std::ostream&		s,
114 	const table_name_t&	table_name)
115 {
116 	return(s << ut_get_name(NULL, table_name.m_name));
117 }
118 
same_encoding(uint16_t a,uint16_t b)119 bool dict_col_t::same_encoding(uint16_t a, uint16_t b)
120 {
121   if (const CHARSET_INFO *acs= get_charset(a, MYF(MY_WME)))
122     if (const CHARSET_INFO *bcs= get_charset(b, MYF(MY_WME)))
123       return Charset(bcs).encoding_allows_reinterpret_as(acs);
124   return false;
125 }
126 
127 /** Create a table memory object.
128 @param name     table name
129 @param space    tablespace
130 @param n_cols   total number of columns (both virtual and non-virtual)
131 @param n_v_cols number of virtual columns
132 @param flags    table flags
133 @param flags2   table flags2
134 @return own: table object */
dict_mem_table_create(const char * name,fil_space_t * space,ulint n_cols,ulint n_v_cols,ulint flags,ulint flags2)135 dict_table_t *dict_mem_table_create(const char *name, fil_space_t *space,
136                                     ulint n_cols, ulint n_v_cols, ulint flags,
137                                     ulint flags2)
138 {
139 	dict_table_t*	table;
140 	mem_heap_t*	heap;
141 
142 	ut_ad(name);
143 	ut_ad(!space
144 	      || space->purpose == FIL_TYPE_TABLESPACE
145 	      || space->purpose == FIL_TYPE_TEMPORARY
146 	      || space->purpose == FIL_TYPE_IMPORT);
147 	ut_a(dict_tf2_is_valid(flags, flags2));
148 	ut_a(!(flags2 & DICT_TF2_UNUSED_BIT_MASK));
149 
150 	heap = mem_heap_create(DICT_HEAP_SIZE);
151 
152 	table = static_cast<dict_table_t*>(
153 		mem_heap_zalloc(heap, sizeof(*table)));
154 
155 	lock_table_lock_list_init(&table->locks);
156 
157 	UT_LIST_INIT(table->indexes, &dict_index_t::indexes);
158 #ifdef BTR_CUR_HASH_ADAPT
159 	UT_LIST_INIT(table->freed_indexes, &dict_index_t::indexes);
160 #endif /* BTR_CUR_HASH_ADAPT */
161 
162 	table->heap = heap;
163 
164 	ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
165 
166 	table->flags = static_cast<unsigned>(flags)
167 		& ((1U << DICT_TF_BITS) - 1);
168 	table->flags2 = static_cast<unsigned>(flags2)
169 		& ((1U << DICT_TF2_BITS) - 1);
170 	table->name.m_name = mem_strdup(name);
171 	table->is_system_db = dict_mem_table_is_system(table->name.m_name);
172 	table->space = space;
173 	table->space_id = space ? space->id : ULINT_UNDEFINED;
174 	table->n_t_cols = static_cast<unsigned>(n_cols + DATA_N_SYS_COLS)
175 		& dict_index_t::MAX_N_FIELDS;
176 	table->n_v_cols = static_cast<unsigned>(n_v_cols)
177 		& dict_index_t::MAX_N_FIELDS;
178 	table->n_cols = static_cast<unsigned>(
179 		table->n_t_cols - table->n_v_cols)
180 		& dict_index_t::MAX_N_FIELDS;
181 
182 	table->cols = static_cast<dict_col_t*>(
183 		mem_heap_alloc(heap, table->n_cols * sizeof(dict_col_t)));
184 	table->v_cols = static_cast<dict_v_col_t*>(
185 		mem_heap_alloc(heap, n_v_cols * sizeof(*table->v_cols)));
186 	for (ulint i = n_v_cols; i--; ) {
187 		new (&table->v_cols[i]) dict_v_col_t();
188 	}
189 
190 	table->autoinc_lock = static_cast<ib_lock_t*>(
191 		mem_heap_alloc(heap, lock_get_size()));
192 
193 	/* If the table has an FTS index or we are in the process
194 	of building one, create the table->fts */
195 	if (dict_table_has_fts_index(table)
196 	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
197 	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
198 		table->fts = fts_create(table);
199 		table->fts->cache = fts_cache_create(table);
200 	}
201 
202 	new(&table->foreign_set) dict_foreign_set();
203 	new(&table->referenced_set) dict_foreign_set();
204 
205 	return(table);
206 }
207 
208 /****************************************************************//**
209 Free a table memory object. */
210 void
dict_mem_table_free(dict_table_t * table)211 dict_mem_table_free(
212 /*================*/
213 	dict_table_t*	table)		/*!< in: table */
214 {
215 	ut_ad(table);
216 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
217 	ut_ad(UT_LIST_GET_LEN(table->indexes) == 0);
218 #ifdef BTR_CUR_HASH_ADAPT
219 	ut_ad(UT_LIST_GET_LEN(table->freed_indexes) == 0);
220 #endif /* BTR_CUR_HASH_ADAPT */
221 	ut_d(table->cached = FALSE);
222 
223 	if (dict_table_has_fts_index(table)
224 	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
225 	    || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
226 		if (table->fts) {
227 			fts_free(table);
228 		}
229 	}
230 
231 	dict_mem_table_free_foreign_vcol_set(table);
232 
233 	table->foreign_set.~dict_foreign_set();
234 	table->referenced_set.~dict_foreign_set();
235 
236 	ut_free(table->name.m_name);
237 	table->name.m_name = NULL;
238 
239 	/* Clean up virtual index info structures that are registered
240 	with virtual columns */
241 	for (ulint i = 0; i < table->n_v_def; i++) {
242 		dict_table_get_nth_v_col(table, i)->~dict_v_col_t();
243 	}
244 
245 	UT_DELETE(table->s_cols);
246 
247 	mem_heap_free(table->heap);
248 }
249 
250 /****************************************************************//**
251 Append 'name' to 'col_names'.  @see dict_table_t::col_names
252 @return new column names array */
253 static
254 const char*
dict_add_col_name(const char * col_names,ulint cols,const char * name,mem_heap_t * heap)255 dict_add_col_name(
256 /*==============*/
257 	const char*	col_names,	/*!< in: existing column names, or
258 					NULL */
259 	ulint		cols,		/*!< in: number of existing columns */
260 	const char*	name,		/*!< in: new column name */
261 	mem_heap_t*	heap)		/*!< in: heap */
262 {
263 	ulint	old_len;
264 	ulint	new_len;
265 	ulint	total_len;
266 	char*	res;
267 
268 	ut_ad(!cols == !col_names);
269 
270 	/* Find out length of existing array. */
271 	if (col_names) {
272 		const char*	s = col_names;
273 		ulint		i;
274 
275 		for (i = 0; i < cols; i++) {
276 			s += strlen(s) + 1;
277 		}
278 
279 		old_len = unsigned(s - col_names);
280 	} else {
281 		old_len = 0;
282 	}
283 
284 	new_len = strlen(name) + 1;
285 	total_len = old_len + new_len;
286 
287 	res = static_cast<char*>(mem_heap_alloc(heap, total_len));
288 
289 	if (old_len > 0) {
290 		memcpy(res, col_names, old_len);
291 	}
292 
293 	memcpy(res + old_len, name, new_len);
294 
295 	return(res);
296 }
297 
298 /**********************************************************************//**
299 Adds a column definition to a table. */
300 void
dict_mem_table_add_col(dict_table_t * table,mem_heap_t * heap,const char * name,ulint mtype,ulint prtype,ulint len)301 dict_mem_table_add_col(
302 /*===================*/
303 	dict_table_t*	table,	/*!< in: table */
304 	mem_heap_t*	heap,	/*!< in: temporary memory heap, or NULL */
305 	const char*	name,	/*!< in: column name, or NULL */
306 	ulint		mtype,	/*!< in: main datatype */
307 	ulint		prtype,	/*!< in: precise type */
308 	ulint		len)	/*!< in: precision */
309 {
310 	dict_col_t*	col;
311 	unsigned	i;
312 
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 	switch (prtype & DATA_VERSIONED) {
343 	case DATA_VERS_START:
344 		ut_ad(!table->vers_start);
345 		table->vers_start = i & dict_index_t::MAX_N_FIELDS;
346 		break;
347 	case DATA_VERS_END:
348 		ut_ad(!table->vers_end);
349 		table->vers_end = i & dict_index_t::MAX_N_FIELDS;
350 	}
351 }
352 
353 /** Adds a virtual column definition to a table.
354 @param[in,out]	table		table
355 @param[in,out]	heap		temporary memory heap, or NULL. It is
356 				used to store name when we have not finished
357 				adding all columns. When all columns are
358 				added, the whole name will copy to memory from
359 				table->heap
360 @param[in]	name		column name
361 @param[in]	mtype		main datatype
362 @param[in]	prtype		precise type
363 @param[in]	len		length
364 @param[in]	pos		position in a table
365 @param[in]	num_base	number of base columns
366 @return the virtual column definition */
367 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)368 dict_mem_table_add_v_col(
369 	dict_table_t*	table,
370 	mem_heap_t*	heap,
371 	const char*	name,
372 	ulint		mtype,
373 	ulint		prtype,
374 	ulint		len,
375 	ulint		pos,
376 	ulint		num_base)
377 {
378 	dict_v_col_t*	v_col;
379 
380 	ut_ad(table);
381 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
382 	ut_ad(!heap == !name);
383 
384 	ut_ad(prtype & DATA_VIRTUAL);
385 
386 	unsigned i = table->n_v_def++;
387 
388 	table->n_t_def++;
389 
390 	if (name != NULL) {
391 		if (table->n_v_def == table->n_v_cols) {
392 			heap = table->heap;
393 		}
394 
395 		if (i && !table->v_col_names) {
396 			/* All preceding column names are empty. */
397 			char* s = static_cast<char*>(
398 				mem_heap_zalloc(heap, table->n_v_def));
399 
400 			table->v_col_names = s;
401 		}
402 
403 		table->v_col_names = dict_add_col_name(table->v_col_names,
404 						       i, name, heap);
405 	}
406 
407 	v_col = &table->v_cols[i];
408 
409 	dict_mem_fill_column_struct(&v_col->m_col, pos, mtype, prtype, len);
410 	v_col->v_pos = i & dict_index_t::MAX_N_FIELDS;
411 
412 	if (num_base != 0) {
413 		v_col->base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
414 					table->heap, num_base * sizeof(
415 						*v_col->base_col)));
416 	} else {
417 		v_col->base_col = NULL;
418 	}
419 
420 	v_col->num_base = static_cast<unsigned>(num_base)
421 		& dict_index_t::MAX_N_FIELDS;
422 
423 	/* Initialize the index list for virtual columns */
424 	ut_ad(v_col->v_indexes.empty());
425 
426 	return(v_col);
427 }
428 
429 /** Adds a stored column definition to a table.
430 @param[in]	table		table
431 @param[in]	num_base	number of base columns. */
432 void
dict_mem_table_add_s_col(dict_table_t * table,ulint num_base)433 dict_mem_table_add_s_col(
434 	dict_table_t*	table,
435 	ulint		num_base)
436 {
437 	unsigned	i = unsigned(table->n_def) - 1;
438 	dict_col_t*	col = dict_table_get_nth_col(table, i);
439 	dict_s_col_t	s_col;
440 
441 	ut_ad(col != NULL);
442 
443 	if (table->s_cols == NULL) {
444 		table->s_cols = UT_NEW_NOKEY(dict_s_col_list());
445 	}
446 
447 	s_col.m_col = col;
448 	s_col.s_pos = i + table->n_v_def;
449 
450 	if (num_base != 0) {
451 		s_col.base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
452 			table->heap, num_base * sizeof(dict_col_t*)));
453 	} else {
454 		s_col.base_col = NULL;
455 	}
456 
457 	s_col.num_base = num_base;
458 	table->s_cols->push_front(s_col);
459 }
460 
461 /**********************************************************************//**
462 Renames a column of a table in the data dictionary cache. */
463 static MY_ATTRIBUTE((nonnull))
464 void
dict_mem_table_col_rename_low(dict_table_t * table,unsigned i,const char * to,const char * s,bool is_virtual)465 dict_mem_table_col_rename_low(
466 /*==========================*/
467 	dict_table_t*	table,	/*!< in/out: table */
468 	unsigned	i,	/*!< in: column offset corresponding to s */
469 	const char*	to,	/*!< in: new column name */
470 	const char*	s,	/*!< in: pointer to table->col_names */
471 	bool		is_virtual)
472 				/*!< in: if this is a virtual column */
473 {
474 	char*	t_col_names = const_cast<char*>(
475 		is_virtual ? table->v_col_names : table->col_names);
476 	ulint	n_col = is_virtual ? table->n_v_def : table->n_def;
477 
478 	size_t from_len = strlen(s), to_len = strlen(to);
479 
480 	ut_ad(i < table->n_def || is_virtual);
481 	ut_ad(i < table->n_v_def || !is_virtual);
482 
483 	ut_ad(from_len <= NAME_LEN);
484 	ut_ad(to_len <= NAME_LEN);
485 
486 	char from[NAME_LEN + 1];
487 	strncpy(from, s, sizeof from - 1);
488 	from[sizeof from - 1] = '\0';
489 
490 	if (from_len == to_len) {
491 		/* The easy case: simply replace the column name in
492 		table->col_names. */
493 		strcpy(const_cast<char*>(s), to);
494 	} else {
495 		/* We need to adjust all affected index->field
496 		pointers, as in dict_index_add_col(). First, copy
497 		table->col_names. */
498 		ulint	prefix_len	= ulint(s - t_col_names);
499 
500 		for (; i < n_col; i++) {
501 			s += strlen(s) + 1;
502 		}
503 
504 		ulint	full_len	= ulint(s - t_col_names);
505 		char*	col_names;
506 
507 		if (to_len > from_len) {
508 			col_names = static_cast<char*>(
509 				mem_heap_alloc(
510 					table->heap,
511 					full_len + to_len - from_len));
512 
513 			memcpy(col_names, t_col_names, prefix_len);
514 		} else {
515 			col_names = const_cast<char*>(t_col_names);
516 		}
517 
518 		memcpy(col_names + prefix_len, to, to_len);
519 		memmove(col_names + prefix_len + to_len,
520 			t_col_names + (prefix_len + from_len),
521 			full_len - (prefix_len + from_len));
522 
523 		/* Replace the field names in every index. */
524 		for (dict_index_t* index = dict_table_get_first_index(table);
525 		     index != NULL;
526 		     index = dict_table_get_next_index(index)) {
527 			ulint	n_fields = dict_index_get_n_fields(index);
528 
529 			for (ulint i = 0; i < n_fields; i++) {
530 				dict_field_t*	field
531 					= dict_index_get_nth_field(
532 						index, i);
533 
534 				ut_ad(!field->name
535 				      == field->col->is_dropped());
536 				if (!field->name) {
537 					/* dropped columns lack a name */
538 					ut_ad(index->is_instant());
539 					continue;
540 				}
541 
542 				/* if is_virtual and that in field->col does
543 				not match, continue */
544 				if ((!is_virtual) !=
545 				    (!field->col->is_virtual())) {
546 					continue;
547 				}
548 
549 				ulint		name_ofs
550 					= ulint(field->name - t_col_names);
551 				if (name_ofs <= prefix_len) {
552 					field->name = col_names + name_ofs;
553 				} else {
554 					ut_a(name_ofs < full_len);
555 					field->name = col_names
556 						+ name_ofs + to_len - from_len;
557 				}
558 			}
559 		}
560 
561 		if (is_virtual) {
562 			table->v_col_names = col_names;
563 		} else {
564 			table->col_names = col_names;
565 		}
566 	}
567 
568 	/* Virtual columns are not allowed for foreign key */
569 	if (is_virtual) {
570 		return;
571 	}
572 
573 	dict_foreign_t*	foreign;
574 
575 	/* Replace the field names in every foreign key constraint. */
576 	for (dict_foreign_set::iterator it = table->foreign_set.begin();
577 	     it != table->foreign_set.end();
578 	     ++it) {
579 
580 		foreign = *it;
581 
582 		if (foreign->foreign_index == NULL) {
583 			/* We may go here when we set foreign_key_checks to 0,
584 			and then try to rename a column and modify the
585 			corresponding foreign key constraint. The index
586 			would have been dropped, we have to find an equivalent
587 			one */
588 			for (unsigned f = 0; f < foreign->n_fields; f++) {
589 				if (strcmp(foreign->foreign_col_names[f], from)
590 				    == 0) {
591 
592 					char** rc = const_cast<char**>(
593 						foreign->foreign_col_names
594 						+ f);
595 
596 					if (to_len <= strlen(*rc)) {
597 						memcpy(*rc, to, to_len + 1);
598 					} else {
599 						*rc = static_cast<char*>(
600 							mem_heap_dup(
601 								foreign->heap,
602 								to,
603 								to_len + 1));
604 					}
605 				}
606 			}
607 
608 			/* New index can be null if InnoDB already dropped
609 			the foreign index when FOREIGN_KEY_CHECKS is
610 			disabled */
611 			foreign->foreign_index = dict_foreign_find_index(
612 				foreign->foreign_table, NULL,
613 				foreign->foreign_col_names,
614 				foreign->n_fields, NULL, true, false,
615 				NULL, NULL, NULL);
616 
617 		} else {
618 
619 			for (unsigned f = 0; f < foreign->n_fields; f++) {
620 				/* These can point straight to
621 				table->col_names, because the foreign key
622 				constraints will be freed at the same time
623 				when the table object is freed. */
624 				foreign->foreign_col_names[f]
625 					= dict_index_get_nth_field(
626 						foreign->foreign_index,
627 						f)->name;
628 			}
629 		}
630 	}
631 
632 	for (dict_foreign_set::iterator it = table->referenced_set.begin();
633 	     it != table->referenced_set.end();
634 	     ++it) {
635 
636 		foreign = *it;
637 
638 		if (!foreign->referenced_index) {
639 			/* Referenced index could have been dropped
640 			when foreign_key_checks is disabled. In that case,
641 			rename the corresponding referenced_col_names and
642 			find the equivalent referenced index also */
643 			for (unsigned f = 0; f < foreign->n_fields; f++) {
644 
645 				const char*& rc =
646 					foreign->referenced_col_names[f];
647 				if (strcmp(rc, from)) {
648 					continue;
649 				}
650 
651 				if (to_len <= strlen(rc)) {
652 					memcpy(const_cast<char*>(rc), to,
653 					       to_len + 1);
654 				} else {
655 					rc = static_cast<char*>(
656 						mem_heap_dup(
657 							foreign->heap,
658 							to, to_len + 1));
659 				}
660 			}
661 
662 			/* New index can be null if InnoDB already dropped
663 			the referenced index when FOREIGN_KEY_CHECKS is
664 			disabled */
665 			foreign->referenced_index = dict_foreign_find_index(
666 				foreign->referenced_table, NULL,
667 				foreign->referenced_col_names,
668 				foreign->n_fields, NULL, true, false,
669 				NULL, NULL, NULL);
670 			return;
671 		}
672 
673 
674 		for (unsigned f = 0; f < foreign->n_fields; f++) {
675 			/* foreign->referenced_col_names[] need to be
676 			copies, because the constraint may become
677 			orphan when foreign_key_checks=0 and the
678 			parent table is dropped. */
679 
680 			const char* col_name = dict_index_get_nth_field(
681 				foreign->referenced_index, f)->name;
682 
683 			if (strcmp(foreign->referenced_col_names[f],
684 				   col_name)) {
685 				char**	rc = const_cast<char**>(
686 					foreign->referenced_col_names + f);
687 				size_t	col_name_len_1 = strlen(col_name) + 1;
688 
689 				if (col_name_len_1 <= strlen(*rc) + 1) {
690 					memcpy(*rc, col_name, col_name_len_1);
691 				} else {
692 					*rc = static_cast<char*>(
693 						mem_heap_dup(
694 							foreign->heap,
695 							col_name,
696 							col_name_len_1));
697 				}
698 			}
699 		}
700 	}
701 }
702 
703 /**********************************************************************//**
704 Renames a column of a table in the data dictionary cache. */
705 void
dict_mem_table_col_rename(dict_table_t * table,ulint nth_col,const char * from,const char * to,bool is_virtual)706 dict_mem_table_col_rename(
707 /*======================*/
708 	dict_table_t*	table,	/*!< in/out: table */
709 	ulint		nth_col,/*!< in: column index */
710 	const char*	from,	/*!< in: old column name */
711 	const char*	to,	/*!< in: new column name */
712 	bool		is_virtual)
713 				/*!< in: if this is a virtual column */
714 {
715 	const char*	s = is_virtual ? table->v_col_names : table->col_names;
716 
717 	ut_ad((!is_virtual && nth_col < table->n_def)
718 	       || (is_virtual && nth_col < table->n_v_def));
719 
720 	for (ulint i = 0; i < nth_col; i++) {
721 		size_t	len = strlen(s);
722 		ut_ad(len > 0);
723 		s += len + 1;
724 	}
725 
726 	ut_ad(!my_strcasecmp(system_charset_info, from, s));
727 
728 	dict_mem_table_col_rename_low(table, static_cast<unsigned>(nth_col),
729 				      to, s, is_virtual);
730 }
731 
732 /**********************************************************************//**
733 This function populates a dict_col_t memory structure with
734 supplied information. */
735 void
dict_mem_fill_column_struct(dict_col_t * column,ulint col_pos,ulint mtype,ulint prtype,ulint col_len)736 dict_mem_fill_column_struct(
737 /*========================*/
738 	dict_col_t*	column,		/*!< out: column struct to be
739 					filled */
740 	ulint		col_pos,	/*!< in: column position */
741 	ulint		mtype,		/*!< in: main data type */
742 	ulint		prtype,		/*!< in: precise type */
743 	ulint		col_len)	/*!< in: column length */
744 {
745 	unsigned mbminlen, mbmaxlen;
746 
747 	column->ind = static_cast<unsigned>(col_pos)
748 		& dict_index_t::MAX_N_FIELDS;
749 	column->ord_part = 0;
750 	column->max_prefix = 0;
751 	column->mtype = static_cast<uint8_t>(mtype);
752 	column->prtype = static_cast<unsigned>(prtype);
753 	column->len = static_cast<uint16_t>(col_len);
754 	dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
755 	column->mbminlen = mbminlen & 7;
756 	column->mbmaxlen = mbmaxlen & 7;
757 	column->def_val.data = NULL;
758 	column->def_val.len = UNIV_SQL_DEFAULT;
759 	ut_ad(!column->is_dropped());
760 }
761 
762 /**********************************************************************//**
763 Creates an index memory object.
764 @return own: index object */
765 dict_index_t*
dict_mem_index_create(dict_table_t * table,const char * index_name,ulint type,ulint n_fields)766 dict_mem_index_create(
767 /*==================*/
768 	dict_table_t*	table,		/*!< in: table */
769 	const char*	index_name,	/*!< in: index name */
770 	ulint		type,		/*!< in: DICT_UNIQUE,
771 					DICT_CLUSTERED, ... ORed */
772 	ulint		n_fields)	/*!< in: number of fields */
773 {
774 	dict_index_t*	index;
775 	mem_heap_t*	heap;
776 
777 	ut_ad(!table || table->magic_n == DICT_TABLE_MAGIC_N);
778 	ut_ad(index_name);
779 
780 	heap = mem_heap_create(DICT_HEAP_SIZE);
781 
782 	index = static_cast<dict_index_t*>(
783 		mem_heap_zalloc(heap, sizeof(*index)));
784 	index->table = table;
785 
786 	dict_mem_fill_index_struct(index, heap, index_name, type, n_fields);
787 
788 	new (&index->zip_pad.mutex) std::mutex();
789 
790 	if (type & DICT_SPATIAL) {
791 		index->rtr_track = new
792 			(mem_heap_alloc(heap, sizeof *index->rtr_track))
793 			rtr_info_track_t();
794 		mutex_create(LATCH_ID_RTR_ACTIVE_MUTEX,
795 			     &index->rtr_track->rtr_active_mutex);
796 	}
797 
798 	return(index);
799 }
800 
801 /**********************************************************************//**
802 Creates and initializes a foreign constraint memory object.
803 @return own: foreign constraint struct */
804 dict_foreign_t*
dict_mem_foreign_create(void)805 dict_mem_foreign_create(void)
806 /*=========================*/
807 {
808 	dict_foreign_t*	foreign;
809 	mem_heap_t*	heap;
810 	DBUG_ENTER("dict_mem_foreign_create");
811 
812 	heap = mem_heap_create(100);
813 
814 	foreign = static_cast<dict_foreign_t*>(
815 		mem_heap_zalloc(heap, sizeof(dict_foreign_t)));
816 
817 	foreign->heap = heap;
818 
819 	foreign->v_cols = NULL;
820 
821 	DBUG_PRINT("dict_mem_foreign_create", ("heap: %p", heap));
822 
823 	DBUG_RETURN(foreign);
824 }
825 
826 /**********************************************************************//**
827 Sets the foreign_table_name_lookup pointer based on the value of
828 lower_case_table_names.  If that is 0 or 1, foreign_table_name_lookup
829 will point to foreign_table_name.  If 2, then another string is
830 allocated from foreign->heap and set to lower case. */
831 void
dict_mem_foreign_table_name_lookup_set(dict_foreign_t * foreign,ibool do_alloc)832 dict_mem_foreign_table_name_lookup_set(
833 /*===================================*/
834 	dict_foreign_t*	foreign,	/*!< in/out: foreign struct */
835 	ibool		do_alloc)	/*!< in: is an alloc needed */
836 {
837 	if (innobase_get_lower_case_table_names() == 2) {
838 		if (do_alloc) {
839 			ulint	len;
840 
841 			len = strlen(foreign->foreign_table_name) + 1;
842 
843 			foreign->foreign_table_name_lookup =
844 				static_cast<char*>(
845 					mem_heap_alloc(foreign->heap, len));
846 		}
847 		strcpy(foreign->foreign_table_name_lookup,
848 		       foreign->foreign_table_name);
849 		innobase_casedn_str(foreign->foreign_table_name_lookup);
850 	} else {
851 		foreign->foreign_table_name_lookup
852 			= foreign->foreign_table_name;
853 	}
854 }
855 
856 /**********************************************************************//**
857 Sets the referenced_table_name_lookup pointer based on the value of
858 lower_case_table_names.  If that is 0 or 1, referenced_table_name_lookup
859 will point to referenced_table_name.  If 2, then another string is
860 allocated from foreign->heap and set to lower case. */
861 void
dict_mem_referenced_table_name_lookup_set(dict_foreign_t * foreign,ibool do_alloc)862 dict_mem_referenced_table_name_lookup_set(
863 /*======================================*/
864 	dict_foreign_t*	foreign,	/*!< in/out: foreign struct */
865 	ibool		do_alloc)	/*!< in: is an alloc needed */
866 {
867 	if (innobase_get_lower_case_table_names() == 2) {
868 		if (do_alloc) {
869 			ulint	len;
870 
871 			len = strlen(foreign->referenced_table_name) + 1;
872 
873 			foreign->referenced_table_name_lookup =
874 				static_cast<char*>(
875 					mem_heap_alloc(foreign->heap, len));
876 		}
877 		strcpy(foreign->referenced_table_name_lookup,
878 		       foreign->referenced_table_name);
879 		innobase_casedn_str(foreign->referenced_table_name_lookup);
880 	} else {
881 		foreign->referenced_table_name_lookup
882 			= foreign->referenced_table_name;
883 	}
884 }
885 
886 /** Fill the virtual column set with virtual column information
887 present in the given virtual index.
888 @param[in]	index	virtual index
889 @param[out]	v_cols	virtual column set. */
890 static
891 void
dict_mem_fill_vcol_has_index(const dict_index_t * index,dict_vcol_set ** v_cols)892 dict_mem_fill_vcol_has_index(
893 	const dict_index_t*	index,
894 	dict_vcol_set**		v_cols)
895 {
896 	for (ulint i = 0; i < index->table->n_v_cols; i++) {
897 		dict_v_col_t*	v_col = dict_table_get_nth_v_col(
898 					index->table, i);
899 		if (!v_col->m_col.ord_part) {
900 			continue;
901 		}
902 
903 		for (const auto& v_idx : v_col->v_indexes) {
904 			if (v_idx.index != index) {
905 				continue;
906 			}
907 
908 			if (*v_cols == NULL) {
909 				*v_cols = UT_NEW_NOKEY(dict_vcol_set());
910 			}
911 
912 			(*v_cols)->insert(v_col);
913 		}
914 	}
915 }
916 
917 /** Fill the virtual column set with the virtual column of the index
918 if the index contains given column name.
919 @param[in]	col_name	column name
920 @param[in]	table		innodb table object
921 @param[out]	v_cols		set of virtual column information. */
922 static
923 void
dict_mem_fill_vcol_from_v_indexes(const char * col_name,const dict_table_t * table,dict_vcol_set ** v_cols)924 dict_mem_fill_vcol_from_v_indexes(
925 	const char*		col_name,
926 	const dict_table_t*	table,
927 	dict_vcol_set**		v_cols)
928 {
929 	/* virtual column can't be Primary Key, so start with
930 	secondary index */
931 	for (dict_index_t* index = dict_table_get_next_index(
932 			dict_table_get_first_index(table));
933 		index;
934 		index = dict_table_get_next_index(index)) {
935 
936 		/* Skip if the index have newly added
937 		virtual column because field name is NULL.
938 		Later virtual column set will be
939 		refreshed during loading of table. */
940 		if (!dict_index_has_virtual(index)
941 		    || index->has_new_v_col()) {
942 			continue;
943 		}
944 
945 		for (ulint i = 0; i < index->n_fields; i++) {
946 			dict_field_t*	field =
947 				dict_index_get_nth_field(index, i);
948 
949 			if (strcmp(field->name, col_name) == 0) {
950 				dict_mem_fill_vcol_has_index(
951 					index, v_cols);
952 			}
953 		}
954 	}
955 }
956 
957 /** Fill the virtual column set with virtual columns which have base columns
958 as the given col_name
959 @param[in]	col_name	column name
960 @param[in]	table		table object
961 @param[out]	v_cols		set of virtual columns. */
962 static
963 void
dict_mem_fill_vcol_set_for_base_col(const char * col_name,const dict_table_t * table,dict_vcol_set ** v_cols)964 dict_mem_fill_vcol_set_for_base_col(
965 	const char*		col_name,
966 	const dict_table_t*	table,
967 	dict_vcol_set**		v_cols)
968 {
969 	for (ulint i = 0; i < table->n_v_cols; i++) {
970 		dict_v_col_t*	v_col = dict_table_get_nth_v_col(table, i);
971 
972 		if (!v_col->m_col.ord_part) {
973 			continue;
974 		}
975 
976 		for (ulint j = 0; j < unsigned{v_col->num_base}; j++) {
977 			if (strcmp(col_name, dict_table_get_col_name(
978 					table,
979 					v_col->base_col[j]->ind)) == 0) {
980 
981 				if (*v_cols == NULL) {
982 					*v_cols = UT_NEW_NOKEY(dict_vcol_set());
983 				}
984 
985 				(*v_cols)->insert(v_col);
986 			}
987 		}
988 	}
989 }
990 
991 /** Fills the dependent virtual columns in a set.
992 Reason for being dependent are
993 1) FK can be present on base column of virtual columns
994 2) FK can be present on column which is a part of virtual index
995 @param[in,out]  foreign foreign key information. */
996 void
dict_mem_foreign_fill_vcol_set(dict_foreign_t * foreign)997 dict_mem_foreign_fill_vcol_set(
998         dict_foreign_t* foreign)
999 {
1000 	ulint	type = foreign->type;
1001 
1002 	if (type == 0) {
1003 		return;
1004 	}
1005 
1006 	for (ulint i = 0; i < foreign->n_fields; i++) {
1007 		/** FK can be present on base columns
1008 		of virtual columns. */
1009 		dict_mem_fill_vcol_set_for_base_col(
1010 			foreign->foreign_col_names[i],
1011 			foreign->foreign_table,
1012 			&foreign->v_cols);
1013 
1014 		/** FK can be present on the columns
1015 		which can be a part of virtual index. */
1016 		dict_mem_fill_vcol_from_v_indexes(
1017 			foreign->foreign_col_names[i],
1018 			foreign->foreign_table,
1019 			&foreign->v_cols);
1020 	}
1021 }
1022 
1023 /** Fill virtual columns set in each fk constraint present in the table.
1024 @param[in,out]	table	innodb table object. */
1025 void
dict_mem_table_fill_foreign_vcol_set(dict_table_t * table)1026 dict_mem_table_fill_foreign_vcol_set(
1027 	dict_table_t*	table)
1028 {
1029 	dict_foreign_set	fk_set = table->foreign_set;
1030 	dict_foreign_t*		foreign;
1031 
1032 	dict_foreign_set::iterator it;
1033 	for (it = fk_set.begin(); it != fk_set.end(); ++it) {
1034 		foreign = *it;
1035 
1036 		dict_mem_foreign_fill_vcol_set(foreign);
1037 	}
1038 }
1039 
1040 /** Free the vcol_set from all foreign key constraint on the table.
1041 @param[in,out]	table	innodb table object. */
1042 void
dict_mem_table_free_foreign_vcol_set(dict_table_t * table)1043 dict_mem_table_free_foreign_vcol_set(
1044 	dict_table_t*	table)
1045 {
1046 	dict_foreign_set	fk_set = table->foreign_set;
1047 	dict_foreign_t*		foreign;
1048 
1049 	dict_foreign_set::iterator it;
1050 	for (it = fk_set.begin(); it != fk_set.end(); ++it) {
1051 
1052 		foreign = *it;
1053 
1054 		if (foreign->v_cols != NULL) {
1055 			UT_DELETE(foreign->v_cols);
1056 			foreign->v_cols = NULL;
1057 		}
1058 	}
1059 }
1060 
1061 /**********************************************************************//**
1062 Adds a field definition to an index. NOTE: does not take a copy
1063 of the column name if the field is a column. The memory occupied
1064 by the column name may be released only after publishing the index. */
1065 void
dict_mem_index_add_field(dict_index_t * index,const char * name,ulint prefix_len)1066 dict_mem_index_add_field(
1067 /*=====================*/
1068 	dict_index_t*	index,		/*!< in: index */
1069 	const char*	name,		/*!< in: column name */
1070 	ulint		prefix_len)	/*!< in: 0 or the column prefix length
1071 					in a MySQL index like
1072 					INDEX (textcol(25)) */
1073 {
1074 	dict_field_t*	field;
1075 
1076 	ut_ad(index);
1077 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1078 
1079 	index->n_def++;
1080 
1081 	field = dict_index_get_nth_field(index, unsigned(index->n_def) - 1);
1082 
1083 	field->name = name;
1084 	field->prefix_len = prefix_len & ((1U << 12) - 1);
1085 }
1086 
1087 /**********************************************************************//**
1088 Frees an index memory object. */
1089 void
dict_mem_index_free(dict_index_t * index)1090 dict_mem_index_free(
1091 /*================*/
1092 	dict_index_t*	index)	/*!< in: index */
1093 {
1094 	ut_ad(index);
1095 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1096 
1097 	index->zip_pad.mutex.~mutex();
1098 
1099 	if (dict_index_is_spatial(index)) {
1100 		for (auto& rtr_info : index->rtr_track->rtr_active) {
1101 			rtr_info->index = NULL;
1102 		}
1103 
1104 		mutex_destroy(&index->rtr_track->rtr_active_mutex);
1105 		index->rtr_track->~rtr_info_track_t();
1106 	}
1107 
1108 	index->detach_columns();
1109 	mem_heap_free(index->heap);
1110 }
1111 
1112 /** Create a temporary tablename like "#sql-ibNNN".
1113 @param[in]	heap	A memory heap
1114 @param[in]	dbtab	Table name in the form database/table name
1115 @param[in]	id	Table id
1116 @return A unique temporary tablename suitable for InnoDB use */
1117 char*
dict_mem_create_temporary_tablename(mem_heap_t * heap,const char * dbtab,table_id_t id)1118 dict_mem_create_temporary_tablename(
1119 	mem_heap_t*	heap,
1120 	const char*	dbtab,
1121 	table_id_t	id)
1122 {
1123 	size_t		size;
1124 	char*		name;
1125 	const char*	dbend   = strchr(dbtab, '/');
1126 	ut_ad(dbend);
1127 	size_t		dblen   = size_t(dbend - dbtab) + 1;
1128 
1129 	size = dblen + (sizeof(TEMP_FILE_PREFIX) + 3 + 20);
1130 	name = static_cast<char*>(mem_heap_alloc(heap, size));
1131 	memcpy(name, dbtab, dblen);
1132 	snprintf(name + dblen, size - dblen,
1133 		 TEMP_FILE_PREFIX_INNODB UINT64PF, id);
1134 
1135 	return(name);
1136 }
1137 
1138 /** Validate the search order in the foreign key set.
1139 @param[in]	fk_set	the foreign key set to be validated
1140 @return true if search order is fine in the set, false otherwise. */
1141 bool
dict_foreign_set_validate(const dict_foreign_set & fk_set)1142 dict_foreign_set_validate(
1143 	const dict_foreign_set&	fk_set)
1144 {
1145 	dict_foreign_not_exists	not_exists(fk_set);
1146 
1147 	dict_foreign_set::const_iterator it = std::find_if(
1148 		fk_set.begin(), fk_set.end(), not_exists);
1149 
1150 	if (it == fk_set.end()) {
1151 		return(true);
1152 	}
1153 
1154 	dict_foreign_t*	foreign = *it;
1155 	std::cerr << "Foreign key lookup failed: " << *foreign;
1156 	std::cerr << fk_set;
1157 	ut_ad(0);
1158 	return(false);
1159 }
1160 
1161 /** Validate the search order in the foreign key sets of the table
1162 (foreign_set and referenced_set).
1163 @param[in]	table	table whose foreign key sets are to be validated
1164 @return true if foreign key sets are fine, false otherwise. */
1165 bool
dict_foreign_set_validate(const dict_table_t & table)1166 dict_foreign_set_validate(
1167 	const dict_table_t&	table)
1168 {
1169 	return(dict_foreign_set_validate(table.foreign_set)
1170 	       && dict_foreign_set_validate(table.referenced_set));
1171 }
1172 
1173 std::ostream&
operator <<(std::ostream & out,const dict_foreign_t & foreign)1174 operator<< (std::ostream& out, const dict_foreign_t& foreign)
1175 {
1176 	out << "[dict_foreign_t: id='" << foreign.id << "'";
1177 
1178 	if (foreign.foreign_table_name != NULL) {
1179 		out << ",for: '" << foreign.foreign_table_name << "'";
1180 	}
1181 
1182 	out << "]";
1183 	return(out);
1184 }
1185 
1186 std::ostream&
operator <<(std::ostream & out,const dict_foreign_set & fk_set)1187 operator<< (std::ostream& out, const dict_foreign_set& fk_set)
1188 {
1189 	out << "[dict_foreign_set:";
1190 	std::for_each(fk_set.begin(), fk_set.end(), dict_foreign_print(out));
1191 	out << "]" << std::endl;
1192 	return(out);
1193 }
1194 
1195 /** Check whether fulltext index gets affected by foreign
1196 key constraint. */
affects_fulltext() const1197 bool dict_foreign_t::affects_fulltext() const
1198 {
1199   if (foreign_table == referenced_table || !foreign_table->fts)
1200     return false;
1201 
1202   for (ulint i= 0; i < n_fields; i++)
1203   {
1204     const dict_col_t *col= dict_index_get_nth_col(foreign_index, i);
1205     if (dict_table_is_fts_column(foreign_table->fts->indexes, col->ind,
1206                                  col->is_virtual()) != ULINT_UNDEFINED)
1207       return true;
1208   }
1209 
1210   return false;
1211 }
1212 
1213 /** Reconstruct the clustered index fields.
1214 @return whether metadata is incorrect */
reconstruct_fields()1215 inline bool dict_index_t::reconstruct_fields()
1216 {
1217 	DBUG_ASSERT(is_primary());
1218 
1219 	n_fields = (n_fields + table->instant->n_dropped)
1220 		& dict_index_t::MAX_N_FIELDS;
1221 	n_def = (n_def + table->instant->n_dropped)
1222 		& dict_index_t::MAX_N_FIELDS;
1223 
1224 	const unsigned n_first = first_user_field();
1225 
1226 	dict_field_t* tfields = static_cast<dict_field_t*>(
1227 		mem_heap_zalloc(heap, n_fields * sizeof *fields));
1228 
1229 	memcpy(tfields, fields, n_first * sizeof *fields);
1230 
1231 	n_nullable = 0;
1232 	ulint n_core_null = 0;
1233 	const bool comp = dict_table_is_comp(table);
1234 	const auto* field_map_it = table->instant->field_map;
1235 	for (unsigned i = n_first, j = 0; i < n_fields; ) {
1236 		dict_field_t& f = tfields[i++];
1237 		auto c = *field_map_it++;
1238 		if (c.is_dropped()) {
1239 			f.col = &table->instant->dropped[j++];
1240 			DBUG_ASSERT(f.col->is_dropped());
1241 			f.fixed_len = dict_col_get_fixed_size(f.col, comp)
1242 				& ((1U << 10) - 1);
1243 		} else {
1244 			DBUG_ASSERT(!c.is_not_null());
1245 			const auto old = std::find_if(
1246 				fields + n_first, fields + n_fields,
1247 				[c](const dict_field_t& o)
1248 				{ return o.col->ind == c.ind(); });
1249 
1250 			if (old >= fields + n_fields
1251 			    || old->prefix_len
1252 			    || old->col != &table->cols[c.ind()]) {
1253 				return true;
1254 			}
1255 
1256 			ut_ad(old >= &fields[n_first]);
1257 			f = *old;
1258 		}
1259 
1260 		f.col->clear_instant();
1261 		if (f.col->is_nullable()) {
1262 			n_nullable++;
1263 			n_core_null += i <= n_core_fields;
1264 		}
1265 	}
1266 
1267 	fields = tfields;
1268 	n_core_null_bytes = static_cast<byte>(UT_BITS_IN_BYTES(n_core_null));
1269 
1270 	return false;
1271 }
1272 
1273 /** Reconstruct dropped or reordered columns.
1274 @param[in]	metadata	data from serialise_columns()
1275 @param[in]	len		length of the metadata, in bytes
1276 @return whether parsing the metadata failed */
deserialise_columns(const byte * metadata,ulint len)1277 bool dict_table_t::deserialise_columns(const byte* metadata, ulint len)
1278 {
1279 	DBUG_ASSERT(!instant);
1280 
1281 	unsigned num_non_pk_fields = mach_read_from_4(metadata);
1282 	metadata += 4;
1283 
1284 	if (num_non_pk_fields >= REC_MAX_N_FIELDS - 3) {
1285 		return true;
1286 	}
1287 
1288 	dict_index_t* index = UT_LIST_GET_FIRST(indexes);
1289 
1290 	if (num_non_pk_fields < unsigned(index->n_fields)
1291 	    - index->first_user_field()) {
1292 		return true;
1293 	}
1294 
1295 	field_map_element_t* field_map = static_cast<field_map_element_t*>(
1296 		mem_heap_alloc(heap,
1297 			       num_non_pk_fields * sizeof *field_map));
1298 
1299 	unsigned n_dropped_cols = 0;
1300 
1301 	for (unsigned i = 0; i < num_non_pk_fields; i++) {
1302 		auto c = field_map[i] = mach_read_from_2(metadata);
1303 		metadata += 2;
1304 
1305 		if (field_map[i].is_dropped()) {
1306 			if (c.ind() > DICT_MAX_FIXED_COL_LEN + 1) {
1307 				return true;
1308 			}
1309 			n_dropped_cols++;
1310 		} else if (c >= n_cols) {
1311 			return true;
1312 		}
1313 	}
1314 
1315 	dict_col_t* dropped_cols = static_cast<dict_col_t*>(mem_heap_zalloc(
1316 		heap, n_dropped_cols * sizeof(dict_col_t)));
1317 	instant = new (mem_heap_alloc(heap, sizeof *instant)) dict_instant_t();
1318 	instant->n_dropped = n_dropped_cols;
1319 	instant->dropped = dropped_cols;
1320 	instant->field_map = field_map;
1321 
1322 	dict_col_t* col = dropped_cols;
1323 	for (unsigned i = 0; i < num_non_pk_fields; i++) {
1324 		if (field_map[i].is_dropped()) {
1325 			auto fixed_len = field_map[i].ind();
1326 			DBUG_ASSERT(fixed_len <= DICT_MAX_FIXED_COL_LEN + 1);
1327 			(col++)->set_dropped(field_map[i].is_not_null(),
1328 					     fixed_len == 1,
1329 					     fixed_len > 1 ? fixed_len - 1
1330 					     : 0);
1331 		}
1332 	}
1333 	DBUG_ASSERT(col == &dropped_cols[n_dropped_cols]);
1334 
1335 	return UT_LIST_GET_FIRST(indexes)->reconstruct_fields();
1336 }
1337 
1338 /** Check if record in clustered index is historical row.
1339 @param[in]	rec	clustered row
1340 @param[in]	offsets	offsets
1341 @return true if row is historical */
1342 bool
vers_history_row(const rec_t * rec,const rec_offs * offsets)1343 dict_index_t::vers_history_row(
1344 	const rec_t*		rec,
1345 	const rec_offs*		offsets)
1346 {
1347 	ut_ad(is_primary());
1348 
1349 	ulint len;
1350 	dict_col_t& col= table->cols[table->vers_end];
1351 	ut_ad(col.vers_sys_end());
1352 	ulint nfield = dict_col_get_clust_pos(&col, this);
1353 	const byte *data = rec_get_nth_field(rec, offsets, nfield, &len);
1354 	if (col.vers_native()) {
1355 		ut_ad(len == sizeof trx_id_max_bytes);
1356 		return 0 != memcmp(data, trx_id_max_bytes, len);
1357 	}
1358 	ut_ad(len == sizeof timestamp_max_bytes);
1359 	return 0 != memcmp(data, timestamp_max_bytes, len);
1360 }
1361 
1362 /** Check if record in secondary index is historical row.
1363 @param[in]	rec	record in a secondary index
1364 @param[out]	history_row true if row is historical
1365 @return true on error */
1366 bool
vers_history_row(const rec_t * rec,bool & history_row)1367 dict_index_t::vers_history_row(
1368 	const rec_t* rec,
1369 	bool &history_row)
1370 {
1371 	ut_ad(!is_primary());
1372 
1373 	bool error = false;
1374 	mem_heap_t* heap = NULL;
1375 	dict_index_t* clust_index = NULL;
1376 	rec_offs offsets_[REC_OFFS_NORMAL_SIZE];
1377 	rec_offs* offsets = offsets_;
1378 	rec_offs_init(offsets_);
1379 
1380 	mtr_t mtr;
1381 	mtr.start();
1382 
1383 	rec_t* clust_rec =
1384 	    row_get_clust_rec(BTR_SEARCH_LEAF, rec, this, &clust_index, &mtr);
1385 	if (clust_rec) {
1386 		offsets = rec_get_offsets(clust_rec, clust_index, offsets,
1387 					  clust_index->n_core_fields,
1388 					  ULINT_UNDEFINED, &heap);
1389 
1390 		history_row = clust_index->vers_history_row(clust_rec, offsets);
1391         } else {
1392 		ib::error() << "foreign constraints: secondary index is out of "
1393 			       "sync";
1394 		ut_ad("secondary index is out of sync" == 0);
1395 		error = true;
1396 	}
1397 	mtr.commit();
1398 	if (heap) {
1399 		mem_heap_free(heap);
1400 	}
1401 	return(error);
1402 }
1403