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