1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2021, Oracle and/or its affiliates.
4 Copyright (c) 2012, Facebook Inc.
5 
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2.0,
8 as published by the Free Software Foundation.
9 
10 This program is also distributed with certain software (including
11 but not limited to OpenSSL) that is licensed under separate terms,
12 as designated in a particular file or component or in included license
13 documentation.  The authors of MySQL hereby grant you an additional
14 permission to link the program and your derivative works with the
15 separately licensed software that they have included with MySQL.
16 
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU General Public License, version 2.0, for more details.
21 
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
25 
26 *****************************************************************************/
27 
28 /******************************************************************//**
29 @file dict/dict0dict.cc
30 Data dictionary system
31 
32 Created 1/8/1996 Heikki Tuuri
33 ***********************************************************************/
34 
35 #include "ha_prototypes.h"
36 #include <mysqld.h>
37 #include <strfunc.h>
38 
39 #include "dict0dict.h"
40 #include "fts0fts.h"
41 #include "fil0fil.h"
42 #include <algorithm>
43 
44 #ifdef UNIV_NONINL
45 #include "dict0dict.ic"
46 #include "dict0priv.ic"
47 #endif
48 
49 /** dummy index for ROW_FORMAT=REDUNDANT supremum and infimum records */
50 dict_index_t*	dict_ind_redundant;
51 
52 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
53 /** Flag to control insert buffer debugging. */
54 extern uint	ibuf_debug;
55 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
56 
57 /**********************************************************************
58 Issue a warning that the row is too big. */
59 void
60 ib_warn_row_too_big(const dict_table_t*	table);
61 
62 #ifndef UNIV_HOTBACKUP
63 #include "btr0btr.h"
64 #include "btr0cur.h"
65 #include "btr0sea.h"
66 #include "buf0buf.h"
67 #include "data0type.h"
68 #include "dict0boot.h"
69 #include "dict0crea.h"
70 #include "dict0mem.h"
71 #include "dict0priv.h"
72 #include "dict0stats.h"
73 #include "fsp0sysspace.h"
74 #include "fts0fts.h"
75 #include "fts0types.h"
76 #include "lock0lock.h"
77 #include "mach0data.h"
78 #include "mem0mem.h"
79 #include "os0once.h"
80 #include "page0page.h"
81 #include "page0zip.h"
82 #include "pars0pars.h"
83 #include "pars0sym.h"
84 #include "que0que.h"
85 #include "rem0cmp.h"
86 #include "row0log.h"
87 #include "row0merge.h"
88 #include "row0mysql.h"
89 #include "row0upd.h"
90 #include "srv0mon.h"
91 #include "srv0start.h"
92 #include "sync0sync.h"
93 #include "trx0undo.h"
94 #include "ut0new.h"
95 
96 #include <vector>
97 #include <algorithm>
98 
99 /** the dictionary system */
100 dict_sys_t*	dict_sys	= NULL;
101 
102 /** @brief the data dictionary rw-latch protecting dict_sys
103 
104 table create, drop, etc. reserve this in X-mode; implicit or
105 backround operations purge, rollback, foreign key checks reserve this
106 in S-mode; we cannot trust that MySQL protects implicit or background
107 operations a table drop since MySQL does not know of them; therefore
108 we need this; NOTE: a transaction which reserves this must keep book
109 on the mode in trx_t::dict_operation_lock_mode */
110 rw_lock_t*	dict_operation_lock;
111 
112 /** Percentage of compression failures that are allowed in a single
113 round */
114 ulong	zip_failure_threshold_pct = 5;
115 
116 /** Maximum percentage of a page that can be allowed as a pad to avoid
117 compression failures */
118 ulong	zip_pad_max = 50;
119 
120 #define	DICT_HEAP_SIZE		100	/*!< initial memory heap size when
121 					creating a table or index object */
122 #define DICT_POOL_PER_TABLE_HASH 512	/*!< buffer pool max size per table
123 					hash table fixed size in bytes */
124 #define DICT_POOL_PER_VARYING	4	/*!< buffer pool max size per data
125 					dictionary varying size in bytes */
126 
127 /** Identifies generated InnoDB foreign key names */
128 static char	dict_ibfk[] = "_ibfk_";
129 
130 /** Tries to find column names for the index and sets the col field of the
131 index.
132 @param[in]	table	table
133 @param[in]	index	index
134 @param[in]	add_v	new virtual columns added along with an add index call
135 @return TRUE if the column names were found */
136 static
137 ibool
138 dict_index_find_cols(
139 	const dict_table_t*	table,
140 	dict_index_t*		index,
141 	const dict_add_v_col_t*	add_v);
142 /*******************************************************************//**
143 Builds the internal dictionary cache representation for a clustered
144 index, containing also system fields not defined by the user.
145 @return own: the internal representation of the clustered index */
146 static
147 dict_index_t*
148 dict_index_build_internal_clust(
149 /*============================*/
150 	const dict_table_t*	table,	/*!< in: table */
151 	dict_index_t*		index);	/*!< in: user representation of
152 					a clustered index */
153 /*******************************************************************//**
154 Builds the internal dictionary cache representation for a non-clustered
155 index, containing also system fields not defined by the user.
156 @return own: the internal representation of the non-clustered index */
157 static
158 dict_index_t*
159 dict_index_build_internal_non_clust(
160 /*================================*/
161 	const dict_table_t*	table,	/*!< in: table */
162 	dict_index_t*		index);	/*!< in: user representation of
163 					a non-clustered index */
164 /**********************************************************************//**
165 Builds the internal dictionary cache representation for an FTS index.
166 @return own: the internal representation of the FTS index */
167 static
168 dict_index_t*
169 dict_index_build_internal_fts(
170 /*==========================*/
171 	dict_table_t*	table,	/*!< in: table */
172 	dict_index_t*	index);	/*!< in: user representation of an FTS index */
173 
174 /**********************************************************************//**
175 Removes an index from the dictionary cache. */
176 static
177 void
178 dict_index_remove_from_cache_low(
179 /*=============================*/
180 	dict_table_t*	table,		/*!< in/out: table */
181 	dict_index_t*	index,		/*!< in, own: index */
182 	ibool		lru_evict);	/*!< in: TRUE if page being evicted
183 					to make room in the table LRU list */
184 #ifdef UNIV_DEBUG
185 /**********************************************************************//**
186 Validate the dictionary table LRU list.
187 @return TRUE if validate OK */
188 static
189 ibool
190 dict_lru_validate(void);
191 /*===================*/
192 /**********************************************************************//**
193 Check if table is in the dictionary table LRU list.
194 @return TRUE if table found */
195 static
196 ibool
197 dict_lru_find_table(
198 /*================*/
199 	const dict_table_t*	find_table);	/*!< in: table to find */
200 /**********************************************************************//**
201 Check if a table exists in the dict table non-LRU list.
202 @return TRUE if table found */
203 static
204 ibool
205 dict_non_lru_find_table(
206 /*====================*/
207 	const dict_table_t*	find_table);	/*!< in: table to find */
208 #endif /* UNIV_DEBUG */
209 
210 /* Stream for storing detailed information about the latest foreign key
211 and unique key errors. Only created if !srv_read_only_mode */
212 FILE*	dict_foreign_err_file		= NULL;
213 /* mutex protecting the foreign and unique error buffers */
214 ib_mutex_t	dict_foreign_err_mutex;
215 
216 /********************************************************************//**
217 Checks if the database name in two table names is the same.
218 @return TRUE if same db name */
219 ibool
dict_tables_have_same_db(const char * name1,const char * name2)220 dict_tables_have_same_db(
221 /*=====================*/
222 	const char*	name1,	/*!< in: table name in the form
223 				dbname '/' tablename */
224 	const char*	name2)	/*!< in: table name in the form
225 				dbname '/' tablename */
226 {
227 	for (; *name1 == *name2; name1++, name2++) {
228 		if (*name1 == '/') {
229 			return(TRUE);
230 		}
231 		ut_a(*name1); /* the names must contain '/' */
232 	}
233 	return(FALSE);
234 }
235 
236 /********************************************************************//**
237 Return the end of table name where we have removed dbname and '/'.
238 @return table name */
239 const char*
dict_remove_db_name(const char * name)240 dict_remove_db_name(
241 /*================*/
242 	const char*	name)	/*!< in: table name in the form
243 				dbname '/' tablename */
244 {
245 	const char*	s = strchr(name, '/');
246 	ut_a(s);
247 
248 	return(s + 1);
249 }
250 
251 /********************************************************************//**
252 Get the database name length in a table name.
253 @return database name length */
254 ulint
dict_get_db_name_len(const char * name)255 dict_get_db_name_len(
256 /*=================*/
257 	const char*	name)	/*!< in: table name in the form
258 				dbname '/' tablename */
259 {
260 	const char*	s;
261 	s = strchr(name, '/');
262 	ut_a(s);
263 	return(s - name);
264 }
265 
266 /********************************************************************//**
267 Reserves the dictionary system mutex for MySQL. */
268 void
dict_mutex_enter_for_mysql(void)269 dict_mutex_enter_for_mysql(void)
270 /*============================*/
271 {
272 	mutex_enter(&dict_sys->mutex);
273 }
274 
275 /********************************************************************//**
276 Releases the dictionary system mutex for MySQL. */
277 void
dict_mutex_exit_for_mysql(void)278 dict_mutex_exit_for_mysql(void)
279 /*===========================*/
280 {
281 	mutex_exit(&dict_sys->mutex);
282 }
283 
284 /** Allocate and init a dict_table_t's stats latch.
285 This function must not be called concurrently on the same table object.
286 @param[in,out]	table_void	table whose stats latch to create */
287 static
288 void
dict_table_stats_latch_alloc(void * table_void)289 dict_table_stats_latch_alloc(
290 	void*	table_void)
291 {
292 	dict_table_t*	table = static_cast<dict_table_t*>(table_void);
293 
294 	/* Note: rw_lock_create() will call the constructor */
295 
296 	table->stats_latch = static_cast<rw_lock_t*>(
297 		ut_malloc_nokey(sizeof(rw_lock_t)));
298 
299 	ut_a(table->stats_latch != NULL);
300 
301 	rw_lock_create(dict_table_stats_key, table->stats_latch,
302 		       SYNC_INDEX_TREE);
303 }
304 
305 /** Deinit and free a dict_table_t's stats latch.
306 This function must not be called concurrently on the same table object.
307 @param[in,out]	table	table whose stats latch to free */
308 static
309 void
dict_table_stats_latch_free(dict_table_t * table)310 dict_table_stats_latch_free(
311 	dict_table_t*	table)
312 {
313 	rw_lock_free(table->stats_latch);
314 	ut_free(table->stats_latch);
315 }
316 
317 /** Create a dict_table_t's stats latch or delay for lazy creation.
318 This function is only called from either single threaded environment
319 or from a thread that has not shared the table object with other threads.
320 @param[in,out]	table	table whose stats latch to create
321 @param[in]	enabled	if false then the latch is disabled
322 and dict_table_stats_lock()/unlock() become noop on this table. */
323 void
dict_table_stats_latch_create(dict_table_t * table,bool enabled)324 dict_table_stats_latch_create(
325 	dict_table_t*	table,
326 	bool		enabled)
327 {
328 	if (!enabled) {
329 		table->stats_latch = NULL;
330 		table->stats_latch_created = os_once::DONE;
331 		return;
332 	}
333 
334 	/* We create this lazily the first time it is used. */
335 	table->stats_latch = NULL;
336 	table->stats_latch_created = os_once::NEVER_DONE;
337 }
338 
339 /** Destroy a dict_table_t's stats latch.
340 This function is only called from either single threaded environment
341 or from a thread that has not shared the table object with other threads.
342 @param[in,out]	table	table whose stats latch to destroy */
343 void
dict_table_stats_latch_destroy(dict_table_t * table)344 dict_table_stats_latch_destroy(
345 	dict_table_t*	table)
346 {
347 	if (table->stats_latch_created == os_once::DONE
348 	    && table->stats_latch != NULL) {
349 
350 		dict_table_stats_latch_free(table);
351 	}
352 }
353 
354 /** Lock the appropriate latch to protect a given table's statistics.
355 @param[in]	table		table whose stats to lock
356 @param[in]	latch_mode	RW_S_LATCH or RW_X_LATCH */
357 void
dict_table_stats_lock(dict_table_t * table,ulint latch_mode)358 dict_table_stats_lock(
359 	dict_table_t*	table,
360 	ulint		latch_mode)
361 {
362 	ut_ad(table != NULL);
363 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
364 
365 	os_once::do_or_wait_for_done(
366 		&table->stats_latch_created,
367 		dict_table_stats_latch_alloc, table);
368 
369 	if (table->stats_latch == NULL) {
370 		/* This is a dummy table object that is private in the current
371 		thread and is not shared between multiple threads, thus we
372 		skip any locking. */
373 		return;
374 	}
375 
376 	switch (latch_mode) {
377 	case RW_S_LATCH:
378 		rw_lock_s_lock(table->stats_latch);
379 		break;
380 	case RW_X_LATCH:
381 		rw_lock_x_lock(table->stats_latch);
382 		break;
383 	case RW_NO_LATCH:
384 		/* fall through */
385 	default:
386 		ut_error;
387 	}
388 }
389 
390 /** Unlock the latch that has been locked by dict_table_stats_lock().
391 @param[in]	table		table whose stats to unlock
392 @param[in]	latch_mode	RW_S_LATCH or RW_X_LATCH */
393 void
dict_table_stats_unlock(dict_table_t * table,ulint latch_mode)394 dict_table_stats_unlock(
395 	dict_table_t*	table,
396 	ulint		latch_mode)
397 {
398 	ut_ad(table != NULL);
399 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
400 
401 	if (table->stats_latch == NULL) {
402 		/* This is a dummy table object that is private in the current
403 		thread and is not shared between multiple threads, thus we
404 		skip any locking. */
405 		return;
406 	}
407 
408 	switch (latch_mode) {
409 	case RW_S_LATCH:
410 		rw_lock_s_unlock(table->stats_latch);
411 		break;
412 	case RW_X_LATCH:
413 		rw_lock_x_unlock(table->stats_latch);
414 		break;
415 	case RW_NO_LATCH:
416 		/* fall through */
417 	default:
418 		ut_error;
419 	}
420 }
421 
422 /**********************************************************************//**
423 Try to drop any indexes after an aborted index creation.
424 This can also be after a server kill during DROP INDEX. */
425 static
426 void
dict_table_try_drop_aborted(dict_table_t * table,table_id_t table_id,ulint ref_count)427 dict_table_try_drop_aborted(
428 /*========================*/
429 	dict_table_t*	table,		/*!< in: table, or NULL if it
430 					needs to be looked up again */
431 	table_id_t	table_id,	/*!< in: table identifier */
432 	ulint		ref_count)	/*!< in: expected table->n_ref_count */
433 {
434 	trx_t*		trx;
435 
436 	trx = trx_allocate_for_background();
437 	trx->op_info = "try to drop any indexes after an aborted index creation";
438 	row_mysql_lock_data_dictionary(trx);
439 	trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
440 
441 	if (table == NULL) {
442 		table = dict_table_open_on_id_low(
443 			table_id, DICT_ERR_IGNORE_NONE);
444 	} else {
445 		ut_ad(table->id == table_id);
446 	}
447 
448 	if (table && table->get_ref_count() == ref_count && table->drop_aborted) {
449 		/* Silence a debug assertion in row_merge_drop_indexes(). */
450 		ut_d(table->acquire());
451 		row_merge_drop_indexes(trx, table, TRUE);
452 		ut_d(table->release());
453 		ut_ad(table->get_ref_count() == ref_count);
454 		trx_commit_for_mysql(trx);
455 	}
456 
457 	row_mysql_unlock_data_dictionary(trx);
458 	trx_free_for_background(trx);
459 }
460 
461 /**********************************************************************//**
462 When opening a table,
463 try to drop any indexes after an aborted index creation.
464 Release the dict_sys->mutex. */
465 static
466 void
dict_table_try_drop_aborted_and_mutex_exit(dict_table_t * table,ibool try_drop)467 dict_table_try_drop_aborted_and_mutex_exit(
468 /*=======================================*/
469 	dict_table_t*	table,		/*!< in: table (may be NULL) */
470 	ibool		try_drop)	/*!< in: FALSE if should try to
471 					drop indexes whose online creation
472 					was aborted */
473 {
474 	if (try_drop
475 	    && table != NULL
476 	    && table->drop_aborted
477 	    && table->get_ref_count() == 1
478 	    && dict_table_get_first_index(table)) {
479 
480 		/* Attempt to drop the indexes whose online creation
481 		was aborted. */
482 		table_id_t	table_id = table->id;
483 
484 		mutex_exit(&dict_sys->mutex);
485 
486 		dict_table_try_drop_aborted(table, table_id, 1);
487 	} else {
488 		mutex_exit(&dict_sys->mutex);
489 	}
490 }
491 
492 /********************************************************************//**
493 Decrements the count of open handles to a table. */
494 void
dict_table_close(dict_table_t * table,ibool dict_locked,ibool try_drop)495 dict_table_close(
496 /*=============*/
497 	dict_table_t*	table,		/*!< in/out: table */
498 	ibool		dict_locked,	/*!< in: TRUE=data dictionary locked */
499 	ibool		try_drop)	/*!< in: TRUE=try to drop any orphan
500 					indexes after an aborted online
501 					index creation */
502 {
503 	ibool		drop_aborted;
504 	if (!dict_locked && !dict_table_is_intrinsic(table)) {
505 		mutex_enter(&dict_sys->mutex);
506 	}
507 
508 	ut_ad(mutex_own(&dict_sys->mutex) || dict_table_is_intrinsic(table));
509 	ut_a(table->get_ref_count() > 0);
510 
511 	drop_aborted = try_drop
512 			&& table->drop_aborted
513 			&& table->get_ref_count() == 1
514 			&& dict_table_get_first_index(table);
515 	table->release();
516 
517 	/* Intrinsic table is not added to dictionary cache so skip other
518 	cache specific actions. */
519 	if (dict_table_is_intrinsic(table)) {
520 		return;
521 	}
522 
523 	/* Force persistent stats re-read upon next open of the table
524 	so that FLUSH TABLE can be used to forcibly fetch stats from disk
525 	if they have been manually modified. We reset table->stat_initialized
526 	only if table reference count is 0 because we do not want too frequent
527 	stats re-reads (e.g. in other cases than FLUSH TABLE). */
528 	if (strchr(table->name.m_name, '/') != NULL
529 	    && table->get_ref_count() == 0
530 	    && dict_stats_is_persistent_enabled(table)) {
531 
532 		dict_stats_deinit(table);
533 	}
534 
535 	MONITOR_DEC(MONITOR_TABLE_REFERENCE);
536 
537 	ut_ad(dict_lru_validate());
538 
539 #ifdef UNIV_DEBUG
540 	if (table->can_be_evicted) {
541 		ut_ad(dict_lru_find_table(table));
542 	} else {
543 		ut_ad(dict_non_lru_find_table(table));
544 	}
545 #endif /* UNIV_DEBUG */
546 
547 	if (!dict_locked) {
548 		table_id_t	table_id	= table->id;
549 
550 		mutex_exit(&dict_sys->mutex);
551 
552 		if (drop_aborted) {
553 			dict_table_try_drop_aborted(NULL, table_id, 0);
554 		}
555 	}
556 }
557 #endif /* !UNIV_HOTBACKUP */
558 
559 /********************************************************************//**
560 Closes the only open handle to a table and drops a table while assuring
561 that dict_sys->mutex is held the whole time.  This assures that the table
562 is not evicted after the close when the count of open handles goes to zero.
563 Because dict_sys->mutex is held, we do not need to call
564 dict_table_prevent_eviction().  */
565 void
dict_table_close_and_drop(trx_t * trx,dict_table_t * table)566 dict_table_close_and_drop(
567 /*======================*/
568 	trx_t*		trx,		/*!< in: data dictionary transaction */
569 	dict_table_t*	table)		/*!< in/out: table */
570 {
571 	ut_ad(mutex_own(&dict_sys->mutex));
572 	ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
573 	ut_ad(trx->dict_operation != TRX_DICT_OP_NONE);
574 	ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
575 
576 	dict_table_close(table, TRUE, FALSE);
577 
578 #if defined UNIV_DEBUG || defined UNIV_DDL_DEBUG
579 	/* Nobody should have initialized the stats of the newly created
580 	table when this is called. So we know that it has not been added
581 	for background stats gathering. */
582 	ut_a(!table->stat_initialized);
583 #endif /* UNIV_DEBUG || UNIV_DDL_DEBUG */
584 
585 	row_merge_drop_table(trx, table);
586 }
587 
588 /** Check if the table has a given (non_virtual) column.
589 @param[in]	table		table object
590 @param[in]	col_name	column name
591 @param[in]	col_nr		column number guessed, 0 as default
592 @return column number if the table has the specified column,
593 otherwise table->n_def */
594 ulint
dict_table_has_column(const dict_table_t * table,const char * col_name,ulint col_nr)595 dict_table_has_column(
596 	const dict_table_t*	table,
597 	const char*		col_name,
598 	ulint			col_nr)
599 {
600 	ulint		col_max = table->n_def;
601 
602 	ut_ad(table);
603 	ut_ad(col_name);
604 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
605 
606 	if (col_nr < col_max
607 	    && innobase_strcasecmp(
608 		col_name, dict_table_get_col_name(table, col_nr)) == 0) {
609 		return(col_nr);
610 	}
611 
612 	/** The order of column may changed, check it with other columns */
613 	for (ulint i = 0; i < col_max; i++) {
614 		if (i != col_nr
615 		    && innobase_strcasecmp(
616 			col_name, dict_table_get_col_name(table, i)) == 0) {
617 
618 			return(i);
619 		}
620 	}
621 
622 	return(col_max);
623 }
624 
625 /**********************************************************************//**
626 Returns a column's name.
627 @return column name. NOTE: not guaranteed to stay valid if table is
628 modified in any way (columns added, etc.). */
629 const char*
dict_table_get_col_name(const dict_table_t * table,ulint col_nr)630 dict_table_get_col_name(
631 /*====================*/
632 	const dict_table_t*	table,	/*!< in: table */
633 	ulint			col_nr)	/*!< in: column number */
634 {
635 	ulint		i;
636 	const char*	s;
637 
638 	ut_ad(table);
639 	ut_ad(col_nr < table->n_def);
640 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
641 
642 	s = table->col_names;
643 	if (s) {
644 		for (i = 0; i < col_nr; i++) {
645 			s += strlen(s) + 1;
646 		}
647 	}
648 
649 	return(s);
650 }
651 
652 /** Returns a virtual column's name.
653 @param[in]	table	target table
654 @param[in]	col_nr	virtual column number (nth virtual column)
655 @return column name or NULL if column number out of range. */
656 const char*
dict_table_get_v_col_name(const dict_table_t * table,ulint col_nr)657 dict_table_get_v_col_name(
658 	const dict_table_t*	table,
659 	ulint			col_nr)
660 {
661 	const char*	s;
662 
663 	ut_ad(table);
664 	ut_ad(col_nr < table->n_v_def);
665 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
666 
667 	if (col_nr >= table->n_v_def) {
668 		return(NULL);
669 	}
670 
671 	s = table->v_col_names;
672 
673 	if (s != NULL) {
674 		for (ulint i = 0; i < col_nr; i++) {
675 			s += strlen(s) + 1;
676 		}
677 	}
678 
679 	return(s);
680 }
681 
682 /** Search virtual column's position in InnoDB according to its position
683 in original table's position
684 @param[in]	table	target table
685 @param[in]	col_nr	column number (nth column in the MySQL table)
686 @return virtual column's position in InnoDB, ULINT_UNDEFINED if not find */
687 static
688 ulint
dict_table_get_v_col_pos_for_mysql(const dict_table_t * table,ulint col_nr)689 dict_table_get_v_col_pos_for_mysql(
690 	const dict_table_t*	table,
691 	ulint			col_nr)
692 {
693 	ulint	i;
694 
695 	ut_ad(table);
696 	ut_ad(col_nr < static_cast<ulint>(table->n_t_def));
697 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
698 
699 	for (i = 0; i < table->n_v_def; i++) {
700 		if (col_nr == dict_get_v_col_mysql_pos(
701 				table->v_cols[i].m_col.ind)) {
702 			break;
703 		}
704 	}
705 
706 	if (i == table->n_v_def) {
707 		return(ULINT_UNDEFINED);
708 	}
709 
710 	return(i);
711 }
712 
713 /** Returns a virtual column's name according to its original
714 MySQL table position.
715 @param[in]	table	target table
716 @param[in]	col_nr	column number (nth column in the table)
717 @return column name. */
718 static
719 const char*
dict_table_get_v_col_name_mysql(const dict_table_t * table,ulint col_nr)720 dict_table_get_v_col_name_mysql(
721 	const dict_table_t*	table,
722 	ulint			col_nr)
723 {
724 	ulint	i = dict_table_get_v_col_pos_for_mysql(table, col_nr);
725 
726 	if (i == ULINT_UNDEFINED) {
727 		return(NULL);
728 	}
729 
730 	return(dict_table_get_v_col_name(table, i));
731 }
732 
733 /** Get nth virtual column according to its original MySQL table position
734 @param[in]	table	target table
735 @param[in]	col_nr	column number in MySQL Table definition
736 @return dict_v_col_t ptr */
737 dict_v_col_t*
dict_table_get_nth_v_col_mysql(const dict_table_t * table,ulint col_nr)738 dict_table_get_nth_v_col_mysql(
739 	const dict_table_t*	table,
740 	ulint			col_nr)
741 {
742 	ulint	i = dict_table_get_v_col_pos_for_mysql(table, col_nr);
743 
744 	if (i == ULINT_UNDEFINED) {
745 		return(NULL);
746 	}
747 
748 	return(dict_table_get_nth_v_col(table, i));
749 }
750 
751 #ifndef UNIV_HOTBACKUP
752 /** Allocate and init the autoinc latch of a given table.
753 This function must not be called concurrently on the same table object.
754 @param[in,out]	table_void	table whose autoinc latch to create */
755 static
756 void
dict_table_autoinc_alloc(void * table_void)757 dict_table_autoinc_alloc(
758 	void*	table_void)
759 {
760 	dict_table_t*	table = static_cast<dict_table_t*>(table_void);
761 	table->autoinc_mutex = UT_NEW_NOKEY(AutoIncMutex());
762 	ut_a(table->autoinc_mutex != NULL);
763 	mutex_create(LATCH_ID_AUTOINC, table->autoinc_mutex);
764 }
765 
766 /** Allocate and init the zip_pad_mutex of a given index.
767 This function must not be called concurrently on the same index object.
768 @param[in,out]	index_void	index whose zip_pad_mutex to create */
769 static
770 void
dict_index_zip_pad_alloc(void * index_void)771 dict_index_zip_pad_alloc(
772 	void*	index_void)
773 {
774 	dict_index_t*	index = static_cast<dict_index_t*>(index_void);
775 	index->zip_pad.mutex = UT_NEW_NOKEY(SysMutex());
776 	ut_a(index->zip_pad.mutex != NULL);
777 	mutex_create(LATCH_ID_ZIP_PAD_MUTEX, index->zip_pad.mutex);
778 }
779 
780 
781 /********************************************************************//**
782 Acquire the autoinc lock. */
783 void
dict_table_autoinc_lock(dict_table_t * table)784 dict_table_autoinc_lock(
785 /*====================*/
786 	dict_table_t*	table)	/*!< in/out: table */
787 {
788 	os_once::do_or_wait_for_done(
789 		&table->autoinc_mutex_created,
790 		dict_table_autoinc_alloc, table);
791 
792 	mutex_enter(table->autoinc_mutex);
793 }
794 
795 /** Acquire the zip_pad_mutex latch.
796 @param[in,out]	index	the index whose zip_pad_mutex to acquire.*/
797 void
dict_index_zip_pad_lock(dict_index_t * index)798 dict_index_zip_pad_lock(
799 	dict_index_t*	index)
800 {
801 	os_once::do_or_wait_for_done(
802 		&index->zip_pad.mutex_created,
803 		dict_index_zip_pad_alloc, index);
804 
805 	mutex_enter(index->zip_pad.mutex);
806 }
807 
808 
809 /********************************************************************//**
810 Unconditionally set the autoinc counter. */
811 void
dict_table_autoinc_initialize(dict_table_t * table,ib_uint64_t value)812 dict_table_autoinc_initialize(
813 /*==========================*/
814 	dict_table_t*	table,	/*!< in/out: table */
815 	ib_uint64_t	value)	/*!< in: next value to assign to a row */
816 {
817 	ut_ad(dict_table_autoinc_own(table));
818 
819 	table->autoinc = value;
820 }
821 
822 /** Get all the FTS indexes on a table.
823 @param[in]	table	table
824 @param[out]	indexes	all FTS indexes on this table
825 @return number of FTS indexes */
826 ulint
dict_table_get_all_fts_indexes(const dict_table_t * table,ib_vector_t * indexes)827 dict_table_get_all_fts_indexes(
828 	const dict_table_t*	table,
829 	ib_vector_t*		indexes)
830 {
831 	dict_index_t* index;
832 
833 	ut_a(ib_vector_size(indexes) == 0);
834 
835 	for (index = dict_table_get_first_index(table);
836 	     index;
837 	     index = dict_table_get_next_index(index)) {
838 
839 		if (index->type == DICT_FTS) {
840 			ib_vector_push(indexes, &index);
841 		}
842 	}
843 
844 	return(ib_vector_size(indexes));
845 }
846 
847 /** Store autoinc value when the table is evicted.
848 @param[in]	table	table evicted */
849 void
dict_table_autoinc_store(const dict_table_t * table)850 dict_table_autoinc_store(
851 	const dict_table_t*	table)
852 {
853 	ut_ad(mutex_own(&dict_sys->mutex));
854 
855 	if (table->autoinc != 0) {
856 		ut_ad(dict_sys->autoinc_map->find(table->id)
857 		      == dict_sys->autoinc_map->end());
858 
859 		dict_sys->autoinc_map->insert(
860 			std::pair<table_id_t, ib_uint64_t>(
861 			table->id, table->autoinc));
862 	}
863 }
864 
865 /** Restore autoinc value when the table is loaded.
866 @param[in]	table	table loaded */
867 void
dict_table_autoinc_restore(dict_table_t * table)868 dict_table_autoinc_restore(
869 	dict_table_t*	table)
870 {
871 	ut_ad(mutex_own(&dict_sys->mutex));
872 
873 	autoinc_map_t::iterator	it;
874 	it = dict_sys->autoinc_map->find(table->id);
875 
876 	if (it != dict_sys->autoinc_map->end()) {
877 		table->autoinc = it->second;
878 		ut_ad(table->autoinc != 0);
879 
880 		dict_sys->autoinc_map->erase(it);
881 	}
882 }
883 
884 /********************************************************************//**
885 Reads the next autoinc value (== autoinc counter value), 0 if not yet
886 initialized.
887 @return value for a new row, or 0 */
888 ib_uint64_t
dict_table_autoinc_read(const dict_table_t * table)889 dict_table_autoinc_read(
890 /*====================*/
891 	const dict_table_t*	table)	/*!< in: table */
892 {
893 	ut_ad(dict_table_autoinc_own(table));
894 
895 	return(table->autoinc);
896 }
897 
898 /********************************************************************//**
899 Updates the autoinc counter if the value supplied is greater than the
900 current value. */
901 void
dict_table_autoinc_update_if_greater(dict_table_t * table,ib_uint64_t value)902 dict_table_autoinc_update_if_greater(
903 /*=================================*/
904 
905 	dict_table_t*	table,	/*!< in/out: table */
906 	ib_uint64_t	value)	/*!< in: value which was assigned to a row */
907 {
908 	ut_ad(dict_table_autoinc_own(table));
909 
910 	if (value > table->autoinc) {
911 
912 		table->autoinc = value;
913 	}
914 }
915 
916 /********************************************************************//**
917 Release the autoinc lock. */
918 void
dict_table_autoinc_unlock(dict_table_t * table)919 dict_table_autoinc_unlock(
920 /*======================*/
921 	dict_table_t*	table)	/*!< in/out: table */
922 {
923 	mutex_exit(table->autoinc_mutex);
924 }
925 
926 /** Create and initialize the analyze index lock for a given table.
927 This lock is used to serialize two concurrent analyze index operations
928 @param[in]	table_void	table whose analyze_index latch to create */
929 static
930 void
dict_table_analyze_index_alloc(void * table_void)931 dict_table_analyze_index_alloc(
932 	void*	table_void)
933 {
934 	dict_table_t*	table = static_cast<dict_table_t*>(table_void);
935 	table->analyze_index_mutex = UT_NEW_NOKEY(AnalyzeIndexMutex());
936 	ut_a(table->analyze_index_mutex != NULL);
937 	mutex_create(LATCH_ID_ANALYZE_INDEX_MUTEX, table->analyze_index_mutex);
938 }
939 
940 /** Acquire the analyze index lock.
941 @param[in]	table table whose analyze_index latch to lock */
942 void
dict_table_analyze_index_lock(dict_table_t * table)943 dict_table_analyze_index_lock(
944 	dict_table_t*	table)
945 {
946 	os_once::do_or_wait_for_done(
947 		&table->analyze_index_mutex_created,
948 		dict_table_analyze_index_alloc, table);
949 
950 	mutex_enter(table->analyze_index_mutex);
951 }
952 
953 /** Release the analyze index lock.
954 @param[in]	table table whose analyze_index latch to unlock */
955 void
dict_table_analyze_index_unlock(dict_table_t * table)956 dict_table_analyze_index_unlock(
957 	dict_table_t*	table)
958 {
959 	ut_a(table->analyze_index_mutex != NULL);
960 	mutex_exit(table->analyze_index_mutex);
961 }
962 #endif /* !UNIV_HOTBACKUP */
963 
964 /** Looks for column n in an index.
965 @param[in]	index		index
966 @param[in]	n		column number
967 @param[in]	inc_prefix	true=consider column prefixes too
968 @param[in]	is_virtual	true==virtual column
969 @param[out]	prefix_col_pos	col num if prefix
970 @return position in internal representation of the index;
971 ULINT_UNDEFINED if not contained */
972 ulint
dict_index_get_nth_col_or_prefix_pos(const dict_index_t * index,ulint n,bool inc_prefix,bool is_virtual,ulint * prefix_col_pos)973 dict_index_get_nth_col_or_prefix_pos(
974 	const dict_index_t*	index,
975 	ulint			n,
976 	bool			inc_prefix,
977 	bool			is_virtual,
978 	ulint*			prefix_col_pos)
979 {
980 	const dict_field_t*	field;
981 	const dict_col_t*	col;
982 	ulint			pos;
983 	ulint			n_fields;
984 	ulint			prefixed_pos_dummy;
985 
986 	ut_ad(index);
987 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
988 	ut_ad((inc_prefix && !prefix_col_pos) || (!inc_prefix));
989 
990 	if (!prefix_col_pos) {
991 		prefix_col_pos = &prefixed_pos_dummy;
992 	}
993 	*prefix_col_pos = ULINT_UNDEFINED;
994 
995 	if (is_virtual) {
996 		col = &(dict_table_get_nth_v_col(index->table, n)->m_col);
997 	} else {
998 		col = dict_table_get_nth_col(index->table, n);
999 	}
1000 
1001 	if (dict_index_is_clust(index)) {
1002 
1003 		return(dict_col_get_clust_pos(col, index));
1004 	}
1005 
1006 	n_fields = dict_index_get_n_fields(index);
1007 
1008 	for (pos = 0; pos < n_fields; pos++) {
1009 		field = dict_index_get_nth_field(index, pos);
1010 
1011 		if (col == field->col) {
1012 			*prefix_col_pos = pos;
1013 			if (inc_prefix || field->prefix_len == 0) {
1014 				return(pos);
1015 			}
1016 		}
1017 	}
1018 
1019 	return(ULINT_UNDEFINED);
1020 }
1021 
1022 #ifndef UNIV_HOTBACKUP
1023 /** Returns TRUE if the index contains a column or a prefix of that column.
1024 @param[in]	index		index
1025 @param[in]	n		column number
1026 @param[in]	is_virtual	whether it is a virtual col
1027 @return TRUE if contains the column or its prefix */
1028 ibool
dict_index_contains_col_or_prefix(const dict_index_t * index,ulint n,bool is_virtual)1029 dict_index_contains_col_or_prefix(
1030 	const dict_index_t*	index,
1031 	ulint			n,
1032 	bool			is_virtual)
1033 {
1034 	const dict_field_t*	field;
1035 	const dict_col_t*	col;
1036 	ulint			pos;
1037 	ulint			n_fields;
1038 
1039 	ut_ad(index);
1040 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1041 
1042 	if (dict_index_is_clust(index)) {
1043 
1044 		return(TRUE);
1045 	}
1046 
1047 	if (is_virtual) {
1048 		col = &dict_table_get_nth_v_col(index->table, n)->m_col;
1049 	} else {
1050 		col = dict_table_get_nth_col(index->table, n);
1051 	}
1052 
1053 	n_fields = dict_index_get_n_fields(index);
1054 
1055 	for (pos = 0; pos < n_fields; pos++) {
1056 		field = dict_index_get_nth_field(index, pos);
1057 
1058 		if (col == field->col) {
1059 
1060 			return(TRUE);
1061 		}
1062 	}
1063 
1064 	return(FALSE);
1065 }
1066 
1067 /********************************************************************//**
1068 Looks for a matching field in an index. The column has to be the same. The
1069 column in index must be complete, or must contain a prefix longer than the
1070 column in index2. That is, we must be able to construct the prefix in index2
1071 from the prefix in index.
1072 @return position in internal representation of the index;
1073 ULINT_UNDEFINED if not contained */
1074 ulint
dict_index_get_nth_field_pos(const dict_index_t * index,const dict_index_t * index2,ulint n)1075 dict_index_get_nth_field_pos(
1076 /*=========================*/
1077 	const dict_index_t*	index,	/*!< in: index from which to search */
1078 	const dict_index_t*	index2,	/*!< in: index */
1079 	ulint			n)	/*!< in: field number in index2 */
1080 {
1081 	const dict_field_t*	field;
1082 	const dict_field_t*	field2;
1083 	ulint			n_fields;
1084 	ulint			pos;
1085 
1086 	ut_ad(index);
1087 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1088 
1089 	field2 = dict_index_get_nth_field(index2, n);
1090 
1091 	n_fields = dict_index_get_n_fields(index);
1092 
1093 	/* Are we looking for a MBR (Minimum Bound Box) field of
1094 	a spatial index */
1095 	bool	is_mbr_fld = (n == 0 && dict_index_is_spatial(index2));
1096 
1097 	for (pos = 0; pos < n_fields; pos++) {
1098 		field = dict_index_get_nth_field(index, pos);
1099 
1100 		/* The first field of a spatial index is a transformed
1101 		MBR (Minimum Bound Box) field made out of original column,
1102 		so its field->col still points to original cluster index
1103 		col, but the actual content is different. So we cannot
1104 		consider them equal if neither of them is MBR field */
1105 		if (pos == 0 && dict_index_is_spatial(index) && !is_mbr_fld) {
1106 			continue;
1107 		}
1108 
1109 		if (field->col == field2->col
1110 		    && (field->prefix_len == 0
1111 			|| (field->prefix_len >= field2->prefix_len
1112 			    && field2->prefix_len != 0))) {
1113 
1114 			return(pos);
1115 		}
1116 	}
1117 
1118 	return(ULINT_UNDEFINED);
1119 }
1120 
1121 /**********************************************************************//**
1122 Returns a table object based on table id.
1123 @return table, NULL if does not exist */
1124 dict_table_t*
dict_table_open_on_id(table_id_t table_id,ibool dict_locked,dict_table_op_t table_op)1125 dict_table_open_on_id(
1126 /*==================*/
1127 	table_id_t	table_id,	/*!< in: table id */
1128 	ibool		dict_locked,	/*!< in: TRUE=data dictionary locked */
1129 	dict_table_op_t	table_op)	/*!< in: operation to perform */
1130 {
1131 	dict_table_t*	table;
1132 
1133 	if (!dict_locked) {
1134 		mutex_enter(&dict_sys->mutex);
1135 	}
1136 
1137 	ut_ad(mutex_own(&dict_sys->mutex));
1138 
1139 	table = dict_table_open_on_id_low(
1140 		table_id,
1141 		table_op == DICT_TABLE_OP_LOAD_TABLESPACE
1142 		? DICT_ERR_IGNORE_RECOVER_LOCK
1143 		: DICT_ERR_IGNORE_NONE);
1144 
1145 	if (table != NULL) {
1146 
1147 		if (table->can_be_evicted) {
1148 			dict_move_to_mru(table);
1149 		}
1150 
1151 		table->acquire();
1152 
1153 		MONITOR_INC(MONITOR_TABLE_REFERENCE);
1154 	}
1155 
1156 	if (!dict_locked) {
1157 		dict_table_try_drop_aborted_and_mutex_exit(
1158 			table, table_op == DICT_TABLE_OP_DROP_ORPHAN);
1159 	}
1160 
1161 	return(table);
1162 }
1163 
1164 /********************************************************************//**
1165 Looks for column n position in the clustered index.
1166 @return position in internal representation of the clustered index */
1167 ulint
dict_table_get_nth_col_pos(const dict_table_t * table,ulint n)1168 dict_table_get_nth_col_pos(
1169 /*=======================*/
1170 	const dict_table_t*	table,	/*!< in: table */
1171 	ulint			n)	/*!< in: column number */
1172 {
1173 	return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
1174 					  n, NULL));
1175 }
1176 
1177 /********************************************************************//**
1178 Checks if a column is in the ordering columns of the clustered index of a
1179 table. Column prefixes are treated like whole columns.
1180 @return TRUE if the column, or its prefix, is in the clustered key */
1181 ibool
dict_table_col_in_clustered_key(const dict_table_t * table,ulint n)1182 dict_table_col_in_clustered_key(
1183 /*============================*/
1184 	const dict_table_t*	table,	/*!< in: table */
1185 	ulint			n)	/*!< in: column number */
1186 {
1187 	const dict_index_t*	index;
1188 	const dict_field_t*	field;
1189 	const dict_col_t*	col;
1190 	ulint			pos;
1191 	ulint			n_fields;
1192 
1193 	ut_ad(table);
1194 
1195 	col = dict_table_get_nth_col(table, n);
1196 
1197 	index = dict_table_get_first_index(table);
1198 
1199 	n_fields = dict_index_get_n_unique(index);
1200 
1201 	for (pos = 0; pos < n_fields; pos++) {
1202 		field = dict_index_get_nth_field(index, pos);
1203 
1204 		if (col == field->col) {
1205 
1206 			return(TRUE);
1207 		}
1208 	}
1209 
1210 	return(FALSE);
1211 }
1212 
1213 /**********************************************************************//**
1214 Inits the data dictionary module. */
1215 void
dict_init(void)1216 dict_init(void)
1217 /*===========*/
1218 {
1219 	dict_operation_lock = static_cast<rw_lock_t*>(
1220 		ut_zalloc_nokey(sizeof(*dict_operation_lock)));
1221 
1222 	dict_sys = static_cast<dict_sys_t*>(ut_zalloc_nokey(sizeof(*dict_sys)));
1223 
1224 	UT_LIST_INIT(dict_sys->table_LRU, &dict_table_t::table_LRU);
1225 	UT_LIST_INIT(dict_sys->table_non_LRU, &dict_table_t::table_LRU);
1226 
1227 	mutex_create(LATCH_ID_DICT_SYS, &dict_sys->mutex);
1228 
1229 	dict_sys->table_hash = hash_create(
1230 		buf_pool_get_curr_size()
1231 		/ (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE));
1232 
1233 	dict_sys->table_id_hash = hash_create(
1234 		buf_pool_get_curr_size()
1235 		/ (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE));
1236 
1237 	dict_sys->hash_size = (hash_get_n_cells(dict_sys->table_hash)
1238 			       + hash_get_n_cells(dict_sys->table_id_hash))
1239 		* sizeof(hash_cell_t);
1240 
1241 	rw_lock_create(dict_operation_lock_key,
1242 		       dict_operation_lock, SYNC_DICT_OPERATION);
1243 
1244 	if (!srv_read_only_mode) {
1245 		dict_foreign_err_file = os_file_create_tmpfile(NULL);
1246 		ut_a(dict_foreign_err_file);
1247 	}
1248 
1249 	mutex_create(LATCH_ID_DICT_FOREIGN_ERR, &dict_foreign_err_mutex);
1250 
1251 	dict_sys->autoinc_map = new autoinc_map_t();
1252 }
1253 
1254 /**********************************************************************//**
1255 Move to the most recently used segment of the LRU list. */
1256 void
dict_move_to_mru(dict_table_t * table)1257 dict_move_to_mru(
1258 /*=============*/
1259 	dict_table_t*	table)		/*!< in: table to move to MRU */
1260 {
1261 	ut_ad(mutex_own(&dict_sys->mutex));
1262 	ut_ad(dict_lru_validate());
1263 	ut_ad(dict_lru_find_table(table));
1264 
1265 	ut_a(table->can_be_evicted);
1266 
1267 	UT_LIST_REMOVE(dict_sys->table_LRU, table);
1268 
1269 	UT_LIST_ADD_FIRST(dict_sys->table_LRU, table);
1270 
1271 	ut_ad(dict_lru_validate());
1272 }
1273 
1274 /**********************************************************************//**
1275 Returns a table object and increment its open handle count.
1276 NOTE! This is a high-level function to be used mainly from outside the
1277 'dict' module. Inside this directory dict_table_get_low
1278 is usually the appropriate function.
1279 @return table, NULL if does not exist */
1280 dict_table_t*
dict_table_open_on_name(const char * table_name,ibool dict_locked,ibool try_drop,dict_err_ignore_t ignore_err)1281 dict_table_open_on_name(
1282 /*====================*/
1283 	const char*	table_name,	/*!< in: table name */
1284 	ibool		dict_locked,	/*!< in: TRUE=data dictionary locked */
1285 	ibool		try_drop,	/*!< in: TRUE=try to drop any orphan
1286 					indexes after an aborted online
1287 					index creation */
1288 	dict_err_ignore_t
1289 			ignore_err)	/*!< in: error to be ignored when
1290 					loading a table definition */
1291 {
1292 	dict_table_t*	table;
1293 	DBUG_ENTER("dict_table_open_on_name");
1294 	DBUG_PRINT("dict_table_open_on_name", ("table: '%s'", table_name));
1295 
1296 	if (!dict_locked) {
1297 		mutex_enter(&dict_sys->mutex);
1298 	}
1299 
1300 	ut_ad(table_name);
1301 	ut_ad(mutex_own(&dict_sys->mutex));
1302 
1303 	table = dict_table_check_if_in_cache_low(table_name);
1304 
1305 	if (table == NULL) {
1306 		table = dict_load_table(table_name, true, ignore_err);
1307 	}
1308 
1309 	ut_ad(!table || table->cached);
1310 
1311 	if (table != NULL) {
1312 
1313 		/* If table is corrupted, return NULL */
1314 		if (ignore_err == DICT_ERR_IGNORE_NONE
1315 		    && table->corrupted) {
1316 
1317 			/* Make life easy for drop table. */
1318 			dict_table_prevent_eviction(table);
1319 
1320 			if (!dict_locked) {
1321 				mutex_exit(&dict_sys->mutex);
1322 			}
1323 
1324 			ib::info() << "Table "
1325 				<< table->name
1326 				<< " is corrupted. Please drop the table"
1327 				" and recreate it";
1328 			DBUG_RETURN(NULL);
1329 		}
1330 
1331 		if (table->can_be_evicted) {
1332 			dict_move_to_mru(table);
1333 		}
1334 
1335 		table->acquire();
1336 
1337 		MONITOR_INC(MONITOR_TABLE_REFERENCE);
1338 	}
1339 
1340 	ut_ad(dict_lru_validate());
1341 
1342 	if (!dict_locked) {
1343 		dict_table_try_drop_aborted_and_mutex_exit(table, try_drop);
1344 	}
1345 
1346 	DBUG_RETURN(table);
1347 }
1348 #endif /* !UNIV_HOTBACKUP */
1349 
1350 /**********************************************************************//**
1351 Adds system columns to a table object. */
1352 void
dict_table_add_system_columns(dict_table_t * table,mem_heap_t * heap)1353 dict_table_add_system_columns(
1354 /*==========================*/
1355 	dict_table_t*	table,	/*!< in/out: table */
1356 	mem_heap_t*	heap)	/*!< in: temporary heap */
1357 {
1358 	ut_ad(table);
1359 	ut_ad(table->n_def ==
1360 	      (table->n_cols - dict_table_get_n_sys_cols(table)));
1361 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1362 	ut_ad(!table->cached);
1363 
1364 	/* NOTE: the system columns MUST be added in the following order
1365 	(so that they can be indexed by the numerical value of DATA_ROW_ID,
1366 	etc.) and as the last columns of the table memory object.
1367 	The clustered index will not always physically contain all system
1368 	columns.
1369 	Intrinsic table don't need DB_ROLL_PTR as UNDO logging is turned off
1370 	for these tables. */
1371 
1372 	dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
1373 			       DATA_ROW_ID | DATA_NOT_NULL,
1374 			       DATA_ROW_ID_LEN);
1375 
1376 #if (DATA_ITT_N_SYS_COLS != 2)
1377 #error "DATA_ITT_N_SYS_COLS != 2"
1378 #endif
1379 
1380 #if DATA_ROW_ID != 0
1381 #error "DATA_ROW_ID != 0"
1382 #endif
1383 	dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
1384 			       DATA_TRX_ID | DATA_NOT_NULL,
1385 			       DATA_TRX_ID_LEN);
1386 #if DATA_TRX_ID != 1
1387 #error "DATA_TRX_ID != 1"
1388 #endif
1389 
1390 	if (!dict_table_is_intrinsic(table)) {
1391 		dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
1392 				       DATA_ROLL_PTR | DATA_NOT_NULL,
1393 				       DATA_ROLL_PTR_LEN);
1394 #if DATA_ROLL_PTR != 2
1395 #error "DATA_ROLL_PTR != 2"
1396 #endif
1397 
1398 		/* This check reminds that if a new system column is added to
1399 		the program, it should be dealt with here */
1400 #if DATA_N_SYS_COLS != 3
1401 #error "DATA_N_SYS_COLS != 3"
1402 #endif
1403 	}
1404 }
1405 
1406 #ifndef UNIV_HOTBACKUP
1407 /** Mark if table has big rows.
1408 @param[in,out]	table	table handler */
1409 void
dict_table_set_big_rows(dict_table_t * table)1410 dict_table_set_big_rows(
1411 	dict_table_t*	table)
1412 {
1413 	ulint	row_len = 0;
1414 	for (ulint i = 0; i < table->n_def; i++) {
1415 		ulint	col_len = dict_col_get_max_size(
1416 			dict_table_get_nth_col(table, i));
1417 
1418 		row_len += col_len;
1419 
1420 		/* If we have a single unbounded field, or several gigantic
1421 		fields, mark the maximum row size as BIG_ROW_SIZE. */
1422 		if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
1423 			row_len = BIG_ROW_SIZE;
1424 
1425 			break;
1426 		}
1427 	}
1428 
1429 	table->big_rows = (row_len >= BIG_ROW_SIZE) ? TRUE : FALSE;
1430 }
1431 
1432 /**********************************************************************//**
1433 Adds a table object to the dictionary cache. */
1434 void
dict_table_add_to_cache(dict_table_t * table,ibool can_be_evicted,mem_heap_t * heap)1435 dict_table_add_to_cache(
1436 /*====================*/
1437 	dict_table_t*	table,		/*!< in: table */
1438 	ibool		can_be_evicted,	/*!< in: TRUE if can be evicted */
1439 	mem_heap_t*	heap)		/*!< in: temporary heap */
1440 {
1441 	ulint	fold;
1442 	ulint	id_fold;
1443 
1444 	ut_ad(dict_lru_validate());
1445 	ut_ad(mutex_own(&dict_sys->mutex));
1446 
1447 	dict_table_add_system_columns(table, heap);
1448 
1449 	table->cached = TRUE;
1450 
1451 	fold = ut_fold_string(table->name.m_name);
1452 	id_fold = ut_fold_ull(table->id);
1453 
1454 	dict_table_set_big_rows(table);
1455 
1456 	/* Look for a table with the same name: error if such exists */
1457 	{
1458 		dict_table_t*	table2;
1459 		HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
1460 			    dict_table_t*, table2, ut_ad(table2->cached),
1461 			    !strcmp(table2->name.m_name, table->name.m_name));
1462 		ut_a(table2 == NULL);
1463 
1464 #ifdef UNIV_DEBUG
1465 		/* Look for the same table pointer with a different name */
1466 		HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
1467 				dict_table_t*, table2, ut_ad(table2->cached),
1468 				table2 == table);
1469 		ut_ad(table2 == NULL);
1470 #endif /* UNIV_DEBUG */
1471 	}
1472 
1473 	/* Look for a table with the same id: error if such exists */
1474 	{
1475 		dict_table_t*	table2;
1476 		HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
1477 			    dict_table_t*, table2, ut_ad(table2->cached),
1478 			    table2->id == table->id);
1479 		ut_a(table2 == NULL);
1480 
1481 #ifdef UNIV_DEBUG
1482 		/* Look for the same table pointer with a different id */
1483 		HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
1484 				dict_table_t*, table2, ut_ad(table2->cached),
1485 				table2 == table);
1486 		ut_ad(table2 == NULL);
1487 #endif /* UNIV_DEBUG */
1488 	}
1489 
1490 	/* Add table to hash table of tables */
1491 	HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1492 		    table);
1493 
1494 	/* Add table to hash table of tables based on table id */
1495 	HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
1496 		    table);
1497 
1498 	table->can_be_evicted = can_be_evicted;
1499 
1500 	if (table->can_be_evicted) {
1501 		UT_LIST_ADD_FIRST(dict_sys->table_LRU, table);
1502 	} else {
1503 		UT_LIST_ADD_FIRST(dict_sys->table_non_LRU, table);
1504 	}
1505 
1506 	dict_table_autoinc_restore(table);
1507 
1508 	ut_ad(dict_lru_validate());
1509 
1510 	dict_sys->size += mem_heap_get_size(table->heap)
1511 		+ strlen(table->name.m_name) + 1;
1512 }
1513 
1514 /**********************************************************************//**
1515 Test whether a table can be evicted from the LRU cache.
1516 @return TRUE if table can be evicted. */
1517 static
1518 ibool
dict_table_can_be_evicted(const dict_table_t * table)1519 dict_table_can_be_evicted(
1520 /*======================*/
1521 	const dict_table_t*	table)		/*!< in: table to test */
1522 {
1523 	ut_ad(mutex_own(&dict_sys->mutex));
1524 	ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
1525 
1526 	ut_a(table->can_be_evicted);
1527 	ut_a(table->foreign_set.empty());
1528 	ut_a(table->referenced_set.empty());
1529 
1530 	if (table->get_ref_count() == 0) {
1531 		dict_index_t*	index;
1532 
1533 		/* The transaction commit and rollback are called from
1534 		outside the handler interface. This means that there is
1535 		a window where the table->n_ref_count can be zero but
1536 		the table instance is in "use". */
1537 
1538 		if (lock_table_has_locks(table)) {
1539 			return(FALSE);
1540 		}
1541 
1542 		for (index = dict_table_get_first_index(table);
1543 		     index != NULL;
1544 		     index = dict_table_get_next_index(index)) {
1545 
1546 			btr_search_t*	info = btr_search_get_info(index);
1547 
1548 			/* We are not allowed to free the in-memory index
1549 			struct dict_index_t until all entries in the adaptive
1550 			hash index that point to any of the page belonging to
1551 			his b-tree index are dropped. This is so because
1552 			dropping of these entries require access to
1553 			dict_index_t struct. To avoid such scenario we keep
1554 			a count of number of such pages in the search_info and
1555 			only free the dict_index_t struct when this count
1556 			drops to zero.
1557 
1558 			See also: dict_index_remove_from_cache_low() */
1559 
1560 			if (btr_search_info_get_ref_count(info, index) > 0) {
1561 				return(FALSE);
1562 			}
1563 		}
1564 
1565 		return(TRUE);
1566 	}
1567 
1568 	return(FALSE);
1569 }
1570 
1571 /**********************************************************************//**
1572 Make room in the table cache by evicting an unused table. The unused table
1573 should not be part of FK relationship and currently not used in any user
1574 transaction. There is no guarantee that it will remove a table.
1575 @return number of tables evicted. If the number of tables in the dict_LRU
1576 is less than max_tables it will not do anything. */
1577 ulint
dict_make_room_in_cache(ulint max_tables,ulint pct_check)1578 dict_make_room_in_cache(
1579 /*====================*/
1580 	ulint		max_tables,	/*!< in: max tables allowed in cache */
1581 	ulint		pct_check)	/*!< in: max percent to check */
1582 {
1583 	ulint		i;
1584 	ulint		len;
1585 	dict_table_t*	table;
1586 	ulint		check_up_to;
1587 	ulint		n_evicted = 0;
1588 
1589 	ut_a(pct_check > 0);
1590 	ut_a(pct_check <= 100);
1591 	ut_ad(mutex_own(&dict_sys->mutex));
1592 	ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
1593 	ut_ad(dict_lru_validate());
1594 
1595 	i = len = UT_LIST_GET_LEN(dict_sys->table_LRU);
1596 
1597 	if (len < max_tables) {
1598 		return(0);
1599 	}
1600 
1601 	check_up_to = len - ((len * pct_check) / 100);
1602 
1603 	/* Check for overflow */
1604 	ut_a(i == 0 || check_up_to <= i);
1605 
1606 	/* Find a suitable candidate to evict from the cache. Don't scan the
1607 	entire LRU list. Only scan pct_check list entries. */
1608 
1609 	for (table = UT_LIST_GET_LAST(dict_sys->table_LRU);
1610 	     table != NULL
1611 	     && i > check_up_to
1612 	     && (len - n_evicted) > max_tables;
1613 	     --i) {
1614 
1615 		dict_table_t*	prev_table;
1616 
1617 	        prev_table = UT_LIST_GET_PREV(table_LRU, table);
1618 
1619 		if (dict_table_can_be_evicted(table)) {
1620 
1621 			DBUG_EXECUTE_IF("crash_if_fts_table_is_evicted",
1622 			{
1623 				  if (table->fts &&
1624 				      dict_table_has_fts_index(table)) {
1625 					ut_ad(0);
1626 				  }
1627 			};);
1628 			dict_table_remove_from_cache_low(table, TRUE);
1629 
1630 			++n_evicted;
1631 		}
1632 
1633 		table = prev_table;
1634 	}
1635 
1636 	return(n_evicted);
1637 }
1638 
1639 /**********************************************************************//**
1640 Move a table to the non-LRU list from the LRU list. */
1641 void
dict_table_move_from_lru_to_non_lru(dict_table_t * table)1642 dict_table_move_from_lru_to_non_lru(
1643 /*================================*/
1644 	dict_table_t*	table)	/*!< in: table to move from LRU to non-LRU */
1645 {
1646 	ut_ad(mutex_own(&dict_sys->mutex));
1647 	ut_ad(dict_lru_find_table(table));
1648 
1649 	ut_a(table->can_be_evicted);
1650 
1651 	UT_LIST_REMOVE(dict_sys->table_LRU, table);
1652 
1653 	UT_LIST_ADD_LAST(dict_sys->table_non_LRU, table);
1654 
1655 	table->can_be_evicted = FALSE;
1656 }
1657 
1658 /** Looks for an index with the given id given a table instance.
1659 @param[in]	table	table instance
1660 @param[in]	id	index id
1661 @return index or NULL */
1662 dict_index_t*
dict_table_find_index_on_id(const dict_table_t * table,index_id_t id)1663 dict_table_find_index_on_id(
1664 	const dict_table_t*	table,
1665 	index_id_t		id)
1666 {
1667 	dict_index_t*	index;
1668 
1669 	for (index = dict_table_get_first_index(table);
1670 	     index != NULL;
1671 	     index = dict_table_get_next_index(index)) {
1672 
1673 		if (id == index->id) {
1674 			/* Found */
1675 
1676 			return(index);
1677 		}
1678 	}
1679 
1680 	return(NULL);
1681 }
1682 
1683 /**********************************************************************//**
1684 Looks for an index with the given id. NOTE that we do not reserve
1685 the dictionary mutex: this function is for emergency purposes like
1686 printing info of a corrupt database page!
1687 @return index or NULL if not found in cache */
1688 dict_index_t*
dict_index_find_on_id_low(index_id_t id)1689 dict_index_find_on_id_low(
1690 /*======================*/
1691 	index_id_t	id)	/*!< in: index id */
1692 {
1693 	dict_table_t*	table;
1694 
1695 	/* This can happen if the system tablespace is the wrong page size */
1696 	if (dict_sys == NULL) {
1697 		return(NULL);
1698 	}
1699 
1700 	for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1701 	     table != NULL;
1702 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
1703 
1704 		dict_index_t*	index = dict_table_find_index_on_id(table, id);
1705 
1706 		if (index != NULL) {
1707 			return(index);
1708 		}
1709 	}
1710 
1711 	for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU);
1712 	     table != NULL;
1713 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
1714 
1715 		dict_index_t*	index = dict_table_find_index_on_id(table, id);
1716 
1717 		if (index != NULL) {
1718 			return(index);
1719 		}
1720 	}
1721 
1722 	return(NULL);
1723 }
1724 
1725 /** Function object to remove a foreign key constraint from the
1726 referenced_set of the referenced table.  The foreign key object is
1727 also removed from the dictionary cache.  The foreign key constraint
1728 is not removed from the foreign_set of the table containing the
1729 constraint. */
1730 struct dict_foreign_remove_partial
1731 {
operator ()dict_foreign_remove_partial1732 	void operator()(dict_foreign_t* foreign) {
1733 		dict_table_t*	table = foreign->referenced_table;
1734 		if (table != NULL) {
1735 			table->referenced_set.erase(foreign);
1736 		}
1737 		dict_foreign_free(foreign);
1738 	}
1739 };
1740 
1741 /**********************************************************************//**
1742 Renames a table object.
1743 @return TRUE if success */
1744 dberr_t
dict_table_rename_in_cache(dict_table_t * table,const char * new_name,ibool rename_also_foreigns)1745 dict_table_rename_in_cache(
1746 /*=======================*/
1747 	dict_table_t*	table,		/*!< in/out: table */
1748 	const char*	new_name,	/*!< in: new name */
1749 	ibool		rename_also_foreigns)/*!< in: in ALTER TABLE we want
1750 					to preserve the original table name
1751 					in constraints which reference it */
1752 {
1753 	dberr_t		err;
1754 	dict_foreign_t*	foreign;
1755 	dict_index_t*	index;
1756 	ulint		fold;
1757 	char		old_name[MAX_FULL_NAME_LEN + 1];
1758 	os_file_type_t	ftype;
1759 	bool		exists;
1760 
1761 	ut_ad(mutex_own(&dict_sys->mutex));
1762 
1763 	/* store the old/current name to an automatic variable */
1764 	if (strlen(table->name.m_name) + 1 <= sizeof(old_name)) {
1765 		strcpy(old_name, table->name.m_name);
1766 	} else {
1767 		ib::fatal() << "Too long table name: "
1768 			<< table->name
1769 			<< ", max length is " << MAX_FULL_NAME_LEN;
1770 	}
1771 
1772 	fold = ut_fold_string(new_name);
1773 
1774 	/* Look for a table with the same name: error if such exists */
1775 	dict_table_t*	table2;
1776 	HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
1777 			dict_table_t*, table2, ut_ad(table2->cached),
1778 			(ut_strcmp(table2->name.m_name, new_name) == 0));
1779 	DBUG_EXECUTE_IF("dict_table_rename_in_cache_failure",
1780 		if (table2 == NULL) {
1781 			table2 = (dict_table_t*) -1;
1782 		} );
1783 	if (table2) {
1784 		ib::error() << "Cannot rename table '" << old_name
1785 			<< "' to '" << new_name << "' since the"
1786 			" dictionary cache already contains '" << new_name << "'.";
1787 		return(DB_ERROR);
1788 	}
1789 
1790 	/* If the table is stored in a single-table tablespace, rename the
1791 	.ibd file and rebuild the .isl file if needed. */
1792 
1793 	if (dict_table_is_discarded(table)) {
1794 		char*		filepath;
1795 
1796 		ut_ad(dict_table_is_file_per_table(table));
1797 		ut_ad(!dict_table_is_temporary(table));
1798 
1799 		/* Make sure the data_dir_path is set. */
1800 		dict_get_and_save_data_dir_path(table, true);
1801 
1802 		if (DICT_TF_HAS_DATA_DIR(table->flags)) {
1803 			ut_a(table->data_dir_path);
1804 
1805 			filepath = fil_make_filepath(
1806 				table->data_dir_path, table->name.m_name,
1807 				IBD, true);
1808 		} else {
1809 			filepath = fil_make_filepath(
1810 				NULL, table->name.m_name, IBD, false);
1811 		}
1812 
1813 		if (filepath == NULL) {
1814 			return(DB_OUT_OF_MEMORY);
1815 		}
1816 
1817 		fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE);
1818 
1819 		/* Delete any temp file hanging around. */
1820 		if (os_file_status(filepath, &exists, &ftype)
1821 		    && exists
1822 		    && !os_file_delete_if_exists(innodb_temp_file_key,
1823 						 filepath, NULL)) {
1824 
1825 			ib::info() << "Delete of " << filepath << " failed.";
1826 		}
1827 
1828 		ut_free(filepath);
1829 
1830 	} else if (dict_table_is_file_per_table(table)) {
1831 
1832 		if (table->dir_path_of_temp_table != NULL) {
1833 			ib::error() << "Trying to rename a TEMPORARY TABLE "
1834 				<< old_name
1835 				<< " ( " << table->dir_path_of_temp_table
1836 				<< " )";
1837 			return(DB_ERROR);
1838 		}
1839 
1840 		char*	new_path = NULL;
1841 		char*	old_path = fil_space_get_first_path(table->space);
1842 
1843 		if (DICT_TF_HAS_DATA_DIR(table->flags)) {
1844 			new_path = os_file_make_new_pathname(
1845 				old_path, new_name);
1846 
1847 			dberr_t	err = RemoteDatafile::create_link_file(
1848 				new_name, new_path);
1849 
1850 			if (err != DB_SUCCESS) {
1851 				ut_free(new_path);
1852 				ut_free(old_path);
1853 				return(DB_TABLESPACE_EXISTS);
1854 			}
1855 		} else {
1856 			new_path = fil_make_filepath(
1857 				NULL, new_name, IBD, false);
1858 		}
1859 
1860 		/* New filepath must not exist. */
1861 		err = fil_rename_tablespace_check(
1862 			table->space, old_path, new_path, false);
1863 		if (err != DB_SUCCESS) {
1864 			ut_free(old_path);
1865 			ut_free(new_path);
1866 			return(err);
1867 		}
1868 
1869 		bool	success = fil_rename_tablespace(
1870 			table->space, old_path, new_name, new_path);
1871 
1872 		ut_free(old_path);
1873 		ut_free(new_path);
1874 
1875 		/* If the tablespace is remote, a new .isl file was created
1876 		If success, delete the old one. If not, delete the new one. */
1877 		if (DICT_TF_HAS_DATA_DIR(table->flags)) {
1878 			RemoteDatafile::delete_link_file(
1879 				success ? old_name : new_name);
1880 		}
1881 
1882 		if (!success) {
1883 			return(DB_ERROR);
1884 		}
1885 	}
1886 
1887 	/* Remove table from the hash tables of tables */
1888 	HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1889 		    ut_fold_string(old_name), table);
1890 
1891 	if (strlen(new_name) > strlen(table->name.m_name)) {
1892 		/* We allocate MAX_FULL_NAME_LEN + 1 bytes here to avoid
1893 		memory fragmentation, we assume a repeated calls of
1894 		ut_realloc() with the same size do not cause fragmentation */
1895 		ut_a(strlen(new_name) <= MAX_FULL_NAME_LEN);
1896 
1897 		table->name.m_name = static_cast<char*>(
1898 			ut_realloc(table->name.m_name, MAX_FULL_NAME_LEN + 1));
1899 	}
1900 	strcpy(table->name.m_name, new_name);
1901 
1902 	/* Add table to hash table of tables */
1903 	HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1904 		    table);
1905 
1906 	dict_sys->size += strlen(new_name) - strlen(old_name);
1907 	ut_a(dict_sys->size > 0);
1908 
1909 	/* Update the table_name field in indexes */
1910 	for (index = dict_table_get_first_index(table);
1911 	     index != NULL;
1912 	     index = dict_table_get_next_index(index)) {
1913 
1914 		index->table_name = table->name.m_name;
1915 	}
1916 
1917 	if (!rename_also_foreigns) {
1918 		/* In ALTER TABLE we think of the rename table operation
1919 		in the direction table -> temporary table (#sql...)
1920 		as dropping the table with the old name and creating
1921 		a new with the new name. Thus we kind of drop the
1922 		constraints from the dictionary cache here. The foreign key
1923 		constraints will be inherited to the new table from the
1924 		system tables through a call of dict_load_foreigns. */
1925 
1926 		/* Remove the foreign constraints from the cache */
1927 		std::for_each(table->foreign_set.begin(),
1928 			      table->foreign_set.end(),
1929 			      dict_foreign_remove_partial());
1930 		table->foreign_set.clear();
1931 
1932 		/* Reset table field in referencing constraints */
1933 		for (dict_foreign_set::iterator it
1934 			= table->referenced_set.begin();
1935 		     it != table->referenced_set.end();
1936 		     ++it) {
1937 
1938 			foreign = *it;
1939 			foreign->referenced_table = NULL;
1940 			foreign->referenced_index = NULL;
1941 
1942 		}
1943 
1944 		/* Make the set of referencing constraints empty */
1945 		table->referenced_set.clear();
1946 
1947 		return(DB_SUCCESS);
1948 	}
1949 
1950 	/* Update the table name fields in foreign constraints, and update also
1951 	the constraint id of new format >= 4.0.18 constraints. Note that at
1952 	this point we have already changed table->name to the new name. */
1953 
1954 	dict_foreign_set	fk_set;
1955 
1956 	for (;;) {
1957 
1958 		dict_foreign_set::iterator	it
1959 			= table->foreign_set.begin();
1960 
1961 		if (it == table->foreign_set.end()) {
1962 			break;
1963 		}
1964 
1965 		foreign = *it;
1966 
1967 		if (foreign->referenced_table) {
1968 			foreign->referenced_table->referenced_set.erase(foreign);
1969 		}
1970 
1971 		if (ut_strlen(foreign->foreign_table_name)
1972 		    < ut_strlen(table->name.m_name)) {
1973 			/* Allocate a longer name buffer;
1974 			TODO: store buf len to save memory */
1975 
1976 			foreign->foreign_table_name = mem_heap_strdup(
1977 				foreign->heap, table->name.m_name);
1978 			dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
1979 		} else {
1980 			strcpy(foreign->foreign_table_name,
1981 			       table->name.m_name);
1982 			dict_mem_foreign_table_name_lookup_set(foreign, FALSE);
1983 		}
1984 		if (strchr(foreign->id, '/')) {
1985 			/* This is a >= 4.0.18 format id */
1986 
1987 			ulint	db_len;
1988 			char*	old_id;
1989 			char    old_name_cs_filename[MAX_FULL_NAME_LEN + 1];
1990 			uint    errors = 0;
1991 
1992 			/* All table names are internally stored in charset
1993 			my_charset_filename (except the temp tables and the
1994 			partition identifier suffix in partition tables). The
1995 			foreign key constraint names are internally stored
1996 			in UTF-8 charset.  The variable fkid here is used
1997 			to store foreign key constraint name in charset
1998 			my_charset_filename for comparison further below. */
1999 			char    fkid[MAX_TABLE_NAME_LEN+20];
2000 			ibool	on_tmp = FALSE;
2001 
2002 			/* The old table name in my_charset_filename is stored
2003 			in old_name_cs_filename */
2004 
2005 			strncpy(old_name_cs_filename, old_name,
2006 				sizeof(old_name_cs_filename));
2007 			if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) {
2008 
2009 				innobase_convert_to_system_charset(
2010 					strchr(old_name_cs_filename, '/') + 1,
2011 					strchr(old_name, '/') + 1,
2012 					MAX_TABLE_NAME_LEN, &errors);
2013 
2014 				if (errors) {
2015 					/* There has been an error to convert
2016 					old table into UTF-8.  This probably
2017 					means that the old table name is
2018 					actually in UTF-8. */
2019 					innobase_convert_to_filename_charset(
2020 						strchr(old_name_cs_filename,
2021 						       '/') + 1,
2022 						strchr(old_name, '/') + 1,
2023 						MAX_TABLE_NAME_LEN);
2024 				} else {
2025 					/* Old name already in
2026 					my_charset_filename */
2027 					strncpy(old_name_cs_filename, old_name,
2028 						sizeof(old_name_cs_filename));
2029 				}
2030 			}
2031 
2032 			strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN);
2033 
2034 			if (strstr(fkid, TEMP_TABLE_PATH_PREFIX) == NULL) {
2035 				innobase_convert_to_filename_charset(
2036 					strchr(fkid, '/') + 1,
2037 					strchr(foreign->id, '/') + 1,
2038 					MAX_TABLE_NAME_LEN+20);
2039 			} else {
2040 				on_tmp = TRUE;
2041 			}
2042 
2043 			old_id = mem_strdup(foreign->id);
2044 
2045 			if (ut_strlen(fkid) > ut_strlen(old_name_cs_filename)
2046 			    + ((sizeof dict_ibfk) - 1)
2047 			    && !memcmp(fkid, old_name_cs_filename,
2048 				       ut_strlen(old_name_cs_filename))
2049 			    && !memcmp(fkid + ut_strlen(old_name_cs_filename),
2050 				       dict_ibfk, (sizeof dict_ibfk) - 1)) {
2051 
2052 				/* This is a generated >= 4.0.18 format id */
2053 
2054 				char	table_name[MAX_TABLE_NAME_LEN + 1] = "";
2055 				uint	errors = 0;
2056 
2057 				if (strlen(table->name.m_name)
2058 				    > strlen(old_name)) {
2059 					foreign->id = static_cast<char*>(
2060 						mem_heap_alloc(
2061 						foreign->heap,
2062 						strlen(table->name.m_name)
2063 						+ strlen(old_id) + 1));
2064 				}
2065 
2066 				/* Convert the table name to UTF-8 */
2067 				strncpy(table_name, table->name.m_name,
2068 					MAX_TABLE_NAME_LEN);
2069 				innobase_convert_to_system_charset(
2070 					strchr(table_name, '/') + 1,
2071 					strchr(table->name.m_name, '/') + 1,
2072 					MAX_TABLE_NAME_LEN, &errors);
2073 
2074 				if (errors) {
2075 					/* Table name could not be converted
2076 					from charset my_charset_filename to
2077 					UTF-8. This means that the table name
2078 					is already in UTF-8 (#mysql#50). */
2079 					strncpy(table_name, table->name.m_name,
2080 						MAX_TABLE_NAME_LEN);
2081 				}
2082 
2083 				/* Replace the prefix 'databasename/tablename'
2084 				with the new names */
2085 				strcpy(foreign->id, table_name);
2086 				if (on_tmp) {
2087 					strcat(foreign->id,
2088 					       old_id + ut_strlen(old_name));
2089 				} else {
2090 					sprintf(strchr(foreign->id, '/') + 1,
2091 						"%s%s",
2092 						strchr(table_name, '/') +1,
2093 						strstr(old_id, "_ibfk_") );
2094 				}
2095 
2096 			} else {
2097 				/* This is a >= 4.0.18 format id where the user
2098 				gave the id name */
2099 				db_len = dict_get_db_name_len(
2100 					table->name.m_name) + 1;
2101 
2102 				if (db_len - 1
2103 				    > dict_get_db_name_len(foreign->id)) {
2104 
2105 					foreign->id = static_cast<char*>(
2106 						mem_heap_alloc(
2107 						foreign->heap,
2108 						db_len + strlen(old_id) + 1));
2109 				}
2110 
2111 				/* Replace the database prefix in id with the
2112 				one from table->name */
2113 
2114 				ut_memcpy(foreign->id,
2115 					  table->name.m_name, db_len);
2116 
2117 				strcpy(foreign->id + db_len,
2118 				       dict_remove_db_name(old_id));
2119 			}
2120 
2121 			ut_free(old_id);
2122 		}
2123 
2124 		table->foreign_set.erase(it);
2125 		fk_set.insert(foreign);
2126 
2127 		if (foreign->referenced_table) {
2128 			foreign->referenced_table->referenced_set.insert(foreign);
2129 		}
2130 	}
2131 
2132 	ut_a(table->foreign_set.empty());
2133 	table->foreign_set.swap(fk_set);
2134 
2135 	for (dict_foreign_set::iterator it = table->referenced_set.begin();
2136 	     it != table->referenced_set.end();
2137 	     ++it) {
2138 
2139 		foreign = *it;
2140 
2141 		if (ut_strlen(foreign->referenced_table_name)
2142 		    < ut_strlen(table->name.m_name)) {
2143 			/* Allocate a longer name buffer;
2144 			TODO: store buf len to save memory */
2145 
2146 			foreign->referenced_table_name = mem_heap_strdup(
2147 				foreign->heap, table->name.m_name);
2148 
2149 			dict_mem_referenced_table_name_lookup_set(
2150 				foreign, TRUE);
2151 		} else {
2152 			/* Use the same buffer */
2153 			strcpy(foreign->referenced_table_name,
2154 			       table->name.m_name);
2155 
2156 			dict_mem_referenced_table_name_lookup_set(
2157 				foreign, FALSE);
2158 		}
2159 	}
2160 
2161 	return(DB_SUCCESS);
2162 }
2163 
2164 /**********************************************************************//**
2165 Change the id of a table object in the dictionary cache. This is used in
2166 DISCARD TABLESPACE. */
2167 void
dict_table_change_id_in_cache(dict_table_t * table,table_id_t new_id)2168 dict_table_change_id_in_cache(
2169 /*==========================*/
2170 	dict_table_t*	table,	/*!< in/out: table object already in cache */
2171 	table_id_t	new_id)	/*!< in: new id to set */
2172 {
2173 	ut_ad(table);
2174 	ut_ad(mutex_own(&dict_sys->mutex));
2175 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2176 
2177 	/* Remove the table from the hash table of id's */
2178 
2179 	HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
2180 		    ut_fold_ull(table->id), table);
2181 	table->id = new_id;
2182 
2183 	/* Add the table back to the hash table */
2184 	HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
2185 		    ut_fold_ull(table->id), table);
2186 }
2187 
2188 /**********************************************************************//**
2189 Removes a table object from the dictionary cache. */
2190 void
dict_table_remove_from_cache_low(dict_table_t * table,ibool lru_evict)2191 dict_table_remove_from_cache_low(
2192 /*=============================*/
2193 	dict_table_t*	table,		/*!< in, own: table */
2194 	ibool		lru_evict)	/*!< in: TRUE if table being evicted
2195 					to make room in the table LRU list */
2196 {
2197 	dict_foreign_t*	foreign;
2198 	dict_index_t*	index;
2199 	lint		size;
2200 
2201 	ut_ad(table);
2202 	ut_ad(dict_lru_validate());
2203 	ut_a(table->get_ref_count() == 0);
2204 	ut_a(table->n_rec_locks == 0);
2205 	ut_ad(mutex_own(&dict_sys->mutex));
2206 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2207 
2208 	/* Remove the foreign constraints from the cache */
2209 	std::for_each(table->foreign_set.begin(), table->foreign_set.end(),
2210 		      dict_foreign_remove_partial());
2211 	table->foreign_set.clear();
2212 
2213 	/* Reset table field in referencing constraints */
2214 	for (dict_foreign_set::iterator it = table->referenced_set.begin();
2215 	     it != table->referenced_set.end();
2216 	     ++it) {
2217 
2218 		foreign = *it;
2219 		foreign->referenced_table = NULL;
2220 		foreign->referenced_index = NULL;
2221 	}
2222 
2223 	if (lru_evict && table->drop_aborted) {
2224 		/* Do as dict_table_try_drop_aborted() does. */
2225 
2226 		trx_t* trx = trx_allocate_for_background();
2227 
2228 		ut_ad(mutex_own(&dict_sys->mutex));
2229 		ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
2230 
2231 		/* Mimic row_mysql_lock_data_dictionary(). */
2232 		trx->dict_operation_lock_mode = RW_X_LATCH;
2233 
2234 		trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
2235 
2236 		/* Silence a debug assertion in row_merge_drop_indexes(). */
2237 		ut_d(table->acquire());
2238 		row_merge_drop_indexes(trx, table, TRUE);
2239 		ut_d(table->release());
2240 		ut_ad(table->get_ref_count() == 0);
2241 		trx_commit_for_mysql(trx);
2242 		trx->dict_operation_lock_mode = 0;
2243 		trx_free_for_background(trx);
2244 	}
2245 	/* Remove the indexes from the cache */
2246 
2247 	for (index = UT_LIST_GET_LAST(table->indexes);
2248 	     index != NULL;
2249 	     index = UT_LIST_GET_LAST(table->indexes)) {
2250 
2251 		dict_index_remove_from_cache_low(table, index, lru_evict);
2252 	}
2253 
2254 	/* Remove table from the hash tables of tables */
2255 
2256 	HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
2257 		    ut_fold_string(table->name.m_name), table);
2258 
2259 	HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
2260 		    ut_fold_ull(table->id), table);
2261 
2262 	/* Remove table from LRU or non-LRU list. */
2263 	if (table->can_be_evicted) {
2264 		ut_ad(dict_lru_find_table(table));
2265 		UT_LIST_REMOVE(dict_sys->table_LRU, table);
2266 	} else {
2267 		ut_ad(dict_non_lru_find_table(table));
2268 		UT_LIST_REMOVE(dict_sys->table_non_LRU, table);
2269 	}
2270 
2271 	ut_ad(dict_lru_validate());
2272 
2273 	if (lru_evict) {
2274 		dict_table_autoinc_store(table);
2275 	}
2276 
2277 	/* Free virtual column template if any */
2278 	if (table->vc_templ != NULL) {
2279 		dict_free_vc_templ(table->vc_templ);
2280 		UT_DELETE(table->vc_templ);
2281 	}
2282 
2283 	size = mem_heap_get_size(table->heap) + strlen(table->name.m_name) + 1;
2284 
2285 	ut_ad(dict_sys->size >= size);
2286 
2287 	dict_sys->size -= size;
2288 
2289 	dict_mem_table_free(table);
2290 }
2291 
2292 /**********************************************************************//**
2293 Removes a table object from the dictionary cache. */
2294 void
dict_table_remove_from_cache(dict_table_t * table)2295 dict_table_remove_from_cache(
2296 /*=========================*/
2297 	dict_table_t*	table)	/*!< in, own: table */
2298 {
2299 	dict_table_remove_from_cache_low(table, FALSE);
2300 }
2301 
2302 /****************************************************************//**
2303 If the given column name is reserved for InnoDB system columns, return
2304 TRUE.
2305 @return TRUE if name is reserved */
2306 ibool
dict_col_name_is_reserved(const char * name)2307 dict_col_name_is_reserved(
2308 /*======================*/
2309 	const char*	name)	/*!< in: column name */
2310 {
2311 	/* This check reminds that if a new system column is added to
2312 	the program, it should be dealt with here. */
2313 #if DATA_N_SYS_COLS != 3
2314 #error "DATA_N_SYS_COLS != 3"
2315 #endif
2316 
2317 	static const char*	reserved_names[] = {
2318 		"DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
2319 	};
2320 
2321 	ulint			i;
2322 
2323 	for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
2324 		if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
2325 
2326 			return(TRUE);
2327 		}
2328 	}
2329 
2330 	return(FALSE);
2331 }
2332 
2333 /****************************************************************//**
2334 Return maximum size of the node pointer record.
2335 @return maximum size of the record in bytes */
2336 ulint
dict_index_node_ptr_max_size(const dict_index_t * index)2337 dict_index_node_ptr_max_size(
2338 /*=========================*/
2339 	const dict_index_t*	index)	/*!< in: index */
2340 {
2341 	ulint	comp;
2342 	ulint	i;
2343 	/* maximum possible storage size of a record */
2344 	ulint	rec_max_size;
2345 
2346 	if (dict_index_is_ibuf(index)) {
2347 		/* cannot estimate accurately */
2348 		/* This is universal index for change buffer.
2349 		The max size of the entry is about max key length * 2.
2350 		(index key + primary key to be inserted to the index)
2351 		(The max key length is UNIV_PAGE_SIZE / 16 * 3 at
2352 		 ha_innobase::max_supported_key_length(),
2353 		 considering MAX_KEY_LENGTH = 3072 at MySQL imposes
2354 		 the 3500 historical InnoDB value for 16K page size case.)
2355 		For the universal index, node_ptr contains most of the entry.
2356 		And 512 is enough to contain ibuf columns and meta-data */
2357 		return(UNIV_PAGE_SIZE / 8 * 3 + 512);
2358 	}
2359 
2360 	comp = dict_table_is_comp(index->table);
2361 	/* Each record has page_no, length of page_no and header. */
2362 	rec_max_size = comp
2363 		? REC_NODE_PTR_SIZE + 1 + REC_N_NEW_EXTRA_BYTES
2364 		: REC_NODE_PTR_SIZE + 2 + REC_N_OLD_EXTRA_BYTES;
2365 
2366 	if (comp) {
2367 		/* Include the "null" flags in the
2368 		maximum possible record size. */
2369 		rec_max_size += UT_BITS_IN_BYTES(index->n_nullable);
2370 	} else {
2371 		/* For each column, include a 2-byte offset and a
2372 		"null" flag. */
2373 		rec_max_size += 2 * index->n_fields;
2374 	}
2375 
2376 	/* Compute the maximum possible record size. */
2377 	for (i = 0; i < dict_index_get_n_unique_in_tree(index); i++) {
2378 		const dict_field_t*	field
2379 			= dict_index_get_nth_field(index, i);
2380 		const dict_col_t*	col
2381 			= dict_field_get_col(field);
2382 		ulint			field_max_size;
2383 		ulint			field_ext_max_size;
2384 
2385 		/* Determine the maximum length of the index field. */
2386 
2387 		field_max_size = dict_col_get_fixed_size(col, comp);
2388 		if (field_max_size) {
2389 			/* dict_index_add_col() should guarantee this */
2390 			ut_ad(!field->prefix_len
2391 			      || field->fixed_len == field->prefix_len);
2392 			/* Fixed lengths are not encoded
2393 			in ROW_FORMAT=COMPACT. */
2394 			rec_max_size += field_max_size;
2395 			continue;
2396 		}
2397 
2398 		field_max_size = dict_col_get_max_size(col);
2399 		/* A varchar(0) case when the max size of field
2400 		can't be estimated accurately */
2401 		if (field_max_size == 0) {
2402 			ulint page_rec_max = srv_page_size == UNIV_PAGE_SIZE_MAX
2403 				? REC_MAX_DATA_SIZE - 1
2404 			: page_get_free_space_of_empty(comp) / 2;
2405 			rec_max_size += page_rec_max;
2406 		}
2407 		field_ext_max_size = field_max_size < 256 ? 1 : 2;
2408 
2409 		if (field->prefix_len
2410 		    && field->prefix_len < field_max_size) {
2411 			field_max_size = field->prefix_len;
2412 		}
2413 
2414 		if (comp) {
2415 			/* Add the extra size for ROW_FORMAT=COMPACT.
2416 			For ROW_FORMAT=REDUNDANT, these bytes were
2417 			added to rec_max_size before this loop. */
2418 			rec_max_size += field_ext_max_size;
2419 		}
2420 
2421 		rec_max_size += field_max_size;
2422 	}
2423 
2424 	return(rec_max_size);
2425 }
2426 
2427 /****************************************************************//**
2428 If a record of this index might not fit on a single B-tree page,
2429 return TRUE.
2430 @return TRUE if the index record could become too big */
2431 static
2432 ibool
dict_index_too_big_for_tree(const dict_table_t * table,const dict_index_t * new_index,bool strict)2433 dict_index_too_big_for_tree(
2434 /*========================*/
2435 	const dict_table_t*	table,		/*!< in: table */
2436 	const dict_index_t*	new_index,	/*!< in: index */
2437 	bool			strict)		/*!< in: TRUE=report error if
2438 						records could be too big to
2439 						fit in an B-tree page */
2440 {
2441 	ulint	comp;
2442 	ulint	i;
2443 	/* maximum possible storage size of a record */
2444 	ulint	rec_max_size;
2445 	/* maximum allowed size of a record on a leaf page */
2446 	ulint	page_rec_max;
2447 	/* maximum allowed size of a node pointer record */
2448 	ulint	page_ptr_max;
2449 
2450 	/* FTS index consists of auxiliary tables, they shall be excluded from
2451 	index row size check */
2452 	if (new_index->type & DICT_FTS) {
2453 		return(false);
2454 	}
2455 
2456 	DBUG_EXECUTE_IF(
2457 		"ib_force_create_table",
2458 		return(FALSE););
2459 
2460 	comp = dict_table_is_comp(table);
2461 
2462 	const page_size_t	page_size(dict_table_page_size(table));
2463 
2464 	if (page_size.is_compressed()
2465 	    && page_size.physical() < univ_page_size.physical()) {
2466 		/* On a compressed page, two records must fit in the
2467 		uncompressed page modification log. On compressed pages
2468 		with size.physical() == univ_page_size.physical(),
2469 		this limit will never be reached. */
2470 		ut_ad(comp);
2471 		/* The maximum allowed record size is the size of
2472 		an empty page, minus a byte for recoding the heap
2473 		number in the page modification log.  The maximum
2474 		allowed node pointer size is half that. */
2475 		page_rec_max = page_zip_empty_size(new_index->n_fields,
2476 						   page_size.physical());
2477 		if (page_rec_max) {
2478 			page_rec_max--;
2479 		}
2480 		page_ptr_max = page_rec_max / 2;
2481 		/* On a compressed page, there is a two-byte entry in
2482 		the dense page directory for every record.  But there
2483 		is no record header. */
2484 		rec_max_size = 2;
2485 	} else {
2486 		/* The maximum allowed record size is half a B-tree
2487 		page(16k for 64k page size).  No additional sparse
2488 		page directory entry will be generated for the first
2489 		few user records. */
2490 		page_rec_max = srv_page_size == UNIV_PAGE_SIZE_MAX
2491 			? REC_MAX_DATA_SIZE - 1
2492 			: page_get_free_space_of_empty(comp) / 2;
2493 		page_ptr_max = page_rec_max;
2494 		/* Each record has a header. */
2495 		rec_max_size = comp
2496 			? REC_N_NEW_EXTRA_BYTES
2497 			: REC_N_OLD_EXTRA_BYTES;
2498 	}
2499 
2500 	if (comp) {
2501 		/* Include the "null" flags in the
2502 		maximum possible record size. */
2503 		rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
2504 	} else {
2505 		/* For each column, include a 2-byte offset and a
2506 		"null" flag.  The 1-byte format is only used in short
2507 		records that do not contain externally stored columns.
2508 		Such records could never exceed the page limit, even
2509 		when using the 2-byte format. */
2510 		rec_max_size += 2 * new_index->n_fields;
2511 	}
2512 
2513 	/* Compute the maximum possible record size. */
2514 	for (i = 0; i < new_index->n_fields; i++) {
2515 		const dict_field_t*	field
2516 			= dict_index_get_nth_field(new_index, i);
2517 		const dict_col_t*	col
2518 			= dict_field_get_col(field);
2519 		ulint			field_max_size;
2520 		ulint			field_ext_max_size;
2521 
2522 		/* In dtuple_convert_big_rec(), variable-length columns
2523 		that are longer than BTR_EXTERN_LOCAL_STORED_MAX_SIZE
2524 		may be chosen for external storage.
2525 
2526 		Fixed-length columns, and all columns of secondary
2527 		index records are always stored inline. */
2528 
2529 		/* Determine the maximum length of the index field.
2530 		The field_ext_max_size should be computed as the worst
2531 		case in rec_get_converted_size_comp() for
2532 		REC_STATUS_ORDINARY records. */
2533 
2534 		field_max_size = dict_col_get_fixed_size(col, comp);
2535 		if (field_max_size && field->fixed_len != 0) {
2536 			/* dict_index_add_col() should guarantee this */
2537 			ut_ad(!field->prefix_len
2538 			      || field->fixed_len == field->prefix_len);
2539 			/* Fixed lengths are not encoded
2540 			in ROW_FORMAT=COMPACT. */
2541 			field_ext_max_size = 0;
2542 			goto add_field_size;
2543 		}
2544 
2545 		field_max_size = dict_col_get_max_size(col);
2546 		field_ext_max_size = field_max_size < 256 ? 1 : 2;
2547 
2548 		if (field->prefix_len) {
2549 			if (field->prefix_len < field_max_size) {
2550 				field_max_size = field->prefix_len;
2551 			}
2552 		} else if (field_max_size > BTR_EXTERN_LOCAL_STORED_MAX_SIZE
2553 			   && dict_index_is_clust(new_index)) {
2554 
2555 			/* In the worst case, we have a locally stored
2556 			column of BTR_EXTERN_LOCAL_STORED_MAX_SIZE bytes.
2557 			The length can be stored in one byte.  If the
2558 			column were stored externally, the lengths in
2559 			the clustered index page would be
2560 			BTR_EXTERN_FIELD_REF_SIZE and 2. */
2561 			field_max_size = BTR_EXTERN_LOCAL_STORED_MAX_SIZE;
2562 			field_ext_max_size = 1;
2563 		}
2564 
2565 		if (comp) {
2566 			/* Add the extra size for ROW_FORMAT=COMPACT.
2567 			For ROW_FORMAT=REDUNDANT, these bytes were
2568 			added to rec_max_size before this loop. */
2569 			rec_max_size += field_ext_max_size;
2570 		}
2571 add_field_size:
2572 		rec_max_size += field_max_size;
2573 
2574 		/* Check the size limit on leaf pages. */
2575 		if (rec_max_size >= page_rec_max) {
2576 			ib::error_or_warn(strict)
2577 				<< "Cannot add field " << field->name
2578 				<< " in table " << table->name
2579 				<< " because after adding it, the row size is "
2580 				<< rec_max_size
2581 				<< " which is greater than maximum allowed"
2582 				" size (" << page_rec_max
2583 				<< ") for a record on index leaf page.";
2584 
2585 			return(TRUE);
2586 		}
2587 
2588 		/* Check the size limit on non-leaf pages.  Records
2589 		stored in non-leaf B-tree pages consist of the unique
2590 		columns of the record (the key columns of the B-tree)
2591 		and a node pointer field.  When we have processed the
2592 		unique columns, rec_max_size equals the size of the
2593 		node pointer record minus the node pointer column. */
2594 		if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
2595 		    && rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {
2596 
2597 			return(TRUE);
2598 		}
2599 	}
2600 
2601 	return(FALSE);
2602 }
2603 
2604 /** Adds an index to the dictionary cache.
2605 @param[in,out]	table	table on which the index is
2606 @param[in,out]	index	index; NOTE! The index memory
2607 			object is freed in this function!
2608 @param[in]	page_no	root page number of the index
2609 @param[in]	strict	TRUE=refuse to create the index
2610 			if records could be too big to fit in
2611 			an B-tree page
2612 @return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
2613 dberr_t
dict_index_add_to_cache(dict_table_t * table,dict_index_t * index,ulint page_no,ibool strict)2614 dict_index_add_to_cache(
2615 	dict_table_t*	table,
2616 	dict_index_t*	index,
2617 	ulint		page_no,
2618 	ibool		strict)
2619 {
2620 	return(dict_index_add_to_cache_w_vcol(
2621 		table, index, NULL, page_no, strict));
2622 }
2623 
2624 /** Clears the virtual column's index list before index is
2625 being freed.
2626 @param[in]  index   Index being freed */
2627 void
dict_index_remove_from_v_col_list(dict_index_t * index)2628 dict_index_remove_from_v_col_list(dict_index_t* index) {
2629 	/* Index is not completely formed */
2630 	if (!index->cached) {
2631 		return;
2632 	}
2633         if (dict_index_has_virtual(index)) {
2634                 const dict_col_t*       col;
2635                 const dict_v_col_t*     vcol;
2636 
2637                 for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
2638                         col =  dict_index_get_nth_col(index, i);
2639                         if (dict_col_is_virtual(col)) {
2640                                 vcol = reinterpret_cast<const dict_v_col_t*>(
2641                                         col);
2642 				/* This could be NULL, when we do add
2643                                 virtual column, add index together. We do not
2644                                 need to track this virtual column's index */
2645 				if (vcol->v_indexes == NULL) {
2646                                         continue;
2647                                 }
2648 				dict_v_idx_list::iterator       it;
2649 				for (it = vcol->v_indexes->begin();
2650                                      it != vcol->v_indexes->end(); ++it) {
2651                                         dict_v_idx_t    v_index = *it;
2652                                         if (v_index.index == index) {
2653                                                 vcol->v_indexes->erase(it);
2654                                                 break;
2655                                         }
2656 				}
2657 			}
2658 		}
2659 	}
2660 }
2661 
2662 /** Adds an index to the dictionary cache, with possible indexing newly
2663 added column.
2664 @param[in,out]	table	table on which the index is
2665 @param[in,out]	index	index; NOTE! The index memory
2666 			object is freed in this function!
2667 @param[in]	add_v	new virtual column that being added along with
2668 			an add index call
2669 @param[in]	page_no	root page number of the index
2670 @param[in]	strict	TRUE=refuse to create the index
2671 			if records could be too big to fit in
2672 			an B-tree page
2673 @return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
2674 dberr_t
dict_index_add_to_cache_w_vcol(dict_table_t * table,dict_index_t * index,const dict_add_v_col_t * add_v,ulint page_no,ibool strict)2675 dict_index_add_to_cache_w_vcol(
2676 	dict_table_t*		table,
2677 	dict_index_t*		index,
2678 	const dict_add_v_col_t* add_v,
2679 	ulint			page_no,
2680 	ibool			strict)
2681 {
2682 	dict_index_t*	new_index;
2683 	ulint		n_ord;
2684 	ulint		i;
2685 
2686 	ut_ad(index);
2687 	ut_ad(mutex_own(&dict_sys->mutex) || dict_table_is_intrinsic(table));
2688 	ut_ad(index->n_def == index->n_fields);
2689 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
2690 	ut_ad(!dict_index_is_online_ddl(index));
2691 	ut_ad(!dict_index_is_ibuf(index));
2692 
2693 	ut_d(mem_heap_validate(index->heap));
2694 	ut_a(!dict_index_is_clust(index)
2695 	     || UT_LIST_GET_LEN(table->indexes) == 0);
2696 
2697 	if (!dict_index_find_cols(table, index, add_v)) {
2698 
2699 		dict_mem_index_free(index);
2700 		return(DB_CORRUPTION);
2701 	}
2702 
2703 	/* Build the cache internal representation of the index,
2704 	containing also the added system fields */
2705 
2706 	if (index->type == DICT_FTS) {
2707 		new_index = dict_index_build_internal_fts(table, index);
2708 	} else if (dict_index_is_clust(index)) {
2709 		new_index = dict_index_build_internal_clust(table, index);
2710 	} else {
2711 		new_index = dict_index_build_internal_non_clust(table, index);
2712 	}
2713 
2714 	/* Set the n_fields value in new_index to the actual defined
2715 	number of fields in the cache internal representation */
2716 
2717 	new_index->n_fields = new_index->n_def;
2718 	new_index->trx_id = index->trx_id;
2719 	new_index->set_committed(index->is_committed());
2720 	new_index->allow_duplicates = index->allow_duplicates;
2721 	new_index->nulls_equal = index->nulls_equal;
2722 	new_index->disable_ahi = index->disable_ahi;
2723 
2724 	if (dict_index_too_big_for_tree(table, new_index, strict)) {
2725 
2726 		if (strict) {
2727 			dict_mem_index_free(new_index);
2728 			dict_mem_index_free(index);
2729 			return(DB_TOO_BIG_RECORD);
2730 		} else if (current_thd != NULL) {
2731 			/* Avoid the warning to be printed
2732 			during recovery. */
2733 			ib_warn_row_too_big(table);
2734 		}
2735 	}
2736 
2737 	n_ord = new_index->n_uniq;
2738 
2739 	/* Flag the ordering columns and also set column max_prefix */
2740 
2741 	for (i = 0; i < n_ord; i++) {
2742 		const dict_field_t*	field
2743 			= dict_index_get_nth_field(new_index, i);
2744 
2745 		/* Check the column being added in the index for
2746 		the first time and flag the ordering column. */
2747 		if (field->col->ord_part == 0 ) {
2748 			field->col->max_prefix = field->prefix_len;
2749 			field->col->ord_part = 1;
2750 		} else if (field->prefix_len == 0) {
2751 			/* Set the max_prefix for a column to 0 if
2752 			its prefix length is 0 (for this index)
2753 			even if it was a part of any other index
2754 			with some prefix length. */
2755 			field->col->max_prefix = 0;
2756 		} else if (field->col->max_prefix != 0
2757 			   && field->prefix_len
2758 			   > field->col->max_prefix) {
2759 			/* Set the max_prefix value based on the
2760 			prefix_len. */
2761 			field->col->max_prefix = field->prefix_len;
2762 		}
2763 		ut_ad(field->col->ord_part == 1);
2764 	}
2765 
2766 	new_index->stat_n_diff_key_vals =
2767 		static_cast<ib_uint64_t*>(mem_heap_zalloc(
2768 			new_index->heap,
2769 			dict_index_get_n_unique(new_index)
2770 			* sizeof(*new_index->stat_n_diff_key_vals)));
2771 
2772 	new_index->stat_n_sample_sizes =
2773 		static_cast<ib_uint64_t*>(mem_heap_zalloc(
2774 			new_index->heap,
2775 			dict_index_get_n_unique(new_index)
2776 			* sizeof(*new_index->stat_n_sample_sizes)));
2777 
2778 	new_index->stat_n_non_null_key_vals =
2779 		static_cast<ib_uint64_t*>(mem_heap_zalloc(
2780 			new_index->heap,
2781 			dict_index_get_n_unique(new_index)
2782 			* sizeof(*new_index->stat_n_non_null_key_vals)));
2783 
2784 	new_index->stat_index_size = 1;
2785 	new_index->stat_n_leaf_pages = 1;
2786 
2787 	/* Add the new index as the last index for the table */
2788 
2789 	UT_LIST_ADD_LAST(table->indexes, new_index);
2790 	new_index->table = table;
2791 	new_index->table_name = table->name.m_name;
2792 	new_index->search_info = btr_search_info_create(new_index->heap);
2793 
2794 	new_index->page = page_no;
2795 	rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
2796 		       SYNC_INDEX_TREE);
2797 
2798 	/* Intrinsic table are not added to dictionary cache instead are
2799 	cached to session specific thread cache. */
2800 	if (!dict_table_is_intrinsic(table)) {
2801 		dict_sys->size += mem_heap_get_size(new_index->heap);
2802 	}
2803 
2804 	/* Check if key part of the index is unique. */
2805 	if (dict_table_is_intrinsic(table)) {
2806 
2807 		new_index->rec_cache.fixed_len_key = true;
2808 		for (i = 0; i < new_index->n_uniq; i++) {
2809 
2810 			const dict_field_t*	field;
2811 			field = dict_index_get_nth_field(new_index, i);
2812 
2813 			if (!field->fixed_len) {
2814 				new_index->rec_cache.fixed_len_key = false;
2815 				break;
2816 			}
2817 		}
2818 
2819 		new_index->rec_cache.key_has_null_cols = false;
2820 		for (i = 0; i < new_index->n_uniq; i++) {
2821 
2822 			const dict_field_t*	field;
2823 			field = dict_index_get_nth_field(new_index, i);
2824 
2825 			if (!(field->col->prtype & DATA_NOT_NULL)) {
2826 				new_index->rec_cache.key_has_null_cols = true;
2827 				break;
2828 			}
2829 		}
2830 	}
2831 
2832 	dict_mem_index_free(index);
2833 
2834 	return(DB_SUCCESS);
2835 }
2836 
2837 /**********************************************************************//**
2838 Removes an index from the dictionary cache. */
2839 static
2840 void
dict_index_remove_from_cache_low(dict_table_t * table,dict_index_t * index,ibool lru_evict)2841 dict_index_remove_from_cache_low(
2842 /*=============================*/
2843 	dict_table_t*	table,		/*!< in/out: table */
2844 	dict_index_t*	index,		/*!< in, own: index */
2845 	ibool		lru_evict)	/*!< in: TRUE if index being evicted
2846 					to make room in the table LRU list */
2847 {
2848 	lint		size;
2849 	ulint		retries = 0;
2850 	btr_search_t*	info;
2851 
2852 	ut_ad(table && index);
2853 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2854 	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
2855 	ut_ad(mutex_own(&dict_sys->mutex));
2856 
2857 	/* No need to acquire the dict_index_t::lock here because
2858 	there can't be any active operations on this index (or table). */
2859 
2860 	if (index->online_log) {
2861 		ut_ad(index->online_status == ONLINE_INDEX_CREATION);
2862 		row_log_free(index->online_log);
2863 	}
2864 
2865 	/* We always create search info whether or not adaptive
2866 	hash index is enabled or not. */
2867 	info = btr_search_get_info(index);
2868 	ut_ad(info);
2869 
2870 	/* We are not allowed to free the in-memory index struct
2871 	dict_index_t until all entries in the adaptive hash index
2872 	that point to any of the page belonging to his b-tree index
2873 	are dropped. This is so because dropping of these entries
2874 	require access to dict_index_t struct. To avoid such scenario
2875 	We keep a count of number of such pages in the search_info and
2876 	only free the dict_index_t struct when this count drops to
2877 	zero. See also: dict_table_can_be_evicted() */
2878 
2879 	do {
2880 		ulint ref_count = btr_search_info_get_ref_count(info, index);
2881 
2882 		if (ref_count == 0) {
2883 			break;
2884 		}
2885 
2886 		/* Sleep for 10ms before trying again. */
2887 		os_thread_sleep(10000);
2888 		++retries;
2889 
2890 		if (retries % 500 == 0) {
2891 			/* No luck after 5 seconds of wait. */
2892 			ib::error() << "Waited for " << retries / 100
2893 				<< " secs for hash index"
2894 				" ref_count (" << ref_count << ") to drop to 0."
2895 				" index: " << index->name
2896 				<< " table: " << table->name;
2897 		}
2898 
2899 		/* To avoid a hang here we commit suicide if the
2900 		ref_count doesn't drop to zero in 600 seconds. */
2901 		if (retries >= 60000) {
2902 			ut_error;
2903 		}
2904 	} while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
2905 
2906 	rw_lock_free(&index->lock);
2907 
2908 	/* The index is being dropped, remove any compression stats for it. */
2909 	if (!lru_evict && DICT_TF_GET_ZIP_SSIZE(index->table->flags)) {
2910 		mutex_enter(&page_zip_stat_per_index_mutex);
2911 		page_zip_stat_per_index.erase(index->id);
2912 		mutex_exit(&page_zip_stat_per_index_mutex);
2913 	}
2914 
2915 	/* Remove the index from the list of indexes of the table */
2916 	UT_LIST_REMOVE(table->indexes, index);
2917 
2918 	/* Remove the index from affected virtual column index list */
2919 	if (dict_index_has_virtual(index)) {
2920 		const dict_col_t*	col;
2921 		const dict_v_col_t*	vcol;
2922 
2923 		for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
2924 			col =  dict_index_get_nth_col(index, i);
2925 			if (dict_col_is_virtual(col)) {
2926 				vcol = reinterpret_cast<const dict_v_col_t*>(
2927 					col);
2928 
2929 				/* This could be NULL, when we do add virtual
2930 				column, add index together. We do not need to
2931 				track this virtual column's index */
2932 				if (vcol->v_indexes == NULL) {
2933 					continue;
2934 				}
2935 
2936 				dict_v_idx_list::iterator	it;
2937 
2938 				for (it = vcol->v_indexes->begin();
2939 				     it != vcol->v_indexes->end(); ++it) {
2940 					dict_v_idx_t	v_index = *it;
2941 					if (v_index.index == index) {
2942 						vcol->v_indexes->erase(it);
2943 						break;
2944 					}
2945 				}
2946 			}
2947 
2948 		}
2949 	}
2950 
2951 	size = mem_heap_get_size(index->heap);
2952 
2953 	ut_ad(!dict_table_is_intrinsic(table));
2954 	ut_ad(dict_sys->size >= size);
2955 
2956 	dict_sys->size -= size;
2957 
2958 	dict_mem_index_free(index);
2959 }
2960 
2961 /**********************************************************************//**
2962 Removes an index from the dictionary cache. */
2963 void
dict_index_remove_from_cache(dict_table_t * table,dict_index_t * index)2964 dict_index_remove_from_cache(
2965 /*=========================*/
2966 	dict_table_t*	table,	/*!< in/out: table */
2967 	dict_index_t*	index)	/*!< in, own: index */
2968 {
2969 	dict_index_remove_from_cache_low(table, index, FALSE);
2970 }
2971 
2972 /** Tries to find column names for the index and sets the col field of the
2973 index.
2974 @param[in]	table	table
2975 @param[in,out]	index	index
2976 @param[in]	add_v	new virtual columns added along with an add index call
2977 @return TRUE if the column names were found */
2978 static
2979 ibool
dict_index_find_cols(const dict_table_t * table,dict_index_t * index,const dict_add_v_col_t * add_v)2980 dict_index_find_cols(
2981 	const dict_table_t*	table,
2982 	dict_index_t*		index,
2983 	const dict_add_v_col_t*	add_v)
2984 {
2985 	std::vector<ulint, ut_allocator<ulint> >	col_added;
2986 	std::vector<ulint, ut_allocator<ulint> >	v_col_added;
2987 
2988 	ut_ad(table != NULL && index != NULL);
2989 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2990 	ut_ad(mutex_own(&dict_sys->mutex) || dict_table_is_intrinsic(table));
2991 
2992 	for (ulint i = 0; i < index->n_fields; i++) {
2993 		ulint		j;
2994 		dict_field_t*	field = dict_index_get_nth_field(index, i);
2995 
2996 		for (j = 0; j < table->n_cols; j++) {
2997 			if (!strcmp(dict_table_get_col_name(table, j),
2998 				    field->name)) {
2999 
3000 				/* Check if same column is being assigned again
3001 				which suggest that column has duplicate name. */
3002 				bool exists =
3003 					std::find(col_added.begin(),
3004 						  col_added.end(), j)
3005 					!= col_added.end();
3006 
3007 				if (exists) {
3008 					/* Duplicate column found. */
3009 					goto dup_err;
3010 				}
3011 
3012 				field->col = dict_table_get_nth_col(table, j);
3013 
3014 				col_added.push_back(j);
3015 
3016 				goto found;
3017 			}
3018 		}
3019 
3020 		/* Let's check if it is a virtual column */
3021 		for (j = 0; j < table->n_v_cols; j++) {
3022 			if (!strcmp(dict_table_get_v_col_name(table, j),
3023 				    field->name)) {
3024 
3025 				/* Check if same column is being assigned again
3026 				which suggest that column has duplicate name. */
3027 				bool exists =
3028 					std::find(v_col_added.begin(),
3029 						  v_col_added.end(), j)
3030 					!= v_col_added.end();
3031 
3032 				if (exists) {
3033 					/* Duplicate column found. */
3034 					break;
3035 				}
3036 
3037 				field->col = reinterpret_cast<dict_col_t*>(
3038 					dict_table_get_nth_v_col(table, j));
3039 
3040 				v_col_added.push_back(j);
3041 
3042 				goto found;
3043 			}
3044 		}
3045 
3046 		if (add_v) {
3047 			for (j = 0; j < add_v->n_v_col; j++) {
3048 				if (!strcmp(add_v->v_col_name[j],
3049 					    field->name)) {
3050 					field->col = const_cast<dict_col_t*>(
3051 						&add_v->v_col[j].m_col);
3052 					goto found;
3053 				}
3054 			}
3055 		}
3056 
3057 dup_err:
3058 #ifdef UNIV_DEBUG
3059 		/* It is an error not to find a matching column. */
3060 		ib::error() << "No matching column for " << field->name
3061 			<< " in index " << index->name
3062 			<< " of table " << table->name;
3063 #endif /* UNIV_DEBUG */
3064 		return(FALSE);
3065 
3066 found:
3067 		;
3068 	}
3069 
3070 	return(TRUE);
3071 }
3072 #endif /* !UNIV_HOTBACKUP */
3073 
3074 /*******************************************************************//**
3075 Adds a column to index. */
3076 void
dict_index_add_col(dict_index_t * index,const dict_table_t * table,dict_col_t * col,ulint prefix_len)3077 dict_index_add_col(
3078 /*===============*/
3079 	dict_index_t*		index,		/*!< in/out: index */
3080 	const dict_table_t*	table,		/*!< in: table */
3081 	dict_col_t*		col,		/*!< in: column */
3082 	ulint			prefix_len)	/*!< in: column prefix length */
3083 {
3084 	dict_field_t*	field;
3085 	const char*	col_name;
3086 
3087 	if (dict_col_is_virtual(col)) {
3088 		dict_v_col_t*	v_col = reinterpret_cast<dict_v_col_t*>(col);
3089 
3090 		/* When v_col->v_indexes==NULL,
3091 		ha_innobase::commit_inplace_alter_table(commit=true)
3092 		will evict and reload the table definition, and
3093 		v_col->v_indexes will not be NULL for the new table. */
3094 		if (v_col->v_indexes != NULL) {
3095 			/* Register the index with the virtual column index
3096 			list */
3097 			struct dict_v_idx_t	new_idx
3098 				 = {index, index->n_def};
3099 
3100 			v_col->v_indexes->push_back(new_idx);
3101 
3102 		}
3103 
3104 		col_name = dict_table_get_v_col_name_mysql(
3105 			table, dict_col_get_no(col));
3106 	} else {
3107 		col_name = dict_table_get_col_name(table, dict_col_get_no(col));
3108 	}
3109 
3110 	dict_mem_index_add_field(index, col_name, prefix_len);
3111 
3112 	field = dict_index_get_nth_field(index, index->n_def - 1);
3113 
3114 	field->col = col;
3115 	/* DATA_POINT is a special type, whose fixed_len should be:
3116 	1) DATA_MBR_LEN, when it's indexed in R-TREE. In this case,
3117 	it must be the first col to be added.
3118 	2) DATA_POINT_LEN(be equal to fixed size of column), when it's
3119 	indexed in B-TREE,
3120 	3) DATA_POINT_LEN, if a POINT col is the PRIMARY KEY, and we are
3121 	adding the PK col to other B-TREE/R-TREE. */
3122 	/* TODO: We suppose the dimension is 2 now. */
3123 	if (dict_index_is_spatial(index) && DATA_POINT_MTYPE(col->mtype)
3124 	    && index->n_def == 1) {
3125 		field->fixed_len = DATA_MBR_LEN;
3126 	} else {
3127 		field->fixed_len = static_cast<unsigned int>(
3128 					dict_col_get_fixed_size(
3129 					col, dict_table_is_comp(table)));
3130 	}
3131 
3132 	if (prefix_len && field->fixed_len > prefix_len) {
3133 		field->fixed_len = (unsigned int) prefix_len;
3134 	}
3135 
3136 	/* Long fixed-length fields that need external storage are treated as
3137 	variable-length fields, so that the extern flag can be embedded in
3138 	the length word. */
3139 
3140 	if (field->fixed_len > DICT_MAX_FIXED_COL_LEN) {
3141 		field->fixed_len = 0;
3142 	}
3143 #if DICT_MAX_FIXED_COL_LEN != 768
3144 	/* The comparison limit above must be constant.  If it were
3145 	changed, the disk format of some fixed-length columns would
3146 	change, which would be a disaster. */
3147 # error "DICT_MAX_FIXED_COL_LEN != 768"
3148 #endif
3149 
3150 	if (!(col->prtype & DATA_NOT_NULL)) {
3151 		index->n_nullable++;
3152 	}
3153 }
3154 
3155 #ifndef UNIV_HOTBACKUP
3156 /*******************************************************************//**
3157 Copies fields contained in index2 to index1. */
3158 static
3159 void
dict_index_copy(dict_index_t * index1,dict_index_t * index2,const dict_table_t * table,ulint start,ulint end)3160 dict_index_copy(
3161 /*============*/
3162 	dict_index_t*		index1,	/*!< in: index to copy to */
3163 	dict_index_t*		index2,	/*!< in: index to copy from */
3164 	const dict_table_t*	table,	/*!< in: table */
3165 	ulint			start,	/*!< in: first position to copy */
3166 	ulint			end)	/*!< in: last position to copy */
3167 {
3168 	dict_field_t*	field;
3169 	ulint		i;
3170 
3171 	/* Copy fields contained in index2 */
3172 
3173 	for (i = start; i < end; i++) {
3174 
3175 		field = dict_index_get_nth_field(index2, i);
3176 
3177 		dict_index_add_col(index1, table, field->col,
3178 				   field->prefix_len);
3179 	}
3180 }
3181 
3182 /*******************************************************************//**
3183 Copies types of fields contained in index to tuple. */
3184 void
dict_index_copy_types(dtuple_t * tuple,const dict_index_t * index,ulint n_fields)3185 dict_index_copy_types(
3186 /*==================*/
3187 	dtuple_t*		tuple,		/*!< in/out: data tuple */
3188 	const dict_index_t*	index,		/*!< in: index */
3189 	ulint			n_fields)	/*!< in: number of
3190 						field types to copy */
3191 {
3192 	ulint		i;
3193 
3194 	if (dict_index_is_ibuf(index)) {
3195 		dtuple_set_types_binary(tuple, n_fields);
3196 
3197 		return;
3198 	}
3199 
3200 	for (i = 0; i < n_fields; i++) {
3201 		const dict_field_t*	ifield;
3202 		dtype_t*		dfield_type;
3203 
3204 		ifield = dict_index_get_nth_field(index, i);
3205 		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
3206 		dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
3207 		if (dict_index_is_spatial(index)
3208 		    && DATA_GEOMETRY_MTYPE(dfield_type->mtype)) {
3209 			dfield_type->prtype |= DATA_GIS_MBR;
3210 		}
3211 	}
3212 }
3213 
3214 /** Copies types of virtual columns contained in table to tuple and sets all
3215 fields of the tuple to the SQL NULL value.  This function should
3216 be called right after dtuple_create().
3217 @param[in,out]	tuple	data tuple
3218 @param[in]	table	table
3219 */
3220 void
dict_table_copy_v_types(dtuple_t * tuple,const dict_table_t * table)3221 dict_table_copy_v_types(
3222 	dtuple_t*		tuple,
3223 	const dict_table_t*	table)
3224 {
3225 	/* tuple could have more virtual columns than existing table,
3226 	if we are calling this for creating index along with adding
3227 	virtual columns */
3228 	ulint	n_fields = ut_min(dtuple_get_n_v_fields(tuple),
3229 				  static_cast<ulint>(table->n_v_def));
3230 
3231 	for (ulint i = 0; i < n_fields; i++) {
3232 
3233 		dfield_t*	dfield	= dtuple_get_nth_v_field(tuple, i);
3234 		dtype_t*	dtype	= dfield_get_type(dfield);
3235 
3236 		dfield_set_null(dfield);
3237 		dict_col_copy_type(
3238 			&(dict_table_get_nth_v_col(table, i)->m_col),
3239 			dtype);
3240 	}
3241 }
3242 /*******************************************************************//**
3243 Copies types of columns contained in table to tuple and sets all
3244 fields of the tuple to the SQL NULL value.  This function should
3245 be called right after dtuple_create(). */
3246 void
dict_table_copy_types(dtuple_t * tuple,const dict_table_t * table)3247 dict_table_copy_types(
3248 /*==================*/
3249 	dtuple_t*		tuple,	/*!< in/out: data tuple */
3250 	const dict_table_t*	table)	/*!< in: table */
3251 {
3252 	ulint		i;
3253 
3254 	for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
3255 
3256 		dfield_t*	dfield	= dtuple_get_nth_field(tuple, i);
3257 		dtype_t*	dtype	= dfield_get_type(dfield);
3258 
3259 		dfield_set_null(dfield);
3260 		dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
3261 	}
3262 
3263 	dict_table_copy_v_types(tuple, table);
3264 }
3265 
3266 /********************************************************************
3267 Wait until all the background threads of the given table have exited, i.e.,
3268 bg_threads == 0. Note: bg_threads_mutex must be reserved when
3269 calling this. */
3270 void
dict_table_wait_for_bg_threads_to_exit(dict_table_t * table,ulint delay)3271 dict_table_wait_for_bg_threads_to_exit(
3272 /*===================================*/
3273 	dict_table_t*	table,	/*< in: table */
3274 	ulint		delay)	/*< in: time in microseconds to wait between
3275 				checks of bg_threads. */
3276 {
3277 	fts_t*		fts = table->fts;
3278 
3279 	ut_ad(mutex_own(&fts->bg_threads_mutex));
3280 
3281 	while (fts->bg_threads > 0) {
3282 		mutex_exit(&fts->bg_threads_mutex);
3283 
3284 		os_thread_sleep(delay);
3285 
3286 		mutex_enter(&fts->bg_threads_mutex);
3287 	}
3288 }
3289 
3290 /*******************************************************************//**
3291 Builds the internal dictionary cache representation for a clustered
3292 index, containing also system fields not defined by the user.
3293 @return own: the internal representation of the clustered index */
3294 static
3295 dict_index_t*
dict_index_build_internal_clust(const dict_table_t * table,dict_index_t * index)3296 dict_index_build_internal_clust(
3297 /*============================*/
3298 	const dict_table_t*	table,	/*!< in: table */
3299 	dict_index_t*		index)	/*!< in: user representation of
3300 					a clustered index */
3301 {
3302 	dict_index_t*	new_index;
3303 	dict_field_t*	field;
3304 	ulint		trx_id_pos;
3305 	ulint		i;
3306 	ibool*		indexed;
3307 
3308 	ut_ad(table && index);
3309 	ut_ad(dict_index_is_clust(index));
3310 	ut_ad(!dict_index_is_ibuf(index));
3311 
3312 	ut_ad(mutex_own(&dict_sys->mutex) || dict_table_is_intrinsic(table));
3313 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
3314 
3315 	/* Create a new index object with certainly enough fields */
3316 	new_index = dict_mem_index_create(table->name.m_name,
3317 					  index->name, table->space,
3318 					  index->type,
3319 					  index->n_fields + table->n_cols);
3320 
3321 	/* Copy other relevant data from the old index struct to the new
3322 	struct: it inherits the values */
3323 
3324 	new_index->n_user_defined_cols = index->n_fields;
3325 
3326 	new_index->id = index->id;
3327 
3328 	/* Copy the fields of index */
3329 	dict_index_copy(new_index, index, table, 0, index->n_fields);
3330 
3331 	if (dict_index_is_unique(index)) {
3332 		/* Only the fields defined so far are needed to identify
3333 		the index entry uniquely */
3334 
3335 		new_index->n_uniq = new_index->n_def;
3336 	} else {
3337 		/* Also the row id is needed to identify the entry */
3338 		new_index->n_uniq = 1 + new_index->n_def;
3339 	}
3340 
3341 	new_index->trx_id_offset = 0;
3342 
3343 	/* Add system columns, trx id first */
3344 
3345 	trx_id_pos = new_index->n_def;
3346 
3347 #if DATA_ROW_ID != 0
3348 # error "DATA_ROW_ID != 0"
3349 #endif
3350 #if DATA_TRX_ID != 1
3351 # error "DATA_TRX_ID != 1"
3352 #endif
3353 #if DATA_ROLL_PTR != 2
3354 # error "DATA_ROLL_PTR != 2"
3355 #endif
3356 
3357 	if (!dict_index_is_unique(index)) {
3358 		dict_index_add_col(new_index, table,
3359 				   dict_table_get_sys_col(
3360 					   table, DATA_ROW_ID),
3361 				   0);
3362 		trx_id_pos++;
3363 	}
3364 
3365 	dict_index_add_col(
3366 		new_index, table,
3367 		dict_table_get_sys_col(table, DATA_TRX_ID), 0);
3368 
3369 
3370 	for (i = 0; i < trx_id_pos; i++) {
3371 
3372 		ulint	fixed_size = dict_col_get_fixed_size(
3373 			dict_index_get_nth_col(new_index, i),
3374 			dict_table_is_comp(table));
3375 
3376 		if (fixed_size == 0) {
3377 			new_index->trx_id_offset = 0;
3378 
3379 			break;
3380 		}
3381 
3382 		dict_field_t* field = dict_index_get_nth_field(
3383 			new_index, i);
3384 		if (field->prefix_len > 0) {
3385 			new_index->trx_id_offset = 0;
3386 
3387 			break;
3388 		}
3389 
3390 		/* Add fixed_size to new_index->trx_id_offset.
3391 		Because the latter is a bit-field, an overflow
3392 		can theoretically occur. Check for it. */
3393 		fixed_size += new_index->trx_id_offset;
3394 
3395 		new_index->trx_id_offset = fixed_size;
3396 
3397 		if (new_index->trx_id_offset != fixed_size) {
3398 			/* Overflow. Pretend that this is a
3399 			variable-length PRIMARY KEY. */
3400 			ut_ad(0);
3401 			new_index->trx_id_offset = 0;
3402 			break;
3403 		}
3404 	}
3405 
3406 	/* UNDO logging is turned-off for intrinsic table and so
3407 	DATA_ROLL_PTR system columns are not added as default system
3408 	columns to such tables. */
3409 	if (!dict_table_is_intrinsic(table)) {
3410 
3411 		dict_index_add_col(
3412 			new_index, table,
3413 			dict_table_get_sys_col(table, DATA_ROLL_PTR),
3414 			0);
3415 	}
3416 
3417 	/* Remember the table columns already contained in new_index */
3418 	indexed = static_cast<ibool*>(
3419 		ut_zalloc_nokey(table->n_cols * sizeof *indexed));
3420 
3421 	/* Mark the table columns already contained in new_index */
3422 	for (i = 0; i < new_index->n_def; i++) {
3423 
3424 		field = dict_index_get_nth_field(new_index, i);
3425 
3426 		/* If there is only a prefix of the column in the index
3427 		field, do not mark the column as contained in the index */
3428 
3429 		if (field->prefix_len == 0) {
3430 
3431 			indexed[field->col->ind] = TRUE;
3432 		}
3433 	}
3434 
3435 	/* Add to new_index non-system columns of table not yet included
3436 	there */
3437 	ulint n_sys_cols = dict_table_get_n_sys_cols(table);
3438 	for (i = 0; i + n_sys_cols < (ulint) table->n_cols; i++) {
3439 
3440 		dict_col_t*	col = dict_table_get_nth_col(table, i);
3441 		ut_ad(col->mtype != DATA_SYS);
3442 
3443 		if (!indexed[col->ind]) {
3444 			dict_index_add_col(new_index, table, col, 0);
3445 		}
3446 	}
3447 
3448 	ut_free(indexed);
3449 
3450 	ut_ad(UT_LIST_GET_LEN(table->indexes) == 0);
3451 
3452 	new_index->cached = TRUE;
3453 
3454 	return(new_index);
3455 }
3456 
3457 /*******************************************************************//**
3458 Builds the internal dictionary cache representation for a non-clustered
3459 index, containing also system fields not defined by the user.
3460 @return own: the internal representation of the non-clustered index */
3461 static
3462 dict_index_t*
dict_index_build_internal_non_clust(const dict_table_t * table,dict_index_t * index)3463 dict_index_build_internal_non_clust(
3464 /*================================*/
3465 	const dict_table_t*	table,	/*!< in: table */
3466 	dict_index_t*		index)	/*!< in: user representation of
3467 					a non-clustered index */
3468 {
3469 	dict_field_t*	field;
3470 	dict_index_t*	new_index;
3471 	dict_index_t*	clust_index;
3472 	ulint		i;
3473 	ibool*		indexed;
3474 
3475 	ut_ad(table && index);
3476 	ut_ad(!dict_index_is_clust(index));
3477 	ut_ad(!dict_index_is_ibuf(index));
3478 	ut_ad(mutex_own(&dict_sys->mutex) || dict_table_is_intrinsic(table));
3479 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
3480 
3481 	/* The clustered index should be the first in the list of indexes */
3482 	clust_index = UT_LIST_GET_FIRST(table->indexes);
3483 
3484 	ut_ad(clust_index);
3485 	ut_ad(dict_index_is_clust(clust_index));
3486 	ut_ad(!dict_index_is_ibuf(clust_index));
3487 
3488 	/* Create a new index */
3489 	new_index = dict_mem_index_create(
3490 		table->name.m_name, index->name, index->space, index->type,
3491 		index->n_fields + 1 + clust_index->n_uniq);
3492 
3493 	/* Copy other relevant data from the old index
3494 	struct to the new struct: it inherits the values */
3495 
3496 	new_index->n_user_defined_cols = index->n_fields;
3497 
3498 	new_index->id = index->id;
3499 
3500 	/* Copy fields from index to new_index */
3501 	dict_index_copy(new_index, index, table, 0, index->n_fields);
3502 
3503 	/* Remember the table columns already contained in new_index */
3504 	indexed = static_cast<ibool*>(
3505 		ut_zalloc_nokey(table->n_cols * sizeof *indexed));
3506 
3507 	/* Mark the table columns already contained in new_index */
3508 	for (i = 0; i < new_index->n_def; i++) {
3509 
3510 		field = dict_index_get_nth_field(new_index, i);
3511 
3512 		if (dict_col_is_virtual(field->col)) {
3513 			continue;
3514 		}
3515 
3516 		/* If there is only a prefix of the column in the index
3517 		field, do not mark the column as contained in the index */
3518 
3519 		if (field->prefix_len == 0) {
3520 
3521 			indexed[field->col->ind] = TRUE;
3522 		}
3523 	}
3524 
3525 	/* Add to new_index the columns necessary to determine the clustered
3526 	index entry uniquely */
3527 
3528 	for (i = 0; i < clust_index->n_uniq; i++) {
3529 
3530 		field = dict_index_get_nth_field(clust_index, i);
3531 
3532 		if (!indexed[field->col->ind]) {
3533 			dict_index_add_col(new_index, table, field->col,
3534 					   field->prefix_len);
3535 		} else if (dict_index_is_spatial(index)) {
3536 			/*For spatial index, we still need to add the
3537 			field to index. */
3538 			dict_index_add_col(new_index, table, field->col,
3539 					   field->prefix_len);
3540 		}
3541 	}
3542 
3543 	ut_free(indexed);
3544 
3545 	if (dict_index_is_unique(index)) {
3546 		new_index->n_uniq = index->n_fields;
3547 	} else {
3548 		new_index->n_uniq = new_index->n_def;
3549 	}
3550 
3551 	/* Set the n_fields value in new_index to the actual defined
3552 	number of fields */
3553 
3554 	new_index->n_fields = new_index->n_def;
3555 
3556 	new_index->cached = TRUE;
3557 
3558 	return(new_index);
3559 }
3560 
3561 /***********************************************************************
3562 Builds the internal dictionary cache representation for an FTS index.
3563 @return own: the internal representation of the FTS index */
3564 static
3565 dict_index_t*
dict_index_build_internal_fts(dict_table_t * table,dict_index_t * index)3566 dict_index_build_internal_fts(
3567 /*==========================*/
3568 	dict_table_t*	table,	/*!< in: table */
3569 	dict_index_t*	index)	/*!< in: user representation of an FTS index */
3570 {
3571 	dict_index_t*	new_index;
3572 
3573 	ut_ad(table && index);
3574 	ut_ad(index->type == DICT_FTS);
3575 	ut_ad(mutex_own(&dict_sys->mutex));
3576 	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
3577 
3578 	/* Create a new index */
3579 	new_index = dict_mem_index_create(
3580 		table->name.m_name, index->name, index->space, index->type,
3581 		index->n_fields);
3582 
3583 	/* Copy other relevant data from the old index struct to the new
3584 	struct: it inherits the values */
3585 
3586 	new_index->n_user_defined_cols = index->n_fields;
3587 
3588 	new_index->id = index->id;
3589 
3590 	/* Copy fields from index to new_index */
3591 	dict_index_copy(new_index, index, table, 0, index->n_fields);
3592 
3593 	new_index->n_uniq = 0;
3594 	new_index->cached = TRUE;
3595 
3596 	if (table->fts->cache == NULL) {
3597 		table->fts->cache = fts_cache_create(table);
3598 	}
3599 
3600 	rw_lock_x_lock(&table->fts->cache->init_lock);
3601 	/* Notify the FTS cache about this index. */
3602 	fts_cache_index_cache_create(table, new_index);
3603 	rw_lock_x_unlock(&table->fts->cache->init_lock);
3604 
3605 	return(new_index);
3606 }
3607 /*====================== FOREIGN KEY PROCESSING ========================*/
3608 
3609 /*********************************************************************//**
3610 Checks if a table is referenced by foreign keys.
3611 @return TRUE if table is referenced by a foreign key */
3612 ibool
dict_table_is_referenced_by_foreign_key(const dict_table_t * table)3613 dict_table_is_referenced_by_foreign_key(
3614 /*====================================*/
3615 	const dict_table_t*	table)	/*!< in: InnoDB table */
3616 {
3617 	return(!table->referenced_set.empty());
3618 }
3619 
3620 /**********************************************************************//**
3621 Removes a foreign constraint struct from the dictionary cache. */
3622 void
dict_foreign_remove_from_cache(dict_foreign_t * foreign)3623 dict_foreign_remove_from_cache(
3624 /*===========================*/
3625 	dict_foreign_t*	foreign)	/*!< in, own: foreign constraint */
3626 {
3627 	ut_ad(mutex_own(&dict_sys->mutex));
3628 	ut_a(foreign);
3629 
3630 	if (foreign->referenced_table != NULL) {
3631 		foreign->referenced_table->referenced_set.erase(foreign);
3632 	}
3633 
3634 	if (foreign->foreign_table != NULL) {
3635 		foreign->foreign_table->foreign_set.erase(foreign);
3636 	}
3637 
3638 	dict_foreign_free(foreign);
3639 }
3640 
3641 /**********************************************************************//**
3642 Looks for the foreign constraint from the foreign and referenced lists
3643 of a table.
3644 @return foreign constraint */
3645 static
3646 dict_foreign_t*
dict_foreign_find(dict_table_t * table,dict_foreign_t * foreign)3647 dict_foreign_find(
3648 /*==============*/
3649 	dict_table_t*	table,		/*!< in: table object */
3650 	dict_foreign_t*	foreign)	/*!< in: foreign constraint */
3651 {
3652 	ut_ad(mutex_own(&dict_sys->mutex));
3653 
3654 	ut_ad(dict_foreign_set_validate(table->foreign_set));
3655 	ut_ad(dict_foreign_set_validate(table->referenced_set));
3656 
3657 	dict_foreign_set::iterator it = table->foreign_set.find(foreign);
3658 
3659 	if (it != table->foreign_set.end()) {
3660 		return(*it);
3661 	}
3662 
3663 	it = table->referenced_set.find(foreign);
3664 
3665 	if (it != table->referenced_set.end()) {
3666 		return(*it);
3667 	}
3668 
3669 	return(NULL);
3670 }
3671 
3672 
3673 /*********************************************************************//**
3674 Tries to find an index whose first fields are the columns in the array,
3675 in the same order and is not marked for deletion and is not the same
3676 as types_idx.
3677 @return matching index, NULL if not found */
3678 dict_index_t*
dict_foreign_find_index(const dict_table_t * table,const char ** col_names,const char ** columns,ulint n_cols,const dict_index_t * types_idx,bool check_charsets,ulint check_null)3679 dict_foreign_find_index(
3680 /*====================*/
3681 	const dict_table_t*	table,	/*!< in: table */
3682 	const char**		col_names,
3683 					/*!< in: column names, or NULL
3684 					to use table->col_names */
3685 	const char**		columns,/*!< in: array of column names */
3686 	ulint			n_cols,	/*!< in: number of columns */
3687 	const dict_index_t*	types_idx,
3688 					/*!< in: NULL or an index
3689 					whose types the column types
3690 					must match */
3691 	bool			check_charsets,
3692 					/*!< in: whether to check
3693 					charsets.  only has an effect
3694 					if types_idx != NULL */
3695 	ulint			check_null)
3696 					/*!< in: nonzero if none of
3697 					the columns must be declared
3698 					NOT NULL */
3699 {
3700 	dict_index_t*	index;
3701 
3702 	ut_ad(mutex_own(&dict_sys->mutex));
3703 
3704 	index = dict_table_get_first_index(table);
3705 
3706 	while (index != NULL) {
3707 		if (types_idx != index
3708 		    && !(index->type & DICT_FTS)
3709 		    && !dict_index_is_spatial(index)
3710 		    && !index->to_be_dropped
3711 		    && (!(index->uncommitted
3712 			&& ((index->online_status
3713 			     ==  ONLINE_INDEX_ABORTED_DROPPED)
3714 			     || (index->online_status
3715 				== ONLINE_INDEX_ABORTED))))
3716 		    && dict_foreign_qualify_index(
3717 			    table, col_names, columns, n_cols,
3718 			    index, types_idx,
3719 			    check_charsets, check_null)) {
3720 			return(index);
3721 		}
3722 
3723 		index = dict_table_get_next_index(index);
3724 	}
3725 
3726 	return(NULL);
3727 }
3728 
3729 /**********************************************************************//**
3730 Report an error in a foreign key definition. */
3731 static
3732 void
dict_foreign_error_report_low(FILE * file,const char * name)3733 dict_foreign_error_report_low(
3734 /*==========================*/
3735 	FILE*		file,	/*!< in: output stream */
3736 	const char*	name)	/*!< in: table name */
3737 {
3738 	rewind(file);
3739 	ut_print_timestamp(file);
3740 	fprintf(file, " Error in foreign key constraint of table %s:\n",
3741 		name);
3742 }
3743 
3744 /**********************************************************************//**
3745 Report an error in a foreign key definition. */
3746 static
3747 void
dict_foreign_error_report(FILE * file,dict_foreign_t * fk,const char * msg)3748 dict_foreign_error_report(
3749 /*======================*/
3750 	FILE*		file,	/*!< in: output stream */
3751 	dict_foreign_t*	fk,	/*!< in: foreign key constraint */
3752 	const char*	msg)	/*!< in: the error message */
3753 {
3754 	mutex_enter(&dict_foreign_err_mutex);
3755 	dict_foreign_error_report_low(file, fk->foreign_table_name);
3756 	fputs(msg, file);
3757 	fputs(" Constraint:\n", file);
3758 	dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
3759 	putc('\n', file);
3760 	if (fk->foreign_index) {
3761 		fprintf(file, "The index in the foreign key in table is"
3762 			" %s\n%s\n", fk->foreign_index->name(),
3763 			FOREIGN_KEY_CONSTRAINTS_MSG);
3764 	}
3765 	mutex_exit(&dict_foreign_err_mutex);
3766 }
3767 
3768 /**********************************************************************//**
3769 Adds a foreign key constraint object to the dictionary cache. May free
3770 the object if there already is an object with the same identifier in.
3771 At least one of the foreign table and the referenced table must already
3772 be in the dictionary cache!
3773 @return DB_SUCCESS or error code */
3774 dberr_t
dict_foreign_add_to_cache(dict_foreign_t * foreign,const char ** col_names,bool check_charsets,dict_err_ignore_t ignore_err)3775 dict_foreign_add_to_cache(
3776 /*======================*/
3777 	dict_foreign_t*		foreign,
3778 				/*!< in, own: foreign key constraint */
3779 	const char**		col_names,
3780 				/*!< in: column names, or NULL to use
3781 				foreign->foreign_table->col_names */
3782 	bool			check_charsets,
3783 				/*!< in: whether to check charset
3784 				compatibility */
3785 	dict_err_ignore_t	ignore_err)
3786 				/*!< in: error to be ignored */
3787 {
3788 	dict_table_t*	for_table;
3789 	dict_table_t*	ref_table;
3790 	dict_foreign_t*	for_in_cache		= NULL;
3791 	dict_index_t*	index;
3792 	ibool		added_to_referenced_list= FALSE;
3793 	FILE*		ef			= dict_foreign_err_file;
3794 
3795 	DBUG_ENTER("dict_foreign_add_to_cache");
3796 	DBUG_PRINT("dict_foreign_add_to_cache", ("id: %s", foreign->id));
3797 
3798 	ut_ad(mutex_own(&dict_sys->mutex));
3799 
3800 	for_table = dict_table_check_if_in_cache_low(
3801 		foreign->foreign_table_name_lookup);
3802 
3803 	ref_table = dict_table_check_if_in_cache_low(
3804 		foreign->referenced_table_name_lookup);
3805 	ut_a(for_table || ref_table);
3806 
3807 	if (for_table) {
3808 		for_in_cache = dict_foreign_find(for_table, foreign);
3809 	}
3810 
3811 	if (!for_in_cache && ref_table) {
3812 		for_in_cache = dict_foreign_find(ref_table, foreign);
3813 	}
3814 
3815 	if (for_in_cache) {
3816 		/* Free the foreign object */
3817 		dict_foreign_free(foreign);
3818 	} else {
3819 		for_in_cache = foreign;
3820 
3821 	}
3822 
3823 
3824 	if (ref_table && !for_in_cache->referenced_table) {
3825 		index = dict_foreign_find_index(
3826 			ref_table, NULL,
3827 			for_in_cache->referenced_col_names,
3828 			for_in_cache->n_fields, for_in_cache->foreign_index,
3829 			check_charsets, false);
3830 
3831 		if (index == NULL
3832 		    && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
3833 			dict_foreign_error_report(
3834 				ef, for_in_cache,
3835 				"there is no index in referenced table"
3836 				" which would contain\n"
3837 				"the columns as the first columns,"
3838 				" or the data types in the\n"
3839 				"referenced table do not match"
3840 				" the ones in table.");
3841 
3842                        if (for_in_cache == foreign) {
3843                                 mem_heap_free(foreign->heap);
3844                         }
3845 
3846 
3847 			DBUG_RETURN(DB_CANNOT_ADD_CONSTRAINT);
3848 		}
3849 
3850 		for_in_cache->referenced_table = ref_table;
3851 		for_in_cache->referenced_index = index;
3852 
3853 		std::pair<dict_foreign_set::iterator, bool>	ret
3854 			= ref_table->referenced_set.insert(for_in_cache);
3855 
3856 		ut_a(ret.second);	/* second is true if the insertion
3857 					took place */
3858 		added_to_referenced_list = TRUE;
3859 	}
3860 
3861 	if (for_table && !for_in_cache->foreign_table) {
3862 		index = dict_foreign_find_index(
3863 			for_table, col_names,
3864 			for_in_cache->foreign_col_names,
3865 			for_in_cache->n_fields,
3866 			for_in_cache->referenced_index, check_charsets,
3867 			for_in_cache->type
3868 			& (DICT_FOREIGN_ON_DELETE_SET_NULL
3869 			   | DICT_FOREIGN_ON_UPDATE_SET_NULL));
3870 
3871 		if (index == NULL
3872 		    && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
3873 			dict_foreign_error_report(
3874 				ef, for_in_cache,
3875 				"there is no index in the table"
3876 				" which would contain\n"
3877 				"the columns as the first columns,"
3878 				" or the data types in the\n"
3879 				"table do not match"
3880 				" the ones in the referenced table\n"
3881 				"or one of the ON ... SET NULL columns"
3882 				" is declared NOT NULL.");
3883 
3884 			if (for_in_cache == foreign) {
3885 				if (added_to_referenced_list) {
3886 					const dict_foreign_set::size_type
3887 						n = ref_table->referenced_set
3888 						  .erase(for_in_cache);
3889 
3890 					ut_a(n == 1);	/* the number of
3891 							elements removed must
3892 							be one */
3893 				}
3894 				mem_heap_free(foreign->heap);
3895 			}
3896 
3897 			DBUG_RETURN(DB_CANNOT_ADD_CONSTRAINT);
3898 		}
3899 
3900 		for_in_cache->foreign_table = for_table;
3901 		for_in_cache->foreign_index = index;
3902 
3903 		std::pair<dict_foreign_set::iterator, bool>	ret
3904 			= for_table->foreign_set.insert(for_in_cache);
3905 
3906 		ut_a(ret.second);	/* second is true if the insertion
3907 					took place */
3908 	}
3909 
3910 	/* We need to move the table to the non-LRU end of the table LRU
3911 	list. Otherwise it will be evicted from the cache. */
3912 
3913 	if (ref_table != NULL) {
3914 		dict_table_prevent_eviction(ref_table);
3915 	}
3916 
3917 	if (for_table != NULL) {
3918 		dict_table_prevent_eviction(for_table);
3919 	}
3920 
3921 	ut_ad(dict_lru_validate());
3922 	DBUG_RETURN(DB_SUCCESS);
3923 }
3924 
3925 /*********************************************************************//**
3926 Scans from pointer onwards. Stops if is at the start of a copy of
3927 'string' where characters are compared without case sensitivity, and
3928 only outside `` or "" quotes. Stops also at NUL.
3929 @return scanned up to this */
3930 static
3931 const char*
dict_scan_to(const char * ptr,const char * string)3932 dict_scan_to(
3933 /*=========*/
3934 	const char*	ptr,	/*!< in: scan from */
3935 	const char*	string)	/*!< in: look for this */
3936 {
3937 	char	quote	= '\0';
3938 	bool	escape	= false;
3939 
3940 	for (; *ptr; ptr++) {
3941 		if (*ptr == quote) {
3942 			/* Closing quote character: do not look for
3943 			starting quote or the keyword. */
3944 
3945 			/* If the quote character is escaped by a
3946 			backslash, ignore it. */
3947 			if (escape) {
3948 				escape = false;
3949 			} else {
3950 				quote = '\0';
3951 			}
3952 		} else if (quote) {
3953 			/* Within quotes: do nothing. */
3954 			if (escape) {
3955 				escape = false;
3956 			} else if (*ptr == '\\') {
3957 				escape = true;
3958 			}
3959 		} else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
3960 			/* Starting quote: remember the quote character. */
3961 			quote = *ptr;
3962 		} else {
3963 			/* Outside quotes: look for the keyword. */
3964 			ulint	i;
3965 			for (i = 0; string[i]; i++) {
3966 				if (toupper((int)(unsigned char)(ptr[i]))
3967 				    != toupper((int)(unsigned char)
3968 					       (string[i]))) {
3969 					goto nomatch;
3970 				}
3971 			}
3972 			break;
3973 nomatch:
3974 			;
3975 		}
3976 	}
3977 
3978 	return(ptr);
3979 }
3980 
3981 /*********************************************************************//**
3982 Accepts a specified string. Comparisons are case-insensitive.
3983 @return if string was accepted, the pointer is moved after that, else
3984 ptr is returned */
3985 static
3986 const char*
dict_accept(CHARSET_INFO * cs,const char * ptr,const char * string,ibool * success)3987 dict_accept(
3988 /*========*/
3989 	CHARSET_INFO*	cs,	/*!< in: the character set of ptr */
3990 	const char*	ptr,	/*!< in: scan from this */
3991 	const char*	string,	/*!< in: accept only this string as the next
3992 				non-whitespace string */
3993 	ibool*		success)/*!< out: TRUE if accepted */
3994 {
3995 	const char*	old_ptr = ptr;
3996 	const char*	old_ptr2;
3997 
3998 	*success = FALSE;
3999 
4000 	while (my_isspace(cs, *ptr)) {
4001 		ptr++;
4002 	}
4003 
4004 	old_ptr2 = ptr;
4005 
4006 	ptr = dict_scan_to(ptr, string);
4007 
4008 	if (*ptr == '\0' || old_ptr2 != ptr) {
4009 		return(old_ptr);
4010 	}
4011 
4012 	*success = TRUE;
4013 
4014 	return(ptr + ut_strlen(string));
4015 }
4016 
4017 /*********************************************************************//**
4018 Scans an id. For the lexical definition of an 'id', see the code below.
4019 Strips backquotes or double quotes from around the id.
4020 @return scanned to */
4021 static
4022 const char*
dict_scan_id(CHARSET_INFO * cs,const char * ptr,mem_heap_t * heap,const char ** id,ibool table_id,ibool accept_also_dot)4023 dict_scan_id(
4024 /*=========*/
4025 	CHARSET_INFO*	cs,	/*!< in: the character set of ptr */
4026 	const char*	ptr,	/*!< in: scanned to */
4027 	mem_heap_t*	heap,	/*!< in: heap where to allocate the id
4028 				(NULL=id will not be allocated, but it
4029 				will point to string near ptr) */
4030 	const char**	id,	/*!< out,own: the id; NULL if no id was
4031 				scannable */
4032 	ibool		table_id,/*!< in: TRUE=convert the allocated id
4033 				as a table name; FALSE=convert to UTF-8 */
4034 	ibool		accept_also_dot)
4035 				/*!< in: TRUE if also a dot can appear in a
4036 				non-quoted id; in a quoted id it can appear
4037 				always */
4038 {
4039 	char		quote	= '\0';
4040 	ulint		len	= 0;
4041 	const char*	s;
4042 	char*		str;
4043 	char*		dst;
4044 
4045 	*id = NULL;
4046 
4047 	while (my_isspace(cs, *ptr)) {
4048 		ptr++;
4049 	}
4050 
4051 	if (*ptr == '\0') {
4052 
4053 		return(ptr);
4054 	}
4055 
4056 	if (*ptr == '`' || *ptr == '"') {
4057 		quote = *ptr++;
4058 	}
4059 
4060 	s = ptr;
4061 
4062 	if (quote) {
4063 		for (;;) {
4064 			if (!*ptr) {
4065 				/* Syntax error */
4066 				return(ptr);
4067 			}
4068 			if (*ptr == quote) {
4069 				ptr++;
4070 				if (*ptr != quote) {
4071 					break;
4072 				}
4073 			}
4074 			ptr++;
4075 			len++;
4076 		}
4077 	} else {
4078 		while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
4079 		       && (accept_also_dot || *ptr != '.')
4080 		       && *ptr != ',' && *ptr != '\0') {
4081 
4082 			ptr++;
4083 		}
4084 
4085 		len = ptr - s;
4086 	}
4087 
4088 	if (heap == NULL) {
4089 		/* no heap given: id will point to source string */
4090 		*id = s;
4091 		return(ptr);
4092 	}
4093 
4094 	if (quote) {
4095 		char*	d;
4096 
4097 		str = d = static_cast<char*>(
4098 			mem_heap_alloc(heap, len + 1));
4099 
4100 		while (len--) {
4101 			if ((*d++ = *s++) == quote) {
4102 				s++;
4103 			}
4104 		}
4105 		*d++ = 0;
4106 		len = d - str;
4107 		ut_ad(*s == quote);
4108 		ut_ad(s + 1 == ptr);
4109 	} else {
4110 		str = mem_heap_strdupl(heap, s, len);
4111 	}
4112 
4113 	if (!table_id) {
4114 convert_id:
4115 		/* Convert the identifier from connection character set
4116 		to UTF-8. */
4117 		len = 3 * len + 1;
4118 		*id = dst = static_cast<char*>(mem_heap_alloc(heap, len));
4119 
4120 		innobase_convert_from_id(cs, dst, str, len);
4121 	} else if (!strncmp(str, srv_mysql50_table_name_prefix,
4122 			    sizeof(srv_mysql50_table_name_prefix) - 1)) {
4123 		/* This is a pre-5.1 table name
4124 		containing chars other than [A-Za-z0-9].
4125 		Discard the prefix and use raw UTF-8 encoding. */
4126 		str += sizeof(srv_mysql50_table_name_prefix) - 1;
4127 		len -= sizeof(srv_mysql50_table_name_prefix) - 1;
4128 		goto convert_id;
4129 	} else {
4130 		/* Encode using filename-safe characters. */
4131 		len = 5 * len + 1;
4132 		*id = dst = static_cast<char*>(mem_heap_alloc(heap, len));
4133 
4134 		innobase_convert_from_table_id(cs, dst, str, len);
4135 	}
4136 
4137 	return(ptr);
4138 }
4139 
4140 /*********************************************************************//**
4141 Tries to scan a column name.
4142 @return scanned to */
4143 static
4144 const char*
dict_scan_col(CHARSET_INFO * cs,const char * ptr,ibool * success,dict_table_t * table,const dict_col_t ** column,mem_heap_t * heap,const char ** name)4145 dict_scan_col(
4146 /*==========*/
4147 	CHARSET_INFO*		cs,	/*!< in: the character set of ptr */
4148 	const char*		ptr,	/*!< in: scanned to */
4149 	ibool*			success,/*!< out: TRUE if success */
4150 	dict_table_t*		table,	/*!< in: table in which the column is */
4151 	const dict_col_t**	column,	/*!< out: pointer to column if success */
4152 	mem_heap_t*		heap,	/*!< in: heap where to allocate */
4153 	const char**		name)	/*!< out,own: the column name;
4154 					NULL if no name was scannable */
4155 {
4156 	ulint		i;
4157 
4158 	*success = FALSE;
4159 
4160 	ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
4161 
4162 	if (*name == NULL) {
4163 
4164 		return(ptr);	/* Syntax error */
4165 	}
4166 
4167 	if (table == NULL) {
4168 		*success = TRUE;
4169 		*column = NULL;
4170 	} else {
4171 		for (i = 0; i < dict_table_get_n_cols(table); i++) {
4172 
4173 			const char*	col_name = dict_table_get_col_name(
4174 				table, i);
4175 
4176 			if (0 == innobase_strcasecmp(col_name, *name)) {
4177 				/* Found */
4178 
4179 				*success = TRUE;
4180 				*column = dict_table_get_nth_col(table, i);
4181 				strcpy((char*) *name, col_name);
4182 
4183 				break;
4184 			}
4185 		}
4186 	}
4187 
4188 	return(ptr);
4189 }
4190 
4191 
4192 /*********************************************************************//**
4193 Open a table from its database and table name, this is currently used by
4194 foreign constraint parser to get the referenced table.
4195 @return complete table name with database and table name, allocated from
4196 heap memory passed in */
4197 char*
dict_get_referenced_table(const char * name,const char * database_name,ulint database_name_len,const char * table_name,ulint table_name_len,dict_table_t ** table,mem_heap_t * heap)4198 dict_get_referenced_table(
4199 /*======================*/
4200 	const char*	name,		/*!< in: foreign key table name */
4201 	const char*	database_name,	/*!< in: table db name */
4202 	ulint		database_name_len, /*!< in: db name length */
4203 	const char*	table_name,	/*!< in: table name */
4204 	ulint		table_name_len, /*!< in: table name length */
4205 	dict_table_t**	table,		/*!< out: table object or NULL */
4206 	mem_heap_t*	heap)		/*!< in/out: heap memory */
4207 {
4208 	char*		ref;
4209 	const char*	db_name;
4210 
4211 	if (!database_name) {
4212 		/* Use the database name of the foreign key table */
4213 
4214 		db_name = name;
4215 		database_name_len = dict_get_db_name_len(name);
4216 	} else {
4217 		db_name = database_name;
4218 	}
4219 
4220 	/* Copy database_name, '/', table_name, '\0' */
4221 	ref = static_cast<char*>(
4222 		mem_heap_alloc(heap, database_name_len + table_name_len + 2));
4223 
4224 	memcpy(ref, db_name, database_name_len);
4225 	ref[database_name_len] = '/';
4226 	memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
4227 
4228 	/* Values;  0 = Store and compare as given; case sensitive
4229 	            1 = Store and compare in lower; case insensitive
4230 	            2 = Store as given, compare in lower; case semi-sensitive */
4231 	if (innobase_get_lower_case_table_names() == 2) {
4232 		innobase_casedn_str(ref);
4233 		*table = dict_table_get_low(ref);
4234 		memcpy(ref, db_name, database_name_len);
4235 		ref[database_name_len] = '/';
4236 		memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
4237 
4238 	} else {
4239 #ifndef _WIN32
4240 		if (innobase_get_lower_case_table_names() == 1) {
4241 			innobase_casedn_str(ref);
4242 		}
4243 #else
4244 		innobase_casedn_str(ref);
4245 #endif /* !_WIN32 */
4246 		*table = dict_table_get_low(ref);
4247 	}
4248 
4249 	return(ref);
4250 }
4251 /*********************************************************************//**
4252 Scans a table name from an SQL string.
4253 @return scanned to */
4254 static
4255 const char*
dict_scan_table_name(CHARSET_INFO * cs,const char * ptr,dict_table_t ** table,const char * name,ibool * success,mem_heap_t * heap,const char ** ref_name)4256 dict_scan_table_name(
4257 /*=================*/
4258 	CHARSET_INFO*	cs,	/*!< in: the character set of ptr */
4259 	const char*	ptr,	/*!< in: scanned to */
4260 	dict_table_t**	table,	/*!< out: table object or NULL */
4261 	const char*	name,	/*!< in: foreign key table name */
4262 	ibool*		success,/*!< out: TRUE if ok name found */
4263 	mem_heap_t*	heap,	/*!< in: heap where to allocate the id */
4264 	const char**	ref_name)/*!< out,own: the table name;
4265 				NULL if no name was scannable */
4266 {
4267 	const char*	database_name	= NULL;
4268 	ulint		database_name_len = 0;
4269 	const char*	table_name	= NULL;
4270 	const char*	scan_name;
4271 
4272 	*success = FALSE;
4273 	*table = NULL;
4274 
4275 	ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
4276 
4277 	if (scan_name == NULL) {
4278 
4279 		return(ptr);	/* Syntax error */
4280 	}
4281 
4282 	if (*ptr == '.') {
4283 		/* We scanned the database name; scan also the table name */
4284 
4285 		ptr++;
4286 
4287 		database_name = scan_name;
4288 		database_name_len = strlen(database_name);
4289 
4290 		ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
4291 
4292 		if (table_name == NULL) {
4293 
4294 			return(ptr);	/* Syntax error */
4295 		}
4296 	} else {
4297 		/* To be able to read table dumps made with InnoDB-4.0.17 or
4298 		earlier, we must allow the dot separator between the database
4299 		name and the table name also to appear within a quoted
4300 		identifier! InnoDB used to print a constraint as:
4301 		... REFERENCES `databasename.tablename` ...
4302 		starting from 4.0.18 it is
4303 		... REFERENCES `databasename`.`tablename` ... */
4304 		const char* s;
4305 
4306 		for (s = scan_name; *s; s++) {
4307 			if (*s == '.') {
4308 				database_name = scan_name;
4309 				database_name_len = s - scan_name;
4310 				scan_name = ++s;
4311 				break;/* to do: multiple dots? */
4312 			}
4313 		}
4314 
4315 		table_name = scan_name;
4316 	}
4317 
4318 	*ref_name = dict_get_referenced_table(
4319 		name, database_name, database_name_len,
4320 		table_name, strlen(table_name), table, heap);
4321 
4322 	*success = TRUE;
4323 	return(ptr);
4324 }
4325 
4326 /*********************************************************************//**
4327 Skips one id. The id is allowed to contain also '.'.
4328 @return scanned to */
4329 static
4330 const char*
dict_skip_word(CHARSET_INFO * cs,const char * ptr,ibool * success)4331 dict_skip_word(
4332 /*===========*/
4333 	CHARSET_INFO*	cs,	/*!< in: the character set of ptr */
4334 	const char*	ptr,	/*!< in: scanned to */
4335 	ibool*		success)/*!< out: TRUE if success, FALSE if just spaces
4336 				left in string or a syntax error */
4337 {
4338 	const char*	start;
4339 
4340 	*success = FALSE;
4341 
4342 	ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
4343 
4344 	if (start) {
4345 		*success = TRUE;
4346 	}
4347 
4348 	return(ptr);
4349 }
4350 
4351 /*********************************************************************//**
4352 Removes MySQL comments from an SQL string. A comment is either
4353 (a) '#' to the end of the line,
4354 (b) '--[space]' to the end of the line, or
4355 (c) '[slash][asterisk]' till the next '[asterisk][slash]' (like the familiar
4356 C comment syntax).
4357 @return own: SQL string stripped from comments; the caller must free
4358 this with ut_free()! */
4359 static
4360 char*
dict_strip_comments(const char * sql_string,size_t sql_length)4361 dict_strip_comments(
4362 /*================*/
4363 	const char*	sql_string,	/*!< in: SQL string */
4364 	size_t		sql_length)	/*!< in: length of sql_string */
4365 {
4366 	char*		str;
4367 	const char*	sptr;
4368 	const char*	eptr	= sql_string + sql_length;
4369 	char*		ptr;
4370 	/* unclosed quote character (0 if none) */
4371 	char		quote	= 0;
4372 	bool		escape = false;
4373 
4374 	DBUG_ENTER("dict_strip_comments");
4375 
4376 	DBUG_PRINT("dict_strip_comments", ("%s", sql_string));
4377 
4378 	str = static_cast<char*>(ut_malloc_nokey(sql_length + 1));
4379 
4380 	sptr = sql_string;
4381 	ptr = str;
4382 
4383 	for (;;) {
4384 scan_more:
4385 		if (sptr >= eptr || *sptr == '\0') {
4386 end_of_string:
4387 			*ptr = '\0';
4388 
4389 			ut_a(ptr <= str + sql_length);
4390 
4391 			DBUG_PRINT("dict_strip_comments", ("%s", str));
4392 			DBUG_RETURN(str);
4393 		}
4394 
4395 		if (*sptr == quote) {
4396 			/* Closing quote character: do not look for
4397 			starting quote or comments. */
4398 
4399 			/* If the quote character is escaped by a
4400 			backslash, ignore it. */
4401 			if (escape) {
4402 				escape = false;
4403 			} else {
4404 				quote = 0;
4405 			}
4406 		} else if (quote) {
4407 			/* Within quotes: do not look for
4408 			starting quotes or comments. */
4409 			if (escape) {
4410 				escape = false;
4411 			} else if (*sptr == '\\') {
4412 				escape = true;
4413 			}
4414 		} else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
4415 			/* Starting quote: remember the quote character. */
4416 			quote = *sptr;
4417 		} else if (*sptr == '#'
4418 			   || (sptr[0] == '-' && sptr[1] == '-'
4419 			       && sptr[2] == ' ')) {
4420 			for (;;) {
4421 				if (++sptr >= eptr) {
4422 					goto end_of_string;
4423 				}
4424 
4425 				/* In Unix a newline is 0x0A while in Windows
4426 				it is 0x0D followed by 0x0A */
4427 
4428 				switch (*sptr) {
4429 				case (char) 0X0A:
4430 				case (char) 0x0D:
4431 				case '\0':
4432 					goto scan_more;
4433 				}
4434 			}
4435 		} else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
4436 			sptr += 2;
4437 			for (;;) {
4438 				if (sptr >= eptr) {
4439 					goto end_of_string;
4440 				}
4441 
4442 				switch (*sptr) {
4443 				case '\0':
4444 					goto scan_more;
4445 				case '*':
4446 					if (sptr[1] == '/') {
4447 						sptr += 2;
4448 						goto scan_more;
4449 					}
4450 				}
4451 
4452 				sptr++;
4453 			}
4454 		}
4455 
4456 		*ptr = *sptr;
4457 
4458 		ptr++;
4459 		sptr++;
4460 	}
4461 }
4462 
4463 /*********************************************************************//**
4464 Finds the highest [number] for foreign key constraints of the table. Looks
4465 only at the >= 4.0.18-format id's, which are of the form
4466 databasename/tablename_ibfk_[number].
4467 @return highest number, 0 if table has no new format foreign key constraints */
4468 ulint
dict_table_get_highest_foreign_id(dict_table_t * table)4469 dict_table_get_highest_foreign_id(
4470 /*==============================*/
4471 	dict_table_t*	table)	/*!< in: table in the dictionary memory cache */
4472 {
4473 	dict_foreign_t*	foreign;
4474 	char*		endp;
4475 	ulint		biggest_id	= 0;
4476 	ulint		id;
4477 	ulint		len;
4478 
4479 	DBUG_ENTER("dict_table_get_highest_foreign_id");
4480 
4481 	ut_a(table);
4482 
4483 	len = ut_strlen(table->name.m_name);
4484 
4485 	for (dict_foreign_set::iterator it = table->foreign_set.begin();
4486 	     it != table->foreign_set.end();
4487 	     ++it) {
4488 		foreign = *it;
4489 
4490 		if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
4491 		    && 0 == ut_memcmp(foreign->id, table->name.m_name, len)
4492 		    && 0 == ut_memcmp(foreign->id + len,
4493 				      dict_ibfk, (sizeof dict_ibfk) - 1)
4494 		    && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
4495 			/* It is of the >= 4.0.18 format */
4496 
4497 			id = strtoul(foreign->id + len
4498 				     + ((sizeof dict_ibfk) - 1),
4499 				     &endp, 10);
4500 			if (*endp == '\0') {
4501 				ut_a(id != biggest_id);
4502 
4503 				if (id > biggest_id) {
4504 					biggest_id = id;
4505 				}
4506 			}
4507 		}
4508 	}
4509 
4510 	DBUG_PRINT("dict_table_get_highest_foreign_id",
4511 		   ("id: %lu", biggest_id));
4512 
4513 	DBUG_RETURN(biggest_id);
4514 }
4515 
4516 /*********************************************************************//**
4517 Reports a simple foreign key create clause syntax error. */
4518 static
4519 void
dict_foreign_report_syntax_err(const char * name,const char * start_of_latest_foreign,const char * ptr)4520 dict_foreign_report_syntax_err(
4521 /*===========================*/
4522 	const char*	name,		/*!< in: table name */
4523 	const char*	start_of_latest_foreign,
4524 					/*!< in: start of the foreign key clause
4525 					in the SQL string */
4526 	const char*	ptr)		/*!< in: place of the syntax error */
4527 {
4528 	ut_ad(!srv_read_only_mode);
4529 
4530 	FILE*	ef = dict_foreign_err_file;
4531 
4532 	mutex_enter(&dict_foreign_err_mutex);
4533 	dict_foreign_error_report_low(ef, name);
4534 	fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
4535 		start_of_latest_foreign, ptr);
4536 	mutex_exit(&dict_foreign_err_mutex);
4537 }
4538 
4539 /*********************************************************************//**
4540 Scans a table create SQL string and adds to the data dictionary the foreign key
4541 constraints declared in the string. This function should be called after the
4542 indexes for a table have been created. Each foreign key constraint must be
4543 accompanied with indexes in bot participating tables. The indexes are allowed
4544 to contain more fields than mentioned in the constraint.
4545 
4546 @param[in]	trx		transaction
4547 @param[in[	heap		memory heap
4548 @param[in[	cs		the character set of sql_string
4549 @param[in]	sql_string	table create statement where
4550 				foreign keys are declared like:
4551 				FOREIGN KEY (a, b) REFERENCES table2(c, d),
4552 				table2 can be written also with the database
4553 				name before it: test.table2; the default
4554 				database id the database of parameter name
4555 @param[in]	sql_length	length of sql_string
4556 @param[in]	name		table full name in normalized form
4557 @param[in,out]	handler		table handler if table is intrinsic
4558 @param[in]	reject_fks	if TRUE, fail with error code
4559 				DB_CANNOT_ADD_CONSTRAINT if any
4560 				foreign keys are found.
4561 @return error code or DB_SUCCESS */
4562 static
4563 dberr_t
dict_create_foreign_constraints_low(trx_t * trx,mem_heap_t * heap,CHARSET_INFO * cs,const char * sql_string,const char * name,ibool reject_fks)4564 dict_create_foreign_constraints_low(
4565 	trx_t*			trx,
4566 	mem_heap_t*		heap,
4567 	CHARSET_INFO*		cs,
4568 	const char*		sql_string,
4569 	const char*		name,
4570 	ibool			reject_fks)
4571 {
4572 	dict_table_t*	table			= NULL;
4573 	dict_table_t*	referenced_table;
4574 	dict_table_t*	table_to_alter;
4575 	ulint		highest_id_so_far	= 0;
4576 	ulint		number			= 1;
4577 	dict_index_t*	index;
4578 	dict_foreign_t*	foreign;
4579 	const char*	ptr			= sql_string;
4580 	const char*	start_of_latest_foreign	= sql_string;
4581 	FILE*		ef			= dict_foreign_err_file;
4582 	const char*	constraint_name;
4583 	ibool		success;
4584 	dberr_t		error;
4585 	const char*	ptr1;
4586 	const char*	ptr2;
4587 	ulint		i;
4588 	ulint		j;
4589 	ibool		is_on_delete;
4590 	ulint		n_on_deletes;
4591 	ulint		n_on_updates;
4592 	const dict_col_t*columns[500];
4593 	const char*	column_names[500];
4594 	const char*	referenced_table_name;
4595 	dict_foreign_set	local_fk_set;
4596 	dict_foreign_set_free	local_fk_set_free(local_fk_set);
4597 
4598 	ut_ad(!srv_read_only_mode);
4599 	ut_ad(mutex_own(&dict_sys->mutex));
4600 
4601 	table = dict_table_get_low(name);
4602 
4603 	if (table == NULL) {
4604 		mutex_enter(&dict_foreign_err_mutex);
4605 		dict_foreign_error_report_low(ef, name);
4606 		fprintf(ef,
4607 			"Cannot find the table in the internal"
4608 			" data dictionary of InnoDB.\n"
4609 			"Create table statement:\n%s\n", sql_string);
4610 		mutex_exit(&dict_foreign_err_mutex);
4611 
4612 		return(DB_ERROR);
4613 	}
4614 
4615 	/* First check if we are actually doing an ALTER TABLE, and in that
4616 	case look for the table being altered */
4617 
4618 	ptr = dict_accept(cs, ptr, "ALTER", &success);
4619 
4620 	if (!success) {
4621 
4622 		goto loop;
4623 	}
4624 
4625 	ptr = dict_accept(cs, ptr, "TABLE", &success);
4626 
4627 	if (!success) {
4628 
4629 		goto loop;
4630 	}
4631 
4632 	/* We are doing an ALTER TABLE: scan the table name we are altering */
4633 
4634 	ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
4635 				   &success, heap, &referenced_table_name);
4636 	if (!success) {
4637 		ib::error() << "Could not find the table being ALTERED in: "
4638 			<< sql_string;
4639 
4640 		return(DB_ERROR);
4641 	}
4642 
4643 	/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
4644 	format databasename/tablename_ibfk_[number], where [number] is local
4645 	to the table; look for the highest [number] for table_to_alter, so
4646 	that we can assign to new constraints higher numbers. */
4647 
4648 	/* If we are altering a temporary table, the table name after ALTER
4649 	TABLE does not correspond to the internal table name, and
4650 	table_to_alter is NULL. TODO: should we fix this somehow? */
4651 
4652 	if (table_to_alter == NULL) {
4653 		highest_id_so_far = 0;
4654 	} else {
4655 		highest_id_so_far = dict_table_get_highest_foreign_id(
4656 			table_to_alter);
4657 	}
4658 
4659 	number = highest_id_so_far + 1;
4660 	/* Scan for foreign key declarations in a loop */
4661 loop:
4662 	/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
4663 
4664 	ptr1 = dict_scan_to(ptr, "CONSTRAINT");
4665 	ptr2 = dict_scan_to(ptr, "FOREIGN");
4666 
4667 	constraint_name = NULL;
4668 
4669 	if (ptr1 < ptr2) {
4670 		/* The user may have specified a constraint name. Pick it so
4671 		that we can store 'databasename/constraintname' as the id of
4672 		of the constraint to system tables. */
4673 		ptr = ptr1;
4674 
4675 		ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
4676 
4677 		ut_a(success);
4678 
4679 		if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
4680 			goto loop;
4681 		}
4682 
4683 		while (my_isspace(cs, *ptr)) {
4684 			ptr++;
4685 		}
4686 
4687 		/* read constraint name unless got "CONSTRAINT FOREIGN" */
4688 		if (ptr != ptr2) {
4689 			ptr = dict_scan_id(cs, ptr, heap,
4690 					   &constraint_name, FALSE, FALSE);
4691 		}
4692 	} else {
4693 		ptr = ptr2;
4694 	}
4695 
4696 	if (*ptr == '\0') {
4697 		/* The proper way to reject foreign keys for temporary
4698 		tables would be to split the lexing and syntactical
4699 		analysis of foreign key clauses from the actual adding
4700 		of them, so that ha_innodb.cc could first parse the SQL
4701 		command, determine if there are any foreign keys, and
4702 		if so, immediately reject the command if the table is a
4703 		temporary one. For now, this kludge will work. */
4704 		if (reject_fks && !local_fk_set.empty()) {
4705 
4706 			return(DB_CANNOT_ADD_CONSTRAINT);
4707 		}
4708 
4709 		if (dict_foreigns_has_s_base_col(local_fk_set, table)) {
4710 			return(DB_NO_FK_ON_S_BASE_COL);
4711 		}
4712 
4713 		/**********************************************************/
4714 		/* The following call adds the foreign key constraints
4715 		to the data dictionary system tables on disk */
4716 
4717 		error = dict_create_add_foreigns_to_dictionary(
4718 			local_fk_set, table, trx);
4719 
4720 		if (error == DB_SUCCESS) {
4721 
4722 			table->foreign_set.insert(local_fk_set.begin(),
4723 						  local_fk_set.end());
4724 			std::for_each(local_fk_set.begin(),
4725 				      local_fk_set.end(),
4726 				      dict_foreign_add_to_referenced_table());
4727 			local_fk_set.clear();
4728 
4729 			dict_mem_table_fill_foreign_vcol_set(table);
4730 		}
4731 		return(error);
4732 	}
4733 
4734 	start_of_latest_foreign = ptr;
4735 
4736 	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
4737 
4738 	if (!success) {
4739 		goto loop;
4740 	}
4741 
4742 	if (!my_isspace(cs, *ptr)) {
4743 		goto loop;
4744 	}
4745 
4746 	ptr = dict_accept(cs, ptr, "KEY", &success);
4747 
4748 	if (!success) {
4749 		goto loop;
4750 	}
4751 
4752 	ptr = dict_accept(cs, ptr, "(", &success);
4753 
4754 	if (!success) {
4755 		/* MySQL allows also an index id before the '('; we
4756 		skip it */
4757 		ptr = dict_skip_word(cs, ptr, &success);
4758 
4759 		if (!success) {
4760 			dict_foreign_report_syntax_err(
4761 				name, start_of_latest_foreign, ptr);
4762 
4763 			return(DB_CANNOT_ADD_CONSTRAINT);
4764 		}
4765 
4766 		ptr = dict_accept(cs, ptr, "(", &success);
4767 
4768 		if (!success) {
4769 			/* We do not flag a syntax error here because in an
4770 			ALTER TABLE we may also have DROP FOREIGN KEY abc */
4771 
4772 			goto loop;
4773 		}
4774 	}
4775 
4776 	i = 0;
4777 
4778 	/* Scan the columns in the first list */
4779 col_loop1:
4780 	ut_a(i < (sizeof column_names) / sizeof *column_names);
4781 	ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
4782 			    heap, column_names + i);
4783 	if (!success) {
4784 		mutex_enter(&dict_foreign_err_mutex);
4785 		dict_foreign_error_report_low(ef, name);
4786 		fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
4787 			start_of_latest_foreign, ptr);
4788 		mutex_exit(&dict_foreign_err_mutex);
4789 
4790 		return(DB_CANNOT_ADD_CONSTRAINT);
4791 	}
4792 
4793 	i++;
4794 
4795 	ptr = dict_accept(cs, ptr, ",", &success);
4796 
4797 	if (success) {
4798 		goto col_loop1;
4799 	}
4800 
4801 	ptr = dict_accept(cs, ptr, ")", &success);
4802 
4803 	if (!success) {
4804 		dict_foreign_report_syntax_err(
4805 			name, start_of_latest_foreign, ptr);
4806 		return(DB_CANNOT_ADD_CONSTRAINT);
4807 	}
4808 
4809 	/* Try to find an index which contains the columns
4810 	as the first fields and in the right order. There is
4811 	no need to check column type match (on types_idx), since
4812 	the referenced table can be NULL if foreign_key_checks is
4813 	set to 0 */
4814 
4815 	index = dict_foreign_find_index(
4816 		table, NULL, column_names, i, NULL, TRUE, FALSE);
4817 
4818 	if (!index) {
4819 		mutex_enter(&dict_foreign_err_mutex);
4820 		dict_foreign_error_report_low(ef, name);
4821 		fputs("There is no index in table ", ef);
4822 		ut_print_name(ef, NULL, name);
4823 		fprintf(ef, " where the columns appear\n"
4824 			"as the first columns. Constraint:\n%s\n%s",
4825 			start_of_latest_foreign,
4826 			FOREIGN_KEY_CONSTRAINTS_MSG);
4827 		mutex_exit(&dict_foreign_err_mutex);
4828 
4829 		return(DB_CHILD_NO_INDEX);
4830 	}
4831 	ptr = dict_accept(cs, ptr, "REFERENCES", &success);
4832 
4833 	if (!success || !my_isspace(cs, *ptr)) {
4834 		dict_foreign_report_syntax_err(
4835 			name, start_of_latest_foreign, ptr);
4836 		return(DB_CANNOT_ADD_CONSTRAINT);
4837 	}
4838 
4839 	/* Don't allow foreign keys on partitioned tables yet. */
4840 	ptr1 = dict_scan_to(ptr, "PARTITION");
4841 	if (ptr1) {
4842 		ptr1 = dict_accept(cs, ptr1, "PARTITION", &success);
4843 		if (success && my_isspace(cs, *ptr1)) {
4844 			ptr2 = dict_accept(cs, ptr1, "BY", &success);
4845 			if (success) {
4846 				my_error(ER_FOREIGN_KEY_ON_PARTITIONED,MYF(0));
4847 				return(DB_CANNOT_ADD_CONSTRAINT);
4848 			}
4849 		}
4850 	}
4851 	if (dict_table_is_partition(table)) {
4852 		my_error(ER_FOREIGN_KEY_ON_PARTITIONED,MYF(0));
4853 		return(DB_CANNOT_ADD_CONSTRAINT);
4854 	}
4855 
4856 	/* Let us create a constraint struct */
4857 
4858 	foreign = dict_mem_foreign_create();
4859 
4860 	if (constraint_name) {
4861 		ulint	db_len;
4862 
4863 		/* Catenate 'databasename/' to the constraint name specified
4864 		by the user: we conceive the constraint as belonging to the
4865 		same MySQL 'database' as the table itself. We store the name
4866 		to foreign->id. */
4867 
4868 		db_len = dict_get_db_name_len(table->name.m_name);
4869 
4870 		foreign->id = static_cast<char*>(mem_heap_alloc(
4871 			foreign->heap, db_len + strlen(constraint_name) + 2));
4872 
4873 		ut_memcpy(foreign->id, table->name.m_name, db_len);
4874 		foreign->id[db_len] = '/';
4875 		strcpy(foreign->id + db_len + 1, constraint_name);
4876 	}
4877 
4878 	if (foreign->id == NULL) {
4879 		error = dict_create_add_foreign_id(
4880 			&number, table->name.m_name, foreign);
4881 		if (error != DB_SUCCESS) {
4882 			dict_foreign_free(foreign);
4883 			return(error);
4884 		}
4885 	}
4886 
4887 	std::pair<dict_foreign_set::iterator, bool>	ret
4888 		= local_fk_set.insert(foreign);
4889 
4890 	if (!ret.second) {
4891 		/* A duplicate foreign key name has been found */
4892 		dict_foreign_free(foreign);
4893 		return(DB_CANNOT_ADD_CONSTRAINT);
4894 	}
4895 
4896 	foreign->foreign_table = table;
4897 	foreign->foreign_table_name = mem_heap_strdup(
4898 		foreign->heap, table->name.m_name);
4899 	dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
4900 
4901 	foreign->foreign_index = index;
4902 	foreign->n_fields = (unsigned int) i;
4903 
4904 	foreign->foreign_col_names = static_cast<const char**>(
4905 		mem_heap_alloc(foreign->heap, i * sizeof(void*)));
4906 
4907 	for (i = 0; i < foreign->n_fields; i++) {
4908 		foreign->foreign_col_names[i] = mem_heap_strdup(
4909 			foreign->heap,
4910 			dict_table_get_col_name(table,
4911 						dict_col_get_no(columns[i])));
4912 	}
4913 
4914 	ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
4915 				   &success, heap, &referenced_table_name);
4916 
4917 	/* Note that referenced_table can be NULL if the user has suppressed
4918 	checking of foreign key constraints! */
4919 
4920 	if (!success || (!referenced_table && trx->check_foreigns)) {
4921 		mutex_enter(&dict_foreign_err_mutex);
4922 		dict_foreign_error_report_low(ef, name);
4923 		fprintf(ef, "%s:\nCannot resolve table name close to:\n"
4924 			"%s\n",
4925 			start_of_latest_foreign, ptr);
4926 		mutex_exit(&dict_foreign_err_mutex);
4927 
4928 		return(DB_CANNOT_ADD_CONSTRAINT);
4929 	}
4930 
4931 	/* Don't allow foreign keys on partitioned tables yet. */
4932 	if (referenced_table && dict_table_is_partition(referenced_table)) {
4933 		/* How could one make a referenced table to be a partition? */
4934 		ut_ad(0);
4935 		my_error(ER_FOREIGN_KEY_ON_PARTITIONED,MYF(0));
4936 		return(DB_CANNOT_ADD_CONSTRAINT);
4937 	}
4938 
4939 	ptr = dict_accept(cs, ptr, "(", &success);
4940 
4941 	if (!success) {
4942 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
4943 					       ptr);
4944 		return(DB_CANNOT_ADD_CONSTRAINT);
4945 	}
4946 
4947 	/* Scan the columns in the second list */
4948 	i = 0;
4949 
4950 col_loop2:
4951 	ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
4952 			    heap, column_names + i);
4953 	i++;
4954 
4955 	if (!success) {
4956 
4957 		mutex_enter(&dict_foreign_err_mutex);
4958 		dict_foreign_error_report_low(ef, name);
4959 		fprintf(ef, "%s:\nCannot resolve column name close to:\n"
4960 			"%s\n",
4961 			start_of_latest_foreign, ptr);
4962 		mutex_exit(&dict_foreign_err_mutex);
4963 
4964 		return(DB_CANNOT_ADD_CONSTRAINT);
4965 	}
4966 
4967 	ptr = dict_accept(cs, ptr, ",", &success);
4968 
4969 	if (success) {
4970 		goto col_loop2;
4971 	}
4972 
4973 	ptr = dict_accept(cs, ptr, ")", &success);
4974 
4975 	if (!success || foreign->n_fields != i) {
4976 
4977 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
4978 					       ptr);
4979 		return(DB_CANNOT_ADD_CONSTRAINT);
4980 	}
4981 
4982 	n_on_deletes = 0;
4983 	n_on_updates = 0;
4984 
4985 scan_on_conditions:
4986 	/* Loop here as long as we can find ON ... conditions */
4987 
4988 	ptr = dict_accept(cs, ptr, "ON", &success);
4989 
4990 	if (!success) {
4991 
4992 		goto try_find_index;
4993 	}
4994 
4995 	ptr = dict_accept(cs, ptr, "DELETE", &success);
4996 
4997 	if (!success) {
4998 		ptr = dict_accept(cs, ptr, "UPDATE", &success);
4999 
5000 		if (!success) {
5001 
5002 			dict_foreign_report_syntax_err(
5003 				name, start_of_latest_foreign, ptr);
5004 			return(DB_CANNOT_ADD_CONSTRAINT);
5005 		}
5006 
5007 		is_on_delete = FALSE;
5008 		n_on_updates++;
5009 	} else {
5010 		is_on_delete = TRUE;
5011 		n_on_deletes++;
5012 	}
5013 
5014 	ptr = dict_accept(cs, ptr, "RESTRICT", &success);
5015 
5016 	if (success) {
5017 		goto scan_on_conditions;
5018 	}
5019 
5020 	ptr = dict_accept(cs, ptr, "CASCADE", &success);
5021 
5022 	if (success) {
5023 		if (is_on_delete) {
5024 			foreign->type |= DICT_FOREIGN_ON_DELETE_CASCADE;
5025 		} else {
5026 			foreign->type |= DICT_FOREIGN_ON_UPDATE_CASCADE;
5027 		}
5028 
5029 		goto scan_on_conditions;
5030 	}
5031 
5032 	ptr = dict_accept(cs, ptr, "NO", &success);
5033 
5034 	if (success) {
5035 		ptr = dict_accept(cs, ptr, "ACTION", &success);
5036 
5037 		if (!success) {
5038 			dict_foreign_report_syntax_err(
5039 				name, start_of_latest_foreign, ptr);
5040 
5041 			return(DB_CANNOT_ADD_CONSTRAINT);
5042 		}
5043 
5044 		if (is_on_delete) {
5045 			foreign->type |= DICT_FOREIGN_ON_DELETE_NO_ACTION;
5046 		} else {
5047 			foreign->type |= DICT_FOREIGN_ON_UPDATE_NO_ACTION;
5048 		}
5049 
5050 		goto scan_on_conditions;
5051 	}
5052 
5053 	ptr = dict_accept(cs, ptr, "SET", &success);
5054 
5055 	if (!success) {
5056 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
5057 					       ptr);
5058 		return(DB_CANNOT_ADD_CONSTRAINT);
5059 	}
5060 
5061 	ptr = dict_accept(cs, ptr, "NULL", &success);
5062 
5063 	if (!success) {
5064 		dict_foreign_report_syntax_err(name, start_of_latest_foreign,
5065 					       ptr);
5066 		return(DB_CANNOT_ADD_CONSTRAINT);
5067 	}
5068 
5069 	for (j = 0; j < foreign->n_fields; j++) {
5070 		if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
5071 		    & DATA_NOT_NULL) {
5072 
5073 			/* It is not sensible to define SET NULL
5074 			if the column is not allowed to be NULL! */
5075 
5076 			mutex_enter(&dict_foreign_err_mutex);
5077 			dict_foreign_error_report_low(ef, name);
5078 			fprintf(ef, "%s:\n"
5079 				"You have defined a SET NULL condition"
5080 				" though some of the\n"
5081 				"columns are defined as NOT NULL.\n",
5082 				start_of_latest_foreign);
5083 			mutex_exit(&dict_foreign_err_mutex);
5084 
5085 			return(DB_CANNOT_ADD_CONSTRAINT);
5086 		}
5087 	}
5088 
5089 	if (is_on_delete) {
5090 		foreign->type |= DICT_FOREIGN_ON_DELETE_SET_NULL;
5091 	} else {
5092 		foreign->type |= DICT_FOREIGN_ON_UPDATE_SET_NULL;
5093 	}
5094 
5095 	goto scan_on_conditions;
5096 
5097 try_find_index:
5098 	if (n_on_deletes > 1 || n_on_updates > 1) {
5099 		/* It is an error to define more than 1 action */
5100 
5101 		mutex_enter(&dict_foreign_err_mutex);
5102 		dict_foreign_error_report_low(ef, name);
5103 		fprintf(ef, "%s:\n"
5104 			"You have twice an ON DELETE clause"
5105 			" or twice an ON UPDATE clause.\n",
5106 			start_of_latest_foreign);
5107 		mutex_exit(&dict_foreign_err_mutex);
5108 
5109 		return(DB_CANNOT_ADD_CONSTRAINT);
5110 	}
5111 
5112 	/* Try to find an index which contains the columns as the first fields
5113 	and in the right order, and the types are the same as in
5114 	foreign->foreign_index */
5115 
5116 	if (referenced_table) {
5117 		index = dict_foreign_find_index(referenced_table, NULL,
5118 						column_names, i,
5119 						foreign->foreign_index,
5120 						TRUE, FALSE);
5121 		if (!index) {
5122 			mutex_enter(&dict_foreign_err_mutex);
5123 			dict_foreign_error_report_low(ef, name);
5124 			fprintf(ef, "%s:\n"
5125 				"Cannot find an index in the"
5126 				" referenced table where the\n"
5127 				"referenced columns appear as the"
5128 				" first columns, or column types\n"
5129 				"in the table and the referenced table"
5130 				" do not match for constraint.\n"
5131 				"Note that the internal storage type of"
5132 				" ENUM and SET changed in\n"
5133 				"tables created with >= InnoDB-4.1.12,"
5134 				" and such columns in old tables\n"
5135 				"cannot be referenced by such columns"
5136 				" in new tables.\n%s\n",
5137 				start_of_latest_foreign,
5138 				FOREIGN_KEY_CONSTRAINTS_MSG);
5139 			mutex_exit(&dict_foreign_err_mutex);
5140 
5141 			return(DB_PARENT_NO_INDEX);
5142 		}
5143 	} else {
5144 		ut_a(trx->check_foreigns == FALSE);
5145 		index = NULL;
5146 	}
5147 
5148 	foreign->referenced_index = index;
5149 	foreign->referenced_table = referenced_table;
5150 
5151 	foreign->referenced_table_name = mem_heap_strdup(
5152 		foreign->heap, referenced_table_name);
5153 	dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
5154 
5155 	foreign->referenced_col_names = static_cast<const char**>(
5156 		mem_heap_alloc(foreign->heap, i * sizeof(void*)));
5157 
5158 	for (i = 0; i < foreign->n_fields; i++) {
5159 		foreign->referenced_col_names[i]
5160 			= mem_heap_strdup(foreign->heap, column_names[i]);
5161 	}
5162 
5163 	goto loop;
5164 }
5165 /**************************************************************************
5166 Determines whether a string starts with the specified keyword.
5167 @return TRUE if str starts with keyword */
5168 ibool
dict_str_starts_with_keyword(THD * thd,const char * str,const char * keyword)5169 dict_str_starts_with_keyword(
5170 /*=========================*/
5171 	THD*		thd,		/*!< in: MySQL thread handle */
5172 	const char*	str,		/*!< in: string to scan for keyword */
5173 	const char*	keyword)	/*!< in: keyword to look for */
5174 {
5175 	CHARSET_INFO*	cs = innobase_get_charset(thd);
5176 	ibool		success;
5177 
5178 	dict_accept(cs, str, keyword, &success);
5179 	return(success);
5180 }
5181 
5182 /** Scans a table create SQL string and adds to the data dictionary
5183 the foreign key constraints declared in the string. This function
5184 should be called after the indexes for a table have been created.
5185 Each foreign key constraint must be accompanied with indexes in
5186 bot participating tables. The indexes are allowed to contain more
5187 fields than mentioned in the constraint.
5188 
5189 @param[in]	trx		transaction
5190 @param[in]	sql_string	table create statement where
5191 				foreign keys are declared like:
5192 				FOREIGN KEY (a, b) REFERENCES table2(c, d),
5193 				table2 can be written also with the database
5194 				name before it: test.table2; the default
5195 				database id the database of parameter name
5196 @param[in]	sql_length	length of sql_string
5197 @param[in]	name		table full name in normalized form
5198 @param[in]	reject_fks	if TRUE, fail with error code
5199 				DB_CANNOT_ADD_CONSTRAINT if any
5200 				foreign keys are found.
5201 @return error code or DB_SUCCESS */
5202 dberr_t
dict_create_foreign_constraints(trx_t * trx,const char * sql_string,size_t sql_length,const char * name,ibool reject_fks)5203 dict_create_foreign_constraints(
5204 	trx_t*			trx,
5205 	const char*		sql_string,
5206 	size_t			sql_length,
5207 	const char*		name,
5208 	ibool			reject_fks)
5209 {
5210 	char*		str;
5211 	dberr_t		err;
5212 	mem_heap_t*	heap;
5213 
5214 	ut_a(trx);
5215 	ut_a(trx->mysql_thd);
5216 
5217 	str = dict_strip_comments(sql_string, sql_length);
5218 	heap = mem_heap_create(10000);
5219 
5220 	err = dict_create_foreign_constraints_low(
5221 		trx, heap, innobase_get_charset(trx->mysql_thd),
5222 		str, name, reject_fks);
5223 
5224 	mem_heap_free(heap);
5225 	ut_free(str);
5226 
5227 	return(err);
5228 }
5229 
5230 /**********************************************************************//**
5231 Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
5232 @return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
5233 constraint id does not match */
5234 dberr_t
dict_foreign_parse_drop_constraints(mem_heap_t * heap,trx_t * trx,dict_table_t * table,ulint * n,const char *** constraints_to_drop)5235 dict_foreign_parse_drop_constraints(
5236 /*================================*/
5237 	mem_heap_t*	heap,			/*!< in: heap from which we can
5238 						allocate memory */
5239 	trx_t*		trx,			/*!< in: transaction */
5240 	dict_table_t*	table,			/*!< in: table */
5241 	ulint*		n,			/*!< out: number of constraints
5242 						to drop */
5243 	const char***	constraints_to_drop)	/*!< out: id's of the
5244 						constraints to drop */
5245 {
5246 	ibool			success;
5247 	char*			str;
5248 	size_t			len;
5249 	const char*		ptr;
5250 	const char*		id;
5251 	CHARSET_INFO*		cs;
5252 
5253 	ut_a(trx);
5254 	ut_a(trx->mysql_thd);
5255 
5256 	cs = innobase_get_charset(trx->mysql_thd);
5257 
5258 	*n = 0;
5259 
5260 	*constraints_to_drop = static_cast<const char**>(
5261 		mem_heap_alloc(heap, 1000 * sizeof(char*)));
5262 
5263 	ptr = innobase_get_stmt_unsafe(trx->mysql_thd, &len);
5264 
5265 	str = dict_strip_comments(ptr, len);
5266 
5267 	ptr = str;
5268 
5269 	ut_ad(mutex_own(&dict_sys->mutex));
5270 loop:
5271 	ptr = dict_scan_to(ptr, "DROP");
5272 
5273 	if (*ptr == '\0') {
5274 		ut_free(str);
5275 
5276 		return(DB_SUCCESS);
5277 	}
5278 
5279 	ptr = dict_accept(cs, ptr, "DROP", &success);
5280 
5281 	if (!my_isspace(cs, *ptr)) {
5282 
5283 		goto loop;
5284 	}
5285 
5286 	ptr = dict_accept(cs, ptr, "FOREIGN", &success);
5287 
5288 	if (!success || !my_isspace(cs, *ptr)) {
5289 
5290 		goto loop;
5291 	}
5292 
5293 	ptr = dict_accept(cs, ptr, "KEY", &success);
5294 
5295 	if (!success) {
5296 
5297 		goto syntax_error;
5298 	}
5299 
5300 	ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
5301 
5302 	if (id == NULL) {
5303 
5304 		goto syntax_error;
5305 	}
5306 
5307 	ut_a(*n < 1000);
5308 	(*constraints_to_drop)[*n] = id;
5309 	(*n)++;
5310 
5311 	if (std::find_if(table->foreign_set.begin(),
5312 			 table->foreign_set.end(),
5313 			 dict_foreign_matches_id(id))
5314 	    == table->foreign_set.end()) {
5315 
5316 		if (!srv_read_only_mode) {
5317 			FILE*	ef = dict_foreign_err_file;
5318 
5319 			mutex_enter(&dict_foreign_err_mutex);
5320 			rewind(ef);
5321 			ut_print_timestamp(ef);
5322 			fputs(" Error in dropping of a foreign key"
5323 			      " constraint of table ", ef);
5324 			ut_print_name(ef, NULL, table->name.m_name);
5325 			fprintf(ef, ",\nin SQL command\n%s"
5326 				"\nCannot find a constraint with the"
5327 				" given id %s.\n", str, id);
5328 			mutex_exit(&dict_foreign_err_mutex);
5329 		}
5330 
5331 		ut_free(str);
5332 
5333 		return(DB_CANNOT_DROP_CONSTRAINT);
5334 	}
5335 
5336 	goto loop;
5337 
5338 syntax_error:
5339 	if (!srv_read_only_mode) {
5340 		FILE*	ef = dict_foreign_err_file;
5341 
5342 		mutex_enter(&dict_foreign_err_mutex);
5343 		rewind(ef);
5344 		ut_print_timestamp(ef);
5345 		fputs(" Syntax error in dropping of a"
5346 		      " foreign key constraint of table ", ef);
5347 		ut_print_name(ef, NULL, table->name.m_name);
5348 		fprintf(ef, ",\n"
5349 			"close to:\n%s\n in SQL command\n%s\n", ptr, str);
5350 		mutex_exit(&dict_foreign_err_mutex);
5351 	}
5352 
5353 	ut_free(str);
5354 
5355 	return(DB_CANNOT_DROP_CONSTRAINT);
5356 }
5357 
5358 /*==================== END OF FOREIGN KEY PROCESSING ====================*/
5359 
5360 /**********************************************************************//**
5361 Returns an index object if it is found in the dictionary cache.
5362 Assumes that dict_sys->mutex is already being held.
5363 @return index, NULL if not found */
5364 dict_index_t*
dict_index_get_if_in_cache_low(index_id_t index_id)5365 dict_index_get_if_in_cache_low(
5366 /*===========================*/
5367 	index_id_t	index_id)	/*!< in: index id */
5368 {
5369 	ut_ad(mutex_own(&dict_sys->mutex));
5370 
5371 	return(dict_index_find_on_id_low(index_id));
5372 }
5373 
5374 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
5375 /**********************************************************************//**
5376 Returns an index object if it is found in the dictionary cache.
5377 @return index, NULL if not found */
5378 dict_index_t*
dict_index_get_if_in_cache(index_id_t index_id)5379 dict_index_get_if_in_cache(
5380 /*=======================*/
5381 	index_id_t	index_id)	/*!< in: index id */
5382 {
5383 	dict_index_t*	index;
5384 
5385 	if (dict_sys == NULL) {
5386 		return(NULL);
5387 	}
5388 
5389 	mutex_enter(&dict_sys->mutex);
5390 
5391 	index = dict_index_get_if_in_cache_low(index_id);
5392 
5393 	mutex_exit(&dict_sys->mutex);
5394 
5395 	return(index);
5396 }
5397 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
5398 
5399 #ifdef UNIV_DEBUG
5400 /**********************************************************************//**
5401 Checks that a tuple has n_fields_cmp value in a sensible range, so that
5402 no comparison can occur with the page number field in a node pointer.
5403 @return TRUE if ok */
5404 ibool
dict_index_check_search_tuple(const dict_index_t * index,const dtuple_t * tuple)5405 dict_index_check_search_tuple(
5406 /*==========================*/
5407 	const dict_index_t*	index,	/*!< in: index tree */
5408 	const dtuple_t*		tuple)	/*!< in: tuple used in a search */
5409 {
5410 	ut_a(index);
5411 	ut_a(dtuple_get_n_fields_cmp(tuple)
5412 	     <= dict_index_get_n_unique_in_tree(index));
5413 	return(TRUE);
5414 }
5415 #endif /* UNIV_DEBUG */
5416 
5417 /**********************************************************************//**
5418 Builds a node pointer out of a physical record and a page number.
5419 @return own: node pointer */
5420 dtuple_t*
dict_index_build_node_ptr(const dict_index_t * index,const rec_t * rec,ulint page_no,mem_heap_t * heap,ulint level)5421 dict_index_build_node_ptr(
5422 /*======================*/
5423 	const dict_index_t*	index,	/*!< in: index */
5424 	const rec_t*		rec,	/*!< in: record for which to build node
5425 					pointer */
5426 	ulint			page_no,/*!< in: page number to put in node
5427 					pointer */
5428 	mem_heap_t*		heap,	/*!< in: memory heap where pointer
5429 					created */
5430 	ulint			level)	/*!< in: level of rec in tree:
5431 					0 means leaf level */
5432 {
5433 	dtuple_t*	tuple;
5434 	dfield_t*	field;
5435 	byte*		buf;
5436 	ulint		n_unique;
5437 
5438 	if (dict_index_is_ibuf(index)) {
5439 		/* In a universal index tree, we take the whole record as
5440 		the node pointer if the record is on the leaf level,
5441 		on non-leaf levels we remove the last field, which
5442 		contains the page number of the child page */
5443 
5444 		ut_a(!dict_table_is_comp(index->table));
5445 		n_unique = rec_get_n_fields_old(rec);
5446 
5447 		if (level > 0) {
5448 			ut_a(n_unique > 1);
5449 			n_unique--;
5450 		}
5451 	} else {
5452 		n_unique = dict_index_get_n_unique_in_tree_nonleaf(index);
5453 	}
5454 
5455 	tuple = dtuple_create(heap, n_unique + 1);
5456 
5457 	/* When searching in the tree for the node pointer, we must not do
5458 	comparison on the last field, the page number field, as on upper
5459 	levels in the tree there may be identical node pointers with a
5460 	different page number; therefore, we set the n_fields_cmp to one
5461 	less: */
5462 
5463 	dtuple_set_n_fields_cmp(tuple, n_unique);
5464 
5465 	dict_index_copy_types(tuple, index, n_unique);
5466 
5467 	buf = static_cast<byte*>(mem_heap_alloc(heap, 4));
5468 
5469 	mach_write_to_4(buf, page_no);
5470 
5471 	field = dtuple_get_nth_field(tuple, n_unique);
5472 	dfield_set_data(field, buf, 4);
5473 
5474 	dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
5475 
5476 	rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
5477 	dtuple_set_info_bits(tuple, dtuple_get_info_bits(tuple)
5478 			     | REC_STATUS_NODE_PTR);
5479 
5480 	ut_ad(dtuple_check_typed(tuple));
5481 
5482 	return(tuple);
5483 }
5484 
5485 /**********************************************************************//**
5486 Copies an initial segment of a physical record, long enough to specify an
5487 index entry uniquely.
5488 @return pointer to the prefix record */
5489 rec_t*
dict_index_copy_rec_order_prefix(const dict_index_t * index,const rec_t * rec,ulint * n_fields,byte ** buf,ulint * buf_size)5490 dict_index_copy_rec_order_prefix(
5491 /*=============================*/
5492 	const dict_index_t*	index,	/*!< in: index */
5493 	const rec_t*		rec,	/*!< in: record for which to
5494 					copy prefix */
5495 	ulint*			n_fields,/*!< out: number of fields copied */
5496 	byte**			buf,	/*!< in/out: memory buffer for the
5497 					copied prefix, or NULL */
5498 	ulint*			buf_size)/*!< in/out: buffer size */
5499 {
5500 	ulint		n;
5501 
5502 	UNIV_PREFETCH_R(rec);
5503 
5504 	if (dict_index_is_ibuf(index)) {
5505 		ut_a(!dict_table_is_comp(index->table));
5506 		n = rec_get_n_fields_old(rec);
5507 	} else {
5508 		if (page_is_leaf(page_align(rec))) {
5509 			n = dict_index_get_n_unique_in_tree(index);
5510 		} else {
5511 			n = dict_index_get_n_unique_in_tree_nonleaf(index);
5512 			/* For internal node of R-tree, since we need to
5513 			compare the page no field, so, we need to copy this
5514 			field as well. */
5515 			if (dict_index_is_spatial(index)) {
5516 				n++;
5517 			}
5518 		}
5519 	}
5520 
5521 	*n_fields = n;
5522 	return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
5523 }
5524 
5525 /**********************************************************************//**
5526 Builds a typed data tuple out of a physical record.
5527 @return own: data tuple */
5528 dtuple_t*
dict_index_build_data_tuple(dict_index_t * index,rec_t * rec,ulint n_fields,mem_heap_t * heap)5529 dict_index_build_data_tuple(
5530 /*========================*/
5531 	dict_index_t*	index,	/*!< in: index tree */
5532 	rec_t*		rec,	/*!< in: record for which to build data tuple */
5533 	ulint		n_fields,/*!< in: number of data fields */
5534 	mem_heap_t*	heap)	/*!< in: memory heap where tuple created */
5535 {
5536 	dtuple_t*	tuple;
5537 
5538 	ut_ad(dict_table_is_comp(index->table)
5539 	      || n_fields <= rec_get_n_fields_old(rec));
5540 
5541 	tuple = dtuple_create(heap, n_fields);
5542 
5543 	dict_index_copy_types(tuple, index, n_fields);
5544 
5545 	rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
5546 
5547 	ut_ad(dtuple_check_typed(tuple));
5548 
5549 	return(tuple);
5550 }
5551 
5552 /*********************************************************************//**
5553 Calculates the minimum record length in an index. */
5554 ulint
dict_index_calc_min_rec_len(const dict_index_t * index)5555 dict_index_calc_min_rec_len(
5556 /*========================*/
5557 	const dict_index_t*	index)	/*!< in: index */
5558 {
5559 	ulint	sum	= 0;
5560 	ulint	i;
5561 	ulint	comp	= dict_table_is_comp(index->table);
5562 
5563 	if (comp) {
5564 		ulint nullable = 0;
5565 		sum = REC_N_NEW_EXTRA_BYTES;
5566 		for (i = 0; i < dict_index_get_n_fields(index); i++) {
5567 			const dict_col_t*	col
5568 				= dict_index_get_nth_col(index, i);
5569 			ulint	size = dict_col_get_fixed_size(col, comp);
5570 			sum += size;
5571 			if (!size) {
5572 				size = col->len;
5573 				sum += size < 128 ? 1 : 2;
5574 			}
5575 			if (!(col->prtype & DATA_NOT_NULL)) {
5576 				nullable++;
5577 			}
5578 		}
5579 
5580 		/* round the NULL flags up to full bytes */
5581 		sum += UT_BITS_IN_BYTES(nullable);
5582 
5583 		return(sum);
5584 	}
5585 
5586 	for (i = 0; i < dict_index_get_n_fields(index); i++) {
5587 		sum += dict_col_get_fixed_size(
5588 			dict_index_get_nth_col(index, i), comp);
5589 	}
5590 
5591 	if (sum > 127) {
5592 		sum += 2 * dict_index_get_n_fields(index);
5593 	} else {
5594 		sum += dict_index_get_n_fields(index);
5595 	}
5596 
5597 	sum += REC_N_OLD_EXTRA_BYTES;
5598 
5599 	return(sum);
5600 }
5601 
5602 /**********************************************************************//**
5603 Outputs info on a foreign key of a table in a format suitable for
5604 CREATE TABLE. */
5605 void
dict_print_info_on_foreign_key_in_create_format(FILE * file,trx_t * trx,dict_foreign_t * foreign,ibool add_newline)5606 dict_print_info_on_foreign_key_in_create_format(
5607 /*============================================*/
5608 	FILE*		file,		/*!< in: file where to print */
5609 	trx_t*		trx,		/*!< in: transaction */
5610 	dict_foreign_t*	foreign,	/*!< in: foreign key constraint */
5611 	ibool		add_newline)	/*!< in: whether to add a newline */
5612 {
5613 	const char*	stripped_id;
5614 	ulint	i;
5615 
5616 	if (strchr(foreign->id, '/')) {
5617 		/* Strip the preceding database name from the constraint id */
5618 		stripped_id = foreign->id + 1
5619 			+ dict_get_db_name_len(foreign->id);
5620 	} else {
5621 		stripped_id = foreign->id;
5622 	}
5623 
5624 	putc(',', file);
5625 
5626 	if (add_newline) {
5627 		/* SHOW CREATE TABLE wants constraints each printed nicely
5628 		on its own line, while error messages want no newlines
5629 		inserted. */
5630 		fputs("\n ", file);
5631 	}
5632 
5633 	fputs(" CONSTRAINT ", file);
5634 	innobase_quote_identifier(file, trx, stripped_id);
5635 	fputs(" FOREIGN KEY (", file);
5636 
5637 	for (i = 0;;) {
5638 		innobase_quote_identifier(
5639 			file, trx, foreign->foreign_col_names[i]);
5640 		if (++i < foreign->n_fields) {
5641 			fputs(", ", file);
5642 		} else {
5643 			break;
5644 		}
5645 	}
5646 
5647 	fputs(") REFERENCES ", file);
5648 
5649 	if (dict_tables_have_same_db(foreign->foreign_table_name_lookup,
5650 				     foreign->referenced_table_name_lookup)) {
5651 		/* Do not print the database name of the referenced table */
5652 		ut_print_name(file, trx,
5653 			      dict_remove_db_name(
5654 				      foreign->referenced_table_name));
5655 	} else {
5656 		ut_print_name(file, trx,
5657 			      foreign->referenced_table_name);
5658 	}
5659 
5660 	putc(' ', file);
5661 	putc('(', file);
5662 
5663 	for (i = 0;;) {
5664 		innobase_quote_identifier(file, trx,
5665 					  foreign->referenced_col_names[i]);
5666 		if (++i < foreign->n_fields) {
5667 			fputs(", ", file);
5668 		} else {
5669 			break;
5670 		}
5671 	}
5672 
5673 	putc(')', file);
5674 
5675 	if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
5676 		fputs(" ON DELETE CASCADE", file);
5677 	}
5678 
5679 	if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
5680 		fputs(" ON DELETE SET NULL", file);
5681 	}
5682 
5683 	if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
5684 		fputs(" ON DELETE NO ACTION", file);
5685 	}
5686 
5687 	if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
5688 		fputs(" ON UPDATE CASCADE", file);
5689 	}
5690 
5691 	if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
5692 		fputs(" ON UPDATE SET NULL", file);
5693 	}
5694 
5695 	if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
5696 		fputs(" ON UPDATE NO ACTION", file);
5697 	}
5698 }
5699 
5700 /**********************************************************************//**
5701 Outputs info on foreign keys of a table. */
5702 void
dict_print_info_on_foreign_keys(ibool create_table_format,FILE * file,trx_t * trx,dict_table_t * table)5703 dict_print_info_on_foreign_keys(
5704 /*============================*/
5705 	ibool		create_table_format, /*!< in: if TRUE then print in
5706 				a format suitable to be inserted into
5707 				a CREATE TABLE, otherwise in the format
5708 				of SHOW TABLE STATUS */
5709 	FILE*		file,	/*!< in: file where to print */
5710 	trx_t*		trx,	/*!< in: transaction */
5711 	dict_table_t*	table)	/*!< in: table */
5712 {
5713 	dict_foreign_t*	foreign;
5714 
5715 	mutex_enter(&dict_sys->mutex);
5716 
5717 	for (dict_foreign_set::iterator it = table->foreign_set.begin();
5718 	     it != table->foreign_set.end();
5719 	     ++it) {
5720 
5721 		foreign = *it;
5722 
5723 		if (create_table_format) {
5724 			dict_print_info_on_foreign_key_in_create_format(
5725 				file, trx, foreign, TRUE);
5726 		} else {
5727 			ulint	i;
5728 			fputs("; (", file);
5729 
5730 			for (i = 0; i < foreign->n_fields; i++) {
5731 				if (i) {
5732 					putc(' ', file);
5733 				}
5734 
5735 				innobase_quote_identifier(
5736 					file, trx,
5737 					foreign->foreign_col_names[i]);
5738 			}
5739 
5740 			fputs(") REFER ", file);
5741 			ut_print_name(file, trx,
5742 				      foreign->referenced_table_name);
5743 			putc('(', file);
5744 
5745 			for (i = 0; i < foreign->n_fields; i++) {
5746 				if (i) {
5747 					putc(' ', file);
5748 				}
5749 				innobase_quote_identifier(
5750 					file, trx,
5751 					foreign->referenced_col_names[i]);
5752 			}
5753 
5754 			putc(')', file);
5755 
5756 			if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
5757 				fputs(" ON DELETE CASCADE", file);
5758 			}
5759 
5760 			if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
5761 				fputs(" ON DELETE SET NULL", file);
5762 			}
5763 
5764 			if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
5765 				fputs(" ON DELETE NO ACTION", file);
5766 			}
5767 
5768 			if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
5769 				fputs(" ON UPDATE CASCADE", file);
5770 			}
5771 
5772 			if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
5773 				fputs(" ON UPDATE SET NULL", file);
5774 			}
5775 
5776 			if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
5777 				fputs(" ON UPDATE NO ACTION", file);
5778 			}
5779 		}
5780 	}
5781 
5782 	mutex_exit(&dict_sys->mutex);
5783 }
5784 
5785 /** Given a space_id of a file-per-table tablespace, search the
5786 dict_sys->table_LRU list and return the dict_table_t* pointer for it.
5787 @param	space_id	Tablespace ID
5788 @return table if found, NULL if not */
5789 static
5790 dict_table_t*
dict_find_single_table_by_space(ulint space_id)5791 dict_find_single_table_by_space(
5792 	ulint	space_id)
5793 {
5794 	dict_table_t*	table;
5795 	ulint		num_item;
5796 	ulint		count = 0;
5797 
5798 	ut_ad(space_id > 0);
5799 
5800 	if (dict_sys == NULL) {
5801 		/* This could happen when it's in redo processing. */
5802 		return(NULL);
5803 	}
5804 
5805 	table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
5806 	num_item =  UT_LIST_GET_LEN(dict_sys->table_LRU);
5807 
5808 	/* This function intentionally does not acquire mutex as it is used
5809 	by error handling code in deep call stack as last means to avoid
5810 	killing the server, so it worth to risk some consequences for
5811 	the action. */
5812 	while (table && count < num_item) {
5813 		if (table->space == space_id) {
5814 			if (dict_table_is_file_per_table(table)) {
5815 				return(table);
5816 			}
5817 			return(NULL);
5818 		}
5819 
5820 		table = UT_LIST_GET_NEXT(table_LRU, table);
5821 		count++;
5822 	}
5823 
5824 	return(NULL);
5825 }
5826 
5827 /** Flags a table with specified space_id encrypted in the data dictionary
5828 cache
5829 @param[in]	space_id	Tablespace id */
5830 void
dict_set_encrypted_by_space(ulint space_id)5831 dict_set_encrypted_by_space(ulint	space_id)
5832 {
5833 	dict_table_t*   table;
5834 
5835 	table = dict_find_single_table_by_space(space_id);
5836 
5837 	if (table)
5838 		table->set_file_unreadable();
5839 }
5840 
5841 /**********************************************************************//**
5842 Flags a table with specified space_id corrupted in the data dictionary
5843 cache
5844 @return TRUE if successful */
5845 ibool
dict_set_corrupted_by_space(ulint space_id)5846 dict_set_corrupted_by_space(
5847 /*========================*/
5848 	ulint	space_id)		/*!< in: space ID */
5849 {
5850 	dict_table_t*   table;
5851 
5852 	table = dict_find_single_table_by_space(space_id);
5853 
5854 	if (!table) {
5855 		return(FALSE);
5856 	}
5857 
5858 	/* mark the table->corrupted bit only, since the caller
5859 	could be too deep in the stack for SYS_INDEXES update */
5860 	table->corrupted = TRUE;
5861 
5862 	return(TRUE);
5863 }
5864 
5865 /**********************************************************************//**
5866 Flags an index corrupted both in the data dictionary cache
5867 and in the SYS_INDEXES */
5868 void
dict_set_corrupted(dict_index_t * index,trx_t * trx,const char * ctx)5869 dict_set_corrupted(
5870 /*===============*/
5871 	dict_index_t*	index,	/*!< in/out: index */
5872 	trx_t*		trx,	/*!< in/out: transaction */
5873 	const char*	ctx)	/*!< in: context */
5874 {
5875 	mem_heap_t*	heap;
5876 	mtr_t		mtr;
5877 	dict_index_t*	sys_index;
5878 	dtuple_t*	tuple;
5879 	dfield_t*	dfield;
5880 	byte*		buf;
5881 	const char*	status;
5882 	btr_cur_t	cursor;
5883 	bool		locked	= RW_X_LATCH == trx->dict_operation_lock_mode;
5884 
5885 	if (!locked) {
5886 		row_mysql_lock_data_dictionary(trx);
5887 	}
5888 
5889 	ut_ad(index);
5890 	ut_ad(mutex_own(&dict_sys->mutex));
5891 	ut_ad(!dict_table_is_comp(dict_sys->sys_tables));
5892 	ut_ad(!dict_table_is_comp(dict_sys->sys_indexes));
5893 
5894 #ifdef UNIV_DEBUG
5895 	{
5896 		dict_sync_check	check(true);
5897 
5898 		ut_ad(!sync_check_iterate(check));
5899 	}
5900 #endif /* UNIV_DEBUG */
5901 
5902 	/* Mark the table as corrupted only if the clustered index
5903 	is corrupted */
5904 	if (dict_index_is_clust(index)) {
5905 		index->table->corrupted = TRUE;
5906 	}
5907 
5908 	if (index->type & DICT_CORRUPT) {
5909 		/* The index was already flagged corrupted. */
5910 		ut_ad(!dict_index_is_clust(index) || index->table->corrupted);
5911 		goto func_exit;
5912 	}
5913 
5914 	/* If this is read only mode, do not update SYS_INDEXES, just
5915 	mark it as corrupted in memory */
5916 	if (srv_read_only_mode) {
5917 		index->type |= DICT_CORRUPT;
5918 		goto func_exit;
5919 	}
5920 
5921 	heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t)
5922 			       + sizeof(que_fork_t) + sizeof(upd_node_t)
5923 			       + sizeof(upd_t) + 12));
5924 	mtr_start(&mtr);
5925 	index->type |= DICT_CORRUPT;
5926 
5927 	sys_index = UT_LIST_GET_FIRST(dict_sys->sys_indexes->indexes);
5928 
5929 	/* Find the index row in SYS_INDEXES */
5930 	tuple = dtuple_create(heap, 2);
5931 
5932 	dfield = dtuple_get_nth_field(tuple, 0);
5933 	buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
5934 	mach_write_to_8(buf, index->table->id);
5935 	dfield_set_data(dfield, buf, 8);
5936 
5937 	dfield = dtuple_get_nth_field(tuple, 1);
5938 	buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
5939 	mach_write_to_8(buf, index->id);
5940 	dfield_set_data(dfield, buf, 8);
5941 
5942 	dict_index_copy_types(tuple, sys_index, 2);
5943 
5944 	btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_LE,
5945 				    BTR_MODIFY_LEAF,
5946 				    &cursor, 0, __FILE__, __LINE__, &mtr);
5947 
5948 	if (cursor.low_match == dtuple_get_n_fields(tuple)) {
5949 		/* UPDATE SYS_INDEXES SET TYPE=index->type
5950 		WHERE TABLE_ID=index->table->id AND INDEX_ID=index->id */
5951 		ulint	len;
5952 		byte*	field	= rec_get_nth_field_old(
5953 			btr_cur_get_rec(&cursor),
5954 			DICT_FLD__SYS_INDEXES__TYPE, &len);
5955 		if (len != 4) {
5956 			goto fail;
5957 		}
5958 		mlog_write_ulint(field, index->type, MLOG_4BYTES, &mtr);
5959 		status = "Flagged";
5960 	} else {
5961 fail:
5962 		status = "Unable to flag";
5963 	}
5964 
5965 	mtr_commit(&mtr);
5966 	mem_heap_empty(heap);
5967 	ib::error() << status << " corruption of " << index->name
5968 		<< " in table " << index->table->name << " in " << ctx;
5969 	mem_heap_free(heap);
5970 
5971 func_exit:
5972 	if (!locked) {
5973 		row_mysql_unlock_data_dictionary(trx);
5974 	}
5975 }
5976 
5977 /** Flags an index corrupted in the data dictionary cache only. This
5978 is used mostly to mark a corrupted index when index's own dictionary
5979 is corrupted, and we force to load such index for repair purpose
5980 @param[in,out]	index	index which is corrupted */
5981 void
dict_set_corrupted_index_cache_only(dict_index_t * index)5982 dict_set_corrupted_index_cache_only(
5983 	dict_index_t*	index)
5984 {
5985 	ut_ad(index != NULL);
5986 	ut_ad(index->table != NULL);
5987 	ut_ad(mutex_own(&dict_sys->mutex));
5988 	ut_ad(!dict_table_is_comp(dict_sys->sys_tables));
5989 	ut_ad(!dict_table_is_comp(dict_sys->sys_indexes));
5990 
5991 	/* Mark the table as corrupted only if the clustered index
5992 	is corrupted */
5993 	if (dict_index_is_clust(index)) {
5994 		index->table->corrupted = TRUE;
5995 	}
5996 
5997 	index->type |= DICT_CORRUPT;
5998 }
5999 
6000 /** Sets merge_threshold in the SYS_INDEXES
6001 @param[in,out]	index		index
6002 @param[in]	merge_threshold	value to set */
6003 void
dict_index_set_merge_threshold(dict_index_t * index,ulint merge_threshold)6004 dict_index_set_merge_threshold(
6005 	dict_index_t*	index,
6006 	ulint		merge_threshold)
6007 {
6008 	mem_heap_t*	heap;
6009 	mtr_t		mtr;
6010 	dict_index_t*	sys_index;
6011 	dtuple_t*	tuple;
6012 	dfield_t*	dfield;
6013 	byte*		buf;
6014 	btr_cur_t	cursor;
6015 
6016 	ut_ad(index != NULL);
6017 	ut_ad(!dict_table_is_comp(dict_sys->sys_tables));
6018 	ut_ad(!dict_table_is_comp(dict_sys->sys_indexes));
6019 
6020 	rw_lock_x_lock(dict_operation_lock);
6021 	mutex_enter(&(dict_sys->mutex));
6022 
6023 	heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t)
6024 			       + sizeof(que_fork_t) + sizeof(upd_node_t)
6025 			       + sizeof(upd_t) + 12));
6026 
6027 	mtr_start(&mtr);
6028 
6029 	sys_index = UT_LIST_GET_FIRST(dict_sys->sys_indexes->indexes);
6030 
6031 	/* Find the index row in SYS_INDEXES */
6032 	tuple = dtuple_create(heap, 2);
6033 
6034 	dfield = dtuple_get_nth_field(tuple, 0);
6035 	buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
6036 	mach_write_to_8(buf, index->table->id);
6037 	dfield_set_data(dfield, buf, 8);
6038 
6039 	dfield = dtuple_get_nth_field(tuple, 1);
6040 	buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
6041 	mach_write_to_8(buf, index->id);
6042 	dfield_set_data(dfield, buf, 8);
6043 
6044 	dict_index_copy_types(tuple, sys_index, 2);
6045 
6046 	btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE,
6047 				    BTR_MODIFY_LEAF,
6048 				    &cursor, 0, __FILE__, __LINE__, &mtr);
6049 
6050 	if (cursor.up_match == dtuple_get_n_fields(tuple)
6051 	    && rec_get_n_fields_old(btr_cur_get_rec(&cursor))
6052 	       == DICT_NUM_FIELDS__SYS_INDEXES) {
6053 		ulint	len;
6054 		byte*	field	= rec_get_nth_field_old(
6055 			btr_cur_get_rec(&cursor),
6056 			DICT_FLD__SYS_INDEXES__MERGE_THRESHOLD, &len);
6057 
6058 		ut_ad(len == 4);
6059 
6060 		if (len == 4) {
6061 			mlog_write_ulint(field, merge_threshold,
6062 					 MLOG_4BYTES, &mtr);
6063 		}
6064 	}
6065 
6066 	mtr_commit(&mtr);
6067 	mem_heap_free(heap);
6068 
6069 	mutex_exit(&(dict_sys->mutex));
6070 	rw_lock_x_unlock(dict_operation_lock);
6071 }
6072 
6073 #ifdef UNIV_DEBUG
6074 /** Sets merge_threshold for all indexes in the list of tables
6075 @param[in]	list	pointer to the list of tables */
6076 inline
6077 void
dict_set_merge_threshold_list_debug(UT_LIST_BASE_NODE_T (dict_table_t)* list,uint merge_threshold_all)6078 dict_set_merge_threshold_list_debug(
6079 	UT_LIST_BASE_NODE_T(dict_table_t)*	list,
6080 	uint					merge_threshold_all)
6081 {
6082 	for (dict_table_t* table = UT_LIST_GET_FIRST(*list);
6083 	     table != NULL;
6084 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
6085 		for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
6086 		     index != NULL;
6087 		     index = UT_LIST_GET_NEXT(indexes, index)) {
6088 			rw_lock_x_lock(dict_index_get_lock(index));
6089 			index->merge_threshold = merge_threshold_all;
6090 			rw_lock_x_unlock(dict_index_get_lock(index));
6091 		}
6092 	}
6093 }
6094 
6095 /** Sets merge_threshold for all indexes in dictionary cache for debug.
6096 @param[in]	merge_threshold_all	value to set for all indexes */
6097 void
dict_set_merge_threshold_all_debug(uint merge_threshold_all)6098 dict_set_merge_threshold_all_debug(
6099 	uint	merge_threshold_all)
6100 {
6101 	mutex_enter(&dict_sys->mutex);
6102 
6103 	dict_set_merge_threshold_list_debug(
6104 		&dict_sys->table_LRU, merge_threshold_all);
6105 	dict_set_merge_threshold_list_debug(
6106 		&dict_sys->table_non_LRU, merge_threshold_all);
6107 
6108 	mutex_exit(&dict_sys->mutex);
6109 }
6110 #endif /* UNIV_DEBUG */
6111 
6112 /*************************************************************************
6113 set is_corrupt flag by space_id*/
6114 
6115 void
dict_table_set_corrupt_by_space(ulint space_id,bool need_mutex)6116 dict_table_set_corrupt_by_space(
6117 /*============================*/
6118 	ulint	space_id,
6119 	bool	need_mutex)
6120 {
6121 	dict_table_t*	table;
6122 	bool		found = false;
6123 
6124 	ut_a(space_id != 0);
6125 	ut_a(space_id < SRV_LOG_SPACE_FIRST_ID);
6126 
6127 	if (need_mutex)
6128 		mutex_enter(&(dict_sys->mutex));
6129 
6130 	table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
6131 
6132 	while (table) {
6133 		if (table->space == space_id) {
6134 			table->is_corrupt = true;
6135 			table->file_unreadable = true;
6136 			found = true;
6137 		}
6138 
6139 		table = UT_LIST_GET_NEXT(table_LRU, table);
6140 	}
6141 
6142 	if (need_mutex)
6143 		mutex_exit(&(dict_sys->mutex));
6144 
6145 	if (!found) {
6146 		ib::warn() << "Space to be marked as crashed was not found "
6147 			"for id " << space_id << ".";
6148 	}
6149 }
6150 
6151 #endif /* !UNIV_HOTBACKUP */
6152 
6153 /**********************************************************************//**
6154 Inits dict_ind_redundant. */
6155 void
dict_ind_init(void)6156 dict_ind_init(void)
6157 /*===============*/
6158 {
6159 	dict_table_t*		table;
6160 
6161 	/* create dummy table and index for REDUNDANT infimum and supremum */
6162 	table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0, 0, 0);
6163 	dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
6164 			       DATA_ENGLISH | DATA_NOT_NULL, 8);
6165 
6166 	dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
6167 						   DICT_HDR_SPACE, 0, 1);
6168 	dict_index_add_col(dict_ind_redundant, table,
6169 			   dict_table_get_nth_col(table, 0), 0);
6170 	dict_ind_redundant->table = table;
6171 	/* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
6172 	dict_ind_redundant->cached = TRUE;
6173 }
6174 
6175 #ifndef UNIV_HOTBACKUP
6176 /**********************************************************************//**
6177 Frees dict_ind_redundant. */
6178 static
6179 void
dict_ind_free(void)6180 dict_ind_free(void)
6181 /*===============*/
6182 {
6183 	dict_table_t*	table;
6184 
6185 	table = dict_ind_redundant->table;
6186 	dict_mem_index_free(dict_ind_redundant);
6187 	dict_ind_redundant = NULL;
6188 	dict_mem_table_free(table);
6189 }
6190 
6191 /** Get an index by name.
6192 @param[in]	table		the table where to look for the index
6193 @param[in]	name		the index name to look for
6194 @param[in]	committed	true=search for committed,
6195 false=search for uncommitted
6196 @return index, NULL if does not exist */
6197 dict_index_t*
dict_table_get_index_on_name(dict_table_t * table,const char * name,bool committed)6198 dict_table_get_index_on_name(
6199 	dict_table_t*	table,
6200 	const char*	name,
6201 	bool		committed)
6202 {
6203 	dict_index_t*	index;
6204 
6205 	index = dict_table_get_first_index(table);
6206 
6207 	while (index != NULL) {
6208 		if (index->is_committed() == committed
6209 		    && innobase_strcasecmp(index->name, name) == 0) {
6210 
6211 			return(index);
6212 		}
6213 
6214 		index = dict_table_get_next_index(index);
6215 	}
6216 
6217 	return(NULL);
6218 }
6219 
6220 /**********************************************************************//**
6221 Replace the index passed in with another equivalent index in the
6222 foreign key lists of the table.
6223 @return whether all replacements were found */
6224 bool
dict_foreign_replace_index(dict_table_t * table,const char ** col_names,const dict_index_t * index)6225 dict_foreign_replace_index(
6226 /*=======================*/
6227 	dict_table_t*		table,  /*!< in/out: table */
6228 	const char**		col_names,
6229 					/*!< in: column names, or NULL
6230 					to use table->col_names */
6231 	const dict_index_t*	index)	/*!< in: index to be replaced */
6232 {
6233 	bool		found	= true;
6234 	dict_foreign_t*	foreign;
6235 
6236 	ut_ad(index->to_be_dropped);
6237 	ut_ad(index->table == table);
6238 
6239 	for (dict_foreign_set::iterator it = table->foreign_set.begin();
6240 	     it != table->foreign_set.end();
6241 	     ++it) {
6242 
6243 		foreign = *it;
6244 		if (foreign->foreign_index == index) {
6245 			ut_ad(foreign->foreign_table == index->table);
6246 
6247 			dict_index_t* new_index = dict_foreign_find_index(
6248 				foreign->foreign_table, col_names,
6249 				foreign->foreign_col_names,
6250 				foreign->n_fields, index,
6251 				/*check_charsets=*/TRUE, /*check_null=*/FALSE);
6252 			if (new_index) {
6253 				ut_ad(new_index->table == index->table);
6254 				ut_ad(!new_index->to_be_dropped);
6255 			} else {
6256 				found = false;
6257 			}
6258 
6259 			foreign->foreign_index = new_index;
6260 		}
6261 	}
6262 
6263 	for (dict_foreign_set::iterator it = table->referenced_set.begin();
6264 	     it != table->referenced_set.end();
6265 	     ++it) {
6266 
6267 		foreign = *it;
6268 		if (foreign->referenced_index == index) {
6269 			ut_ad(foreign->referenced_table == index->table);
6270 
6271 			dict_index_t* new_index = dict_foreign_find_index(
6272 				foreign->referenced_table, NULL,
6273 				foreign->referenced_col_names,
6274 				foreign->n_fields, index,
6275 				/*check_charsets=*/TRUE, /*check_null=*/FALSE);
6276 			/* There must exist an alternative index,
6277 			since this must have been checked earlier. */
6278 			if (new_index) {
6279 				ut_ad(new_index->table == index->table);
6280 				ut_ad(!new_index->to_be_dropped);
6281 			} else {
6282 				found = false;
6283 			}
6284 
6285 			foreign->referenced_index = new_index;
6286 		}
6287 	}
6288 
6289 	return(found);
6290 }
6291 
6292 #ifdef UNIV_DEBUG
6293 /**********************************************************************//**
6294 Check for duplicate index entries in a table [using the index name] */
6295 void
dict_table_check_for_dup_indexes(const dict_table_t * table,enum check_name check)6296 dict_table_check_for_dup_indexes(
6297 /*=============================*/
6298 	const dict_table_t*	table,	/*!< in: Check for dup indexes
6299 					in this table */
6300 	enum check_name		check)	/*!< in: whether and when to allow
6301 					temporary index names */
6302 {
6303 	/* Check for duplicates, ignoring indexes that are marked
6304 	as to be dropped */
6305 
6306 	const dict_index_t*	index1;
6307 	const dict_index_t*	index2;
6308 
6309 	ut_ad(mutex_own(&dict_sys->mutex));
6310 
6311 	/* The primary index _must_ exist */
6312 	ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
6313 
6314 	index1 = UT_LIST_GET_FIRST(table->indexes);
6315 
6316 	do {
6317 		if (!index1->is_committed()) {
6318 			ut_a(!dict_index_is_clust(index1));
6319 
6320 			switch (check) {
6321 			case CHECK_ALL_COMPLETE:
6322 				ut_error;
6323 			case CHECK_ABORTED_OK:
6324 				switch (dict_index_get_online_status(index1)) {
6325 				case ONLINE_INDEX_COMPLETE:
6326 				case ONLINE_INDEX_CREATION:
6327 					ut_error;
6328 					break;
6329 				case ONLINE_INDEX_ABORTED:
6330 				case ONLINE_INDEX_ABORTED_DROPPED:
6331 					break;
6332 				}
6333 				/* fall through */
6334 			case CHECK_PARTIAL_OK:
6335 				break;
6336 			}
6337 		}
6338 
6339 		for (index2 = UT_LIST_GET_NEXT(indexes, index1);
6340 		     index2 != NULL;
6341 		     index2 = UT_LIST_GET_NEXT(indexes, index2)) {
6342 			ut_ad(index1->is_committed()
6343 			      != index2->is_committed()
6344 			      || strcmp(index1->name, index2->name) != 0);
6345 		}
6346 
6347 		index1 = UT_LIST_GET_NEXT(indexes, index1);
6348 	} while (index1);
6349 }
6350 #endif /* UNIV_DEBUG */
6351 
6352 /** Auxiliary macro used inside dict_table_schema_check(). */
6353 #define CREATE_TYPES_NAMES() \
6354 	dtype_sql_name((unsigned) req_schema->columns[i].mtype, \
6355 		       (unsigned) req_schema->columns[i].prtype_mask, \
6356 		       (unsigned) req_schema->columns[i].len, \
6357 		       req_type, sizeof(req_type)); \
6358 	dtype_sql_name(table->cols[j].mtype, \
6359 		       table->cols[j].prtype, \
6360 		       table->cols[j].len, \
6361 		       actual_type, sizeof(actual_type))
6362 
6363 /*********************************************************************//**
6364 Checks whether a table exists and whether it has the given structure.
6365 The table must have the same number of columns with the same names and
6366 types. The order of the columns does not matter.
6367 The caller must own the dictionary mutex.
6368 dict_table_schema_check() @{
6369 @return DB_SUCCESS if the table exists and contains the necessary columns */
6370 dberr_t
dict_table_schema_check(dict_table_schema_t * req_schema,char * errstr,size_t errstr_sz)6371 dict_table_schema_check(
6372 /*====================*/
6373 	dict_table_schema_t*	req_schema,	/*!< in/out: required table
6374 						schema */
6375 	char*			errstr,		/*!< out: human readable error
6376 						message if != DB_SUCCESS is
6377 						returned */
6378 	size_t			errstr_sz)	/*!< in: errstr size */
6379 {
6380 	char		buf[MAX_FULL_NAME_LEN];
6381 	char		req_type[64];
6382 	char		actual_type[64];
6383 	dict_table_t*	table;
6384 	ulint		i;
6385 
6386 	ut_ad(mutex_own(&dict_sys->mutex));
6387 
6388 	table = dict_table_get_low(req_schema->table_name);
6389 
6390 	if (table == NULL) {
6391 		/* no such table */
6392 
6393 		ut_snprintf(errstr, errstr_sz,
6394 			    "Table %s not found.",
6395 			    ut_format_name(req_schema->table_name,
6396 					   buf, sizeof(buf)));
6397 
6398 		return(DB_TABLE_NOT_FOUND);
6399 	}
6400 
6401 	if (!table->is_readable() &&
6402 	    fil_space_get(table->space) == NULL) {
6403 		/* missing tablespace */
6404 
6405 		ut_snprintf(errstr, errstr_sz,
6406 			    "Tablespace for table %s is missing.",
6407 			    ut_format_name(req_schema->table_name,
6408 					   buf, sizeof(buf)));
6409 
6410 		return(DB_TABLE_NOT_FOUND);
6411 	}
6412 
6413 	ulint n_sys_cols = dict_table_get_n_sys_cols(table);
6414 	if ((ulint) table->n_def - n_sys_cols != req_schema->n_cols) {
6415 		/* the table has a different number of columns than required */
6416 		ut_snprintf(errstr, errstr_sz,
6417 			    "%s has %lu columns but should have %lu.",
6418 			    ut_format_name(req_schema->table_name,
6419 					   buf, sizeof(buf)),
6420 			    table->n_def - n_sys_cols,
6421 			    req_schema->n_cols);
6422 
6423 		return(DB_ERROR);
6424 	}
6425 
6426 	/* For each column from req_schema->columns[] search
6427 	whether it is present in table->cols[].
6428 	The following algorithm is O(n_cols^2), but is optimized to
6429 	be O(n_cols) if the columns are in the same order in both arrays. */
6430 
6431 	for (i = 0; i < req_schema->n_cols; i++) {
6432 		ulint	j = dict_table_has_column(
6433 			table, req_schema->columns[i].name, i);
6434 
6435 		if (j == table->n_def) {
6436 
6437 			ut_snprintf(errstr, errstr_sz,
6438 				    "required column %s"
6439 				    " not found in table %s.",
6440 				    req_schema->columns[i].name,
6441 				    ut_format_name(
6442 					    req_schema->table_name,
6443 					    buf, sizeof(buf)));
6444 
6445 			return(DB_ERROR);
6446 		}
6447 
6448 		/* we found a column with the same name on j'th position,
6449 		compare column types and flags */
6450 
6451 		/* check length for exact match */
6452 		if (req_schema->columns[i].len != table->cols[j].len) {
6453 
6454 			if(!strcmp(req_schema->table_name, TABLE_STATS_NAME)
6455 			   || !strcmp(req_schema->table_name, INDEX_STATS_NAME)) {
6456 				ut_ad(table->cols[j].len <
6457 					req_schema->columns[i].len);
6458 				ib::warn() << "Table " << req_schema->table_name
6459 					   << " has length mismatch in the"
6460 					   << " column name "
6461 					   << req_schema->columns[i].name
6462 					   << ".  Please run mysql_upgrade";
6463 			} else {
6464 
6465 				CREATE_TYPES_NAMES();
6466 
6467 				ut_snprintf(errstr, errstr_sz,
6468 				    "Column %s in table %s is %s"
6469 				    " but should be %s (length mismatch).",
6470 				    req_schema->columns[i].name,
6471 				    ut_format_name(req_schema->table_name,
6472 						   buf, sizeof(buf)),
6473 				    actual_type, req_type);
6474 
6475 				return(DB_ERROR);
6476 			}
6477 		}
6478 
6479 		/* check mtype for exact match */
6480 		if (req_schema->columns[i].mtype != table->cols[j].mtype) {
6481 
6482 			CREATE_TYPES_NAMES();
6483 
6484 			ut_snprintf(errstr, errstr_sz,
6485 				    "Column %s in table %s is %s"
6486 				    " but should be %s (type mismatch).",
6487 				    req_schema->columns[i].name,
6488 				    ut_format_name(req_schema->table_name,
6489 						   buf, sizeof(buf)),
6490 				    actual_type, req_type);
6491 
6492 			return(DB_ERROR);
6493 		}
6494 
6495 		/* check whether required prtype mask is set */
6496 		if (req_schema->columns[i].prtype_mask != 0
6497 		    && (table->cols[j].prtype
6498 			& req_schema->columns[i].prtype_mask)
6499 		       != req_schema->columns[i].prtype_mask) {
6500 
6501 			CREATE_TYPES_NAMES();
6502 
6503 			ut_snprintf(errstr, errstr_sz,
6504 				    "Column %s in table %s is %s"
6505 				    " but should be %s (flags mismatch).",
6506 				    req_schema->columns[i].name,
6507 				    ut_format_name(req_schema->table_name,
6508 						   buf, sizeof(buf)),
6509 				    actual_type, req_type);
6510 
6511 			return(DB_ERROR);
6512 		}
6513 
6514 		/* check whether column has the same COMPRESSED attriute */
6515 		if ((req_schema->columns[i].prtype_mask & DATA_COMPRESSED) !=
6516 			(table->cols[j].prtype & DATA_COMPRESSED)) {
6517 
6518 			ut_snprintf(errstr, errstr_sz,
6519 				"Column %s in table %s has "
6520 				"unexpected COMPRESSED attribute.",
6521 				req_schema->columns[i].name,
6522 				ut_format_name(req_schema->table_name,
6523 					buf, sizeof(buf)));
6524 
6525 			return(DB_ERROR);
6526 		}
6527 	}
6528 
6529 	if (req_schema->n_foreign != table->foreign_set.size()) {
6530 		ut_snprintf(
6531 			errstr, errstr_sz,
6532 			"Table %s has " ULINTPF " foreign key(s) pointing"
6533 			" to other tables, but it must have %lu.",
6534 			ut_format_name(req_schema->table_name,
6535 				       buf, sizeof(buf)),
6536 			static_cast<ulint>(table->foreign_set.size()),
6537 			req_schema->n_foreign);
6538 		return(DB_ERROR);
6539 	}
6540 
6541 	if (req_schema->n_referenced != table->referenced_set.size()) {
6542 		ut_snprintf(
6543 			errstr, errstr_sz,
6544 			"There are " ULINTPF " foreign key(s) pointing to %s, "
6545 			"but there must be %lu.",
6546 			static_cast<ulint>(table->referenced_set.size()),
6547 			ut_format_name(req_schema->table_name,
6548 				       buf, sizeof(buf)),
6549 			req_schema->n_referenced);
6550 		return(DB_ERROR);
6551 	}
6552 
6553 	return(DB_SUCCESS);
6554 }
6555 /* @} */
6556 
6557 /*********************************************************************//**
6558 Converts a database and table name from filesystem encoding
6559 (e.g. d@i1b/a@q1b@1Kc, same format as used in dict_table_t::name) in two
6560 strings in UTF8 encoding (e.g. dцb and aюbØc). The output buffers must be
6561 at least MAX_DB_UTF8_LEN and MAX_TABLE_UTF8_LEN bytes. */
6562 void
dict_fs2utf8(const char * db_and_table,char * db_utf8,size_t db_utf8_size,char * table_utf8,size_t table_utf8_size)6563 dict_fs2utf8(
6564 /*=========*/
6565 	const char*	db_and_table,	/*!< in: database and table names,
6566 					e.g. d@i1b/a@q1b@1Kc */
6567 	char*		db_utf8,	/*!< out: database name, e.g. dцb */
6568 	size_t		db_utf8_size,	/*!< in: dbname_utf8 size */
6569 	char*		table_utf8,	/*!< out: table name, e.g. aюbØc */
6570 	size_t		table_utf8_size)/*!< in: table_utf8 size */
6571 {
6572 	char	db[MAX_DATABASE_NAME_LEN + 1];
6573 	ulint	db_len;
6574 	uint	errors;
6575 
6576 	db_len = dict_get_db_name_len(db_and_table);
6577 
6578 	ut_a(db_len <= sizeof(db));
6579 
6580 	memcpy(db, db_and_table, db_len);
6581 	db[db_len] = '\0';
6582 
6583 	strconvert(
6584 		&my_charset_filename, db, system_charset_info,
6585 		db_utf8, db_utf8_size, &errors);
6586 
6587 	/* convert each # to @0023 in table name and store the result in buf */
6588 	const char*	table = dict_remove_db_name(db_and_table);
6589 	const char*	table_p;
6590 	char		buf[MAX_TABLE_NAME_LEN * 5 + 1];
6591 	char*		buf_p;
6592 	for (table_p = table, buf_p = buf; table_p[0] != '\0'; table_p++) {
6593 		if (table_p[0] != '#') {
6594 			buf_p[0] = table_p[0];
6595 			buf_p++;
6596 		} else {
6597 			buf_p[0] = '@';
6598 			buf_p[1] = '0';
6599 			buf_p[2] = '0';
6600 			buf_p[3] = '2';
6601 			buf_p[4] = '3';
6602 			buf_p += 5;
6603 		}
6604 		ut_a((size_t) (buf_p - buf) < sizeof(buf));
6605 	}
6606 	buf_p[0] = '\0';
6607 
6608 	errors = 0;
6609 	strconvert(
6610 		&my_charset_filename, buf, system_charset_info,
6611 		table_utf8, table_utf8_size,
6612 		&errors);
6613 
6614 	if (errors != 0) {
6615 		ut_snprintf(table_utf8, table_utf8_size, "%s%s",
6616 			    srv_mysql50_table_name_prefix, table);
6617 	}
6618 }
6619 
6620 /** Resize the hash tables besed on the current buffer pool size. */
6621 void
dict_resize()6622 dict_resize()
6623 {
6624 	dict_table_t*	table;
6625 
6626 	mutex_enter(&dict_sys->mutex);
6627 
6628 	/* all table entries are in table_LRU and table_non_LRU lists */
6629 	hash_table_free(dict_sys->table_hash);
6630 	hash_table_free(dict_sys->table_id_hash);
6631 
6632 	dict_sys->table_hash = hash_create(
6633 		buf_pool_get_curr_size()
6634 		/ (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE));
6635 
6636 	dict_sys->table_id_hash = hash_create(
6637 		buf_pool_get_curr_size()
6638 		/ (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE));
6639 
6640 	dict_sys->hash_size = (hash_get_n_cells(dict_sys->table_hash)
6641 			       + hash_get_n_cells(dict_sys->table_id_hash))
6642 		* sizeof(hash_cell_t);
6643 
6644 	for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU); table;
6645 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
6646 		ulint	fold = ut_fold_string(table->name.m_name);
6647 		ulint	id_fold = ut_fold_ull(table->id);
6648 
6649 		HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash,
6650 			    fold, table);
6651 
6652 		HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
6653 			    id_fold, table);
6654 	}
6655 
6656 	for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU); table;
6657 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
6658 		ulint	fold = ut_fold_string(table->name.m_name);
6659 		ulint	id_fold = ut_fold_ull(table->id);
6660 
6661 		HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash,
6662 			    fold, table);
6663 
6664 		HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
6665 			    id_fold, table);
6666 	}
6667 
6668 	mutex_exit(&dict_sys->mutex);
6669 }
6670 
6671 /**********************************************************************//**
6672 Closes the data dictionary module. */
6673 void
dict_close(void)6674 dict_close(void)
6675 /*============*/
6676 {
6677 	ulint	i;
6678 
6679 	/* Free the hash elements. We don't remove them from the table
6680 	because we are going to destroy the table anyway. */
6681 	for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
6682 		dict_table_t*	table;
6683 
6684 		table = static_cast<dict_table_t*>(
6685 			HASH_GET_FIRST(dict_sys->table_hash, i));
6686 
6687 		while (table) {
6688 			dict_table_t*	prev_table = table;
6689 
6690 			table = static_cast<dict_table_t*>(
6691 				HASH_GET_NEXT(name_hash, prev_table));
6692 			ut_ad(prev_table->magic_n == DICT_TABLE_MAGIC_N);
6693 			/* Acquire only because it's a pre-condition. */
6694 			mutex_enter(&dict_sys->mutex);
6695 
6696 			dict_table_remove_from_cache(prev_table);
6697 
6698 			mutex_exit(&dict_sys->mutex);
6699 		}
6700 	}
6701 
6702 	hash_table_free(dict_sys->table_hash);
6703 
6704 	/* The elements are the same instance as in dict_sys->table_hash,
6705 	therefore we don't delete the individual elements. */
6706 	hash_table_free(dict_sys->table_id_hash);
6707 
6708 	dict_ind_free();
6709 
6710 	mutex_free(&dict_sys->mutex);
6711 
6712 	rw_lock_free(dict_operation_lock);
6713 
6714 	ut_free(dict_operation_lock);
6715 	dict_operation_lock = NULL;
6716 
6717 	mutex_free(&dict_foreign_err_mutex);
6718 
6719 	delete dict_sys->autoinc_map;
6720 
6721 	ut_ad(dict_sys->size == 0);
6722 
6723 	ut_free(dict_sys);
6724 
6725 	dict_sys = NULL;
6726 }
6727 
6728 #ifdef UNIV_DEBUG
6729 /**********************************************************************//**
6730 Validate the dictionary table LRU list.
6731 @return TRUE if valid */
6732 static
6733 ibool
dict_lru_validate(void)6734 dict_lru_validate(void)
6735 /*===================*/
6736 {
6737 	dict_table_t*	table;
6738 
6739 	ut_ad(mutex_own(&dict_sys->mutex));
6740 
6741 	for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
6742 	     table != NULL;
6743 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
6744 
6745 		ut_a(table->can_be_evicted);
6746 	}
6747 
6748 	for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU);
6749 	     table != NULL;
6750 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
6751 
6752 		ut_a(!table->can_be_evicted);
6753 	}
6754 
6755 	return(TRUE);
6756 }
6757 
6758 /**********************************************************************//**
6759 Check if a table exists in the dict table LRU list.
6760 @return TRUE if table found in LRU list */
6761 static
6762 ibool
dict_lru_find_table(const dict_table_t * find_table)6763 dict_lru_find_table(
6764 /*================*/
6765 	const dict_table_t*	find_table)	/*!< in: table to find */
6766 {
6767 	dict_table_t*		table;
6768 
6769 	ut_ad(find_table != NULL);
6770 	ut_ad(mutex_own(&dict_sys->mutex));
6771 
6772 	for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
6773 	     table != NULL;
6774 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
6775 
6776 		ut_a(table->can_be_evicted);
6777 
6778 		if (table == find_table) {
6779 			return(TRUE);
6780 		}
6781 	}
6782 
6783 	return(FALSE);
6784 }
6785 
6786 /**********************************************************************//**
6787 Check if a table exists in the dict table non-LRU list.
6788 @return TRUE if table found in non-LRU list */
6789 static
6790 ibool
dict_non_lru_find_table(const dict_table_t * find_table)6791 dict_non_lru_find_table(
6792 /*====================*/
6793 	const dict_table_t*	find_table)	/*!< in: table to find */
6794 {
6795 	dict_table_t*		table;
6796 
6797 	ut_ad(find_table != NULL);
6798 	ut_ad(mutex_own(&dict_sys->mutex));
6799 
6800 	for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU);
6801 	     table != NULL;
6802 	     table = UT_LIST_GET_NEXT(table_LRU, table)) {
6803 
6804 		ut_a(!table->can_be_evicted);
6805 
6806 		if (table == find_table) {
6807 			return(TRUE);
6808 		}
6809 	}
6810 
6811 	return(FALSE);
6812 }
6813 #endif /* UNIV_DEBUG */
6814 /*********************************************************************//**
6815 Check an index to see whether its first fields are the columns in the array,
6816 in the same order and is not marked for deletion and is not the same
6817 as types_idx.
6818 @return true if the index qualifies, otherwise false */
6819 bool
dict_foreign_qualify_index(const dict_table_t * table,const char ** col_names,const char ** columns,ulint n_cols,const dict_index_t * index,const dict_index_t * types_idx,bool check_charsets,ulint check_null)6820 dict_foreign_qualify_index(
6821 /*=======================*/
6822 	const dict_table_t*	table,	/*!< in: table */
6823 	const char**		col_names,
6824 					/*!< in: column names, or NULL
6825 					to use table->col_names */
6826 	const char**		columns,/*!< in: array of column names */
6827 	ulint			n_cols,	/*!< in: number of columns */
6828 	const dict_index_t*	index,	/*!< in: index to check */
6829 	const dict_index_t*	types_idx,
6830 					/*!< in: NULL or an index
6831 					whose types the column types
6832 					must match */
6833 	bool			check_charsets,
6834 					/*!< in: whether to check
6835 					charsets.  only has an effect
6836 					if types_idx != NULL */
6837 	ulint			check_null)
6838 					/*!< in: nonzero if none of
6839 					the columns must be declared
6840 					NOT NULL */
6841 {
6842 	if (dict_index_get_n_fields(index) < n_cols) {
6843 		return(false);
6844 	}
6845 
6846 	if (index->type & DICT_SPATIAL) {
6847 		/* Spatial index cannot be used as foreign keys */
6848 		return(false);
6849 	}
6850 
6851 	for (ulint i = 0; i < n_cols; i++) {
6852 		dict_field_t*	field;
6853 		const char*	col_name;
6854 		ulint		col_no;
6855 
6856 		field = dict_index_get_nth_field(index, i);
6857 		col_no = dict_col_get_no(field->col);
6858 
6859 		if (field->prefix_len != 0) {
6860 			/* We do not accept column prefix
6861 			indexes here */
6862 			return(false);
6863 		}
6864 
6865 		if (check_null
6866 		    && (field->col->prtype & DATA_NOT_NULL)) {
6867 			return(false);
6868 		}
6869 
6870 		col_name = col_names
6871 			? col_names[col_no]
6872 			: dict_table_get_col_name(table, col_no);
6873 
6874 		if (0 != innobase_strcasecmp(columns[i], col_name)) {
6875 			return(false);
6876 		}
6877 
6878 		if (types_idx && !cmp_cols_are_equal(
6879 			    dict_index_get_nth_col(index, i),
6880 			    dict_index_get_nth_col(types_idx, i),
6881 			    check_charsets)) {
6882 			return(false);
6883 		}
6884 	}
6885 
6886 	return(true);
6887 }
6888 
6889 /*********************************************************************//**
6890 Update the state of compression failure padding heuristics. This is
6891 called whenever a compression operation succeeds or fails.
6892 The caller must be holding info->mutex */
6893 static
6894 void
dict_index_zip_pad_update(zip_pad_info_t * info,ulint zip_threshold)6895 dict_index_zip_pad_update(
6896 /*======================*/
6897 	zip_pad_info_t*	info,	/*<! in/out: info to be updated */
6898 	ulint	zip_threshold)	/*<! in: zip threshold value */
6899 {
6900 	ulint	total;
6901 	ulint	fail_pct;
6902 
6903 	ut_ad(info);
6904 
6905 	total = info->success + info->failure;
6906 
6907 	ut_ad(total > 0);
6908 
6909 	if (zip_threshold == 0) {
6910 		/* User has just disabled the padding. */
6911 		return;
6912 	}
6913 
6914 	if (total < ZIP_PAD_ROUND_LEN) {
6915 		/* We are in middle of a round. Do nothing. */
6916 		return;
6917 	}
6918 
6919 	/* We are at a 'round' boundary. Reset the values but first
6920 	calculate fail rate for our heuristic. */
6921 	fail_pct = (info->failure * 100) / total;
6922 	info->failure = 0;
6923 	info->success = 0;
6924 
6925 	if (fail_pct > zip_threshold) {
6926 		/* Compression failures are more then user defined
6927 		threshold. Increase the pad size to reduce chances of
6928 		compression failures. */
6929 		ut_ad(info->pad % ZIP_PAD_INCR == 0);
6930 
6931 		/* Only do increment if it won't increase padding
6932 		beyond max pad size. */
6933 		if (info->pad + ZIP_PAD_INCR
6934 		    < (UNIV_PAGE_SIZE * zip_pad_max) / 100) {
6935 			/* Use atomics even though we have the mutex.
6936 			This is to ensure that we are able to read
6937 			info->pad atomically. */
6938 			os_atomic_increment_ulint(&info->pad, ZIP_PAD_INCR);
6939 
6940 			MONITOR_INC(MONITOR_PAD_INCREMENTS);
6941 		}
6942 
6943 		info->n_rounds = 0;
6944 
6945 	} else {
6946 		/* Failure rate was OK. Another successful round
6947 		completed. */
6948 		++info->n_rounds;
6949 
6950 		/* If enough successful rounds are completed with
6951 		compression failure rate in control, decrease the
6952 		padding. */
6953 		if (info->n_rounds >= ZIP_PAD_SUCCESSFUL_ROUND_LIMIT
6954 		    && info->pad > 0) {
6955 
6956 			ut_ad(info->pad % ZIP_PAD_INCR == 0);
6957 			/* Use atomics even though we have the mutex.
6958 			This is to ensure that we are able to read
6959 			info->pad atomically. */
6960 			os_atomic_decrement_ulint(&info->pad, ZIP_PAD_INCR);
6961 
6962 			info->n_rounds = 0;
6963 
6964 			MONITOR_INC(MONITOR_PAD_DECREMENTS);
6965 		}
6966 	}
6967 }
6968 
6969 /*********************************************************************//**
6970 This function should be called whenever a page is successfully
6971 compressed. Updates the compression padding information. */
6972 void
dict_index_zip_success(dict_index_t * index)6973 dict_index_zip_success(
6974 /*===================*/
6975 	dict_index_t*	index)	/*!< in/out: index to be updated. */
6976 {
6977 	ut_ad(index);
6978 
6979 	ulint zip_threshold = zip_failure_threshold_pct;
6980 	if (!zip_threshold) {
6981 		/* Disabled by user. */
6982 		return;
6983 	}
6984 
6985 	dict_index_zip_pad_lock(index);
6986 	++index->zip_pad.success;
6987 	dict_index_zip_pad_update(&index->zip_pad, zip_threshold);
6988 	dict_index_zip_pad_unlock(index);
6989 }
6990 
6991 /*********************************************************************//**
6992 This function should be called whenever a page compression attempt
6993 fails. Updates the compression padding information. */
6994 void
dict_index_zip_failure(dict_index_t * index)6995 dict_index_zip_failure(
6996 /*===================*/
6997 	dict_index_t*	index)	/*!< in/out: index to be updated. */
6998 {
6999 	ut_ad(index);
7000 
7001 	ulint zip_threshold = zip_failure_threshold_pct;
7002 	if (!zip_threshold) {
7003 		/* Disabled by user. */
7004 		return;
7005 	}
7006 
7007 	dict_index_zip_pad_lock(index);
7008 	++index->zip_pad.failure;
7009 	dict_index_zip_pad_update(&index->zip_pad, zip_threshold);
7010 	dict_index_zip_pad_unlock(index);
7011 }
7012 
7013 
7014 /*********************************************************************//**
7015 Return the optimal page size, for which page will likely compress.
7016 @return page size beyond which page might not compress */
7017 ulint
dict_index_zip_pad_optimal_page_size(dict_index_t * index)7018 dict_index_zip_pad_optimal_page_size(
7019 /*=================================*/
7020 	dict_index_t*	index)	/*!< in: index for which page size
7021 				is requested */
7022 {
7023 	ulint	pad;
7024 	ulint	min_sz;
7025 	ulint	sz;
7026 
7027 	ut_ad(index);
7028 
7029 	if (!zip_failure_threshold_pct) {
7030 		/* Disabled by user. */
7031 		return(UNIV_PAGE_SIZE);
7032 	}
7033 
7034 	/* We use atomics to read index->zip_pad.pad. Here we use zero
7035 	as increment as are not changing the value of the 'pad'. */
7036 
7037 	pad = os_atomic_increment_ulint(&index->zip_pad.pad, 0);
7038 
7039 	ut_ad(pad < UNIV_PAGE_SIZE);
7040 	sz = UNIV_PAGE_SIZE - pad;
7041 
7042 	/* Min size allowed by user. */
7043 	ut_ad(zip_pad_max < 100);
7044 	min_sz = (UNIV_PAGE_SIZE * (100 - zip_pad_max)) / 100;
7045 
7046 	return(ut_max(sz, min_sz));
7047 }
7048 
7049 /** Convert a 32 bit integer table flags to the 32 bit FSP Flags.
7050 Fsp Flags are written into the tablespace header at the offset
7051 FSP_SPACE_FLAGS and are also stored in the fil_space_t::flags field.
7052 The following chart shows the translation of the low order bit.
7053 Other bits are the same.
7054 			Low order bit
7055 		    | REDUNDANT | COMPACT | COMPRESSED | DYNAMIC
7056 dict_table_t::flags |     0     |    1    |     1      |    1
7057 fil_space_t::flags  |     0     |    0    |     1      |    1
7058 @param[in]	table_flags	dict_table_t::flags
7059 @param[in]	is_temp		whether the tablespace is temporary
7060 @param[in]	is_encrypted	whether the tablespace is encrypted
7061 @return tablespace flags (fil_space_t::flags) */
7062 ulint
dict_tf_to_fsp_flags(ulint table_flags,bool is_temp,bool is_encrypted)7063 dict_tf_to_fsp_flags(
7064 	ulint	table_flags,
7065 	bool	is_temp,
7066 	bool	is_encrypted)
7067 {
7068 	DBUG_EXECUTE_IF("dict_tf_to_fsp_flags_failure",
7069 			return(ULINT_UNDEFINED););
7070 
7071 	bool		has_atomic_blobs =
7072 				 DICT_TF_HAS_ATOMIC_BLOBS(table_flags);
7073 	page_size_t	page_size = dict_tf_get_page_size(table_flags);
7074 	bool		has_data_dir = DICT_TF_HAS_DATA_DIR(table_flags);
7075 	bool		is_shared = DICT_TF_HAS_SHARED_SPACE(table_flags);
7076 
7077 	ut_ad(!page_size.is_compressed() || has_atomic_blobs);
7078 
7079 	/* General tablespaces that are not compressed do not get the
7080 	flags for dynamic row format (POST_ANTELOPE & ATOMIC_BLOBS) */
7081 	if (is_shared && !page_size.is_compressed()) {
7082 		has_atomic_blobs = false;
7083 	}
7084 
7085 	ulint		fsp_flags = fsp_flags_init(page_size,
7086 						   has_atomic_blobs,
7087 						   has_data_dir,
7088 						   is_shared,
7089 						   is_temp,
7090 						   is_encrypted);
7091 
7092 	return(fsp_flags);
7093 }
7094 
7095 /*************************************************************//**
7096 Convert table flag to row format string.
7097 @return row format name. */
7098 const char*
dict_tf_to_row_format_string(ulint table_flag)7099 dict_tf_to_row_format_string(
7100 /*=========================*/
7101 	ulint	table_flag)		/*!< in: row format setting */
7102 {
7103 	switch (dict_tf_get_rec_format(table_flag)) {
7104 	case REC_FORMAT_REDUNDANT:
7105 		return("ROW_TYPE_REDUNDANT");
7106 	case REC_FORMAT_COMPACT:
7107 		return("ROW_TYPE_COMPACT");
7108 	case REC_FORMAT_COMPRESSED:
7109 		return("ROW_TYPE_COMPRESSED");
7110 	case REC_FORMAT_DYNAMIC:
7111 		return("ROW_TYPE_DYNAMIC");
7112 	}
7113 
7114 	ut_error;
7115 	return(0);
7116 }
7117 
7118 /** Look for any dictionary objects that are found in the given tablespace.
7119 @param[in]	space_id	Tablespace ID to search for.
7120 @return true if tablespace is empty. */
7121 bool
dict_space_is_empty(ulint space_id)7122 dict_space_is_empty(
7123 	ulint	space_id)
7124 {
7125 	btr_pcur_t	pcur;
7126 	const rec_t*	rec;
7127 	mtr_t		mtr;
7128 	bool		found = false;
7129 
7130 	rw_lock_x_lock(dict_operation_lock);
7131 	mutex_enter(&dict_sys->mutex);
7132 	mtr_start(&mtr);
7133 
7134 	for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
7135 	     rec != NULL;
7136 	     rec = dict_getnext_system(&pcur, &mtr)) {
7137 		const byte*	field;
7138 		ulint		len;
7139 		ulint		space_id_for_table;
7140 
7141 		field = rec_get_nth_field_old(
7142 			rec, DICT_FLD__SYS_TABLES__SPACE, &len);
7143 		ut_ad(len == 4);
7144 		space_id_for_table = mach_read_from_4(field);
7145 
7146 		if (space_id_for_table == space_id) {
7147 			found = true;
7148 		}
7149 	}
7150 
7151 	mtr_commit(&mtr);
7152 	mutex_exit(&dict_sys->mutex);
7153 	rw_lock_x_unlock(dict_operation_lock);
7154 
7155 	return(!found);
7156 }
7157 
7158 /** Find the space_id for the given name in sys_tablespaces.
7159 @param[in]	name	Tablespace name to search for.
7160 @return the tablespace ID. */
7161 ulint
dict_space_get_id(const char * name)7162 dict_space_get_id(
7163 	const char*	name)
7164 {
7165 	btr_pcur_t	pcur;
7166 	const rec_t*	rec;
7167 	mtr_t		mtr;
7168 	ulint		name_len = strlen(name);
7169 	ulint		id = ULINT_UNDEFINED;
7170 
7171 	rw_lock_x_lock(dict_operation_lock);
7172 	mutex_enter(&dict_sys->mutex);
7173 	mtr_start(&mtr);
7174 
7175 	for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES);
7176 	     rec != NULL;
7177 	     rec = dict_getnext_system(&pcur, &mtr)) {
7178 		const byte*	field;
7179 		ulint		len;
7180 
7181 		field = rec_get_nth_field_old(
7182 			rec, DICT_FLD__SYS_TABLESPACES__NAME, &len);
7183 		ut_ad(len > 0);
7184 		ut_ad(len < OS_FILE_MAX_PATH);
7185 
7186 		if (len == name_len && ut_memcmp(name, field, len) == 0) {
7187 
7188 			field = rec_get_nth_field_old(
7189 				rec, DICT_FLD__SYS_TABLESPACES__SPACE, &len);
7190 			ut_ad(len == 4);
7191 			id = mach_read_from_4(field);
7192 
7193 			/* This is normally called by dict_getnext_system()
7194 			at the end of the index. */
7195 			btr_pcur_close(&pcur);
7196 			break;
7197 		}
7198 	}
7199 
7200 	mtr_commit(&mtr);
7201 	mutex_exit(&dict_sys->mutex);
7202 	rw_lock_x_unlock(dict_operation_lock);
7203 
7204 	return(id);
7205 }
7206 #endif /* !UNIV_HOTBACKUP */
7207 
7208 /** Determine the extent size (in pages) for the given table
7209 @param[in]	table	the table whose extent size is being
7210 			calculated.
7211 @return extent size in pages (256, 128 or 64) */
7212 ulint
dict_table_extent_size(const dict_table_t * table)7213 dict_table_extent_size(
7214 	const dict_table_t*	table)
7215 {
7216 	const ulint	mb_1 = 1024 * 1024;
7217 	const ulint	mb_2 = 2 * mb_1;
7218 	const ulint	mb_4 = 4 * mb_1;
7219 
7220 	page_size_t	page_size = dict_table_page_size(table);
7221 	ulint	pages_in_extent = FSP_EXTENT_SIZE;
7222 
7223 	if (page_size.is_compressed()) {
7224 
7225 		ulint	disk_page_size	= page_size.physical();
7226 
7227 		switch (disk_page_size) {
7228 		case 1024:
7229 			pages_in_extent = mb_1/1024;
7230 			break;
7231 		case 2048:
7232 			pages_in_extent = mb_1/2048;
7233 			break;
7234 		case 4096:
7235 			pages_in_extent = mb_1/4096;
7236 			break;
7237 		case 8192:
7238 			pages_in_extent = mb_1/8192;
7239 			break;
7240 		case 16384:
7241 			pages_in_extent = mb_1/16384;
7242 			break;
7243 		case 32768:
7244 			pages_in_extent = mb_2/32768;
7245 			break;
7246 		case 65536:
7247 			pages_in_extent = mb_4/65536;
7248 			break;
7249 		default:
7250 			ut_ad(0);
7251 		}
7252 	}
7253 
7254 	return(pages_in_extent);
7255 }
7256 
7257 /** Insert a records into SYS_ZIP_DICT.
7258 @retval	DB_SUCCESS	if OK
7259 @retval	dberr_t		if the insert failed */
7260 dberr_t
dict_create_zip_dict(const char * name,ulint name_len,const char * data,ulint data_len)7261 dict_create_zip_dict(
7262 	const char*	name,		/*!< in: zip_dict name */
7263 	ulint		name_len,	/*!< in: zip_dict name length*/
7264 	const char*	data,		/*!< in: zip_dict data */
7265 	ulint		data_len)	/*!< in: zip_dict data length */
7266 {
7267 	dberr_t		err = DB_SUCCESS;
7268 	trx_t*		trx;
7269 
7270 	ut_ad(name);
7271 	ut_ad(data);
7272 
7273 	rw_lock_x_lock(dict_operation_lock);
7274 	dict_mutex_enter_for_mysql();
7275 
7276 	trx = trx_allocate_for_background();
7277 	trx->op_info = "insert zip_dict";
7278 	trx->dict_operation_lock_mode = RW_X_LATCH;
7279 	trx_start_if_not_started(trx, true);
7280 
7281 	err = dict_create_add_zip_dict(name, name_len, data, data_len, trx);
7282 
7283 	if (err == DB_SUCCESS) {
7284 		trx_commit_for_mysql(trx);
7285 	}
7286 	else {
7287 		trx->op_info = "rollback of internal trx on zip_dict table";
7288 		trx_rollback_to_savepoint(trx, NULL);
7289 		ut_a(trx->error_state == DB_SUCCESS);
7290 	}
7291 	trx->op_info = "";
7292 	trx->dict_operation_lock_mode = 0;
7293 	trx_free_for_background(trx);
7294 
7295 	dict_mutex_exit_for_mysql();
7296 	rw_lock_x_unlock(dict_operation_lock);
7297 
7298 	return err;
7299 }
7300 /** Get single compression dictionary id for the given
7301 (table id, column pos) pair.
7302 @retval	DB_SUCCESS		if OK
7303 @retval	DB_RECORD_NOT_FOUND	if not found */
7304 dberr_t
dict_get_dictionary_id_by_key(table_id_t table_id,ulint column_pos,ulint * dict_id,bool dict_locked)7305 dict_get_dictionary_id_by_key(
7306 	table_id_t	table_id,	/*!< in: table id */
7307 	ulint		column_pos,	/*!< in: column position */
7308 	ulint*		dict_id,	/*!< out: zip_dict id */
7309 	bool		dict_locked)	/*!< in: true if data dictionary locked */
7310 {
7311 	dberr_t		err = DB_SUCCESS;
7312 	trx_t*		trx;
7313 	bool		dict_operation_locked = dict_locked;
7314 	DBUG_EXECUTE_IF("ib_purge_virtual_index_callback",
7315 		dict_operation_locked = true; );
7316 
7317 	if (!dict_operation_locked) {
7318 		rw_lock_s_lock(dict_operation_lock);
7319 	}
7320 	if (!dict_locked) {
7321 		dict_mutex_enter_for_mysql();
7322 	}
7323 
7324 	trx = trx_allocate_for_background();
7325 	trx->op_info = "get zip dict id by composite key";
7326 	trx->dict_operation_lock_mode = RW_S_LATCH;
7327 	trx_start_if_not_started(trx, false);
7328 
7329 	err = dict_create_get_zip_dict_id_by_reference(table_id, column_pos,
7330 		dict_id, trx);
7331 
7332 	trx_commit_for_mysql(trx);
7333 	trx->dict_operation_lock_mode = 0;
7334 	trx_free_for_background(trx);
7335 
7336 	if (!dict_locked) {
7337 		dict_mutex_exit_for_mysql();
7338 	}
7339 	if (!dict_operation_locked) {
7340 		rw_lock_s_unlock(dict_operation_lock);
7341 	}
7342 
7343 	return err;
7344 }
7345 /** Get compression dictionary info (name and data) for the given id.
7346 Allocates memory in name->str and data->str on success.
7347 Must be freed with mem_free().
7348 @retval	DB_SUCCESS		if OK
7349 @retval	DB_RECORD_NOT_FOUND	if not found */
7350 dberr_t
dict_get_dictionary_info_by_id(ulint dict_id,char ** name,ulint * name_len,char ** data,ulint * data_len,bool dict_locked)7351 dict_get_dictionary_info_by_id(
7352 	ulint	dict_id,	/*!< in: dictionary id */
7353 	char**	name,		/*!< out: dictionary name */
7354 	ulint*	name_len,	/*!< out: dictionary name length*/
7355 	char**	data,		/*!< out: dictionary data */
7356 	ulint*	data_len,	/*!< out: dictionary data length*/
7357 	bool	dict_locked)	/*!< in: true if data dictionary locked */
7358 {
7359 	dberr_t		err = DB_SUCCESS;
7360 	trx_t*		trx;
7361 	bool		dict_operation_locked = dict_locked;
7362 	DBUG_EXECUTE_IF("ib_purge_virtual_index_callback",
7363 		dict_operation_locked = true; );
7364 
7365 	if (!dict_operation_locked) {
7366 		rw_lock_s_lock(dict_operation_lock);
7367 	}
7368 	if (!dict_locked) {
7369 		dict_mutex_enter_for_mysql();
7370 	}
7371 
7372 	trx = trx_allocate_for_background();
7373 	trx->op_info = "get zip dict name and data by id";
7374 	trx->dict_operation_lock_mode = RW_S_LATCH;
7375 	trx_start_if_not_started(trx, false);
7376 
7377 	err = dict_create_get_zip_dict_info_by_id(dict_id, name, name_len,
7378 		data, data_len, trx);
7379 
7380 	trx_commit_for_mysql(trx);
7381 	trx->dict_operation_lock_mode = 0;
7382 	trx_free_for_background(trx);
7383 
7384 	if (!dict_locked) {
7385 		dict_mutex_exit_for_mysql();
7386 	}
7387 	if (!dict_operation_locked) {
7388 		rw_lock_s_unlock(dict_operation_lock);
7389 	}
7390 
7391 	return err;
7392 }
7393 /** Delete a record in SYS_ZIP_DICT with the given name.
7394 @retval	DB_SUCCESS		if OK
7395 @retval	DB_RECORD_NOT_FOUND	if not found
7396 @retval	DB_ROW_IS_REFERENCED	if in use */
7397 dberr_t
dict_drop_zip_dict(const char * name,ulint name_len)7398 dict_drop_zip_dict(
7399 	const char*	name,		/*!< in: zip_dict name */
7400 	ulint		name_len)	/*!< in: zip_dict name length*/
7401 {
7402 	dberr_t		err = DB_SUCCESS;
7403 	trx_t*		trx;
7404 
7405 	ut_ad(name);
7406 
7407 	rw_lock_x_lock(dict_operation_lock);
7408 	dict_mutex_enter_for_mysql();
7409 
7410 	trx = trx_allocate_for_background();
7411 	trx->op_info = "delete zip_dict";
7412 	trx->dict_operation_lock_mode = RW_X_LATCH;
7413 	trx_start_if_not_started(trx, true);
7414 
7415 	err = dict_create_remove_zip_dict(name, name_len, trx);
7416 
7417 	if (err == DB_SUCCESS) {
7418 		trx_commit_for_mysql(trx);
7419 	}
7420 	else {
7421 		trx->op_info = "rollback of internal trx on zip_dict table";
7422 		trx_rollback_to_savepoint(trx, NULL);
7423 		ut_a(trx->error_state == DB_SUCCESS);
7424 	}
7425 	trx->op_info = "";
7426 	trx->dict_operation_lock_mode = 0;
7427 	trx_free_for_background(trx);
7428 
7429 	dict_mutex_exit_for_mysql();
7430 	rw_lock_x_unlock(dict_operation_lock);
7431 
7432 	return err;
7433 }
7434 
7435 /** @return number of base columns of virtual column in foreign key column
7436 @param[in]      vcol    in-memory virtual column
7437 @param[in]      foreign in-memory Foreign key constraint */
dict_vcol_base_is_foreign_key(dict_v_col_t * vcol,dict_foreign_t * foreign)7438 uint32_t dict_vcol_base_is_foreign_key(dict_v_col_t *vcol,
7439                                    dict_foreign_t *foreign) {
7440 
7441 	const dict_table_t *table = foreign->foreign_table;
7442 	uint32_t foreign_col_count = 0;
7443 
7444 	for (uint32_t i = 0; i < foreign->n_fields; i++) {
7445 		const char *foreign_col_name = foreign->foreign_col_names[i];
7446 		for (uint32_t j = 0; j < vcol->num_base; j++) {
7447 			if (innobase_strcasecmp(foreign_col_name,
7448 			    dict_table_get_col_name(table,
7449 			    vcol->base_col[j]->ind)) == 0) {
7450 				foreign_col_count++;
7451 			}
7452 		}
7453 	}
7454 	return foreign_col_count;
7455 }
7456