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