MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
dict0dict.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2012, Facebook Inc.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /******************************************************************/
27 #include "dict0dict.h"
28 #include "fts0fts.h"
29 #include "fil0fil.h"
30 
31 #ifdef UNIV_NONINL
32 #include "dict0dict.ic"
33 #include "dict0priv.ic"
34 #endif
35 
40 
41 #ifndef UNIV_HOTBACKUP
42 #include "buf0buf.h"
43 #include "data0type.h"
44 #include "mach0data.h"
45 #include "dict0boot.h"
46 #include "dict0mem.h"
47 #include "dict0crea.h"
48 #include "dict0stats.h"
49 #include "trx0undo.h"
50 #include "btr0btr.h"
51 #include "btr0cur.h"
52 #include "btr0sea.h"
53 #include "page0zip.h"
54 #include "page0page.h"
55 #include "pars0pars.h"
56 #include "pars0sym.h"
57 #include "que0que.h"
58 #include "rem0cmp.h"
59 #include "fts0fts.h"
60 #include "fts0types.h"
61 #include "m_ctype.h" /* my_isspace() */
62 #include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str() */
63 #include "srv0mon.h"
64 #include "srv0start.h"
65 #include "lock0lock.h"
66 #include "dict0priv.h"
67 #include "row0upd.h"
68 #include "row0mysql.h"
69 #include "row0merge.h"
70 #include "row0log.h"
71 #include "ut0ut.h" /* ut_format_name() */
72 #include "m_string.h"
73 #include "my_sys.h"
74 #include "mysqld.h" /* system_charset_info */
75 #include "strfunc.h" /* strconvert() */
76 
77 #include <ctype.h>
78 
80 UNIV_INTERN dict_sys_t* dict_sys = NULL;
81 
91 
94 UNIV_INTERN ulong zip_failure_threshold_pct = 5;
95 
98 UNIV_INTERN ulong zip_pad_max = 50;
99 
100 /* Keys to register rwlocks and mutexes with performance schema */
101 #ifdef UNIV_PFS_RWLOCK
102 UNIV_INTERN mysql_pfs_key_t dict_operation_lock_key;
103 UNIV_INTERN mysql_pfs_key_t index_tree_rw_lock_key;
104 UNIV_INTERN mysql_pfs_key_t index_online_log_key;
105 UNIV_INTERN mysql_pfs_key_t dict_table_stats_latch_key;
106 #endif /* UNIV_PFS_RWLOCK */
107 
108 #ifdef UNIV_PFS_MUTEX
109 UNIV_INTERN mysql_pfs_key_t zip_pad_mutex_key;
110 UNIV_INTERN mysql_pfs_key_t dict_sys_mutex_key;
111 UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key;
112 #endif /* UNIV_PFS_MUTEX */
113 
114 #define DICT_HEAP_SIZE 100
116 #define DICT_POOL_PER_TABLE_HASH 512
118 #define DICT_POOL_PER_VARYING 4
122 static char dict_ibfk[] = "_ibfk_";
123 
134 #define DICT_TABLE_STATS_LATCHES_SIZE 64
135 static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
136 
137 /*******************************************************************/
141 static
142 ibool
143 dict_index_find_cols(
144 /*=================*/
146  dict_index_t* index);
147 /*******************************************************************/
151 static
153 dict_index_build_internal_clust(
154 /*============================*/
155  const dict_table_t* table,
156  dict_index_t* index);
158 /*******************************************************************/
162 static
164 dict_index_build_internal_non_clust(
165 /*================================*/
166  const dict_table_t* table,
167  dict_index_t* index);
169 /**********************************************************************/
172 static
174 dict_index_build_internal_fts(
175 /*==========================*/
177  dict_index_t* index);
178 /**********************************************************************/
180 static
181 void
182 dict_col_print_low(
183 /*===============*/
184  const dict_table_t* table,
185  const dict_col_t* col);
186 /**********************************************************************/
188 static
189 void
190 dict_index_print_low(
191 /*=================*/
192  dict_index_t* index);
193 /**********************************************************************/
195 static
196 void
197 dict_field_print_low(
198 /*=================*/
199  const dict_field_t* field);
201 /**********************************************************************/
203 static
204 void
205 dict_index_remove_from_cache_low(
206 /*=============================*/
209  ibool lru_evict);
211 /**********************************************************************/
213 static
214 void
215 dict_table_remove_from_cache_low(
216 /*=============================*/
218  ibool lru_evict);
219 #ifdef UNIV_DEBUG
220 /**********************************************************************/
223 static
224 ibool
225 dict_lru_validate(void);
226 /*===================*/
227 /**********************************************************************/
230 static
231 ibool
232 dict_lru_find_table(
233 /*================*/
234  const dict_table_t* find_table);
235 /**********************************************************************/
238 static
239 ibool
240 dict_non_lru_find_table(
241 /*====================*/
242  const dict_table_t* find_table);
243 #endif /* UNIV_DEBUG */
244 
245 /* Stream for storing detailed information about the latest foreign key
246 and unique key errors. Only created if !srv_read_only_mode */
247 UNIV_INTERN FILE* dict_foreign_err_file = NULL;
248 /* mutex protecting the foreign and unique error buffers */
249 UNIV_INTERN ib_mutex_t dict_foreign_err_mutex;
250 
251 /******************************************************************/
253 UNIV_INTERN
254 void
256 /*============*/
257  char* a)
258 {
260 }
261 
262 /********************************************************************/
265 UNIV_INTERN
266 ibool
268 /*=====================*/
269  const char* name1,
271  const char* name2)
273 {
274  for (; *name1 == *name2; name1++, name2++) {
275  if (*name1 == '/') {
276  return(TRUE);
277  }
278  ut_a(*name1); /* the names must contain '/' */
279  }
280  return(FALSE);
281 }
282 
283 /********************************************************************/
286 UNIV_INTERN
287 const char*
289 /*================*/
290  const char* name)
292 {
293  const char* s = strchr(name, '/');
294  ut_a(s);
295 
296  return(s + 1);
297 }
298 
299 /********************************************************************/
302 UNIV_INTERN
303 ulint
305 /*=================*/
306  const char* name)
308 {
309  const char* s;
310  s = strchr(name, '/');
311  ut_a(s);
312  return(s - name);
313 }
314 
315 /********************************************************************/
317 UNIV_INTERN
318 void
320 /*============================*/
321 {
322  mutex_enter(&(dict_sys->mutex));
323 }
324 
325 /********************************************************************/
327 UNIV_INTERN
328 void
330 /*===========================*/
331 {
332  mutex_exit(&(dict_sys->mutex));
333 }
334 
336 #define GET_TABLE_STATS_LATCH(table) \
337  (&dict_table_stats_latches[ut_fold_ull((ib_uint64_t) table) \
338  % DICT_TABLE_STATS_LATCHES_SIZE])
339 
340 /**********************************************************************/
344 UNIV_INTERN
345 void
347 /*==================*/
348  const dict_table_t* table,
349  ulint latch_mode)
351 {
352  ut_ad(table != NULL);
353  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
354 
355  switch (latch_mode) {
356  case RW_S_LATCH:
358  break;
359  case RW_X_LATCH:
360  rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
361  break;
362  case RW_NO_LATCH:
363  /* fall through */
364  default:
365  ut_error;
366  }
367 }
368 
369 /**********************************************************************/
371 UNIV_INTERN
372 void
374 /*====================*/
375  const dict_table_t* table,
376  ulint latch_mode)
378 {
379  ut_ad(table != NULL);
380  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
381 
382  switch (latch_mode) {
383  case RW_S_LATCH:
384  rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
385  break;
386  case RW_X_LATCH:
387  rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
388  break;
389  case RW_NO_LATCH:
390  /* fall through */
391  default:
392  ut_error;
393  }
394 }
395 
396 /**********************************************************************/
399 static
400 void
401 dict_table_try_drop_aborted(
402 /*========================*/
405  table_id_t table_id,
406  ulint ref_count)
407 {
408  trx_t* trx;
409 
411  trx->op_info = "try to drop any indexes after an aborted index creation";
412  row_mysql_lock_data_dictionary(trx);
414 
415  if (table == NULL) {
417  table_id, DICT_ERR_IGNORE_NONE);
418  } else {
419  ut_ad(table->id == table_id);
420  }
421 
422  if (table && table->n_ref_count == ref_count && table->drop_aborted) {
423  /* Silence a debug assertion in row_merge_drop_indexes(). */
424  ut_d(table->n_ref_count++);
425  row_merge_drop_indexes(trx, table, TRUE);
426  ut_d(table->n_ref_count--);
427  ut_ad(table->n_ref_count == ref_count);
429  }
430 
433 }
434 
435 /**********************************************************************/
439 static
440 void
441 dict_table_try_drop_aborted_and_mutex_exit(
442 /*=======================================*/
443  dict_table_t* table,
444  ibool try_drop)
447 {
448  if (try_drop
449  && table != NULL
450  && table->drop_aborted
451  && table->n_ref_count == 1
452  && dict_table_get_first_index(table)) {
453 
454  /* Attempt to drop the indexes whose online creation
455  was aborted. */
456  table_id_t table_id = table->id;
457 
458  mutex_exit(&dict_sys->mutex);
459 
460  dict_table_try_drop_aborted(table, table_id, 1);
461  } else {
462  mutex_exit(&dict_sys->mutex);
463  }
464 }
465 
466 /********************************************************************/
468 UNIV_INTERN
469 void
471 /*=============*/
472  dict_table_t* table,
473  ibool dict_locked,
474  ibool try_drop)
477 {
478  if (!dict_locked) {
479  mutex_enter(&dict_sys->mutex);
480  }
481 
482  ut_ad(mutex_own(&dict_sys->mutex));
483  ut_a(table->n_ref_count > 0);
484 
485  --table->n_ref_count;
486 
487  /* Force persistent stats re-read upon next open of the table
488  so that FLUSH TABLE can be used to forcibly fetch stats from disk
489  if they have been manually modified. We reset table->stat_initialized
490  only if table reference count is 0 because we do not want too frequent
491  stats re-reads (e.g. in other cases than FLUSH TABLE). */
492  if (strchr(table->name, '/') != NULL
493  && table->n_ref_count == 0
495 
496  dict_stats_deinit(table);
497  }
498 
499  MONITOR_DEC(MONITOR_TABLE_REFERENCE);
500 
501  ut_ad(dict_lru_validate());
502 
503 #ifdef UNIV_DEBUG
504  if (table->can_be_evicted) {
505  ut_ad(dict_lru_find_table(table));
506  } else {
507  ut_ad(dict_non_lru_find_table(table));
508  }
509 #endif /* UNIV_DEBUG */
510 
511  if (!dict_locked) {
512  table_id_t table_id = table->id;
513  ibool drop_aborted;
514 
515  drop_aborted = try_drop
516  && table->drop_aborted
517  && table->n_ref_count == 1
518  && dict_table_get_first_index(table);
519 
520  mutex_exit(&dict_sys->mutex);
521 
522  if (drop_aborted) {
523  dict_table_try_drop_aborted(NULL, table_id, 0);
524  }
525  }
526 }
527 #endif /* !UNIV_HOTBACKUP */
528 
529 /**********************************************************************/
533 UNIV_INTERN
534 const char*
536 /*====================*/
537  const dict_table_t* table,
538  ulint col_nr)
539 {
540  ulint i;
541  const char* s;
542 
543  ut_ad(table);
544  ut_ad(col_nr < table->n_def);
545  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
546 
547  s = table->col_names;
548  if (s) {
549  for (i = 0; i < col_nr; i++) {
550  s += strlen(s) + 1;
551  }
552  }
553 
554  return(s);
555 }
556 
557 #ifndef UNIV_HOTBACKUP
558 /********************************************************************/
560 UNIV_INTERN
561 void
563 /*====================*/
564  dict_table_t* table)
565 {
566  mutex_enter(&table->autoinc_mutex);
567 }
568 
569 /********************************************************************/
571 UNIV_INTERN
572 void
574 /*==========================*/
575  dict_table_t* table,
576  ib_uint64_t value)
577 {
578  ut_ad(mutex_own(&table->autoinc_mutex));
579 
580  table->autoinc = value;
581 }
582 
583 /************************************************************************
584 Get all the FTS indexes on a table.
585 @return number of FTS indexes */
586 UNIV_INTERN
587 ulint
589 /*===========================*/
590  dict_table_t* table,
591  ib_vector_t* indexes)
593 {
595 
596  ut_a(ib_vector_size(indexes) == 0);
597 
598  for (index = dict_table_get_first_index(table);
599  index;
600  index = dict_table_get_next_index(index)) {
601 
602  if (index->type == DICT_FTS) {
603  ib_vector_push(indexes, &index);
604  }
605  }
606 
607  return(ib_vector_size(indexes));
608 }
609 
610 /********************************************************************/
614 UNIV_INTERN
615 ib_uint64_t
617 /*====================*/
618  const dict_table_t* table)
619 {
620  ut_ad(mutex_own(&table->autoinc_mutex));
621 
622  return(table->autoinc);
623 }
624 
625 /********************************************************************/
628 UNIV_INTERN
629 void
631 /*=================================*/
632 
633  dict_table_t* table,
634  ib_uint64_t value)
635 {
636  ut_ad(mutex_own(&table->autoinc_mutex));
637 
638  if (value > table->autoinc) {
639 
640  table->autoinc = value;
641  }
642 }
643 
644 /********************************************************************/
646 UNIV_INTERN
647 void
649 /*======================*/
650  dict_table_t* table)
651 {
652  mutex_exit(&table->autoinc_mutex);
653 }
654 #endif /* !UNIV_HOTBACKUP */
655 
656 /********************************************************************/
660 UNIV_INTERN
661 ulint
663 /*=================================*/
664  const dict_index_t* index,
665  ulint n,
666  ibool inc_prefix)
668 {
669  const dict_field_t* field;
670  const dict_col_t* col;
671  ulint pos;
672  ulint n_fields;
673 
674  ut_ad(index);
675  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
676 
677  col = dict_table_get_nth_col(index->table, n);
678 
679  if (dict_index_is_clust(index)) {
680 
681  return(dict_col_get_clust_pos(col, index));
682  }
683 
684  n_fields = dict_index_get_n_fields(index);
685 
686  for (pos = 0; pos < n_fields; pos++) {
687  field = dict_index_get_nth_field(index, pos);
688 
689  if (col == field->col
690  && (inc_prefix || field->prefix_len == 0)) {
691 
692  return(pos);
693  }
694  }
695 
696  return(ULINT_UNDEFINED);
697 }
698 
699 #ifndef UNIV_HOTBACKUP
700 /********************************************************************/
703 UNIV_INTERN
704 ibool
706 /*==============================*/
707  const dict_index_t* index,
708  ulint n)
709 {
710  const dict_field_t* field;
711  const dict_col_t* col;
712  ulint pos;
713  ulint n_fields;
714 
715  ut_ad(index);
716  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
717 
718  if (dict_index_is_clust(index)) {
719 
720  return(TRUE);
721  }
722 
723  col = dict_table_get_nth_col(index->table, n);
724 
725  n_fields = dict_index_get_n_fields(index);
726 
727  for (pos = 0; pos < n_fields; pos++) {
728  field = dict_index_get_nth_field(index, pos);
729 
730  if (col == field->col) {
731 
732  return(TRUE);
733  }
734  }
735 
736  return(FALSE);
737 }
738 
739 /********************************************************************/
746 UNIV_INTERN
747 ulint
749 /*=========================*/
750  const dict_index_t* index,
751  const dict_index_t* index2,
752  ulint n)
753 {
754  const dict_field_t* field;
755  const dict_field_t* field2;
756  ulint n_fields;
757  ulint pos;
758 
759  ut_ad(index);
760  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
761 
762  field2 = dict_index_get_nth_field(index2, n);
763 
764  n_fields = dict_index_get_n_fields(index);
765 
766  for (pos = 0; pos < n_fields; pos++) {
767  field = dict_index_get_nth_field(index, pos);
768 
769  if (field->col == field2->col
770  && (field->prefix_len == 0
771  || (field->prefix_len >= field2->prefix_len
772  && field2->prefix_len != 0))) {
773 
774  return(pos);
775  }
776  }
777 
778  return(ULINT_UNDEFINED);
779 }
780 
781 /**********************************************************************/
784 UNIV_INTERN
787 /*==================*/
788  table_id_t table_id,
789  ibool dict_locked,
790  dict_table_op_t table_op)
791 {
793 
794  if (!dict_locked) {
795  mutex_enter(&dict_sys->mutex);
796  }
797 
798  ut_ad(mutex_own(&dict_sys->mutex));
799 
801  table_id,
805 
806  if (table != NULL) {
807 
808  if (table->can_be_evicted) {
809  dict_move_to_mru(table);
810  }
811 
812  ++table->n_ref_count;
813 
814  MONITOR_INC(MONITOR_TABLE_REFERENCE);
815  }
816 
817  if (!dict_locked) {
818  dict_table_try_drop_aborted_and_mutex_exit(
819  table, table_op == DICT_TABLE_OP_DROP_ORPHAN);
820  }
821 
822  return(table);
823 }
824 
825 /********************************************************************/
828 UNIV_INTERN
829 ulint
831 /*=======================*/
832  const dict_table_t* table,
833  ulint n)
834 {
835  return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
836  n));
837 }
838 
839 /********************************************************************/
843 UNIV_INTERN
844 ibool
846 /*============================*/
847  const dict_table_t* table,
848  ulint n)
849 {
850  const dict_index_t* index;
851  const dict_field_t* field;
852  const dict_col_t* col;
853  ulint pos;
854  ulint n_fields;
855 
856  ut_ad(table);
857 
858  col = dict_table_get_nth_col(table, n);
859 
860  index = dict_table_get_first_index(table);
861 
862  n_fields = dict_index_get_n_unique(index);
863 
864  for (pos = 0; pos < n_fields; pos++) {
865  field = dict_index_get_nth_field(index, pos);
866 
867  if (col == field->col) {
868 
869  return(TRUE);
870  }
871  }
872 
873  return(FALSE);
874 }
875 
876 /**********************************************************************/
878 UNIV_INTERN
879 void
881 /*===========*/
882 {
883  int i;
884 
885  dict_sys = static_cast<dict_sys_t*>(mem_zalloc(sizeof(*dict_sys)));
886 
887  mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
888 
891  * UNIV_WORD_SIZE));
894  * UNIV_WORD_SIZE));
895  rw_lock_create(dict_operation_lock_key,
896  &dict_operation_lock, SYNC_DICT_OPERATION);
897 
898  if (!srv_read_only_mode) {
899  dict_foreign_err_file = os_file_create_tmpfile();
900  ut_a(dict_foreign_err_file);
901 
902  mutex_create(dict_foreign_err_mutex_key,
903  &dict_foreign_err_mutex, SYNC_NO_ORDER_CHECK);
904  }
905 
906  for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
907  rw_lock_create(dict_table_stats_latch_key,
908  &dict_table_stats_latches[i], SYNC_INDEX_TREE);
909  }
910 }
911 
912 /**********************************************************************/
914 UNIV_INTERN
915 void
917 /*=============*/
918  dict_table_t* table)
919 {
920  ut_ad(mutex_own(&dict_sys->mutex));
921  ut_ad(dict_lru_validate());
922  ut_ad(dict_lru_find_table(table));
923 
924  ut_a(table->can_be_evicted);
925 
926  UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
927 
928  UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
929 
930  ut_ad(dict_lru_validate());
931 }
932 
933 /**********************************************************************/
939 UNIV_INTERN
942 /*====================*/
943  const char* table_name,
944  ibool dict_locked,
945  ibool try_drop,
949  ignore_err)
951 {
953 
954  if (!dict_locked) {
955  mutex_enter(&(dict_sys->mutex));
956  }
957 
958  ut_ad(table_name);
959  ut_ad(mutex_own(&dict_sys->mutex));
960 
961  table = dict_table_check_if_in_cache_low(table_name);
962 
963  if (table == NULL) {
964  table = dict_load_table(table_name, TRUE, ignore_err);
965  }
966 
967  ut_ad(!table || table->cached);
968 
969  if (table != NULL) {
970 
971  /* If table is corrupted, return NULL */
972  if (ignore_err == DICT_ERR_IGNORE_NONE
973  && table->corrupted) {
974 
975  /* Make life easy for drop table. */
976  if (table->can_be_evicted) {
978  }
979 
980  if (!dict_locked) {
981  mutex_exit(&dict_sys->mutex);
982  }
983 
984  ut_print_timestamp(stderr);
985 
986  fprintf(stderr, " InnoDB: table ");
987  ut_print_name(stderr, NULL, TRUE, table->name);
988  fprintf(stderr, "is corrupted. Please drop the table "
989  "and recreate\n");
990 
991  return(NULL);
992  }
993 
994  if (table->can_be_evicted) {
995  dict_move_to_mru(table);
996  }
997 
998  ++table->n_ref_count;
999 
1000  MONITOR_INC(MONITOR_TABLE_REFERENCE);
1001  }
1002 
1003  ut_ad(dict_lru_validate());
1004 
1005  if (!dict_locked) {
1006  dict_table_try_drop_aborted_and_mutex_exit(table, try_drop);
1007  }
1008 
1009  return(table);
1010 }
1011 #endif /* !UNIV_HOTBACKUP */
1012 
1013 /**********************************************************************/
1015 UNIV_INTERN
1016 void
1018 /*==========================*/
1019  dict_table_t* table,
1020  mem_heap_t* heap)
1021 {
1022  ut_ad(table);
1023  ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
1024  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1025  ut_ad(!table->cached);
1026 
1027  /* NOTE: the system columns MUST be added in the following order
1028  (so that they can be indexed by the numerical value of DATA_ROW_ID,
1029  etc.) and as the last columns of the table memory object.
1030  The clustered index will not always physically contain all
1031  system columns. */
1032 
1033  dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
1034  DATA_ROW_ID | DATA_NOT_NULL,
1035  DATA_ROW_ID_LEN);
1036 #if DATA_ROW_ID != 0
1037 #error "DATA_ROW_ID != 0"
1038 #endif
1039  dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
1040  DATA_TRX_ID | DATA_NOT_NULL,
1041  DATA_TRX_ID_LEN);
1042 #if DATA_TRX_ID != 1
1043 #error "DATA_TRX_ID != 1"
1044 #endif
1045  dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
1046  DATA_ROLL_PTR | DATA_NOT_NULL,
1047  DATA_ROLL_PTR_LEN);
1048 #if DATA_ROLL_PTR != 2
1049 #error "DATA_ROLL_PTR != 2"
1050 #endif
1051 
1052  /* This check reminds that if a new system column is added to
1053  the program, it should be dealt with here */
1054 #if DATA_N_SYS_COLS != 3
1055 #error "DATA_N_SYS_COLS != 3"
1056 #endif
1057 }
1058 
1059 #ifndef UNIV_HOTBACKUP
1060 /**********************************************************************/
1062 UNIV_INTERN
1063 void
1065 /*====================*/
1066  dict_table_t* table,
1067  ibool can_be_evicted,
1068  mem_heap_t* heap)
1069 {
1070  ulint fold;
1071  ulint id_fold;
1072  ulint i;
1073  ulint row_len;
1074 
1075  ut_ad(dict_lru_validate());
1076 
1077  /* The lower limit for what we consider a "big" row */
1078 #define BIG_ROW_SIZE 1024
1079 
1080  ut_ad(mutex_own(&(dict_sys->mutex)));
1081 
1082  dict_table_add_system_columns(table, heap);
1083 
1084  table->cached = TRUE;
1085 
1086  fold = ut_fold_string(table->name);
1087  id_fold = ut_fold_ull(table->id);
1088 
1089  row_len = 0;
1090  for (i = 0; i < table->n_def; i++) {
1091  ulint col_len = dict_col_get_max_size(
1092  dict_table_get_nth_col(table, i));
1093 
1094  row_len += col_len;
1095 
1096  /* If we have a single unbounded field, or several gigantic
1097  fields, mark the maximum row size as BIG_ROW_SIZE. */
1098  if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
1099  row_len = BIG_ROW_SIZE;
1100 
1101  break;
1102  }
1103  }
1104 
1105  table->big_rows = row_len >= BIG_ROW_SIZE;
1106 
1107  /* Look for a table with the same name: error if such exists */
1108  {
1109  dict_table_t* table2;
1110  HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
1111  dict_table_t*, table2, ut_ad(table2->cached),
1112  ut_strcmp(table2->name, table->name) == 0);
1113  ut_a(table2 == NULL);
1114 
1115 #ifdef UNIV_DEBUG
1116  /* Look for the same table pointer with a different name */
1117  HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
1118  dict_table_t*, table2, ut_ad(table2->cached),
1119  table2 == table);
1120  ut_ad(table2 == NULL);
1121 #endif /* UNIV_DEBUG */
1122  }
1123 
1124  /* Look for a table with the same id: error if such exists */
1125  {
1126  dict_table_t* table2;
1127  HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
1128  dict_table_t*, table2, ut_ad(table2->cached),
1129  table2->id == table->id);
1130  ut_a(table2 == NULL);
1131 
1132 #ifdef UNIV_DEBUG
1133  /* Look for the same table pointer with a different id */
1135  dict_table_t*, table2, ut_ad(table2->cached),
1136  table2 == table);
1137  ut_ad(table2 == NULL);
1138 #endif /* UNIV_DEBUG */
1139  }
1140 
1141  /* Add table to hash table of tables */
1142  HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1143  table);
1144 
1145  /* Add table to hash table of tables based on table id */
1146  HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
1147  table);
1148 
1149  table->can_be_evicted = can_be_evicted;
1150 
1151  if (table->can_be_evicted) {
1152  UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
1153  } else {
1154  UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_non_LRU, table);
1155  }
1156 
1157  ut_ad(dict_lru_validate());
1158 
1159  dict_sys->size += mem_heap_get_size(table->heap)
1160  + strlen(table->name) + 1;
1161 }
1162 
1163 /**********************************************************************/
1166 static
1167 ibool
1168 dict_table_can_be_evicted(
1169 /*======================*/
1170  const dict_table_t* table)
1171 {
1172  ut_ad(mutex_own(&dict_sys->mutex));
1173 #ifdef UNIV_SYNC_DEBUG
1174  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1175 #endif /* UNIV_SYNC_DEBUG */
1176 
1177  ut_a(table->can_be_evicted);
1178  ut_a(UT_LIST_GET_LEN(table->foreign_list) == 0);
1179  ut_a(UT_LIST_GET_LEN(table->referenced_list) == 0);
1180 
1181  if (table->n_ref_count == 0) {
1183 
1184  /* The transaction commit and rollback are called from
1185  outside the handler interface. This means that there is
1186  a window where the table->n_ref_count can be zero but
1187  the table instance is in "use". */
1188 
1189  if (lock_table_has_locks(table)) {
1190  return(FALSE);
1191  }
1192 
1193  for (index = dict_table_get_first_index(table);
1194  index != NULL;
1195  index = dict_table_get_next_index(index)) {
1196 
1197  btr_search_t* info = btr_search_get_info(index);
1198 
1199  /* We are not allowed to free the in-memory index
1200  struct dict_index_t until all entries in the adaptive
1201  hash index that point to any of the page belonging to
1202  his b-tree index are dropped. This is so because
1203  dropping of these entries require access to
1204  dict_index_t struct. To avoid such scenario we keep
1205  a count of number of such pages in the search_info and
1206  only free the dict_index_t struct when this count
1207  drops to zero.
1208 
1209  See also: dict_index_remove_from_cache_low() */
1210 
1211  if (btr_search_info_get_ref_count(info) > 0) {
1212  return(FALSE);
1213  }
1214  }
1215 
1216  return(TRUE);
1217  }
1218 
1219  return(FALSE);
1220 }
1221 
1222 /**********************************************************************/
1228 UNIV_INTERN
1229 ulint
1231 /*====================*/
1232  ulint max_tables,
1233  ulint pct_check)
1234 {
1235  ulint i;
1236  ulint len;
1238  ulint check_up_to;
1239  ulint n_evicted = 0;
1240 
1241  ut_a(pct_check > 0);
1242  ut_a(pct_check <= 100);
1243  ut_ad(mutex_own(&dict_sys->mutex));
1244 #ifdef UNIV_SYNC_DEBUG
1245  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1246 #endif /* UNIV_SYNC_DEBUG */
1247  ut_ad(dict_lru_validate());
1248 
1249  i = len = UT_LIST_GET_LEN(dict_sys->table_LRU);
1250 
1251  if (len < max_tables) {
1252  return(0);
1253  }
1254 
1255  check_up_to = len - ((len * pct_check) / 100);
1256 
1257  /* Check for overflow */
1258  ut_a(i == 0 || check_up_to <= i);
1259 
1260  /* Find a suitable candidate to evict from the cache. Don't scan the
1261  entire LRU list. Only scan pct_check list entries. */
1262 
1263  for (table = UT_LIST_GET_LAST(dict_sys->table_LRU);
1264  table != NULL
1265  && i > check_up_to
1266  && (len - n_evicted) > max_tables;
1267  --i) {
1268 
1269  dict_table_t* prev_table;
1270 
1271  prev_table = UT_LIST_GET_PREV(table_LRU, table);
1272 
1273  if (dict_table_can_be_evicted(table)) {
1274 
1275  dict_table_remove_from_cache_low(table, TRUE);
1276 
1277  ++n_evicted;
1278  }
1279 
1280  table = prev_table;
1281  }
1282 
1283  return(n_evicted);
1284 }
1285 
1286 /**********************************************************************/
1288 UNIV_INTERN
1289 void
1291 /*================================*/
1292  dict_table_t* table)
1293 {
1294  ut_ad(mutex_own(&dict_sys->mutex));
1295  ut_ad(dict_lru_find_table(table));
1296 
1297  ut_a(table->can_be_evicted);
1298 
1299  UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1300 
1301  UT_LIST_ADD_LAST(table_LRU, dict_sys->table_non_LRU, table);
1302 
1303  table->can_be_evicted = FALSE;
1304 }
1305 
1306 /**********************************************************************/
1308 UNIV_INTERN
1309 void
1311 /*================================*/
1312  dict_table_t* table)
1313 {
1314  ut_ad(mutex_own(&dict_sys->mutex));
1315  ut_ad(dict_non_lru_find_table(table));
1316 
1317  ut_a(!table->can_be_evicted);
1318 
1319  UT_LIST_REMOVE(table_LRU, dict_sys->table_non_LRU, table);
1320 
1321  UT_LIST_ADD_LAST(table_LRU, dict_sys->table_LRU, table);
1322 
1323  table->can_be_evicted = TRUE;
1324 }
1325 
1326 /**********************************************************************/
1329 static
1330 dict_index_t*
1331 dict_table_find_index_on_id(
1332 /*========================*/
1333  const dict_table_t* table,
1334  index_id_t id)
1335 {
1337 
1338  for (index = dict_table_get_first_index(table);
1339  index != NULL;
1340  index = dict_table_get_next_index(index)) {
1341 
1342  if (id == index->id) {
1343  /* Found */
1344 
1345  return(index);
1346  }
1347  }
1348 
1349  return(NULL);
1350 }
1351 
1352 /**********************************************************************/
1357 UNIV_INTERN
1358 dict_index_t*
1360 /*======================*/
1361  index_id_t id)
1362 {
1364 
1365  /* This can happen if the system tablespace is the wrong page size */
1366  if (dict_sys == NULL) {
1367  return(NULL);
1368  }
1369 
1370  for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
1371  table != NULL;
1372  table = UT_LIST_GET_NEXT(table_LRU, table)) {
1373 
1374  dict_index_t* index = dict_table_find_index_on_id(table, id);
1375 
1376  if (index != NULL) {
1377  return(index);
1378  }
1379  }
1380 
1381  for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU);
1382  table != NULL;
1383  table = UT_LIST_GET_NEXT(table_LRU, table)) {
1384 
1385  dict_index_t* index = dict_table_find_index_on_id(table, id);
1386 
1387  if (index != NULL) {
1388  return(index);
1389  }
1390  }
1391 
1392  return(NULL);
1393 }
1394 
1395 /**********************************************************************/
1398 UNIV_INTERN
1399 dberr_t
1401 /*=======================*/
1402  dict_table_t* table,
1403  const char* new_name,
1404  ibool rename_also_foreigns)
1407 {
1408  dict_foreign_t* foreign;
1410  ulint fold;
1411  char old_name[MAX_FULL_NAME_LEN + 1];
1412 
1413  ut_ad(mutex_own(&(dict_sys->mutex)));
1414 
1415  /* store the old/current name to an automatic variable */
1416  if (strlen(table->name) + 1 <= sizeof(old_name)) {
1417  memcpy(old_name, table->name, strlen(table->name) + 1);
1418  } else {
1419  ut_print_timestamp(stderr);
1420  fprintf(stderr, "InnoDB: too long table name: '%s', "
1421  "max length is %d\n", table->name,
1422  MAX_FULL_NAME_LEN);
1423  ut_error;
1424  }
1425 
1426  fold = ut_fold_string(new_name);
1427 
1428  /* Look for a table with the same name: error if such exists */
1429  dict_table_t* table2;
1430  HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
1431  dict_table_t*, table2, ut_ad(table2->cached),
1432  (ut_strcmp(table2->name, new_name) == 0));
1433  DBUG_EXECUTE_IF("dict_table_rename_in_cache_failure",
1434  if (table2 == NULL) {
1435  table2 = (dict_table_t*) -1;
1436  } );
1437  if (table2) {
1438  ib_logf(IB_LOG_LEVEL_ERROR,
1439  "Cannot rename table '%s' to '%s' since the "
1440  "dictionary cache already contains '%s'.",
1441  old_name, new_name, new_name);
1442  return(DB_ERROR);
1443  }
1444 
1445  /* If the table is stored in a single-table tablespace, rename the
1446  .ibd file and rebuild the .isl file if needed. */
1447 
1448  if (dict_table_is_discarded(table)) {
1449  os_file_type_t type;
1450  ibool exists;
1451  char* filepath;
1452 
1453  ut_ad(table->space != TRX_SYS_SPACE);
1454 
1455  if (DICT_TF_HAS_DATA_DIR(table->flags)) {
1456 
1457  dict_get_and_save_data_dir_path(table, true);
1458  ut_a(table->data_dir_path);
1459 
1460  filepath = os_file_make_remote_pathname(
1461  table->data_dir_path, table->name, "ibd");
1462  } else {
1463  filepath = fil_make_ibd_name(table->name, false);
1464  }
1465 
1467 
1468  /* Delete any temp file hanging around. */
1469  if (os_file_status(filepath, &exists, &type)
1470  && exists
1471  && !os_file_delete_if_exists(innodb_file_temp_key,
1472  filepath)) {
1473 
1474  ib_logf(IB_LOG_LEVEL_INFO,
1475  "Delete of %s failed.", filepath);
1476  }
1477 
1478  mem_free(filepath);
1479 
1480  } else if (table->space != TRX_SYS_SPACE) {
1481  char* new_path = NULL;
1482 
1483  if (table->dir_path_of_temp_table != NULL) {
1484  ut_print_timestamp(stderr);
1485  fputs(" InnoDB: Error: trying to rename a"
1486  " TEMPORARY TABLE ", stderr);
1487  ut_print_name(stderr, NULL, TRUE, old_name);
1488  fputs(" (", stderr);
1489  ut_print_filename(stderr,
1490  table->dir_path_of_temp_table);
1491  fputs(" )\n", stderr);
1492  return(DB_ERROR);
1493 
1494  } else if (DICT_TF_HAS_DATA_DIR(table->flags)) {
1495  char* old_path;
1496 
1497  old_path = fil_space_get_first_path(table->space);
1498 
1499  new_path = os_file_make_new_pathname(
1500  old_path, new_name);
1501 
1502  mem_free(old_path);
1503 
1505  new_name, new_path);
1506 
1507  if (err != DB_SUCCESS) {
1508  mem_free(new_path);
1509  return(DB_TABLESPACE_EXISTS);
1510  }
1511  }
1512 
1513  ibool success = fil_rename_tablespace(
1514  old_name, table->space, new_name, new_path);
1515 
1516  /* If the tablespace is remote, a new .isl file was created
1517  If success, delete the old one. If not, delete the new one. */
1518  if (new_path) {
1519 
1520  mem_free(new_path);
1521  fil_delete_link_file(success ? old_name : new_name);
1522  }
1523 
1524  if (!success) {
1525  return(DB_ERROR);
1526  }
1527  }
1528 
1529  /* Remove table from the hash tables of tables */
1531  ut_fold_string(old_name), table);
1532 
1533  if (strlen(new_name) > strlen(table->name)) {
1534  /* We allocate MAX_FULL_NAME_LEN + 1 bytes here to avoid
1535  memory fragmentation, we assume a repeated calls of
1536  ut_realloc() with the same size do not cause fragmentation */
1537  ut_a(strlen(new_name) <= MAX_FULL_NAME_LEN);
1538 
1539  table->name = static_cast<char*>(
1540  ut_realloc(table->name, MAX_FULL_NAME_LEN + 1));
1541  }
1542  memcpy(table->name, new_name, strlen(new_name) + 1);
1543 
1544  /* Add table to hash table of tables */
1545  HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1546  table);
1547 
1548  dict_sys->size += strlen(new_name) - strlen(old_name);
1549  ut_a(dict_sys->size > 0);
1550 
1551  /* Update the table_name field in indexes */
1552  for (index = dict_table_get_first_index(table);
1553  index != NULL;
1554  index = dict_table_get_next_index(index)) {
1555 
1556  index->table_name = table->name;
1557  }
1558 
1559  if (!rename_also_foreigns) {
1560  /* In ALTER TABLE we think of the rename table operation
1561  in the direction table -> temporary table (#sql...)
1562  as dropping the table with the old name and creating
1563  a new with the new name. Thus we kind of drop the
1564  constraints from the dictionary cache here. The foreign key
1565  constraints will be inherited to the new table from the
1566  system tables through a call of dict_load_foreigns. */
1567 
1568  /* Remove the foreign constraints from the cache */
1569  foreign = UT_LIST_GET_LAST(table->foreign_list);
1570 
1571  while (foreign != NULL) {
1573  foreign = UT_LIST_GET_LAST(table->foreign_list);
1574  }
1575 
1576  /* Reset table field in referencing constraints */
1577 
1578  foreign = UT_LIST_GET_FIRST(table->referenced_list);
1579 
1580  while (foreign != NULL) {
1581  foreign->referenced_table = NULL;
1582  foreign->referenced_index = NULL;
1583 
1584  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1585  }
1586 
1587  /* Make the list of referencing constraints empty */
1588 
1589  UT_LIST_INIT(table->referenced_list);
1590 
1591  return(DB_SUCCESS);
1592  }
1593 
1594  /* Update the table name fields in foreign constraints, and update also
1595  the constraint id of new format >= 4.0.18 constraints. Note that at
1596  this point we have already changed table->name to the new name. */
1597 
1598  foreign = UT_LIST_GET_FIRST(table->foreign_list);
1599 
1600  while (foreign != NULL) {
1601  if (ut_strlen(foreign->foreign_table_name)
1602  < ut_strlen(table->name)) {
1603  /* Allocate a longer name buffer;
1604  TODO: store buf len to save memory */
1605 
1607  foreign->heap, table->name);
1609  } else {
1610  strcpy(foreign->foreign_table_name, table->name);
1612  }
1613  if (strchr(foreign->id, '/')) {
1614  /* This is a >= 4.0.18 format id */
1615 
1616  ulint db_len;
1617  char* old_id;
1618  char old_name_cs_filename[MAX_TABLE_NAME_LEN+20];
1619  uint errors = 0;
1620 
1621  /* All table names are internally stored in charset
1622  my_charset_filename (except the temp tables and the
1623  partition identifier suffix in partition tables). The
1624  foreign key constraint names are internally stored
1625  in UTF-8 charset. The variable fkid here is used
1626  to store foreign key constraint name in charset
1627  my_charset_filename for comparison further below. */
1628  char fkid[MAX_TABLE_NAME_LEN+20];
1629  ibool on_tmp = FALSE;
1630 
1631  /* The old table name in my_charset_filename is stored
1632  in old_name_cs_filename */
1633 
1634  strncpy(old_name_cs_filename, old_name,
1636  if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) {
1637 
1638  innobase_convert_to_system_charset(
1639  strchr(old_name_cs_filename, '/') + 1,
1640  strchr(old_name, '/') + 1,
1641  MAX_TABLE_NAME_LEN, &errors);
1642 
1643  if (errors) {
1644  /* There has been an error to convert
1645  old table into UTF-8. This probably
1646  means that the old table name is
1647  actually in UTF-8. */
1648  innobase_convert_to_filename_charset(
1649  strchr(old_name_cs_filename,
1650  '/') + 1,
1651  strchr(old_name, '/') + 1,
1653  } else {
1654  /* Old name already in
1655  my_charset_filename */
1656  strncpy(old_name_cs_filename, old_name,
1658  }
1659  }
1660 
1661  strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN);
1662 
1663  if (strstr(fkid, TEMP_TABLE_PATH_PREFIX) == NULL) {
1664  innobase_convert_to_filename_charset(
1665  strchr(fkid, '/') + 1,
1666  strchr(foreign->id, '/') + 1,
1667  MAX_TABLE_NAME_LEN+20);
1668  } else {
1669  on_tmp = TRUE;
1670  }
1671 
1672  old_id = mem_strdup(foreign->id);
1673 
1674  if (ut_strlen(fkid) > ut_strlen(old_name_cs_filename)
1675  + ((sizeof dict_ibfk) - 1)
1676  && !memcmp(fkid, old_name_cs_filename,
1677  ut_strlen(old_name_cs_filename))
1678  && !memcmp(fkid + ut_strlen(old_name_cs_filename),
1679  dict_ibfk, (sizeof dict_ibfk) - 1)) {
1680 
1681  /* This is a generated >= 4.0.18 format id */
1682 
1683  char table_name[MAX_TABLE_NAME_LEN] = "";
1684  uint errors = 0;
1685 
1686  if (strlen(table->name) > strlen(old_name)) {
1687  foreign->id = static_cast<char*>(
1689  foreign->heap,
1690  strlen(table->name)
1691  + strlen(old_id) + 1));
1692  }
1693 
1694  /* Convert the table name to UTF-8 */
1695  strncpy(table_name, table->name,
1697  innobase_convert_to_system_charset(
1698  strchr(table_name, '/') + 1,
1699  strchr(table->name, '/') + 1,
1700  MAX_TABLE_NAME_LEN, &errors);
1701 
1702  if (errors) {
1703  /* Table name could not be converted
1704  from charset my_charset_filename to
1705  UTF-8. This means that the table name
1706  is already in UTF-8 (#mysql#50). */
1707  strncpy(table_name, table->name,
1709  }
1710 
1711  /* Replace the prefix 'databasename/tablename'
1712  with the new names */
1713  strcpy(foreign->id, table_name);
1714  if (on_tmp) {
1715  strcat(foreign->id,
1716  old_id + ut_strlen(old_name));
1717  } else {
1718  sprintf(strchr(foreign->id, '/') + 1,
1719  "%s%s",
1720  strchr(table_name, '/') +1,
1721  strstr(old_id, "_ibfk_") );
1722  }
1723 
1724  } else {
1725  /* This is a >= 4.0.18 format id where the user
1726  gave the id name */
1727  db_len = dict_get_db_name_len(table->name) + 1;
1728 
1729  if (dict_get_db_name_len(table->name)
1730  > dict_get_db_name_len(foreign->id)) {
1731 
1732  foreign->id = static_cast<char*>(
1734  foreign->heap,
1735  db_len + strlen(old_id) + 1));
1736  }
1737 
1738  /* Replace the database prefix in id with the
1739  one from table->name */
1740 
1741  ut_memcpy(foreign->id, table->name, db_len);
1742 
1743  strcpy(foreign->id + db_len,
1744  dict_remove_db_name(old_id));
1745  }
1746 
1747  mem_free(old_id);
1748  }
1749 
1750  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1751  }
1752 
1753  for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
1754  foreign != NULL;
1755  foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
1756 
1757  if (ut_strlen(foreign->referenced_table_name)
1758  < ut_strlen(table->name)) {
1759  /* Allocate a longer name buffer;
1760  TODO: store buf len to save memory */
1761 
1763  foreign->heap, table->name);
1764 
1766  foreign, TRUE);
1767  } else {
1768  /* Use the same buffer */
1769  strcpy(foreign->referenced_table_name, table->name);
1770 
1772  foreign, FALSE);
1773  }
1774  }
1775 
1776  return(DB_SUCCESS);
1777 }
1778 
1779 /**********************************************************************/
1782 UNIV_INTERN
1783 void
1785 /*==========================*/
1786  dict_table_t* table,
1787  table_id_t new_id)
1788 {
1789  ut_ad(table);
1790  ut_ad(mutex_own(&(dict_sys->mutex)));
1791  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1792 
1793  /* Remove the table from the hash table of id's */
1794 
1796  ut_fold_ull(table->id), table);
1797  table->id = new_id;
1798 
1799  /* Add the table back to the hash table */
1801  ut_fold_ull(table->id), table);
1802 }
1803 
1804 /**********************************************************************/
1806 static
1807 void
1808 dict_table_remove_from_cache_low(
1809 /*=============================*/
1810  dict_table_t* table,
1811  ibool lru_evict)
1813 {
1814  dict_foreign_t* foreign;
1816  ulint size;
1817 
1818  ut_ad(table);
1819  ut_ad(dict_lru_validate());
1820  ut_a(table->n_ref_count == 0);
1821  ut_a(table->n_rec_locks == 0);
1822  ut_ad(mutex_own(&(dict_sys->mutex)));
1823  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1824 
1825 #if 0
1826  fputs("Removing table ", stderr);
1827  ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1828  fputs(" from dictionary cache\n", stderr);
1829 #endif
1830 
1831  /* Remove the foreign constraints from the cache */
1832 
1833  for (foreign = UT_LIST_GET_LAST(table->foreign_list);
1834  foreign != NULL;
1835  foreign = UT_LIST_GET_LAST(table->foreign_list)) {
1836 
1838  }
1839 
1840  /* Reset table field in referencing constraints */
1841 
1842  for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
1843  foreign != NULL;
1844  foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
1845 
1846  foreign->referenced_table = NULL;
1847  foreign->referenced_index = NULL;
1848  }
1849 
1850  /* Remove the indexes from the cache */
1851 
1852  for (index = UT_LIST_GET_LAST(table->indexes);
1853  index != NULL;
1854  index = UT_LIST_GET_LAST(table->indexes)) {
1855 
1856  dict_index_remove_from_cache_low(table, index, lru_evict);
1857  }
1858 
1859  /* Remove table from the hash tables of tables */
1860 
1862  ut_fold_string(table->name), table);
1863 
1865  ut_fold_ull(table->id), table);
1866 
1867  /* Remove table from LRU or non-LRU list. */
1868  if (table->can_be_evicted) {
1869  ut_ad(dict_lru_find_table(table));
1870  UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1871  } else {
1872  ut_ad(dict_non_lru_find_table(table));
1873  UT_LIST_REMOVE(table_LRU, dict_sys->table_non_LRU, table);
1874  }
1875 
1876  ut_ad(dict_lru_validate());
1877 
1878  if (lru_evict && table->drop_aborted) {
1879  /* Do as dict_table_try_drop_aborted() does. */
1880 
1882 
1883  ut_ad(mutex_own(&dict_sys->mutex));
1884 #ifdef UNIV_SYNC_DEBUG
1885  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1886 #endif /* UNIV_SYNC_DEBUG */
1887  /* Mimic row_mysql_lock_data_dictionary(). */
1888  trx->dict_operation_lock_mode = RW_X_LATCH;
1889 
1891 
1892  /* Silence a debug assertion in row_merge_drop_indexes(). */
1893  ut_d(table->n_ref_count++);
1894  row_merge_drop_indexes(trx, table, TRUE);
1895  ut_d(table->n_ref_count--);
1896  ut_ad(table->n_ref_count == 0);
1897  trx_commit_for_mysql(trx);
1898  trx->dict_operation_lock_mode = 0;
1900  }
1901 
1902  size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
1903 
1904  ut_ad(dict_sys->size >= size);
1905 
1906  dict_sys->size -= size;
1907 
1908  dict_mem_table_free(table);
1909 }
1910 
1911 /**********************************************************************/
1913 UNIV_INTERN
1914 void
1916 /*=========================*/
1917  dict_table_t* table)
1918 {
1919  dict_table_remove_from_cache_low(table, FALSE);
1920 }
1921 
1922 /****************************************************************/
1926 UNIV_INTERN
1927 ibool
1929 /*======================*/
1930  const char* name)
1931 {
1932  /* This check reminds that if a new system column is added to
1933  the program, it should be dealt with here. */
1934 #if DATA_N_SYS_COLS != 3
1935 #error "DATA_N_SYS_COLS != 3"
1936 #endif
1937 
1938  static const char* reserved_names[] = {
1939  "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1940  };
1941 
1942  ulint i;
1943 
1944  for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1945  if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
1946 
1947  return(TRUE);
1948  }
1949  }
1950 
1951  return(FALSE);
1952 }
1953 
1954 #if 1 /* This function is not very accurate at determining
1955  whether an UNDO record will be too big. See innodb_4k.test,
1956  Bug 13336585, for a testcase that shows an index that can
1957  be created but cannot be updated. */
1958 
1959 /****************************************************************/
1963 static
1964 ibool
1965 dict_index_too_big_for_undo(
1966 /*========================*/
1967  const dict_table_t* table,
1968  const dict_index_t* new_index)
1969 {
1970  /* Make sure that all column prefixes will fit in the undo log record
1971  in trx_undo_page_report_modify() right after trx_undo_page_init(). */
1972 
1973  ulint i;
1974  const dict_index_t* clust_index
1975  = dict_table_get_first_index(table);
1976  ulint undo_page_len
1978  + 2 /* next record pointer */
1979  + 1 /* type_cmpl */
1980  + 11 /* trx->undo_no */ + 11 /* table->id */
1981  + 1 /* rec_get_info_bits() */
1982  + 11 /* DB_TRX_ID */
1983  + 11 /* DB_ROLL_PTR */
1984  + 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
1985  + 2/* pointer to previous undo log record */;
1986 
1987  /* FTS index consists of auxiliary tables, they shall be excluded from
1988  index row size check */
1989  if (new_index->type & DICT_FTS) {
1990  return(false);
1991  }
1992 
1993  if (!clust_index) {
1994  ut_a(dict_index_is_clust(new_index));
1995  clust_index = new_index;
1996  }
1997 
1998  /* Add the size of the ordering columns in the
1999  clustered index. */
2000  for (i = 0; i < clust_index->n_uniq; i++) {
2001  const dict_col_t* col
2002  = dict_index_get_nth_col(clust_index, i);
2003 
2004  /* Use the maximum output size of
2005  mach_write_compressed(), although the encoded
2006  length should always fit in 2 bytes. */
2007  undo_page_len += 5 + dict_col_get_max_size(col);
2008  }
2009 
2010  /* Add the old values of the columns to be updated.
2011  First, the amount and the numbers of the columns.
2012  These are written by mach_write_compressed() whose
2013  maximum output length is 5 bytes. However, given that
2014  the quantities are below REC_MAX_N_FIELDS (10 bits),
2015  the maximum length is 2 bytes per item. */
2016  undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
2017 
2018  for (i = 0; i < clust_index->n_def; i++) {
2019  const dict_col_t* col
2020  = dict_index_get_nth_col(clust_index, i);
2021  ulint max_size
2022  = dict_col_get_max_size(col);
2023  ulint fixed_size
2025  dict_table_is_comp(table));
2026  ulint max_prefix
2027  = col->max_prefix;
2028 
2029  if (fixed_size) {
2030  /* Fixed-size columns are stored locally. */
2031  max_size = fixed_size;
2032  } else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
2033  /* Short columns are stored locally. */
2034  } else if (!col->ord_part
2035  || (col->max_prefix
2036  < (ulint) DICT_MAX_FIELD_LEN_BY_FORMAT(table))) {
2037  /* See if col->ord_part would be set
2038  because of new_index. Also check if the new
2039  index could have longer prefix on columns
2040  that already had ord_part set */
2041  ulint j;
2042 
2043  for (j = 0; j < new_index->n_uniq; j++) {
2045  new_index, j) == col) {
2046  const dict_field_t* field
2047  = dict_index_get_nth_field(
2048  new_index, j);
2049 
2050  if (field->prefix_len
2051  > col->max_prefix) {
2052  max_prefix =
2053  field->prefix_len;
2054  }
2055 
2056  goto is_ord_part;
2057  }
2058  }
2059 
2060  if (col->ord_part) {
2061  goto is_ord_part;
2062  }
2063 
2064  /* This is not an ordering column in any index.
2065  Thus, it can be stored completely externally. */
2066  max_size = BTR_EXTERN_FIELD_REF_SIZE;
2067  } else {
2068  ulint max_field_len;
2069 is_ord_part:
2070  max_field_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
2071 
2072  /* This is an ordering column in some index.
2073  A long enough prefix must be written to the
2074  undo log. See trx_undo_page_fetch_ext(). */
2075  max_size = ut_min(max_size, max_field_len);
2076 
2077  /* We only store the needed prefix length in undo log */
2078  if (max_prefix) {
2080  >= UNIV_FORMAT_B);
2081 
2082  max_size = ut_min(max_prefix, max_size);
2083  }
2084 
2085  max_size += BTR_EXTERN_FIELD_REF_SIZE;
2086  }
2087 
2088  undo_page_len += 5 + max_size;
2089  }
2090 
2091  return(undo_page_len >= UNIV_PAGE_SIZE);
2092 }
2093 #endif
2094 
2095 /****************************************************************/
2099 static
2100 ibool
2101 dict_index_too_big_for_tree(
2102 /*========================*/
2103  const dict_table_t* table,
2104  const dict_index_t* new_index)
2105 {
2106  ulint zip_size;
2107  ulint comp;
2108  ulint i;
2109  /* maximum possible storage size of a record */
2110  ulint rec_max_size;
2111  /* maximum allowed size of a record on a leaf page */
2112  ulint page_rec_max;
2113  /* maximum allowed size of a node pointer record */
2114  ulint page_ptr_max;
2115 
2116  /* FTS index consists of auxiliary tables, they shall be excluded from
2117  index row size check */
2118  if (new_index->type & DICT_FTS) {
2119  return(false);
2120  }
2121 
2122  DBUG_EXECUTE_IF(
2123  "ib_force_create_table",
2124  return(FALSE););
2125 
2126  comp = dict_table_is_comp(table);
2127  zip_size = dict_table_zip_size(table);
2128 
2129  if (zip_size && zip_size < UNIV_PAGE_SIZE) {
2130  /* On a compressed page, two records must fit in the
2131  uncompressed page modification log. On compressed
2132  pages with zip_size == UNIV_PAGE_SIZE, this limit will
2133  never be reached. */
2134  ut_ad(comp);
2135  /* The maximum allowed record size is the size of
2136  an empty page, minus a byte for recoding the heap
2137  number in the page modification log. The maximum
2138  allowed node pointer size is half that. */
2139  page_rec_max = page_zip_empty_size(new_index->n_fields,
2140  zip_size);
2141  if (page_rec_max) {
2142  page_rec_max--;
2143  }
2144  page_ptr_max = page_rec_max / 2;
2145  /* On a compressed page, there is a two-byte entry in
2146  the dense page directory for every record. But there
2147  is no record header. */
2148  rec_max_size = 2;
2149  } else {
2150  /* The maximum allowed record size is half a B-tree
2151  page. No additional sparse page directory entry will
2152  be generated for the first few user records. */
2153  page_rec_max = page_get_free_space_of_empty(comp) / 2;
2154  page_ptr_max = page_rec_max;
2155  /* Each record has a header. */
2156  rec_max_size = comp
2157  ? REC_N_NEW_EXTRA_BYTES
2158  : REC_N_OLD_EXTRA_BYTES;
2159  }
2160 
2161  if (comp) {
2162  /* Include the "null" flags in the
2163  maximum possible record size. */
2164  rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
2165  } else {
2166  /* For each column, include a 2-byte offset and a
2167  "null" flag. The 1-byte format is only used in short
2168  records that do not contain externally stored columns.
2169  Such records could never exceed the page limit, even
2170  when using the 2-byte format. */
2171  rec_max_size += 2 * new_index->n_fields;
2172  }
2173 
2174  /* Compute the maximum possible record size. */
2175  for (i = 0; i < new_index->n_fields; i++) {
2176  const dict_field_t* field
2177  = dict_index_get_nth_field(new_index, i);
2178  const dict_col_t* col
2179  = dict_field_get_col(field);
2180  ulint field_max_size;
2181  ulint field_ext_max_size;
2182 
2183  /* In dtuple_convert_big_rec(), variable-length columns
2184  that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
2185  may be chosen for external storage.
2186 
2187  Fixed-length columns, and all columns of secondary
2188  index records are always stored inline. */
2189 
2190  /* Determine the maximum length of the index field.
2191  The field_ext_max_size should be computed as the worst
2192  case in rec_get_converted_size_comp() for
2193  REC_STATUS_ORDINARY records. */
2194 
2195  field_max_size = dict_col_get_fixed_size(col, comp);
2196  if (field_max_size) {
2197  /* dict_index_add_col() should guarantee this */
2198  ut_ad(!field->prefix_len
2199  || field->fixed_len == field->prefix_len);
2200  /* Fixed lengths are not encoded
2201  in ROW_FORMAT=COMPACT. */
2202  field_ext_max_size = 0;
2203  goto add_field_size;
2204  }
2205 
2206  field_max_size = dict_col_get_max_size(col);
2207  field_ext_max_size = field_max_size < 256 ? 1 : 2;
2208 
2209  if (field->prefix_len) {
2210  if (field->prefix_len < field_max_size) {
2211  field_max_size = field->prefix_len;
2212  }
2213  } else if (field_max_size > BTR_EXTERN_FIELD_REF_SIZE * 2
2214  && dict_index_is_clust(new_index)) {
2215 
2216  /* In the worst case, we have a locally stored
2217  column of BTR_EXTERN_FIELD_REF_SIZE * 2 bytes.
2218  The length can be stored in one byte. If the
2219  column were stored externally, the lengths in
2220  the clustered index page would be
2221  BTR_EXTERN_FIELD_REF_SIZE and 2. */
2222  field_max_size = BTR_EXTERN_FIELD_REF_SIZE * 2;
2223  field_ext_max_size = 1;
2224  }
2225 
2226  if (comp) {
2227  /* Add the extra size for ROW_FORMAT=COMPACT.
2228  For ROW_FORMAT=REDUNDANT, these bytes were
2229  added to rec_max_size before this loop. */
2230  rec_max_size += field_ext_max_size;
2231  }
2232 add_field_size:
2233  rec_max_size += field_max_size;
2234 
2235  /* Check the size limit on leaf pages. */
2236  if (UNIV_UNLIKELY(rec_max_size >= page_rec_max)) {
2237 
2238  return(TRUE);
2239  }
2240 
2241  /* Check the size limit on non-leaf pages. Records
2242  stored in non-leaf B-tree pages consist of the unique
2243  columns of the record (the key columns of the B-tree)
2244  and a node pointer field. When we have processed the
2245  unique columns, rec_max_size equals the size of the
2246  node pointer record minus the node pointer column. */
2247  if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
2248  && rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {
2249 
2250  return(TRUE);
2251  }
2252  }
2253 
2254  return(FALSE);
2255 }
2256 
2257 /**********************************************************************/
2260 UNIV_INTERN
2261 dberr_t
2263 /*====================*/
2264  dict_table_t* table,
2265  dict_index_t* index,
2267  ulint page_no,
2268  ibool strict)
2271 {
2272  dict_index_t* new_index;
2273  ulint n_ord;
2274  ulint i;
2275 
2276  ut_ad(index);
2277  ut_ad(mutex_own(&(dict_sys->mutex)));
2278  ut_ad(index->n_def == index->n_fields);
2279  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
2281 
2282  ut_ad(mem_heap_validate(index->heap));
2283  ut_a(!dict_index_is_clust(index)
2284  || UT_LIST_GET_LEN(table->indexes) == 0);
2285 
2286  if (!dict_index_find_cols(table, index)) {
2287 
2288  dict_mem_index_free(index);
2289  return(DB_CORRUPTION);
2290  }
2291 
2292  /* Build the cache internal representation of the index,
2293  containing also the added system fields */
2294 
2295  if (index->type == DICT_FTS) {
2296  new_index = dict_index_build_internal_fts(table, index);
2297  } else if (dict_index_is_clust(index)) {
2298  new_index = dict_index_build_internal_clust(table, index);
2299  } else {
2300  new_index = dict_index_build_internal_non_clust(table, index);
2301  }
2302 
2303  /* Set the n_fields value in new_index to the actual defined
2304  number of fields in the cache internal representation */
2305 
2306  new_index->n_fields = new_index->n_def;
2307  new_index->trx_id = index->trx_id;
2308 
2309  if (strict && dict_index_too_big_for_tree(table, new_index)) {
2310 too_big:
2311  dict_mem_index_free(new_index);
2312  dict_mem_index_free(index);
2313  return(DB_TOO_BIG_RECORD);
2314  }
2315 
2316  if (dict_index_is_univ(index)) {
2317  n_ord = new_index->n_fields;
2318  } else {
2319  n_ord = new_index->n_uniq;
2320  }
2321 
2322 #if 1 /* The following code predetermines whether to call
2323  dict_index_too_big_for_undo(). This function is not
2324  accurate. See innodb_4k.test, Bug 13336585, for a
2325  testcase that shows an index that can be created but
2326  cannot be updated. */
2327 
2328  switch (dict_table_get_format(table)) {
2329  case UNIV_FORMAT_A:
2330  /* ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT store
2331  prefixes of externally stored columns locally within
2332  the record. There are no special considerations for
2333  the undo log record size. */
2334  goto undo_size_ok;
2335 
2336  case UNIV_FORMAT_B:
2337  /* In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED,
2338  column prefix indexes require that prefixes of
2339  externally stored columns are written to the undo log.
2340  This may make the undo log record bigger than the
2341  record on the B-tree page. The maximum size of an
2342  undo log record is the page size. That must be
2343  checked for below. */
2344  break;
2345 
2346 #if UNIV_FORMAT_B != UNIV_FORMAT_MAX
2347 # error "UNIV_FORMAT_B != UNIV_FORMAT_MAX"
2348 #endif
2349  }
2350 
2351  for (i = 0; i < n_ord; i++) {
2352  const dict_field_t* field
2353  = dict_index_get_nth_field(new_index, i);
2354  const dict_col_t* col
2355  = dict_field_get_col(field);
2356 
2357  /* In dtuple_convert_big_rec(), variable-length columns
2358  that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
2359  may be chosen for external storage. If the column appears
2360  in an ordering column of an index, a longer prefix determined
2361  by dict_max_field_len_store_undo() will be copied to the undo
2362  log by trx_undo_page_report_modify() and
2363  trx_undo_page_fetch_ext(). It suffices to check the
2364  capacity of the undo log whenever new_index includes
2365  a column prefix on a column that may be stored externally. */
2366 
2367  if (field->prefix_len /* prefix index */
2368  && (!col->ord_part /* not yet ordering column */
2369  || field->prefix_len > col->max_prefix)
2370  && !dict_col_get_fixed_size(col, TRUE) /* variable-length */
2371  && dict_col_get_max_size(col)
2372  > BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
2373 
2374  if (dict_index_too_big_for_undo(table, new_index)) {
2375  /* An undo log record might not fit in
2376  a single page. Refuse to create this index. */
2377 
2378  goto too_big;
2379  }
2380 
2381  break;
2382  }
2383  }
2384 
2385 undo_size_ok:
2386 #endif
2387  /* Flag the ordering columns and also set column max_prefix */
2388 
2389  for (i = 0; i < n_ord; i++) {
2390  const dict_field_t* field
2391  = dict_index_get_nth_field(new_index, i);
2392 
2393  field->col->ord_part = 1;
2394 
2395  if (field->prefix_len > field->col->max_prefix) {
2396  field->col->max_prefix = field->prefix_len;
2397  }
2398  }
2399 
2400  if (!dict_index_is_univ(new_index)) {
2401 
2402  new_index->stat_n_diff_key_vals =
2403  static_cast<ib_uint64_t*>(mem_heap_zalloc(
2404  new_index->heap,
2405  dict_index_get_n_unique(new_index)
2406  * sizeof(*new_index->stat_n_diff_key_vals)));
2407 
2408  new_index->stat_n_sample_sizes =
2409  static_cast<ib_uint64_t*>(mem_heap_zalloc(
2410  new_index->heap,
2411  dict_index_get_n_unique(new_index)
2412  * sizeof(*new_index->stat_n_sample_sizes)));
2413 
2414  new_index->stat_n_non_null_key_vals =
2415  static_cast<ib_uint64_t*>(mem_heap_zalloc(
2416  new_index->heap,
2417  dict_index_get_n_unique(new_index)
2418  * sizeof(*new_index->stat_n_non_null_key_vals)));
2419  }
2420 
2421  new_index->stat_index_size = 1;
2422  new_index->stat_n_leaf_pages = 1;
2423 
2424  /* Add the new index as the last index for the table */
2425 
2426  UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
2427  new_index->table = table;
2428  new_index->table_name = table->name;
2429  new_index->search_info = btr_search_info_create(new_index->heap);
2430 
2431  new_index->page = page_no;
2432  rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
2433  dict_index_is_ibuf(index)
2434  ? SYNC_IBUF_INDEX_TREE : SYNC_INDEX_TREE);
2435 
2436  dict_sys->size += mem_heap_get_size(new_index->heap);
2437 
2438  dict_mem_index_free(index);
2439 
2440  return(DB_SUCCESS);
2441 }
2442 
2443 /**********************************************************************/
2445 static
2446 void
2447 dict_index_remove_from_cache_low(
2448 /*=============================*/
2449  dict_table_t* table,
2450  dict_index_t* index,
2451  ibool lru_evict)
2453 {
2454  ulint size;
2455  ulint retries = 0;
2456  btr_search_t* info;
2457 
2458  ut_ad(table && index);
2459  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2460  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
2461  ut_ad(mutex_own(&(dict_sys->mutex)));
2462 
2463  /* No need to acquire the dict_index_t::lock here because
2464  there can't be any active operations on this index (or table). */
2465 
2466  if (index->online_log) {
2468  row_log_free(index->online_log);
2469  }
2470 
2471  /* We always create search info whether or not adaptive
2472  hash index is enabled or not. */
2473  info = btr_search_get_info(index);
2474  ut_ad(info);
2475 
2476  /* We are not allowed to free the in-memory index struct
2477  dict_index_t until all entries in the adaptive hash index
2478  that point to any of the page belonging to his b-tree index
2479  are dropped. This is so because dropping of these entries
2480  require access to dict_index_t struct. To avoid such scenario
2481  We keep a count of number of such pages in the search_info and
2482  only free the dict_index_t struct when this count drops to
2483  zero. See also: dict_table_can_be_evicted() */
2484 
2485  do {
2486  ulint ref_count = btr_search_info_get_ref_count(info);
2487 
2488  if (ref_count == 0) {
2489  break;
2490  }
2491 
2492  /* Sleep for 10ms before trying again. */
2493  os_thread_sleep(10000);
2494  ++retries;
2495 
2496  if (retries % 500 == 0) {
2497  /* No luck after 5 seconds of wait. */
2498  fprintf(stderr, "InnoDB: Error: Waited for"
2499  " %lu secs for hash index"
2500  " ref_count (%lu) to drop"
2501  " to 0.\n"
2502  "index: \"%s\""
2503  " table: \"%s\"\n",
2504  retries/100,
2505  ref_count,
2506  index->name,
2507  table->name);
2508  }
2509 
2510  /* To avoid a hang here we commit suicide if the
2511  ref_count doesn't drop to zero in 600 seconds. */
2512  if (retries >= 60000) {
2513  ut_error;
2514  }
2515  } while (srv_shutdown_state == SRV_SHUTDOWN_NONE || !lru_evict);
2516 
2517  rw_lock_free(&index->lock);
2518 
2519  /* Remove the index from the list of indexes of the table */
2520  UT_LIST_REMOVE(indexes, table->indexes, index);
2521 
2522  size = mem_heap_get_size(index->heap);
2523 
2524  ut_ad(dict_sys->size >= size);
2525 
2526  dict_sys->size -= size;
2527 
2528  dict_mem_index_free(index);
2529 }
2530 
2531 /**********************************************************************/
2533 UNIV_INTERN
2534 void
2536 /*=========================*/
2537  dict_table_t* table,
2538  dict_index_t* index)
2539 {
2540  dict_index_remove_from_cache_low(table, index, FALSE);
2541 }
2542 
2543 /*******************************************************************/
2547 static
2548 ibool
2549 dict_index_find_cols(
2550 /*=================*/
2551  dict_table_t* table,
2552  dict_index_t* index)
2553 {
2554  ulint i;
2555 
2556  ut_ad(table && index);
2557  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2558  ut_ad(mutex_own(&(dict_sys->mutex)));
2559 
2560  for (i = 0; i < index->n_fields; i++) {
2561  ulint j;
2562  dict_field_t* field = dict_index_get_nth_field(index, i);
2563 
2564  for (j = 0; j < table->n_cols; j++) {
2565  if (!strcmp(dict_table_get_col_name(table, j),
2566  field->name)) {
2567  field->col = dict_table_get_nth_col(table, j);
2568 
2569  goto found;
2570  }
2571  }
2572 
2573 #ifdef UNIV_DEBUG
2574  /* It is an error not to find a matching column. */
2575  fputs("InnoDB: Error: no matching column for ", stderr);
2576  ut_print_name(stderr, NULL, FALSE, field->name);
2577  fputs(" in ", stderr);
2578  dict_index_name_print(stderr, NULL, index);
2579  fputs("!\n", stderr);
2580 #endif /* UNIV_DEBUG */
2581  return(FALSE);
2582 
2583 found:
2584  ;
2585  }
2586 
2587  return(TRUE);
2588 }
2589 #endif /* !UNIV_HOTBACKUP */
2590 
2591 /*******************************************************************/
2593 UNIV_INTERN
2594 void
2596 /*===============*/
2597  dict_index_t* index,
2598  const dict_table_t* table,
2599  dict_col_t* col,
2600  ulint prefix_len)
2601 {
2602  dict_field_t* field;
2603  const char* col_name;
2604 
2605  col_name = dict_table_get_col_name(table, dict_col_get_no(col));
2606 
2607  dict_mem_index_add_field(index, col_name, prefix_len);
2608 
2609  field = dict_index_get_nth_field(index, index->n_def - 1);
2610 
2611  field->col = col;
2612  field->fixed_len = (unsigned int) dict_col_get_fixed_size(
2613  col, dict_table_is_comp(table));
2614 
2615  if (prefix_len && field->fixed_len > prefix_len) {
2616  field->fixed_len = (unsigned int) prefix_len;
2617  }
2618 
2619  /* Long fixed-length fields that need external storage are treated as
2620  variable-length fields, so that the extern flag can be embedded in
2621  the length word. */
2622 
2623  if (field->fixed_len > DICT_MAX_FIXED_COL_LEN) {
2624  field->fixed_len = 0;
2625  }
2626 #if DICT_MAX_FIXED_COL_LEN != 768
2627  /* The comparison limit above must be constant. If it were
2628  changed, the disk format of some fixed-length columns would
2629  change, which would be a disaster. */
2630 # error "DICT_MAX_FIXED_COL_LEN != 768"
2631 #endif
2632 
2633  if (!(col->prtype & DATA_NOT_NULL)) {
2634  index->n_nullable++;
2635  }
2636 }
2637 
2638 #ifndef UNIV_HOTBACKUP
2639 /*******************************************************************/
2641 static
2642 void
2643 dict_index_copy(
2644 /*============*/
2645  dict_index_t* index1,
2646  dict_index_t* index2,
2647  const dict_table_t* table,
2648  ulint start,
2649  ulint end)
2650 {
2651  dict_field_t* field;
2652  ulint i;
2653 
2654  /* Copy fields contained in index2 */
2655 
2656  for (i = start; i < end; i++) {
2657 
2658  field = dict_index_get_nth_field(index2, i);
2659  dict_index_add_col(index1, table, field->col,
2660  field->prefix_len);
2661  }
2662 }
2663 
2664 /*******************************************************************/
2666 UNIV_INTERN
2667 void
2669 /*==================*/
2670  dtuple_t* tuple,
2671  const dict_index_t* index,
2672  ulint n_fields)
2674 {
2675  ulint i;
2676 
2677  if (dict_index_is_univ(index)) {
2678  dtuple_set_types_binary(tuple, n_fields);
2679 
2680  return;
2681  }
2682 
2683  for (i = 0; i < n_fields; i++) {
2684  const dict_field_t* ifield;
2685  dtype_t* dfield_type;
2686 
2687  ifield = dict_index_get_nth_field(index, i);
2688  dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
2689  dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
2690  }
2691 }
2692 
2693 /*******************************************************************/
2697 UNIV_INTERN
2698 void
2700 /*==================*/
2701  dtuple_t* tuple,
2702  const dict_table_t* table)
2703 {
2704  ulint i;
2705 
2706  for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
2707 
2708  dfield_t* dfield = dtuple_get_nth_field(tuple, i);
2709  dtype_t* dtype = dfield_get_type(dfield);
2710 
2711  dfield_set_null(dfield);
2712  dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
2713  }
2714 }
2715 
2716 /********************************************************************
2717 Wait until all the background threads of the given table have exited, i.e.,
2718 bg_threads == 0. Note: bg_threads_mutex must be reserved when
2719 calling this. */
2720 UNIV_INTERN
2721 void
2722 dict_table_wait_for_bg_threads_to_exit(
2723 /*===================================*/
2724  dict_table_t* table, /*< in: table */
2725  ulint delay) /*< in: time in microseconds to wait between
2726  checks of bg_threads. */
2727 {
2728  fts_t* fts = table->fts;
2729 
2730 #ifdef UNIV_SYNC_DEBUG
2731  ut_ad(mutex_own(&fts->bg_threads_mutex));
2732 #endif /* UNIV_SYNC_DEBUG */
2733 
2734  while (fts->bg_threads > 0) {
2735  mutex_exit(&fts->bg_threads_mutex);
2736 
2737  os_thread_sleep(delay);
2738 
2739  mutex_enter(&fts->bg_threads_mutex);
2740  }
2741 }
2742 
2743 /*******************************************************************/
2747 static
2748 dict_index_t*
2749 dict_index_build_internal_clust(
2750 /*============================*/
2751  const dict_table_t* table,
2752  dict_index_t* index)
2754 {
2755  dict_index_t* new_index;
2756  dict_field_t* field;
2757  ulint trx_id_pos;
2758  ulint i;
2759  ibool* indexed;
2760 
2761  ut_ad(table && index);
2762  ut_ad(dict_index_is_clust(index));
2763  ut_ad(mutex_own(&(dict_sys->mutex)));
2764  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2765 
2766  /* Create a new index object with certainly enough fields */
2767  new_index = dict_mem_index_create(table->name,
2768  index->name, table->space,
2769  index->type,
2770  index->n_fields + table->n_cols);
2771 
2772  /* Copy other relevant data from the old index struct to the new
2773  struct: it inherits the values */
2774 
2775  new_index->n_user_defined_cols = index->n_fields;
2776 
2777  new_index->id = index->id;
2778 
2779  /* Copy the fields of index */
2780  dict_index_copy(new_index, index, table, 0, index->n_fields);
2781 
2782  if (dict_index_is_univ(index)) {
2783  /* No fixed number of fields determines an entry uniquely */
2784 
2785  new_index->n_uniq = REC_MAX_N_FIELDS;
2786 
2787  } else if (dict_index_is_unique(index)) {
2788  /* Only the fields defined so far are needed to identify
2789  the index entry uniquely */
2790 
2791  new_index->n_uniq = new_index->n_def;
2792  } else {
2793  /* Also the row id is needed to identify the entry */
2794  new_index->n_uniq = 1 + new_index->n_def;
2795  }
2796 
2797  new_index->trx_id_offset = 0;
2798 
2799  if (!dict_index_is_ibuf(index)) {
2800  /* Add system columns, trx id first */
2801 
2802  trx_id_pos = new_index->n_def;
2803 
2804 #if DATA_ROW_ID != 0
2805 # error "DATA_ROW_ID != 0"
2806 #endif
2807 #if DATA_TRX_ID != 1
2808 # error "DATA_TRX_ID != 1"
2809 #endif
2810 #if DATA_ROLL_PTR != 2
2811 # error "DATA_ROLL_PTR != 2"
2812 #endif
2813 
2814  if (!dict_index_is_unique(index)) {
2815  dict_index_add_col(new_index, table,
2816  dict_table_get_sys_col(
2817  table, DATA_ROW_ID),
2818  0);
2819  trx_id_pos++;
2820  }
2821 
2822  dict_index_add_col(new_index, table,
2823  dict_table_get_sys_col(table, DATA_TRX_ID),
2824  0);
2825 
2826  dict_index_add_col(new_index, table,
2827  dict_table_get_sys_col(table,
2828  DATA_ROLL_PTR),
2829  0);
2830 
2831  for (i = 0; i < trx_id_pos; i++) {
2832 
2833  ulint fixed_size = dict_col_get_fixed_size(
2834  dict_index_get_nth_col(new_index, i),
2835  dict_table_is_comp(table));
2836 
2837  if (fixed_size == 0) {
2838  new_index->trx_id_offset = 0;
2839 
2840  break;
2841  }
2842 
2843  if (dict_index_get_nth_field(new_index, i)->prefix_len
2844  > 0) {
2845  new_index->trx_id_offset = 0;
2846 
2847  break;
2848  }
2849 
2850  /* Add fixed_size to new_index->trx_id_offset.
2851  Because the latter is a bit-field, an overflow
2852  can theoretically occur. Check for it. */
2853  fixed_size += new_index->trx_id_offset;
2854 
2855  new_index->trx_id_offset = fixed_size;
2856 
2857  if (new_index->trx_id_offset != fixed_size) {
2858  /* Overflow. Pretend that this is a
2859  variable-length PRIMARY KEY. */
2860  ut_ad(0);
2861  new_index->trx_id_offset = 0;
2862  break;
2863  }
2864  }
2865 
2866  }
2867 
2868  /* Remember the table columns already contained in new_index */
2869  indexed = static_cast<ibool*>(
2870  mem_zalloc(table->n_cols * sizeof *indexed));
2871 
2872  /* Mark the table columns already contained in new_index */
2873  for (i = 0; i < new_index->n_def; i++) {
2874 
2875  field = dict_index_get_nth_field(new_index, i);
2876 
2877  /* If there is only a prefix of the column in the index
2878  field, do not mark the column as contained in the index */
2879 
2880  if (field->prefix_len == 0) {
2881 
2882  indexed[field->col->ind] = TRUE;
2883  }
2884  }
2885 
2886  /* Add to new_index non-system columns of table not yet included
2887  there */
2888  for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
2889 
2890  dict_col_t* col = dict_table_get_nth_col(table, i);
2891  ut_ad(col->mtype != DATA_SYS);
2892 
2893  if (!indexed[col->ind]) {
2894  dict_index_add_col(new_index, table, col, 0);
2895  }
2896  }
2897 
2898  mem_free(indexed);
2899 
2900  ut_ad(dict_index_is_ibuf(index)
2901  || (UT_LIST_GET_LEN(table->indexes) == 0));
2902 
2903  new_index->cached = TRUE;
2904 
2905  return(new_index);
2906 }
2907 
2908 /*******************************************************************/
2912 static
2913 dict_index_t*
2914 dict_index_build_internal_non_clust(
2915 /*================================*/
2916  const dict_table_t* table,
2917  dict_index_t* index)
2919 {
2920  dict_field_t* field;
2921  dict_index_t* new_index;
2922  dict_index_t* clust_index;
2923  ulint i;
2924  ibool* indexed;
2925 
2926  ut_ad(table && index);
2927  ut_ad(!dict_index_is_clust(index));
2928  ut_ad(mutex_own(&(dict_sys->mutex)));
2929  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2930 
2931  /* The clustered index should be the first in the list of indexes */
2932  clust_index = UT_LIST_GET_FIRST(table->indexes);
2933 
2934  ut_ad(clust_index);
2935  ut_ad(dict_index_is_clust(clust_index));
2936  ut_ad(!dict_index_is_univ(clust_index));
2937 
2938  /* Create a new index */
2939  new_index = dict_mem_index_create(
2940  table->name, index->name, index->space, index->type,
2941  index->n_fields + 1 + clust_index->n_uniq);
2942 
2943  /* Copy other relevant data from the old index
2944  struct to the new struct: it inherits the values */
2945 
2946  new_index->n_user_defined_cols = index->n_fields;
2947 
2948  new_index->id = index->id;
2949 
2950  /* Copy fields from index to new_index */
2951  dict_index_copy(new_index, index, table, 0, index->n_fields);
2952 
2953  /* Remember the table columns already contained in new_index */
2954  indexed = static_cast<ibool*>(
2955  mem_zalloc(table->n_cols * sizeof *indexed));
2956 
2957  /* Mark the table columns already contained in new_index */
2958  for (i = 0; i < new_index->n_def; i++) {
2959 
2960  field = dict_index_get_nth_field(new_index, i);
2961 
2962  /* If there is only a prefix of the column in the index
2963  field, do not mark the column as contained in the index */
2964 
2965  if (field->prefix_len == 0) {
2966 
2967  indexed[field->col->ind] = TRUE;
2968  }
2969  }
2970 
2971  /* Add to new_index the columns necessary to determine the clustered
2972  index entry uniquely */
2973 
2974  for (i = 0; i < clust_index->n_uniq; i++) {
2975 
2976  field = dict_index_get_nth_field(clust_index, i);
2977 
2978  if (!indexed[field->col->ind]) {
2979  dict_index_add_col(new_index, table, field->col,
2980  field->prefix_len);
2981  }
2982  }
2983 
2984  mem_free(indexed);
2985 
2986  if (dict_index_is_unique(index)) {
2987  new_index->n_uniq = index->n_fields;
2988  } else {
2989  new_index->n_uniq = new_index->n_def;
2990  }
2991 
2992  /* Set the n_fields value in new_index to the actual defined
2993  number of fields */
2994 
2995  new_index->n_fields = new_index->n_def;
2996 
2997  new_index->cached = TRUE;
2998 
2999  return(new_index);
3000 }
3001 
3002 /***********************************************************************
3003 Builds the internal dictionary cache representation for an FTS index.
3004 @return own: the internal representation of the FTS index */
3005 static
3006 dict_index_t*
3007 dict_index_build_internal_fts(
3008 /*==========================*/
3009  dict_table_t* table,
3010  dict_index_t* index)
3011 {
3012  dict_index_t* new_index;
3013 
3014  ut_ad(table && index);
3015  ut_ad(index->type == DICT_FTS);
3016 #ifdef UNIV_SYNC_DEBUG
3017  ut_ad(mutex_own(&(dict_sys->mutex)));
3018 #endif /* UNIV_SYNC_DEBUG */
3019  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
3020 
3021  /* Create a new index */
3022  new_index = dict_mem_index_create(
3023  table->name, index->name, index->space, index->type,
3024  index->n_fields);
3025 
3026  /* Copy other relevant data from the old index struct to the new
3027  struct: it inherits the values */
3028 
3029  new_index->n_user_defined_cols = index->n_fields;
3030 
3031  new_index->id = index->id;
3032 
3033  /* Copy fields from index to new_index */
3034  dict_index_copy(new_index, index, table, 0, index->n_fields);
3035 
3036  new_index->n_uniq = 0;
3037  new_index->cached = TRUE;
3038 
3039  if (table->fts->cache == NULL) {
3040  table->fts->cache = fts_cache_create(table);
3041  }
3042 
3043  rw_lock_x_lock(&table->fts->cache->init_lock);
3044  /* Notify the FTS cache about this index. */
3045  fts_cache_index_cache_create(table, new_index);
3046  rw_lock_x_unlock(&table->fts->cache->init_lock);
3047 
3048  return(new_index);
3049 }
3050 /*====================== FOREIGN KEY PROCESSING ========================*/
3051 
3052 /*********************************************************************/
3055 UNIV_INTERN
3056 ibool
3058 /*====================================*/
3059  const dict_table_t* table)
3060 {
3061  return(UT_LIST_GET_LEN(table->referenced_list) > 0);
3062 }
3063 
3064 /*********************************************************************/
3069 UNIV_INTERN
3072 /*=================================*/
3073  dict_table_t* table,
3074  dict_index_t* index)
3075 {
3076  dict_foreign_t* foreign;
3077 
3078  ut_ad(index != NULL);
3079  ut_ad(table != NULL);
3080 
3081  for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
3082  foreign;
3083  foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
3084 
3085  if (foreign->referenced_index == index) {
3086 
3087  return(foreign);
3088  }
3089  }
3090 
3091  return(NULL);
3092 }
3093 
3094 /*********************************************************************/
3100 UNIV_INTERN
3103 /*==============================*/
3104  dict_table_t* table,
3105  dict_index_t* index)
3106 {
3107  dict_foreign_t* foreign;
3108 
3109  ut_ad(index != NULL);
3110  ut_ad(table != NULL);
3111 
3112  for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
3113  foreign;
3114  foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
3115 
3116  if (foreign->foreign_index == index) {
3117 
3118  return(foreign);
3119  }
3120  }
3121 
3122  return(NULL);
3123 }
3124 
3125 /*********************************************************************/
3127 UNIV_INTERN
3128 void
3130 /*==============*/
3131  dict_foreign_t* foreign)
3132 {
3133  mem_heap_free(foreign->heap);
3134 }
3135 
3136 /**********************************************************************/
3138 UNIV_INTERN
3139 void
3141 /*===========================*/
3142  dict_foreign_t* foreign)
3143 {
3144  ut_ad(mutex_own(&(dict_sys->mutex)));
3145  ut_a(foreign);
3146 
3147  if (foreign->referenced_table) {
3148  UT_LIST_REMOVE(referenced_list,
3150  foreign);
3151  }
3152 
3153  if (foreign->foreign_table) {
3154  UT_LIST_REMOVE(foreign_list,
3155  foreign->foreign_table->foreign_list,
3156  foreign);
3157  }
3158 
3159  dict_foreign_free(foreign);
3160 }
3161 
3162 /**********************************************************************/
3166 static
3168 dict_foreign_find(
3169 /*==============*/
3170  dict_table_t* table,
3171  const char* id)
3172 {
3173  dict_foreign_t* foreign;
3174 
3175  ut_ad(mutex_own(&(dict_sys->mutex)));
3176 
3177  foreign = UT_LIST_GET_FIRST(table->foreign_list);
3178 
3179  while (foreign) {
3180  if (ut_strcmp(id, foreign->id) == 0) {
3181 
3182  return(foreign);
3183  }
3184 
3185  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3186  }
3187 
3188  foreign = UT_LIST_GET_FIRST(table->referenced_list);
3189 
3190  while (foreign) {
3191  if (ut_strcmp(id, foreign->id) == 0) {
3192 
3193  return(foreign);
3194  }
3195 
3196  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3197  }
3198 
3199  return(NULL);
3200 }
3201 
3202 
3203 /*********************************************************************/
3208 UNIV_INTERN
3209 dict_index_t*
3211 /*====================*/
3212  const dict_table_t* table,
3213  const char** col_names,
3216  const char** columns,
3217  ulint n_cols,
3218  const dict_index_t* types_idx,
3222  bool check_charsets,
3226  ulint check_null)
3230 {
3232 
3233  ut_ad(mutex_own(&dict_sys->mutex));
3234 
3235  index = dict_table_get_first_index(table);
3236 
3237  while (index != NULL) {
3238  if (types_idx != index
3239  && !(index->type & DICT_FTS)
3240  && !index->to_be_dropped
3242  table, col_names, columns, n_cols,
3243  index, types_idx,
3244  check_charsets, check_null)) {
3245  return(index);
3246  }
3247 
3248  index = dict_table_get_next_index(index);
3249  }
3250 
3251  return(NULL);
3252 }
3253 
3254 /**********************************************************************/
3256 static
3257 void
3258 dict_foreign_error_report_low(
3259 /*==========================*/
3260  FILE* file,
3261  const char* name)
3262 {
3263  rewind(file);
3264  ut_print_timestamp(file);
3265  fprintf(file, " Error in foreign key constraint of table %s:\n",
3266  name);
3267 }
3268 
3269 /**********************************************************************/
3271 static
3272 void
3273 dict_foreign_error_report(
3274 /*======================*/
3275  FILE* file,
3276  dict_foreign_t* fk,
3277  const char* msg)
3278 {
3279  mutex_enter(&dict_foreign_err_mutex);
3280  dict_foreign_error_report_low(file, fk->foreign_table_name);
3281  fputs(msg, file);
3282  fputs(" Constraint:\n", file);
3284  putc('\n', file);
3285  if (fk->foreign_index) {
3286  fputs("The index in the foreign key in table is ", file);
3287  ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
3288  fputs("\n"
3289  "See " REFMAN "innodb-foreign-key-constraints.html\n"
3290  "for correct foreign key definition.\n",
3291  file);
3292  }
3293  mutex_exit(&dict_foreign_err_mutex);
3294 }
3295 
3296 /**********************************************************************/
3302 UNIV_INTERN
3303 dberr_t
3305 /*======================*/
3306  dict_foreign_t* foreign,
3308  const char** col_names,
3311  bool check_charsets,
3314  dict_err_ignore_t ignore_err)
3316 {
3317  dict_table_t* for_table;
3318  dict_table_t* ref_table;
3319  dict_foreign_t* for_in_cache = NULL;
3321  ibool added_to_referenced_list= FALSE;
3322  FILE* ef = dict_foreign_err_file;
3323 
3324  ut_ad(mutex_own(&(dict_sys->mutex)));
3325 
3327  foreign->foreign_table_name_lookup);
3328 
3330  foreign->referenced_table_name_lookup);
3331  ut_a(for_table || ref_table);
3332 
3333  if (for_table) {
3334  for_in_cache = dict_foreign_find(for_table, foreign->id);
3335  }
3336 
3337  if (!for_in_cache && ref_table) {
3338  for_in_cache = dict_foreign_find(ref_table, foreign->id);
3339  }
3340 
3341  if (for_in_cache) {
3342  /* Free the foreign object */
3343  mem_heap_free(foreign->heap);
3344  } else {
3345  for_in_cache = foreign;
3346  }
3347 
3348  if (ref_table && !for_in_cache->referenced_table) {
3349  index = dict_foreign_find_index(
3350  ref_table, NULL,
3351  for_in_cache->referenced_col_names,
3352  for_in_cache->n_fields, for_in_cache->foreign_index,
3353  check_charsets, false);
3354 
3355  if (index == NULL
3356  && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
3357  dict_foreign_error_report(
3358  ef, for_in_cache,
3359  "there is no index in referenced table"
3360  " which would contain\n"
3361  "the columns as the first columns,"
3362  " or the data types in the\n"
3363  "referenced table do not match"
3364  " the ones in table.");
3365 
3366  if (for_in_cache == foreign) {
3367  mem_heap_free(foreign->heap);
3368  }
3369 
3370  return(DB_CANNOT_ADD_CONSTRAINT);
3371  }
3372 
3373  for_in_cache->referenced_table = ref_table;
3374  for_in_cache->referenced_index = index;
3375  UT_LIST_ADD_LAST(referenced_list,
3376  ref_table->referenced_list,
3377  for_in_cache);
3378  added_to_referenced_list = TRUE;
3379  }
3380 
3381  if (for_table && !for_in_cache->foreign_table) {
3382  index = dict_foreign_find_index(
3383  for_table, col_names,
3384  for_in_cache->foreign_col_names,
3385  for_in_cache->n_fields,
3386  for_in_cache->referenced_index, check_charsets,
3387  for_in_cache->type
3390 
3391  if (index == NULL
3392  && !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
3393  dict_foreign_error_report(
3394  ef, for_in_cache,
3395  "there is no index in the table"
3396  " which would contain\n"
3397  "the columns as the first columns,"
3398  " or the data types in the\n"
3399  "table do not match"
3400  " the ones in the referenced table\n"
3401  "or one of the ON ... SET NULL columns"
3402  " is declared NOT NULL.");
3403 
3404  if (for_in_cache == foreign) {
3405  if (added_to_referenced_list) {
3407  referenced_list,
3408  ref_table->referenced_list,
3409  for_in_cache);
3410  }
3411 
3412  mem_heap_free(foreign->heap);
3413  }
3414 
3415  return(DB_CANNOT_ADD_CONSTRAINT);
3416  }
3417 
3418  for_in_cache->foreign_table = for_table;
3419  for_in_cache->foreign_index = index;
3420  UT_LIST_ADD_LAST(foreign_list,
3421  for_table->foreign_list,
3422  for_in_cache);
3423  }
3424 
3425  /* We need to move the table to the non-LRU end of the table LRU
3426  list. Otherwise it will be evicted from the cache. */
3427 
3428  if (ref_table != NULL && ref_table->can_be_evicted) {
3430  }
3431 
3432  if (for_table != NULL && for_table->can_be_evicted) {
3434  }
3435 
3436  ut_ad(dict_lru_validate());
3437 
3438  return(DB_SUCCESS);
3439 }
3440 
3441 /*********************************************************************/
3446 static
3447 const char*
3448 dict_scan_to(
3449 /*=========*/
3450  const char* ptr,
3451  const char* string)
3452 {
3453  char quote = '\0';
3454  bool escape = false;
3455 
3456  for (; *ptr; ptr++) {
3457  if (*ptr == quote) {
3458  /* Closing quote character: do not look for
3459  starting quote or the keyword. */
3460 
3461  /* If the quote character is escaped by a
3462  backslash, ignore it. */
3463  if (escape) {
3464  escape = false;
3465  } else {
3466  quote = '\0';
3467  }
3468  } else if (quote) {
3469  /* Within quotes: do nothing. */
3470  if (escape) {
3471  escape = false;
3472  } else if (*ptr == '\\') {
3473  escape = true;
3474  }
3475  } else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
3476  /* Starting quote: remember the quote character. */
3477  quote = *ptr;
3478  } else {
3479  /* Outside quotes: look for the keyword. */
3480  ulint i;
3481  for (i = 0; string[i]; i++) {
3482  if (toupper((int)(unsigned char)(ptr[i]))
3483  != toupper((int)(unsigned char)
3484  (string[i]))) {
3485  goto nomatch;
3486  }
3487  }
3488  break;
3489 nomatch:
3490  ;
3491  }
3492  }
3493 
3494  return(ptr);
3495 }
3496 
3497 /*********************************************************************/
3501 static
3502 const char*
3503 dict_accept(
3504 /*========*/
3505  struct charset_info_st* cs,
3506  const char* ptr,
3507  const char* string,
3509  ibool* success)
3510 {
3511  const char* old_ptr = ptr;
3512  const char* old_ptr2;
3513 
3514  *success = FALSE;
3515 
3516  while (my_isspace(cs, *ptr)) {
3517  ptr++;
3518  }
3519 
3520  old_ptr2 = ptr;
3521 
3522  ptr = dict_scan_to(ptr, string);
3523 
3524  if (*ptr == '\0' || old_ptr2 != ptr) {
3525  return(old_ptr);
3526  }
3527 
3528  *success = TRUE;
3529 
3530  return(ptr + ut_strlen(string));
3531 }
3532 
3533 /*********************************************************************/
3537 static
3538 const char*
3539 dict_scan_id(
3540 /*=========*/
3541  struct charset_info_st* cs,
3542  const char* ptr,
3543  mem_heap_t* heap,
3546  const char** id,
3548  ibool table_id,
3550  ibool accept_also_dot)
3554 {
3555  char quote = '\0';
3556  ulint len = 0;
3557  const char* s;
3558  char* str;
3559  char* dst;
3560 
3561  *id = NULL;
3562 
3563  while (my_isspace(cs, *ptr)) {
3564  ptr++;
3565  }
3566 
3567  if (*ptr == '\0') {
3568 
3569  return(ptr);
3570  }
3571 
3572  if (*ptr == '`' || *ptr == '"') {
3573  quote = *ptr++;
3574  }
3575 
3576  s = ptr;
3577 
3578  if (quote) {
3579  for (;;) {
3580  if (!*ptr) {
3581  /* Syntax error */
3582  return(ptr);
3583  }
3584  if (*ptr == quote) {
3585  ptr++;
3586  if (*ptr != quote) {
3587  break;
3588  }
3589  }
3590  ptr++;
3591  len++;
3592  }
3593  } else {
3594  while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
3595  && (accept_also_dot || *ptr != '.')
3596  && *ptr != ',' && *ptr != '\0') {
3597 
3598  ptr++;
3599  }
3600 
3601  len = ptr - s;
3602  }
3603 
3604  if (UNIV_UNLIKELY(!heap)) {
3605  /* no heap given: id will point to source string */
3606  *id = s;
3607  return(ptr);
3608  }
3609 
3610  if (quote) {
3611  char* d;
3612 
3613  str = d = static_cast<char*>(
3614  mem_heap_alloc(heap, len + 1));
3615 
3616  while (len--) {
3617  if ((*d++ = *s++) == quote) {
3618  s++;
3619  }
3620  }
3621  *d++ = 0;
3622  len = d - str;
3623  ut_ad(*s == quote);
3624  ut_ad(s + 1 == ptr);
3625  } else {
3626  str = mem_heap_strdupl(heap, s, len);
3627  }
3628 
3629  if (!table_id) {
3630 convert_id:
3631  /* Convert the identifier from connection character set
3632  to UTF-8. */
3633  len = 3 * len + 1;
3634  *id = dst = static_cast<char*>(mem_heap_alloc(heap, len));
3635 
3636  innobase_convert_from_id(cs, dst, str, len);
3637  } else if (!strncmp(str, srv_mysql50_table_name_prefix,
3638  sizeof(srv_mysql50_table_name_prefix) - 1)) {
3639  /* This is a pre-5.1 table name
3640  containing chars other than [A-Za-z0-9].
3641  Discard the prefix and use raw UTF-8 encoding. */
3642  str += sizeof(srv_mysql50_table_name_prefix) - 1;
3643  len -= sizeof(srv_mysql50_table_name_prefix) - 1;
3644  goto convert_id;
3645  } else {
3646  /* Encode using filename-safe characters. */
3647  len = 5 * len + 1;
3648  *id = dst = static_cast<char*>(mem_heap_alloc(heap, len));
3649 
3650  innobase_convert_from_table_id(cs, dst, str, len);
3651  }
3652 
3653  return(ptr);
3654 }
3655 
3656 /*********************************************************************/
3659 static
3660 const char*
3661 dict_scan_col(
3662 /*==========*/
3663  struct charset_info_st* cs,
3664  const char* ptr,
3665  ibool* success,
3666  dict_table_t* table,
3667  const dict_col_t** column,
3668  mem_heap_t* heap,
3669  const char** name)
3671 {
3672  ulint i;
3673 
3674  *success = FALSE;
3675 
3676  ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
3677 
3678  if (*name == NULL) {
3679 
3680  return(ptr); /* Syntax error */
3681  }
3682 
3683  if (table == NULL) {
3684  *success = TRUE;
3685  *column = NULL;
3686  } else {
3687  for (i = 0; i < dict_table_get_n_cols(table); i++) {
3688 
3689  const char* col_name = dict_table_get_col_name(
3690  table, i);
3691 
3692  if (0 == innobase_strcasecmp(col_name, *name)) {
3693  /* Found */
3694 
3695  *success = TRUE;
3696  *column = dict_table_get_nth_col(table, i);
3697  strcpy((char*) *name, col_name);
3698 
3699  break;
3700  }
3701  }
3702  }
3703 
3704  return(ptr);
3705 }
3706 
3707 
3708 /*********************************************************************/
3713 UNIV_INTERN
3714 char*
3716 /*======================*/
3717  const char* name,
3718  const char* database_name,
3719  ulint database_name_len,
3720  const char* table_name,
3721  ulint table_name_len,
3722  dict_table_t** table,
3723  mem_heap_t* heap)
3724 {
3725  char* ref;
3726  const char* db_name;
3727 
3728  if (!database_name) {
3729  /* Use the database name of the foreign key table */
3730 
3731  db_name = name;
3732  database_name_len = dict_get_db_name_len(name);
3733  } else {
3734  db_name = database_name;
3735  }
3736 
3737  /* Copy database_name, '/', table_name, '\0' */
3738  ref = static_cast<char*>(
3739  mem_heap_alloc(heap, database_name_len + table_name_len + 2));
3740 
3741  memcpy(ref, db_name, database_name_len);
3742  ref[database_name_len] = '/';
3743  memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
3744 
3745  /* Values; 0 = Store and compare as given; case sensitive
3746  1 = Store and compare in lower; case insensitive
3747  2 = Store as given, compare in lower; case semi-sensitive */
3749  innobase_casedn_str(ref);
3750  *table = dict_table_get_low(ref);
3751  memcpy(ref, db_name, database_name_len);
3752  ref[database_name_len] = '/';
3753  memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
3754 
3755  } else {
3756 #ifndef __WIN__
3758  innobase_casedn_str(ref);
3759  }
3760 #else
3761  innobase_casedn_str(ref);
3762 #endif /* !__WIN__ */
3763  *table = dict_table_get_low(ref);
3764  }
3765 
3766  return(ref);
3767 }
3768 /*********************************************************************/
3771 static
3772 const char*
3773 dict_scan_table_name(
3774 /*=================*/
3775  struct charset_info_st* cs,
3776  const char* ptr,
3777  dict_table_t** table,
3778  const char* name,
3779  ibool* success,
3780  mem_heap_t* heap,
3781  const char** ref_name)
3783 {
3784  const char* database_name = NULL;
3785  ulint database_name_len = 0;
3786  const char* table_name = NULL;
3787  const char* scan_name;
3788 
3789  *success = FALSE;
3790  *table = NULL;
3791 
3792  ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
3793 
3794  if (scan_name == NULL) {
3795 
3796  return(ptr); /* Syntax error */
3797  }
3798 
3799  if (*ptr == '.') {
3800  /* We scanned the database name; scan also the table name */
3801 
3802  ptr++;
3803 
3804  database_name = scan_name;
3805  database_name_len = strlen(database_name);
3806 
3807  ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
3808 
3809  if (table_name == NULL) {
3810 
3811  return(ptr); /* Syntax error */
3812  }
3813  } else {
3814  /* To be able to read table dumps made with InnoDB-4.0.17 or
3815  earlier, we must allow the dot separator between the database
3816  name and the table name also to appear within a quoted
3817  identifier! InnoDB used to print a constraint as:
3818  ... REFERENCES `databasename.tablename` ...
3819  starting from 4.0.18 it is
3820  ... REFERENCES `databasename`.`tablename` ... */
3821  const char* s;
3822 
3823  for (s = scan_name; *s; s++) {
3824  if (*s == '.') {
3825  database_name = scan_name;
3826  database_name_len = s - scan_name;
3827  scan_name = ++s;
3828  break;/* to do: multiple dots? */
3829  }
3830  }
3831 
3832  table_name = scan_name;
3833  }
3834 
3835  *ref_name = dict_get_referenced_table(
3836  name, database_name, database_name_len,
3837  table_name, strlen(table_name), table, heap);
3838 
3839  *success = TRUE;
3840  return(ptr);
3841 }
3842 
3843 /*********************************************************************/
3846 static
3847 const char*
3848 dict_skip_word(
3849 /*===========*/
3850  struct charset_info_st* cs,
3851  const char* ptr,
3852  ibool* success)
3854 {
3855  const char* start;
3856 
3857  *success = FALSE;
3858 
3859  ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
3860 
3861  if (start) {
3862  *success = TRUE;
3863  }
3864 
3865  return(ptr);
3866 }
3867 
3868 /*********************************************************************/
3876 static
3877 char*
3878 dict_strip_comments(
3879 /*================*/
3880  const char* sql_string,
3881  size_t sql_length)
3882 {
3883  char* str;
3884  const char* sptr;
3885  const char* eptr = sql_string + sql_length;
3886  char* ptr;
3887  /* unclosed quote character (0 if none) */
3888  char quote = 0;
3889  bool escape = false;
3890 
3891  DBUG_ENTER("dict_strip_comments");
3892 
3893  DBUG_PRINT("dict_strip_comments", ("%s", sql_string));
3894 
3895  str = static_cast<char*>(mem_alloc(sql_length + 1));
3896 
3897  sptr = sql_string;
3898  ptr = str;
3899 
3900  for (;;) {
3901 scan_more:
3902  if (sptr >= eptr || *sptr == '\0') {
3903 end_of_string:
3904  *ptr = '\0';
3905 
3906  ut_a(ptr <= str + sql_length);
3907 
3908  DBUG_PRINT("dict_strip_comments", ("%s", str));
3909  DBUG_RETURN(str);
3910  }
3911 
3912  if (*sptr == quote) {
3913  /* Closing quote character: do not look for
3914  starting quote or comments. */
3915 
3916  /* If the quote character is escaped by a
3917  backslash, ignore it. */
3918  if (escape) {
3919  escape = false;
3920  } else {
3921  quote = 0;
3922  }
3923  } else if (quote) {
3924  /* Within quotes: do not look for
3925  starting quotes or comments. */
3926  if (escape) {
3927  escape = false;
3928  } else if (*sptr == '\\') {
3929  escape = true;
3930  }
3931  } else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
3932  /* Starting quote: remember the quote character. */
3933  quote = *sptr;
3934  } else if (*sptr == '#'
3935  || (sptr[0] == '-' && sptr[1] == '-'
3936  && sptr[2] == ' ')) {
3937  for (;;) {
3938  if (++sptr >= eptr) {
3939  goto end_of_string;
3940  }
3941 
3942  /* In Unix a newline is 0x0A while in Windows
3943  it is 0x0D followed by 0x0A */
3944 
3945  switch (*sptr) {
3946  case (char) 0X0A:
3947  case (char) 0x0D:
3948  case '\0':
3949  goto scan_more;
3950  }
3951  }
3952  } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
3953  sptr += 2;
3954  for (;;) {
3955  if (sptr >= eptr) {
3956  goto end_of_string;
3957  }
3958 
3959  switch (*sptr) {
3960  case '\0':
3961  goto scan_more;
3962  case '*':
3963  if (sptr[1] == '/') {
3964  sptr += 2;
3965  goto scan_more;
3966  }
3967  }
3968 
3969  sptr++;
3970  }
3971  }
3972 
3973  *ptr = *sptr;
3974 
3975  ptr++;
3976  sptr++;
3977  }
3978 }
3979 
3980 /*********************************************************************/
3985 UNIV_INTERN
3986 ulint
3988 /*==============================*/
3989  dict_table_t* table)
3990 {
3991  dict_foreign_t* foreign;
3992  char* endp;
3993  ulint biggest_id = 0;
3994  ulint id;
3995  ulint len;
3996 
3997  ut_a(table);
3998 
3999  len = ut_strlen(table->name);
4000  foreign = UT_LIST_GET_FIRST(table->foreign_list);
4001 
4002  while (foreign) {
4003  if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
4004  && 0 == ut_memcmp(foreign->id, table->name, len)
4005  && 0 == ut_memcmp(foreign->id + len,
4006  dict_ibfk, (sizeof dict_ibfk) - 1)
4007  && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
4008  /* It is of the >= 4.0.18 format */
4009 
4010  id = strtoul(foreign->id + len
4011  + ((sizeof dict_ibfk) - 1),
4012  &endp, 10);
4013  if (*endp == '\0') {
4014  ut_a(id != biggest_id);
4015 
4016  if (id > biggest_id) {
4017  biggest_id = id;
4018  }
4019  }
4020  }
4021 
4022  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4023  }
4024 
4025  return(biggest_id);
4026 }
4027 
4028 /*********************************************************************/
4030 static
4031 void
4032 dict_foreign_report_syntax_err(
4033 /*===========================*/
4034  const char* name,
4035  const char* start_of_latest_foreign,
4038  const char* ptr)
4039 {
4041 
4042  FILE* ef = dict_foreign_err_file;
4043 
4044  mutex_enter(&dict_foreign_err_mutex);
4045  dict_foreign_error_report_low(ef, name);
4046  fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
4047  start_of_latest_foreign, ptr);
4048  mutex_exit(&dict_foreign_err_mutex);
4049 }
4050 
4051 /*********************************************************************/
4058 static
4059 dberr_t
4060 dict_create_foreign_constraints_low(
4061 /*================================*/
4062  trx_t* trx,
4063  mem_heap_t* heap,
4064  struct charset_info_st* cs,
4065  const char* sql_string,
4072  const char* name,
4074  ibool reject_fks)
4078 {
4081  dict_table_t* table_to_alter;
4082  ulint highest_id_so_far = 0;
4084  dict_foreign_t* foreign;
4085  const char* ptr = sql_string;
4086  const char* start_of_latest_foreign = sql_string;
4087  FILE* ef = dict_foreign_err_file;
4088  const char* constraint_name;
4089  ibool success;
4090  dberr_t error;
4091  const char* ptr1;
4092  const char* ptr2;
4093  ulint i;
4094  ulint j;
4095  ibool is_on_delete;
4096  ulint n_on_deletes;
4097  ulint n_on_updates;
4098  const dict_col_t*columns[500];
4099  const char* column_names[500];
4100  const char* referenced_table_name;
4101 
4103  ut_ad(mutex_own(&(dict_sys->mutex)));
4104 
4105  table = dict_table_get_low(name);
4106 
4107  if (table == NULL) {
4108  mutex_enter(&dict_foreign_err_mutex);
4109  dict_foreign_error_report_low(ef, name);
4110  fprintf(ef,
4111  "Cannot find the table in the internal"
4112  " data dictionary of InnoDB.\n"
4113  "Create table statement:\n%s\n", sql_string);
4114  mutex_exit(&dict_foreign_err_mutex);
4115 
4116  return(DB_ERROR);
4117  }
4118 
4119  /* First check if we are actually doing an ALTER TABLE, and in that
4120  case look for the table being altered */
4121 
4122  ptr = dict_accept(cs, ptr, "ALTER", &success);
4123 
4124  if (!success) {
4125 
4126  goto loop;
4127  }
4128 
4129  ptr = dict_accept(cs, ptr, "TABLE", &success);
4130 
4131  if (!success) {
4132 
4133  goto loop;
4134  }
4135 
4136  /* We are doing an ALTER TABLE: scan the table name we are altering */
4137 
4138  ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
4139  &success, heap, &referenced_table_name);
4140  if (!success) {
4141  fprintf(stderr,
4142  "InnoDB: Error: could not find"
4143  " the table being ALTERED in:\n%s\n",
4144  sql_string);
4145 
4146  return(DB_ERROR);
4147  }
4148 
4149  /* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
4150  format databasename/tablename_ibfk_[number], where [number] is local
4151  to the table; look for the highest [number] for table_to_alter, so
4152  that we can assign to new constraints higher numbers. */
4153 
4154  /* If we are altering a temporary table, the table name after ALTER
4155  TABLE does not correspond to the internal table name, and
4156  table_to_alter is NULL. TODO: should we fix this somehow? */
4157 
4158  if (table_to_alter == NULL) {
4159  highest_id_so_far = 0;
4160  } else {
4161  highest_id_so_far = dict_table_get_highest_foreign_id(
4162  table_to_alter);
4163  }
4164 
4165  /* Scan for foreign key declarations in a loop */
4166 loop:
4167  /* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
4168 
4169  ptr1 = dict_scan_to(ptr, "CONSTRAINT");
4170  ptr2 = dict_scan_to(ptr, "FOREIGN");
4171 
4172  constraint_name = NULL;
4173 
4174  if (ptr1 < ptr2) {
4175  /* The user may have specified a constraint name. Pick it so
4176  that we can store 'databasename/constraintname' as the id of
4177  of the constraint to system tables. */
4178  ptr = ptr1;
4179 
4180  ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
4181 
4182  ut_a(success);
4183 
4184  if (!my_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
4185  goto loop;
4186  }
4187 
4188  while (my_isspace(cs, *ptr)) {
4189  ptr++;
4190  }
4191 
4192  /* read constraint name unless got "CONSTRAINT FOREIGN" */
4193  if (ptr != ptr2) {
4194  ptr = dict_scan_id(cs, ptr, heap,
4195  &constraint_name, FALSE, FALSE);
4196  }
4197  } else {
4198  ptr = ptr2;
4199  }
4200 
4201  if (*ptr == '\0') {
4202  /* The proper way to reject foreign keys for temporary
4203  tables would be to split the lexing and syntactical
4204  analysis of foreign key clauses from the actual adding
4205  of them, so that ha_innodb.cc could first parse the SQL
4206  command, determine if there are any foreign keys, and
4207  if so, immediately reject the command if the table is a
4208  temporary one. For now, this kludge will work. */
4209  if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
4210 
4211  return(DB_CANNOT_ADD_CONSTRAINT);
4212  }
4213 
4214  /**********************************************************/
4215  /* The following call adds the foreign key constraints
4216  to the data dictionary system tables on disk */
4217 
4219  highest_id_so_far, table, trx);
4220  return(error);
4221  }
4222 
4223  start_of_latest_foreign = ptr;
4224 
4225  ptr = dict_accept(cs, ptr, "FOREIGN", &success);
4226 
4227  if (!success) {
4228  goto loop;
4229  }
4230 
4231  if (!my_isspace(cs, *ptr)) {
4232  goto loop;
4233  }
4234 
4235  ptr = dict_accept(cs, ptr, "KEY", &success);
4236 
4237  if (!success) {
4238  goto loop;
4239  }
4240 
4241  ptr = dict_accept(cs, ptr, "(", &success);
4242 
4243  if (!success) {
4244  /* MySQL allows also an index id before the '('; we
4245  skip it */
4246  ptr = dict_skip_word(cs, ptr, &success);
4247 
4248  if (!success) {
4249  dict_foreign_report_syntax_err(
4250  name, start_of_latest_foreign, ptr);
4251 
4252  return(DB_CANNOT_ADD_CONSTRAINT);
4253  }
4254 
4255  ptr = dict_accept(cs, ptr, "(", &success);
4256 
4257  if (!success) {
4258  /* We do not flag a syntax error here because in an
4259  ALTER TABLE we may also have DROP FOREIGN KEY abc */
4260 
4261  goto loop;
4262  }
4263  }
4264 
4265  i = 0;
4266 
4267  /* Scan the columns in the first list */
4268 col_loop1:
4269  ut_a(i < (sizeof column_names) / sizeof *column_names);
4270  ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
4271  heap, column_names + i);
4272  if (!success) {
4273  mutex_enter(&dict_foreign_err_mutex);
4274  dict_foreign_error_report_low(ef, name);
4275  fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
4276  start_of_latest_foreign, ptr);
4277  mutex_exit(&dict_foreign_err_mutex);
4278 
4279  return(DB_CANNOT_ADD_CONSTRAINT);
4280  }
4281 
4282  i++;
4283 
4284  ptr = dict_accept(cs, ptr, ",", &success);
4285 
4286  if (success) {
4287  goto col_loop1;
4288  }
4289 
4290  ptr = dict_accept(cs, ptr, ")", &success);
4291 
4292  if (!success) {
4293  dict_foreign_report_syntax_err(
4294  name, start_of_latest_foreign, ptr);
4295  return(DB_CANNOT_ADD_CONSTRAINT);
4296  }
4297 
4298  /* Try to find an index which contains the columns
4299  as the first fields and in the right order. There is
4300  no need to check column type match (on types_idx), since
4301  the referenced table can be NULL if foreign_key_checks is
4302  set to 0 */
4303 
4304  index = dict_foreign_find_index(
4305  table, NULL, column_names, i, NULL, TRUE, FALSE);
4306 
4307  if (!index) {
4308  mutex_enter(&dict_foreign_err_mutex);
4309  dict_foreign_error_report_low(ef, name);
4310  fputs("There is no index in table ", ef);
4311  ut_print_name(ef, NULL, TRUE, name);
4312  fprintf(ef, " where the columns appear\n"
4313  "as the first columns. Constraint:\n%s\n"
4314  "See " REFMAN "innodb-foreign-key-constraints.html\n"
4315  "for correct foreign key definition.\n",
4316  start_of_latest_foreign);
4317  mutex_exit(&dict_foreign_err_mutex);
4318 
4319  return(DB_CHILD_NO_INDEX);
4320  }
4321  ptr = dict_accept(cs, ptr, "REFERENCES", &success);
4322 
4323  if (!success || !my_isspace(cs, *ptr)) {
4324  dict_foreign_report_syntax_err(
4325  name, start_of_latest_foreign, ptr);
4326  return(DB_CANNOT_ADD_CONSTRAINT);
4327  }
4328 
4329  /* Let us create a constraint struct */
4330 
4331  foreign = dict_mem_foreign_create();
4332 
4333  if (constraint_name) {
4334  ulint db_len;
4335 
4336  /* Catenate 'databasename/' to the constraint name specified
4337  by the user: we conceive the constraint as belonging to the
4338  same MySQL 'database' as the table itself. We store the name
4339  to foreign->id. */
4340 
4341  db_len = dict_get_db_name_len(table->name);
4342 
4343  foreign->id = static_cast<char*>(mem_heap_alloc(
4344  foreign->heap, db_len + strlen(constraint_name) + 2));
4345 
4346  ut_memcpy(foreign->id, table->name, db_len);
4347  foreign->id[db_len] = '/';
4348  strcpy(foreign->id + db_len + 1, constraint_name);
4349  }
4350 
4351  foreign->foreign_table = table;
4353  foreign->heap, table->name);
4355 
4356  foreign->foreign_index = index;
4357  foreign->n_fields = (unsigned int) i;
4358 
4359  foreign->foreign_col_names = static_cast<const char**>(
4360  mem_heap_alloc(foreign->heap, i * sizeof(void*)));
4361 
4362  for (i = 0; i < foreign->n_fields; i++) {
4363  foreign->foreign_col_names[i] = mem_heap_strdup(
4364  foreign->heap,
4366  dict_col_get_no(columns[i])));
4367  }
4368 
4369  ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
4370  &success, heap, &referenced_table_name);
4371 
4372  /* Note that referenced_table can be NULL if the user has suppressed
4373  checking of foreign key constraints! */
4374 
4375  if (!success || (!referenced_table && trx->check_foreigns)) {
4376  dict_foreign_free(foreign);
4377 
4378  mutex_enter(&dict_foreign_err_mutex);
4379  dict_foreign_error_report_low(ef, name);
4380  fprintf(ef, "%s:\nCannot resolve table name close to:\n"
4381  "%s\n",
4382  start_of_latest_foreign, ptr);
4383  mutex_exit(&dict_foreign_err_mutex);
4384 
4385  return(DB_CANNOT_ADD_CONSTRAINT);
4386  }
4387 
4388  ptr = dict_accept(cs, ptr, "(", &success);
4389 
4390  if (!success) {
4391  dict_foreign_free(foreign);
4392  dict_foreign_report_syntax_err(name, start_of_latest_foreign,
4393  ptr);
4394  return(DB_CANNOT_ADD_CONSTRAINT);
4395  }
4396 
4397  /* Scan the columns in the second list */
4398  i = 0;
4399 
4400 col_loop2:
4401  ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
4402  heap, column_names + i);
4403  i++;
4404 
4405  if (!success) {
4406  dict_foreign_free(foreign);
4407 
4408  mutex_enter(&dict_foreign_err_mutex);
4409  dict_foreign_error_report_low(ef, name);
4410  fprintf(ef, "%s:\nCannot resolve column name close to:\n"
4411  "%s\n",
4412  start_of_latest_foreign, ptr);
4413  mutex_exit(&dict_foreign_err_mutex);
4414 
4415  return(DB_CANNOT_ADD_CONSTRAINT);
4416  }
4417 
4418  ptr = dict_accept(cs, ptr, ",", &success);
4419 
4420  if (success) {
4421  goto col_loop2;
4422  }
4423 
4424  ptr = dict_accept(cs, ptr, ")", &success);
4425 
4426  if (!success || foreign->n_fields != i) {
4427  dict_foreign_free(foreign);
4428 
4429  dict_foreign_report_syntax_err(name, start_of_latest_foreign,
4430  ptr);
4431  return(DB_CANNOT_ADD_CONSTRAINT);
4432  }
4433 
4434  n_on_deletes = 0;
4435  n_on_updates = 0;
4436 
4437 scan_on_conditions:
4438  /* Loop here as long as we can find ON ... conditions */
4439 
4440  ptr = dict_accept(cs, ptr, "ON", &success);
4441 
4442  if (!success) {
4443 
4444  goto try_find_index;
4445  }
4446 
4447  ptr = dict_accept(cs, ptr, "DELETE", &success);
4448 
4449  if (!success) {
4450  ptr = dict_accept(cs, ptr, "UPDATE", &success);
4451 
4452  if (!success) {
4453  dict_foreign_free(foreign);
4454 
4455  dict_foreign_report_syntax_err(
4456  name, start_of_latest_foreign, ptr);
4457  return(DB_CANNOT_ADD_CONSTRAINT);
4458  }
4459 
4460  is_on_delete = FALSE;
4461  n_on_updates++;
4462  } else {
4463  is_on_delete = TRUE;
4464  n_on_deletes++;
4465  }
4466 
4467  ptr = dict_accept(cs, ptr, "RESTRICT", &success);
4468 
4469  if (success) {
4470  goto scan_on_conditions;
4471  }
4472 
4473  ptr = dict_accept(cs, ptr, "CASCADE", &success);
4474 
4475  if (success) {
4476  if (is_on_delete) {
4478  } else {
4480  }
4481 
4482  goto scan_on_conditions;
4483  }
4484 
4485  ptr = dict_accept(cs, ptr, "NO", &success);
4486 
4487  if (success) {
4488  ptr = dict_accept(cs, ptr, "ACTION", &success);
4489 
4490  if (!success) {
4491  dict_foreign_free(foreign);
4492  dict_foreign_report_syntax_err(
4493  name, start_of_latest_foreign, ptr);
4494 
4495  return(DB_CANNOT_ADD_CONSTRAINT);
4496  }
4497 
4498  if (is_on_delete) {
4500  } else {
4502  }
4503 
4504  goto scan_on_conditions;
4505  }
4506 
4507  ptr = dict_accept(cs, ptr, "SET", &success);
4508 
4509  if (!success) {
4510  dict_foreign_free(foreign);
4511  dict_foreign_report_syntax_err(name, start_of_latest_foreign,
4512  ptr);
4513  return(DB_CANNOT_ADD_CONSTRAINT);
4514  }
4515 
4516  ptr = dict_accept(cs, ptr, "NULL", &success);
4517 
4518  if (!success) {
4519  dict_foreign_free(foreign);
4520  dict_foreign_report_syntax_err(name, start_of_latest_foreign,
4521  ptr);
4522  return(DB_CANNOT_ADD_CONSTRAINT);
4523  }
4524 
4525  for (j = 0; j < foreign->n_fields; j++) {
4526  if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
4527  & DATA_NOT_NULL) {
4528 
4529  /* It is not sensible to define SET NULL
4530  if the column is not allowed to be NULL! */
4531 
4532  dict_foreign_free(foreign);
4533 
4534  mutex_enter(&dict_foreign_err_mutex);
4535  dict_foreign_error_report_low(ef, name);
4536  fprintf(ef, "%s:\n"
4537  "You have defined a SET NULL condition"
4538  " though some of the\n"
4539  "columns are defined as NOT NULL.\n",
4540  start_of_latest_foreign);
4541  mutex_exit(&dict_foreign_err_mutex);
4542 
4543  return(DB_CANNOT_ADD_CONSTRAINT);
4544  }
4545  }
4546 
4547  if (is_on_delete) {
4549  } else {
4551  }
4552 
4553  goto scan_on_conditions;
4554 
4555 try_find_index:
4556  if (n_on_deletes > 1 || n_on_updates > 1) {
4557  /* It is an error to define more than 1 action */
4558 
4559  dict_foreign_free(foreign);
4560 
4561  mutex_enter(&dict_foreign_err_mutex);
4562  dict_foreign_error_report_low(ef, name);
4563  fprintf(ef, "%s:\n"
4564  "You have twice an ON DELETE clause"
4565  " or twice an ON UPDATE clause.\n",
4566  start_of_latest_foreign);
4567  mutex_exit(&dict_foreign_err_mutex);
4568 
4569  return(DB_CANNOT_ADD_CONSTRAINT);
4570  }
4571 
4572  /* Try to find an index which contains the columns as the first fields
4573  and in the right order, and the types are the same as in
4574  foreign->foreign_index */
4575 
4576  if (referenced_table) {
4577  index = dict_foreign_find_index(referenced_table, NULL,
4578  column_names, i,
4579  foreign->foreign_index,
4580  TRUE, FALSE);
4581  if (!index) {
4582  dict_foreign_free(foreign);
4583  mutex_enter(&dict_foreign_err_mutex);
4584  dict_foreign_error_report_low(ef, name);
4585  fprintf(ef, "%s:\n"
4586  "Cannot find an index in the"
4587  " referenced table where the\n"
4588  "referenced columns appear as the"
4589  " first columns, or column types\n"
4590  "in the table and the referenced table"
4591  " do not match for constraint.\n"
4592  "Note that the internal storage type of"
4593  " ENUM and SET changed in\n"
4594  "tables created with >= InnoDB-4.1.12,"
4595  " and such columns in old tables\n"
4596  "cannot be referenced by such columns"
4597  " in new tables.\n"
4598  "See " REFMAN
4599  "innodb-foreign-key-constraints.html\n"
4600  "for correct foreign key definition.\n",
4601  start_of_latest_foreign);
4602  mutex_exit(&dict_foreign_err_mutex);
4603 
4604  return(DB_PARENT_NO_INDEX);
4605  }
4606  } else {
4607  ut_a(trx->check_foreigns == FALSE);
4608  index = NULL;
4609  }
4610 
4611  foreign->referenced_index = index;
4613 
4615  foreign->heap, referenced_table_name);
4617 
4618  foreign->referenced_col_names = static_cast<const char**>(
4619  mem_heap_alloc(foreign->heap, i * sizeof(void*)));
4620 
4621  for (i = 0; i < foreign->n_fields; i++) {
4622  foreign->referenced_col_names[i]
4623  = mem_heap_strdup(foreign->heap, column_names[i]);
4624  }
4625 
4626  /* We found an ok constraint definition: add to the lists */
4627 
4628  UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
4629 
4630  if (referenced_table) {
4631  UT_LIST_ADD_LAST(referenced_list,
4632  referenced_table->referenced_list,
4633  foreign);
4634  }
4635 
4636  goto loop;
4637 }
4638 /**************************************************************************
4639 Determines whether a string starts with the specified keyword.
4640 @return TRUE if str starts with keyword */
4641 UNIV_INTERN
4642 ibool
4644 /*=========================*/
4645  THD* thd,
4646  const char* str,
4647  const char* keyword)
4648 {
4649  struct charset_info_st* cs = innobase_get_charset(thd);
4650  ibool success;
4651 
4652  dict_accept(cs, str, keyword, &success);
4653  return(success);
4654 }
4655 
4656 /*********************************************************************/
4663 UNIV_INTERN
4664 dberr_t
4666 /*============================*/
4667  trx_t* trx,
4668  const char* sql_string,
4676  size_t sql_length,
4677  const char* name,
4680  ibool reject_fks)
4683 {
4684  char* str;
4685  dberr_t err;
4686  mem_heap_t* heap;
4687 
4688  ut_a(trx);
4689  ut_a(trx->mysql_thd);
4690 
4691  str = dict_strip_comments(sql_string, sql_length);
4692  heap = mem_heap_create(10000);
4693 
4694  err = dict_create_foreign_constraints_low(
4695  trx, heap, innobase_get_charset(trx->mysql_thd), str, name,
4696  reject_fks);
4697 
4698  mem_heap_free(heap);
4699  mem_free(str);
4700 
4701  return(err);
4702 }
4703 
4704 /**********************************************************************/
4708 UNIV_INTERN
4709 dberr_t
4711 /*================================*/
4712  mem_heap_t* heap,
4714  trx_t* trx,
4715  dict_table_t* table,
4716  ulint* n,
4718  const char*** constraints_to_drop)
4720 {
4721  dict_foreign_t* foreign;
4722  ibool success;
4723  char* str;
4724  size_t len;
4725  const char* ptr;
4726  const char* id;
4727  struct charset_info_st* cs;
4728 
4729  ut_a(trx);
4730  ut_a(trx->mysql_thd);
4731 
4732  cs = innobase_get_charset(trx->mysql_thd);
4733 
4734  *n = 0;
4735 
4736  *constraints_to_drop = static_cast<const char**>(
4737  mem_heap_alloc(heap, 1000 * sizeof(char*)));
4738 
4739  ptr = innobase_get_stmt(trx->mysql_thd, &len);
4740 
4741  str = dict_strip_comments(ptr, len);
4742 
4743  ptr = str;
4744 
4745  ut_ad(mutex_own(&(dict_sys->mutex)));
4746 loop:
4747  ptr = dict_scan_to(ptr, "DROP");
4748 
4749  if (*ptr == '\0') {
4750  mem_free(str);
4751 
4752  return(DB_SUCCESS);
4753  }
4754 
4755  ptr = dict_accept(cs, ptr, "DROP", &success);
4756 
4757  if (!my_isspace(cs, *ptr)) {
4758 
4759  goto loop;
4760  }
4761 
4762  ptr = dict_accept(cs, ptr, "FOREIGN", &success);
4763 
4764  if (!success || !my_isspace(cs, *ptr)) {
4765 
4766  goto loop;
4767  }
4768 
4769  ptr = dict_accept(cs, ptr, "KEY", &success);
4770 
4771  if (!success) {
4772 
4773  goto syntax_error;
4774  }
4775 
4776  ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
4777 
4778  if (id == NULL) {
4779 
4780  goto syntax_error;
4781  }
4782 
4783  ut_a(*n < 1000);
4784  (*constraints_to_drop)[*n] = id;
4785  (*n)++;
4786 
4787  /* Look for the given constraint id */
4788 
4789  foreign = UT_LIST_GET_FIRST(table->foreign_list);
4790 
4791  while (foreign != NULL) {
4792  if (0 == innobase_strcasecmp(foreign->id, id)
4793  || (strchr(foreign->id, '/')
4794  && 0 == innobase_strcasecmp(
4795  id,
4796  dict_remove_db_name(foreign->id)))) {
4797  /* Found */
4798  break;
4799  }
4800 
4801  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4802  }
4803 
4804 
4805  if (foreign == NULL) {
4806 
4807  if (!srv_read_only_mode) {
4808  FILE* ef = dict_foreign_err_file;
4809 
4810  mutex_enter(&dict_foreign_err_mutex);
4811  rewind(ef);
4812  ut_print_timestamp(ef);
4813  fputs(" Error in dropping of a foreign key "
4814  "constraint of table ", ef);
4815  ut_print_name(ef, NULL, TRUE, table->name);
4816  fputs(",\nin SQL command\n", ef);
4817  fputs(str, ef);
4818  fputs("\nCannot find a constraint with the "
4819  "given id ", ef);
4820  ut_print_name(ef, NULL, FALSE, id);
4821  fputs(".\n", ef);
4822  mutex_exit(&dict_foreign_err_mutex);
4823  }
4824 
4825  mem_free(str);
4826 
4827  return(DB_CANNOT_DROP_CONSTRAINT);
4828  }
4829 
4830  goto loop;
4831 
4832 syntax_error:
4833  if (!srv_read_only_mode) {
4834  FILE* ef = dict_foreign_err_file;
4835 
4836  mutex_enter(&dict_foreign_err_mutex);
4837  rewind(ef);
4838  ut_print_timestamp(ef);
4839  fputs(" Syntax error in dropping of a"
4840  " foreign key constraint of table ", ef);
4841  ut_print_name(ef, NULL, TRUE, table->name);
4842  fprintf(ef, ",\n"
4843  "close to:\n%s\n in SQL command\n%s\n", ptr, str);
4844  mutex_exit(&dict_foreign_err_mutex);
4845  }
4846 
4847  mem_free(str);
4848 
4849  return(DB_CANNOT_DROP_CONSTRAINT);
4850 }
4851 
4852 /*==================== END OF FOREIGN KEY PROCESSING ====================*/
4853 
4854 /**********************************************************************/
4858 UNIV_INTERN
4859 dict_index_t*
4861 /*===========================*/
4862  index_id_t index_id)
4863 {
4864  ut_ad(mutex_own(&(dict_sys->mutex)));
4865 
4866  return(dict_index_find_on_id_low(index_id));
4867 }
4868 
4869 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
4870 /**********************************************************************/
4873 UNIV_INTERN
4874 dict_index_t*
4875 dict_index_get_if_in_cache(
4876 /*=======================*/
4877  index_id_t index_id)
4878 {
4880 
4881  if (dict_sys == NULL) {
4882  return(NULL);
4883  }
4884 
4885  mutex_enter(&(dict_sys->mutex));
4886 
4887  index = dict_index_get_if_in_cache_low(index_id);
4888 
4889  mutex_exit(&(dict_sys->mutex));
4890 
4891  return(index);
4892 }
4893 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
4894 
4895 #ifdef UNIV_DEBUG
4896 /**********************************************************************/
4900 UNIV_INTERN
4901 ibool
4902 dict_index_check_search_tuple(
4903 /*==========================*/
4904  const dict_index_t* index,
4905  const dtuple_t* tuple)
4906 {
4907  ut_a(index);
4910  return(TRUE);
4911 }
4912 #endif /* UNIV_DEBUG */
4913 
4914 /**********************************************************************/
4917 UNIV_INTERN
4918 dtuple_t*
4920 /*======================*/
4921  const dict_index_t* index,
4922  const rec_t* rec,
4924  ulint page_no,
4926  mem_heap_t* heap,
4928  ulint level)
4930 {
4931  dtuple_t* tuple;
4932  dfield_t* field;
4933  byte* buf;
4934  ulint n_unique;
4935 
4936  if (dict_index_is_univ(index)) {
4937  /* In a universal index tree, we take the whole record as
4938  the node pointer if the record is on the leaf level,
4939  on non-leaf levels we remove the last field, which
4940  contains the page number of the child page */
4941 
4942  ut_a(!dict_table_is_comp(index->table));
4943  n_unique = rec_get_n_fields_old(rec);
4944 
4945  if (level > 0) {
4946  ut_a(n_unique > 1);
4947  n_unique--;
4948  }
4949  } else {
4950  n_unique = dict_index_get_n_unique_in_tree(index);
4951  }
4952 
4953  tuple = dtuple_create(heap, n_unique + 1);
4954 
4955  /* When searching in the tree for the node pointer, we must not do
4956  comparison on the last field, the page number field, as on upper
4957  levels in the tree there may be identical node pointers with a
4958  different page number; therefore, we set the n_fields_cmp to one
4959  less: */
4960 
4961  dtuple_set_n_fields_cmp(tuple, n_unique);
4962 
4963  dict_index_copy_types(tuple, index, n_unique);
4964 
4965  buf = static_cast<byte*>(mem_heap_alloc(heap, 4));
4966 
4967  mach_write_to_4(buf, page_no);
4968 
4969  field = dtuple_get_nth_field(tuple, n_unique);
4970  dfield_set_data(field, buf, 4);
4971 
4972  dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
4973 
4974  rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
4976  | REC_STATUS_NODE_PTR);
4977 
4978  ut_ad(dtuple_check_typed(tuple));
4979 
4980  return(tuple);
4981 }
4982 
4983 /**********************************************************************/
4987 UNIV_INTERN
4988 rec_t*
4990 /*=============================*/
4991  const dict_index_t* index,
4992  const rec_t* rec,
4994  ulint* n_fields,
4995  byte** buf,
4997  ulint* buf_size)
4998 {
4999  ulint n;
5000 
5001  UNIV_PREFETCH_R(rec);
5002 
5003  if (dict_index_is_univ(index)) {
5004  ut_a(!dict_table_is_comp(index->table));
5005  n = rec_get_n_fields_old(rec);
5006  } else {
5008  }
5009 
5010  *n_fields = n;
5011  return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
5012 }
5013 
5014 /**********************************************************************/
5017 UNIV_INTERN
5018 dtuple_t*
5020 /*========================*/
5021  dict_index_t* index,
5022  rec_t* rec,
5023  ulint n_fields,
5024  mem_heap_t* heap)
5025 {
5026  dtuple_t* tuple;
5027 
5029  || n_fields <= rec_get_n_fields_old(rec));
5030 
5031  tuple = dtuple_create(heap, n_fields);
5032 
5033  dict_index_copy_types(tuple, index, n_fields);
5034 
5035  rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
5036 
5037  ut_ad(dtuple_check_typed(tuple));
5038 
5039  return(tuple);
5040 }
5041 
5042 /*********************************************************************/
5044 UNIV_INTERN
5045 ulint
5047 /*========================*/
5048  const dict_index_t* index)
5049 {
5050  ulint sum = 0;
5051  ulint i;
5052  ulint comp = dict_table_is_comp(index->table);
5053 
5054  if (comp) {
5055  ulint nullable = 0;
5056  sum = REC_N_NEW_EXTRA_BYTES;
5057  for (i = 0; i < dict_index_get_n_fields(index); i++) {
5058  const dict_col_t* col
5059  = dict_index_get_nth_col(index, i);
5060  ulint size = dict_col_get_fixed_size(col, comp);
5061  sum += size;
5062  if (!size) {
5063  size = col->len;
5064  sum += size < 128 ? 1 : 2;
5065  }
5066  if (!(col->prtype & DATA_NOT_NULL)) {
5067  nullable++;
5068  }
5069  }
5070 
5071  /* round the NULL flags up to full bytes */
5072  sum += UT_BITS_IN_BYTES(nullable);
5073 
5074  return(sum);
5075  }
5076 
5077  for (i = 0; i < dict_index_get_n_fields(index); i++) {
5078  sum += dict_col_get_fixed_size(
5079  dict_index_get_nth_col(index, i), comp);
5080  }
5081 
5082  if (sum > 127) {
5083  sum += 2 * dict_index_get_n_fields(index);
5084  } else {
5085  sum += dict_index_get_n_fields(index);
5086  }
5087 
5088  sum += REC_N_OLD_EXTRA_BYTES;
5089 
5090  return(sum);
5091 }
5092 
5093 /**********************************************************************/
5095 static
5096 void
5097 dict_foreign_print_low(
5098 /*===================*/
5099  dict_foreign_t* foreign)
5100 {
5101  ulint i;
5102 
5103  ut_ad(mutex_own(&(dict_sys->mutex)));
5104 
5105  fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
5106  foreign->id, foreign->foreign_table_name);
5107 
5108  for (i = 0; i < foreign->n_fields; i++) {
5109  fprintf(stderr, " %s", foreign->foreign_col_names[i]);
5110  }
5111 
5112  fprintf(stderr, " )\n"
5113  " REFERENCES %s (",
5114  foreign->referenced_table_name);
5115 
5116  for (i = 0; i < foreign->n_fields; i++) {
5117  fprintf(stderr, " %s", foreign->referenced_col_names[i]);
5118  }
5119 
5120  fputs(" )\n", stderr);
5121 }
5122 
5123 /**********************************************************************/
5125 UNIV_INTERN
5126 void
5128 /*=============*/
5129  dict_table_t* table)
5130 {
5132  dict_foreign_t* foreign;
5133  ulint i;
5134 
5135  ut_ad(mutex_own(&(dict_sys->mutex)));
5136 
5137  dict_table_stats_lock(table, RW_X_LATCH);
5138 
5139  if (!table->stat_initialized) {
5141  }
5142 
5143  fprintf(stderr,
5144  "--------------------------------------\n"
5145  "TABLE: name %s, id %llu, flags %lx, columns %lu,"
5146  " indexes %lu, appr.rows " UINT64PF "\n"
5147  " COLUMNS: ",
5148  table->name,
5149  (ullint) table->id,
5150  (ulong) table->flags,
5151  (ulong) table->n_cols,
5152  (ulong) UT_LIST_GET_LEN(table->indexes),
5153  table->stat_n_rows);
5154 
5155  for (i = 0; i < (ulint) table->n_cols; i++) {
5156  dict_col_print_low(table, dict_table_get_nth_col(table, i));
5157  fputs("; ", stderr);
5158  }
5159 
5160  putc('\n', stderr);
5161 
5162  index = UT_LIST_GET_FIRST(table->indexes);
5163 
5164  while (index != NULL) {
5165  dict_index_print_low(index);
5166  index = UT_LIST_GET_NEXT(indexes, index);
5167  }
5168 
5169  table->stat_initialized = FALSE;
5170 
5171  dict_table_stats_unlock(table, RW_X_LATCH);
5172 
5173  foreign = UT_LIST_GET_FIRST(table->foreign_list);
5174 
5175  while (foreign != NULL) {
5176  dict_foreign_print_low(foreign);
5177  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
5178  }
5179 
5180  foreign = UT_LIST_GET_FIRST(table->referenced_list);
5181 
5182  while (foreign != NULL) {
5183  dict_foreign_print_low(foreign);
5184  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
5185  }
5186 }
5187 
5188 /**********************************************************************/
5190 static
5191 void
5192 dict_col_print_low(
5193 /*===============*/
5194  const dict_table_t* table,
5195  const dict_col_t* col)
5196 {
5197  dtype_t type;
5198 
5199  ut_ad(mutex_own(&(dict_sys->mutex)));
5200 
5201  dict_col_copy_type(col, &type);
5202  fprintf(stderr, "%s: ", dict_table_get_col_name(table,
5203  dict_col_get_no(col)));
5204 
5205  dtype_print(&type);
5206 }
5207 
5208 /**********************************************************************/
5210 static
5211 void
5212 dict_index_print_low(
5213 /*=================*/
5214  dict_index_t* index)
5215 {
5216  ib_int64_t n_vals;
5217  ulint i;
5218 
5219  ut_a(index->table->stat_initialized);
5220 
5221  ut_ad(mutex_own(&(dict_sys->mutex)));
5222 
5223  if (index->n_user_defined_cols > 0) {
5224  n_vals = index->stat_n_diff_key_vals[
5225  index->n_user_defined_cols - 1];
5226  } else {
5227  n_vals = index->stat_n_diff_key_vals[0];
5228  }
5229 
5230  fprintf(stderr,
5231  " INDEX: name %s, id %llu, fields %lu/%lu,"
5232  " uniq %lu, type %lu\n"
5233  " root page %lu, appr.key vals %lu,"
5234  " leaf pages %lu, size pages %lu\n"
5235  " FIELDS: ",
5236  index->name,
5237  (ullint) index->id,
5238  (ulong) index->n_user_defined_cols,
5239  (ulong) index->n_fields,
5240  (ulong) index->n_uniq,
5241  (ulong) index->type,
5242  (ulong) index->page,
5243  (ulong) n_vals,
5244  (ulong) index->stat_n_leaf_pages,
5245  (ulong) index->stat_index_size);
5246 
5247  for (i = 0; i < index->n_fields; i++) {
5248  dict_field_print_low(dict_index_get_nth_field(index, i));
5249  }
5250 
5251  putc('\n', stderr);
5252 
5253 #ifdef UNIV_BTR_PRINT
5254  btr_print_size(index);
5255 
5256  btr_print_index(index, 7);
5257 #endif /* UNIV_BTR_PRINT */
5258 }
5259 
5260 /**********************************************************************/
5262 static
5263 void
5264 dict_field_print_low(
5265 /*=================*/
5266  const dict_field_t* field)
5267 {
5268  ut_ad(mutex_own(&(dict_sys->mutex)));
5269 
5270  fprintf(stderr, " %s", field->name);
5271 
5272  if (field->prefix_len != 0) {
5273  fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
5274  }
5275 }
5276 
5277 /**********************************************************************/
5280 UNIV_INTERN
5281 void
5283 /*============================================*/
5284  FILE* file,
5285  trx_t* trx,
5286  dict_foreign_t* foreign,
5287  ibool add_newline)
5288 {
5289  const char* stripped_id;
5290  ulint i;
5291 
5292  if (strchr(foreign->id, '/')) {
5293  /* Strip the preceding database name from the constraint id */
5294  stripped_id = foreign->id + 1
5295  + dict_get_db_name_len(foreign->id);
5296  } else {
5297  stripped_id = foreign->id;
5298  }
5299 
5300  putc(',', file);
5301 
5302  if (add_newline) {
5303  /* SHOW CREATE TABLE wants constraints each printed nicely
5304  on its own line, while error messages want no newlines
5305  inserted. */
5306  fputs("\n ", file);
5307  }
5308 
5309  fputs(" CONSTRAINT ", file);
5310  ut_print_name(file, trx, FALSE, stripped_id);
5311  fputs(" FOREIGN KEY (", file);
5312 
5313  for (i = 0;;) {
5314  ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
5315  if (++i < foreign->n_fields) {
5316  fputs(", ", file);
5317  } else {
5318  break;
5319  }
5320  }
5321 
5322  fputs(") REFERENCES ", file);
5323 
5325  foreign->referenced_table_name_lookup)) {
5326  /* Do not print the database name of the referenced table */
5327  ut_print_name(file, trx, TRUE,
5329  foreign->referenced_table_name));
5330  } else {
5331  ut_print_name(file, trx, TRUE,
5332  foreign->referenced_table_name);
5333  }
5334 
5335  putc(' ', file);
5336  putc('(', file);
5337 
5338  for (i = 0;;) {
5339  ut_print_name(file, trx, FALSE,
5340  foreign->referenced_col_names[i]);
5341  if (++i < foreign->n_fields) {
5342  fputs(", ", file);
5343  } else {
5344  break;
5345  }
5346  }
5347 
5348  putc(')', file);
5349 
5350  if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
5351  fputs(" ON DELETE CASCADE", file);
5352  }
5353 
5354  if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
5355  fputs(" ON DELETE SET NULL", file);
5356  }
5357 
5358  if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
5359  fputs(" ON DELETE NO ACTION", file);
5360  }
5361 
5362  if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
5363  fputs(" ON UPDATE CASCADE", file);
5364  }
5365 
5366  if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
5367  fputs(" ON UPDATE SET NULL", file);
5368  }
5369 
5370  if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
5371  fputs(" ON UPDATE NO ACTION", file);
5372  }
5373 }
5374 
5375 /**********************************************************************/
5377 UNIV_INTERN
5378 void
5380 /*============================*/
5381  ibool create_table_format,
5385  FILE* file,
5386  trx_t* trx,
5387  dict_table_t* table)
5388 {
5389  dict_foreign_t* foreign;
5390 
5391  mutex_enter(&(dict_sys->mutex));
5392 
5393  foreign = UT_LIST_GET_FIRST(table->foreign_list);
5394 
5395  if (foreign == NULL) {
5396  mutex_exit(&(dict_sys->mutex));
5397 
5398  return;
5399  }
5400 
5401  while (foreign != NULL) {
5402  if (create_table_format) {
5404  file, trx, foreign, TRUE);
5405  } else {
5406  ulint i;
5407  fputs("; (", file);
5408 
5409  for (i = 0; i < foreign->n_fields; i++) {
5410  if (i) {
5411  putc(' ', file);
5412  }
5413 
5414  ut_print_name(file, trx, FALSE,
5415  foreign->foreign_col_names[i]);
5416  }
5417 
5418  fputs(") REFER ", file);
5419  ut_print_name(file, trx, TRUE,
5420  foreign->referenced_table_name);
5421  putc('(', file);
5422 
5423  for (i = 0; i < foreign->n_fields; i++) {
5424  if (i) {
5425  putc(' ', file);
5426  }
5427  ut_print_name(
5428  file, trx, FALSE,
5429  foreign->referenced_col_names[i]);
5430  }
5431 
5432  putc(')', file);
5433 
5434  if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
5435  fputs(" ON DELETE CASCADE", file);
5436  }
5437 
5438  if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
5439  fputs(" ON DELETE SET NULL", file);
5440  }
5441 
5442  if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
5443  fputs(" ON DELETE NO ACTION", file);
5444  }
5445 
5446  if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
5447  fputs(" ON UPDATE CASCADE", file);
5448  }
5449 
5450  if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
5451  fputs(" ON UPDATE SET NULL", file);
5452  }
5453 
5454  if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
5455  fputs(" ON UPDATE NO ACTION", file);
5456  }
5457  }
5458 
5459  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
5460  }
5461 
5462  mutex_exit(&(dict_sys->mutex));
5463 }
5464 
5465 /********************************************************************/
5467 UNIV_INTERN
5468 void
5470 /*==================*/
5471  FILE* file,
5472  const trx_t* trx,
5473  const dict_index_t* index)
5474 {
5475  fputs("index ", file);
5476  ut_print_name(file, trx, FALSE, index->name);
5477  fputs(" of table ", file);
5478  ut_print_name(file, trx, TRUE, index->table_name);
5479 }
5480 
5481 /**********************************************************************/
5484 static
5485 dict_table_t*
5486 dict_find_table_by_space(
5487 /*=====================*/
5488  ulint space_id)
5489 {
5491  ulint num_item;
5492  ulint count = 0;
5493 
5494  ut_ad(space_id > 0);
5495 
5497  num_item = UT_LIST_GET_LEN(dict_sys->table_LRU);
5498 
5499  /* This function intentionally does not acquire mutex as it is used
5500  by error handling code in deep call stack as last means to avoid
5501  killing the server, so it worth to risk some consequencies for
5502  the action. */
5503  while (table && count < num_item) {
5504  if (table->space == space_id) {
5505  return(table);
5506  }
5507 
5508  table = UT_LIST_GET_NEXT(table_LRU, table);
5509  count++;
5510  }
5511 
5512  return(NULL);
5513 }
5514 
5515 /**********************************************************************/
5519 UNIV_INTERN
5520 ibool
5522 /*========================*/
5523  ulint space_id)
5524 {
5526 
5527  table = dict_find_table_by_space(space_id);
5528 
5529  if (!table) {
5530  return(FALSE);
5531  }
5532 
5533  /* mark the table->corrupted bit only, since the caller
5534  could be too deep in the stack for SYS_INDEXES update */
5535  table->corrupted = TRUE;
5536 
5537  return(TRUE);
5538 }
5539 
5540 /**********************************************************************/
5543 UNIV_INTERN
5544 void
5546 /*===============*/
5547  dict_index_t* index,
5548  trx_t* trx,
5549  const char* ctx)
5550 {
5551  mem_heap_t* heap;
5552  mtr_t mtr;
5553  dict_index_t* sys_index;
5554  dtuple_t* tuple;
5555  dfield_t* dfield;
5556  byte* buf;
5557  char* table_name;
5558  const char* status;
5559  btr_cur_t cursor;
5560  bool locked = RW_X_LATCH == trx->dict_operation_lock_mode;
5561 
5562  if (!locked) {
5563  row_mysql_lock_data_dictionary(trx);
5564  }
5565 
5566  ut_ad(index);
5567  ut_ad(mutex_own(&dict_sys->mutex));
5570 
5571 #ifdef UNIV_SYNC_DEBUG
5572  ut_ad(sync_thread_levels_empty_except_dict());
5573 #endif
5574 
5575  /* Mark the table as corrupted only if the clustered index
5576  is corrupted */
5577  if (dict_index_is_clust(index)) {
5578  index->table->corrupted = TRUE;
5579  }
5580 
5581  if (index->type & DICT_CORRUPT) {
5582  /* The index was already flagged corrupted. */
5583  ut_ad(!dict_index_is_clust(index) || index->table->corrupted);
5584  goto func_exit;
5585  }
5586 
5587  heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t)
5588  + sizeof(que_fork_t) + sizeof(upd_node_t)
5589  + sizeof(upd_t) + 12));
5590  mtr_start(&mtr);
5591  index->type |= DICT_CORRUPT;
5592 
5594 
5595  /* Find the index row in SYS_INDEXES */
5596  tuple = dtuple_create(heap, 2);
5597 
5598  dfield = dtuple_get_nth_field(tuple, 0);
5599  buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
5600  mach_write_to_8(buf, index->table->id);
5601  dfield_set_data(dfield, buf, 8);
5602 
5603  dfield = dtuple_get_nth_field(tuple, 1);
5604  buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
5605  mach_write_to_8(buf, index->id);
5606  dfield_set_data(dfield, buf, 8);
5607 
5608  dict_index_copy_types(tuple, sys_index, 2);
5609 
5610  btr_cur_search_to_nth_level(sys_index, 0, tuple, PAGE_CUR_GE,
5612  &cursor, 0, __FILE__, __LINE__, &mtr);
5613 
5614  if (cursor.up_match == dtuple_get_n_fields(tuple)) {
5615  /* UPDATE SYS_INDEXES SET TYPE=index->type
5616  WHERE TABLE_ID=index->table->id AND INDEX_ID=index->id */
5617  ulint len;
5618  byte* field = rec_get_nth_field_old(
5619  btr_cur_get_rec(&cursor),
5620  DICT_FLD__SYS_INDEXES__TYPE, &len);
5621  if (len != 4) {
5622  goto fail;
5623  }
5624  mlog_write_ulint(field, index->type, MLOG_4BYTES, &mtr);
5625  status = "Flagged";
5626  } else {
5627 fail:
5628  status = "Unable to flag";
5629  }
5630 
5631  mtr_commit(&mtr);
5632  mem_heap_empty(heap);
5633  table_name = static_cast<char*>(mem_heap_alloc(heap, FN_REFLEN + 1));
5635  table_name, FN_REFLEN,
5636  index->table_name, strlen(index->table_name),
5637  NULL, TRUE) = 0;
5638 
5639  ib_logf(IB_LOG_LEVEL_ERROR, "%s corruption of %s in table %s in %s",
5640  status, index->name, table_name, ctx);
5641 
5642  mem_heap_free(heap);
5643 
5644 func_exit:
5645  if (!locked) {
5647  }
5648 }
5649 
5650 /**********************************************************************/
5654 UNIV_INTERN
5655 void
5657 /*================================*/
5658  dict_index_t* index,
5659  dict_table_t* table)
5660 {
5661  ut_ad(index);
5662  ut_ad(mutex_own(&dict_sys->mutex));
5665 
5666  /* Mark the table as corrupted only if the clustered index
5667  is corrupted */
5668  if (dict_index_is_clust(index)) {
5669  dict_table_t* corrupt_table;
5670 
5671  corrupt_table = table ? table : index->table;
5672  ut_ad(!index->table || !table || index->table == table);
5673 
5674  if (corrupt_table) {
5675  corrupt_table->corrupted = TRUE;
5676  }
5677  }
5678 
5679  index->type |= DICT_CORRUPT;
5680 }
5681 #endif /* !UNIV_HOTBACKUP */
5682 
5683 /**********************************************************************/
5685 UNIV_INTERN
5686 void
5688 /*===============*/
5689 {
5691 
5692  /* create dummy table and index for REDUNDANT infimum and supremum */
5693  table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0, 0);
5694  dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
5695  DATA_ENGLISH | DATA_NOT_NULL, 8);
5696 
5697  dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
5698  DICT_HDR_SPACE, 0, 1);
5700  dict_table_get_nth_col(table, 0), 0);
5702 
5703  /* create dummy table and index for COMPACT infimum and supremum */
5704  table = dict_mem_table_create("SYS_DUMMY2",
5705  DICT_HDR_SPACE, 1,
5706  DICT_TF_COMPACT, 0);
5707  dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
5708  DATA_ENGLISH | DATA_NOT_NULL, 8);
5709  dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
5710  DICT_HDR_SPACE, 0, 1);
5712  dict_table_get_nth_col(table, 0), 0);
5714 
5715  /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
5717 }
5718 
5719 #ifndef UNIV_HOTBACKUP
5720 /**********************************************************************/
5722 static
5723 void
5724 dict_ind_free(void)
5725 /*===============*/
5726 {
5728 
5729  table = dict_ind_compact->table;
5731  dict_ind_compact = NULL;
5732  dict_mem_table_free(table);
5733 
5734  table = dict_ind_redundant->table;
5736  dict_ind_redundant = NULL;
5737  dict_mem_table_free(table);
5738 }
5739 
5740 /**********************************************************************/
5743 UNIV_INTERN
5744 dict_index_t*
5746 /*=========================*/
5747  dict_table_t* table,
5748  const char* name)
5749 {
5751 
5752  /* If name is NULL, just return */
5753  if (!name) {
5754  return(NULL);
5755  }
5756 
5757  index = dict_table_get_first_index(table);
5758 
5759  while (index != NULL) {
5760  if (innobase_strcasecmp(index->name, name) == 0) {
5761 
5762  return(index);
5763  }
5764 
5765  index = dict_table_get_next_index(index);
5766  }
5767 
5768  return(NULL);
5769 }
5770 
5771 /**********************************************************************/
5775 UNIV_INTERN
5776 bool
5778 /*=======================*/
5779  dict_table_t* table,
5780  const char** col_names,
5783  const dict_index_t* index)
5784 {
5785  bool found = true;
5786  dict_foreign_t* foreign;
5787 
5788  ut_ad(index->to_be_dropped);
5789  ut_ad(index->table == table);
5790 
5791  for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
5792  foreign;
5793  foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
5794 
5795  if (foreign->foreign_index == index) {
5796  ut_ad(foreign->foreign_table == index->table);
5797 
5799  foreign->foreign_table, col_names,
5800  foreign->foreign_col_names,
5801  foreign->n_fields, index,
5802  /*check_charsets=*/TRUE, /*check_null=*/FALSE);
5803  if (new_index) {
5804  ut_ad(new_index->table == index->table);
5805  ut_ad(!new_index->to_be_dropped);
5806  } else {
5807  found = false;
5808  }
5809 
5810  foreign->foreign_index = new_index;
5811  }
5812  }
5813 
5814  for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
5815  foreign;
5816  foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
5817 
5818  if (foreign->referenced_index == index) {
5819  ut_ad(foreign->referenced_table == index->table);
5820 
5822  foreign->referenced_table, NULL,
5823  foreign->referenced_col_names,
5824  foreign->n_fields, index,
5825  /*check_charsets=*/TRUE, /*check_null=*/FALSE);
5826  /* There must exist an alternative index,
5827  since this must have been checked earlier. */
5828  if (new_index) {
5829  ut_ad(new_index->table == index->table);
5830  ut_ad(!new_index->to_be_dropped);
5831  } else {
5832  found = false;
5833  }
5834 
5835  foreign->referenced_index = new_index;
5836  }
5837  }
5838 
5839  return(found);
5840 }
5841 
5842 /**********************************************************************/
5846 UNIV_INTERN
5847 dict_index_t*
5849 /*=====================================*/
5850  dict_table_t* table,
5851  const char* name)
5852 {
5854  dict_index_t* min_index; /* Index with matching name and min(id) */
5855 
5856  min_index = NULL;
5857  index = dict_table_get_first_index(table);
5858 
5859  while (index != NULL) {
5860  if (ut_strcmp(index->name, name) == 0) {
5861  if (!min_index || index->id < min_index->id) {
5862 
5863  min_index = index;
5864  }
5865  }
5866 
5867  index = dict_table_get_next_index(index);
5868  }
5869 
5870  return(min_index);
5871 
5872 }
5873 
5874 #ifdef UNIV_DEBUG
5875 /**********************************************************************/
5877 UNIV_INTERN
5878 void
5879 dict_table_check_for_dup_indexes(
5880 /*=============================*/
5881  const dict_table_t* table,
5883  enum check_name check)
5885 {
5886  /* Check for duplicates, ignoring indexes that are marked
5887  as to be dropped */
5888 
5889  const dict_index_t* index1;
5890  const dict_index_t* index2;
5891 
5892  ut_ad(mutex_own(&dict_sys->mutex));
5893 
5894  /* The primary index _must_ exist */
5895  ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
5896 
5897  index1 = UT_LIST_GET_FIRST(table->indexes);
5898 
5899  do {
5900  if (*index1->name == TEMP_INDEX_PREFIX) {
5901  ut_a(!dict_index_is_clust(index1));
5902 
5903  switch (check) {
5904  case CHECK_ALL_COMPLETE:
5905  ut_error;
5906  case CHECK_ABORTED_OK:
5907  switch (dict_index_get_online_status(index1)) {
5908  case ONLINE_INDEX_COMPLETE:
5909  case ONLINE_INDEX_CREATION:
5910  ut_error;
5911  break;
5912  case ONLINE_INDEX_ABORTED:
5914  break;
5915  }
5916  /* fall through */
5917  case CHECK_PARTIAL_OK:
5918  break;
5919  }
5920  }
5921 
5922  for (index2 = UT_LIST_GET_NEXT(indexes, index1);
5923  index2 != NULL;
5924  index2 = UT_LIST_GET_NEXT(indexes, index2)) {
5925  ut_ad(ut_strcmp(index1->name, index2->name));
5926  }
5927 
5928  index1 = UT_LIST_GET_NEXT(indexes, index1);
5929  } while (index1);
5930 }
5931 #endif /* UNIV_DEBUG */
5932 
5933 /*********************************************************************/
5940 UNIV_INTERN
5941 dberr_t
5943 /*====================*/
5944  dict_table_schema_t* req_schema,
5946  char* errstr,
5949  size_t errstr_sz)
5950 {
5951  char buf[MAX_FULL_NAME_LEN];
5953  ulint i;
5954 
5955  ut_ad(mutex_own(&dict_sys->mutex));
5956 
5957  table = dict_table_get_low(req_schema->table_name);
5958 
5959  if (table == NULL) {
5960  /* no such table */
5961 
5962  ut_snprintf(errstr, errstr_sz,
5963  "Table %s not found.",
5964  ut_format_name(req_schema->table_name,
5965  TRUE, buf, sizeof(buf)));
5966 
5967  return(DB_TABLE_NOT_FOUND);
5968  }
5969 
5970  if (table->ibd_file_missing) {
5971  /* missing tablespace */
5972 
5973  ut_snprintf(errstr, errstr_sz,
5974  "Tablespace for table %s is missing.",
5975  ut_format_name(req_schema->table_name,
5976  TRUE, buf, sizeof(buf)));
5977 
5978  return(DB_TABLE_NOT_FOUND);
5979  }
5980 
5981  if ((ulint) table->n_def - DATA_N_SYS_COLS != req_schema->n_cols) {
5982  /* the table has a different number of columns than
5983  required */
5984 
5985  ut_snprintf(errstr, errstr_sz,
5986  "%s has %d columns but should have %lu.",
5987  ut_format_name(req_schema->table_name,
5988  TRUE, buf, sizeof(buf)),
5989  table->n_def - DATA_N_SYS_COLS,
5990  req_schema->n_cols);
5991 
5992  return(DB_ERROR);
5993  }
5994 
5995  /* For each column from req_schema->columns[] search
5996  whether it is present in table->cols[].
5997  The following algorithm is O(n_cols^2), but is optimized to
5998  be O(n_cols) if the columns are in the same order in both arrays. */
5999 
6000  for (i = 0; i < req_schema->n_cols; i++) {
6001  ulint j;
6002 
6003  char req_type[64];
6004  char actual_type[64];
6005 
6006  /* check if i'th column is the same in both arrays */
6007  if (innobase_strcasecmp(req_schema->columns[i].name,
6008  dict_table_get_col_name(table, i)) == 0) {
6009 
6010  /* we found the column in table->cols[] quickly */
6011  j = i;
6012  } else {
6013 
6014  /* columns in both arrays are not in the same order,
6015  do a full scan of the second array */
6016  for (j = 0; j < table->n_def; j++) {
6017  const char* name;
6018 
6019  name = dict_table_get_col_name(table, j);
6020 
6021  if (innobase_strcasecmp(name,
6022  req_schema->columns[i].name) == 0) {
6023 
6024  /* found the column on j'th
6025  position */
6026  break;
6027  }
6028  }
6029 
6030  if (j == table->n_def) {
6031 
6032  ut_snprintf(errstr, errstr_sz,
6033  "required column %s "
6034  "not found in table %s.",
6035  req_schema->columns[i].name,
6037  req_schema->table_name,
6038  TRUE, buf, sizeof(buf)));
6039 
6040  return(DB_ERROR);
6041  }
6042  }
6043 
6044  /* we found a column with the same name on j'th position,
6045  compare column types and flags */
6046 
6047  dtype_sql_name(req_schema->columns[i].mtype,
6048  req_schema->columns[i].prtype_mask,
6049  req_schema->columns[i].len,
6050  req_type, sizeof(req_type));
6051 
6052  dtype_sql_name(table->cols[j].mtype,
6053  table->cols[j].prtype,
6054  table->cols[j].len,
6055  actual_type, sizeof(actual_type));
6056 
6057  /* check length for exact match */
6058  if (req_schema->columns[i].len != table->cols[j].len) {
6059 
6060  ut_snprintf(errstr, errstr_sz,
6061  "Column %s in table %s is %s "
6062  "but should be %s (length mismatch).",
6063  req_schema->columns[i].name,
6064  ut_format_name(req_schema->table_name,
6065  TRUE, buf, sizeof(buf)),
6066  actual_type, req_type);
6067 
6068  return(DB_ERROR);
6069  }
6070 
6071  /* check mtype for exact match */
6072  if (req_schema->columns[i].mtype != table->cols[j].mtype) {
6073 
6074  ut_snprintf(errstr, errstr_sz,
6075  "Column %s in table %s is %s "
6076  "but should be %s (type mismatch).",
6077  req_schema->columns[i].name,
6078  ut_format_name(req_schema->table_name,
6079  TRUE, buf, sizeof(buf)),
6080  actual_type, req_type);
6081 
6082  return(DB_ERROR);
6083  }
6084 
6085  /* check whether required prtype mask is set */
6086  if (req_schema->columns[i].prtype_mask != 0
6087  && (table->cols[j].prtype
6088  & req_schema->columns[i].prtype_mask)
6089  != req_schema->columns[i].prtype_mask) {
6090 
6091  ut_snprintf(errstr, errstr_sz,
6092  "Column %s in table %s is %s "
6093  "but should be %s (flags mismatch).",
6094  req_schema->columns[i].name,
6095  ut_format_name(req_schema->table_name,
6096  TRUE, buf, sizeof(buf)),
6097  actual_type, req_type);
6098 
6099  return(DB_ERROR);
6100  }
6101  }
6102 
6103  if (req_schema->n_foreign != UT_LIST_GET_LEN(table->foreign_list)) {
6104  ut_snprintf(
6105  errstr, errstr_sz,
6106  "Table %s has %lu foreign key(s) pointing to other "
6107  "tables, but it must have %lu.",
6108  ut_format_name(req_schema->table_name,
6109  TRUE, buf, sizeof(buf)),
6110  UT_LIST_GET_LEN(table->foreign_list),
6111  req_schema->n_foreign);
6112  return(DB_ERROR);
6113  }
6114 
6115  if (req_schema->n_referenced != UT_LIST_GET_LEN(table->referenced_list)) {
6116  ut_snprintf(
6117  errstr, errstr_sz,
6118  "There are %lu foreign key(s) pointing to %s, "
6119  "but there must be %lu.",
6121  ut_format_name(req_schema->table_name,
6122  TRUE, buf, sizeof(buf)),
6123  req_schema->n_referenced);
6124  return(DB_ERROR);
6125  }
6126 
6127  return(DB_SUCCESS);
6128 }
6129 /* @} */
6130 
6131 /*********************************************************************/
6136 UNIV_INTERN
6137 void
6139 /*=========*/
6140  const char* db_and_table,
6142  char* db_utf8,
6143  size_t db_utf8_size,
6144  char* table_utf8,
6145  size_t table_utf8_size)
6146 {
6147  char db[MAX_DATABASE_NAME_LEN + 1];
6148  ulint db_len;
6149  uint errors;
6150 
6151  db_len = dict_get_db_name_len(db_and_table);
6152 
6153  ut_a(db_len <= sizeof(db));
6154 
6155  memcpy(db, db_and_table, db_len);
6156  db[db_len] = '\0';
6157 
6158  strconvert(
6159  &my_charset_filename, db,
6160  system_charset_info, db_utf8, db_utf8_size,
6161  &errors);
6162 
6163  /* convert each # to @0023 in table name and store the result in buf */
6164  const char* table = dict_remove_db_name(db_and_table);
6165  const char* table_p;
6166  char buf[MAX_TABLE_NAME_LEN * 5 + 1];
6167  char* buf_p;
6168  for (table_p = table, buf_p = buf; table_p[0] != '\0'; table_p++) {
6169  if (table_p[0] != '#') {
6170  buf_p[0] = table_p[0];
6171  buf_p++;
6172  } else {
6173  buf_p[0] = '@';
6174  buf_p[1] = '0';
6175  buf_p[2] = '0';
6176  buf_p[3] = '2';
6177  buf_p[4] = '3';
6178  buf_p += 5;
6179  }
6180  ut_a((size_t) (buf_p - buf) < sizeof(buf));
6181  }
6182  buf_p[0] = '\0';
6183 
6184  errors = 0;
6185  strconvert(
6186  &my_charset_filename, buf,
6187  system_charset_info, table_utf8, table_utf8_size,
6188  &errors);
6189 
6190  if (errors != 0) {
6191  ut_snprintf(table_utf8, table_utf8_size, "%s%s",
6193  }
6194 }
6195 
6196 /**********************************************************************/
6198 UNIV_INTERN
6199 void
6201 /*============*/
6202 {
6203  ulint i;
6204 
6205  /* Free the hash elements. We don't remove them from the table
6206  because we are going to destroy the table anyway. */
6207  for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
6209 
6210  table = static_cast<dict_table_t*>(
6212 
6213  while (table) {
6214  dict_table_t* prev_table = table;
6215 
6216  table = static_cast<dict_table_t*>(
6217  HASH_GET_NEXT(name_hash, prev_table));
6218 #ifdef UNIV_DEBUG
6219  ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
6220 #endif
6221  /* Acquire only because it's a pre-condition. */
6222  mutex_enter(&dict_sys->mutex);
6223 
6224  dict_table_remove_from_cache(prev_table);
6225 
6226  mutex_exit(&dict_sys->mutex);
6227  }
6228  }
6229 
6231 
6232  /* The elements are the same instance as in dict_sys->table_hash,
6233  therefore we don't delete the individual elements. */
6235 
6236  dict_ind_free();
6237 
6238  mutex_free(&dict_sys->mutex);
6239 
6240  rw_lock_free(&dict_operation_lock);
6241  memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
6242 
6243  if (!srv_read_only_mode) {
6244  mutex_free(&dict_foreign_err_mutex);
6245  }
6246 
6247  mem_free(dict_sys);
6248  dict_sys = NULL;
6249 
6250  for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
6251  rw_lock_free(&dict_table_stats_latches[i]);
6252  }
6253 }
6254 
6255 #ifdef UNIV_DEBUG
6256 /**********************************************************************/
6259 static
6260 ibool
6261 dict_lru_validate(void)
6262 /*===================*/
6263 {
6265 
6266  ut_ad(mutex_own(&dict_sys->mutex));
6267 
6268  for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
6269  table != NULL;
6270  table = UT_LIST_GET_NEXT(table_LRU, table)) {
6271 
6272  ut_a(table->can_be_evicted);
6273  }
6274 
6275  for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU);
6276  table != NULL;
6277  table = UT_LIST_GET_NEXT(table_LRU, table)) {
6278 
6279  ut_a(!table->can_be_evicted);
6280  }
6281 
6282  return(TRUE);
6283 }
6284 
6285 /**********************************************************************/
6288 static
6289 ibool
6290 dict_lru_find_table(
6291 /*================*/
6292  const dict_table_t* find_table)
6293 {
6295 
6296  ut_ad(find_table != NULL);
6297  ut_ad(mutex_own(&dict_sys->mutex));
6298 
6299  for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
6300  table != NULL;
6301  table = UT_LIST_GET_NEXT(table_LRU, table)) {
6302 
6303  ut_a(table->can_be_evicted);
6304 
6305  if (table == find_table) {
6306  return(TRUE);
6307  }
6308  }
6309 
6310  return(FALSE);
6311 }
6312 
6313 /**********************************************************************/
6316 static
6317 ibool
6318 dict_non_lru_find_table(
6319 /*====================*/
6320  const dict_table_t* find_table)
6321 {
6323 
6324  ut_ad(find_table != NULL);
6325  ut_ad(mutex_own(&dict_sys->mutex));
6326 
6327  for (table = UT_LIST_GET_FIRST(dict_sys->table_non_LRU);
6328  table != NULL;
6329  table = UT_LIST_GET_NEXT(table_LRU, table)) {
6330 
6331  ut_a(!table->can_be_evicted);
6332 
6333  if (table == find_table) {
6334  return(TRUE);
6335  }
6336  }
6337 
6338  return(FALSE);
6339 }
6340 #endif /* UNIV_DEBUG */
6341 /*********************************************************************/
6346 UNIV_INTERN
6347 bool
6349 /*=======================*/
6350  const dict_table_t* table,
6351  const char** col_names,
6354  const char** columns,
6355  ulint n_cols,
6356  const dict_index_t* index,
6357  const dict_index_t* types_idx,
6361  bool check_charsets,
6365  ulint check_null)
6369 {
6370  if (dict_index_get_n_fields(index) < n_cols) {
6371  return(false);
6372  }
6373 
6374  for (ulint i = 0; i < n_cols; i++) {
6375  dict_field_t* field;
6376  const char* col_name;
6377  ulint col_no;
6378 
6379  field = dict_index_get_nth_field(index, i);
6380  col_no = dict_col_get_no(field->col);
6381 
6382  if (field->prefix_len != 0) {
6383  /* We do not accept column prefix
6384  indexes here */
6385  return(false);
6386  }
6387 
6388  if (check_null
6389  && (field->col->prtype & DATA_NOT_NULL)) {
6390  return(false);
6391  }
6392 
6393  col_name = col_names
6394  ? col_names[col_no]
6395  : dict_table_get_col_name(table, col_no);
6396 
6397  if (0 != innobase_strcasecmp(columns[i], col_name)) {
6398  return(false);
6399  }
6400 
6401  if (types_idx && !cmp_cols_are_equal(
6402  dict_index_get_nth_col(index, i),
6403  dict_index_get_nth_col(types_idx, i),
6404  check_charsets)) {
6405  return(false);
6406  }
6407  }
6408 
6409  return(true);
6410 }
6411 
6412 /*********************************************************************/
6416 static
6417 void
6418 dict_index_zip_pad_update(
6419 /*======================*/
6420  zip_pad_info_t* info, /*<! in/out: info to be updated */
6421  ulint zip_threshold) /*<! in: zip threshold value */
6422 {
6423  ulint total;
6424  ulint fail_pct;
6425 
6426  ut_ad(info);
6427 
6428  total = info->success + info->failure;
6429 
6430  ut_ad(total > 0);
6431 
6432  if(zip_threshold == 0) {
6433  /* User has just disabled the padding. */
6434  return;
6435  }
6436 
6437  if (total < ZIP_PAD_ROUND_LEN) {
6438  /* We are in middle of a round. Do nothing. */
6439  return;
6440  }
6441 
6442  /* We are at a 'round' boundary. Reset the values but first
6443  calculate fail rate for our heuristic. */
6444  fail_pct = (info->failure * 100) / total;
6445  info->failure = 0;
6446  info->success = 0;
6447 
6448  if (fail_pct > zip_threshold) {
6449  /* Compression failures are more then user defined
6450  threshold. Increase the pad size to reduce chances of
6451  compression failures. */
6452  ut_ad(info->pad % ZIP_PAD_INCR == 0);
6453 
6454  /* Only do increment if it won't increase padding
6455  beyond max pad size. */
6456  if (info->pad + ZIP_PAD_INCR
6457  < (UNIV_PAGE_SIZE * zip_pad_max) / 100) {
6458 #ifdef HAVE_ATOMIC_BUILTINS
6459  /* Use atomics even though we have the mutex.
6460  This is to ensure that we are able to read
6461  info->pad atomically where atomics are
6462  supported. */
6463  os_atomic_increment_ulint(&info->pad, ZIP_PAD_INCR);
6464 #else /* HAVE_ATOMIC_BUILTINS */
6465  info->pad += ZIP_PAD_INCR;
6466 #endif /* HAVE_ATOMIC_BUILTINS */
6467 
6468  MONITOR_INC(MONITOR_PAD_INCREMENTS);
6469  }
6470 
6471  info->n_rounds = 0;
6472 
6473  } else {
6474  /* Failure rate was OK. Another successful round
6475  completed. */
6476  ++info->n_rounds;
6477 
6478  /* If enough successful rounds are completed with
6479  compression failure rate in control, decrease the
6480  padding. */
6482  && info->pad > 0) {
6483 
6484  ut_ad(info->pad % ZIP_PAD_INCR == 0);
6485 #ifdef HAVE_ATOMIC_BUILTINS
6486  /* Use atomics even though we have the mutex.
6487  This is to ensure that we are able to read
6488  info->pad atomically where atomics are
6489  supported. */
6490  os_atomic_decrement_ulint(&info->pad, ZIP_PAD_INCR);
6491 #else /* HAVE_ATOMIC_BUILTINS */
6492  info->pad -= ZIP_PAD_INCR;
6493 #endif /* HAVE_ATOMIC_BUILTINS */
6494 
6495  info->n_rounds = 0;
6496 
6497  MONITOR_INC(MONITOR_PAD_DECREMENTS);
6498  }
6499  }
6500 }
6501 
6502 /*********************************************************************/
6505 UNIV_INTERN
6506 void
6508 /*===================*/
6509  dict_index_t* index)
6510 {
6511  ut_ad(index);
6512 
6513  ulint zip_threshold = zip_failure_threshold_pct;
6514  if (!zip_threshold) {
6515  /* Disabled by user. */
6516  return;
6517  }
6518 
6519  os_fast_mutex_lock(&index->zip_pad.mutex);
6520  ++index->zip_pad.success;
6521  dict_index_zip_pad_update(&index->zip_pad, zip_threshold);
6522  os_fast_mutex_unlock(&index->zip_pad.mutex);
6523 }
6524 
6525 /*********************************************************************/
6528 UNIV_INTERN
6529 void
6531 /*===================*/
6532  dict_index_t* index)
6533 {
6534  ut_ad(index);
6535 
6536  ulint zip_threshold = zip_failure_threshold_pct;
6537  if (!zip_threshold) {
6538  /* Disabled by user. */
6539  return;
6540  }
6541 
6542  os_fast_mutex_lock(&index->zip_pad.mutex);
6543  ++index->zip_pad.failure;
6544  dict_index_zip_pad_update(&index->zip_pad, zip_threshold);
6545  os_fast_mutex_unlock(&index->zip_pad.mutex);
6546 }
6547 
6548 
6549 /*********************************************************************/
6552 UNIV_INTERN
6553 ulint
6555 /*=================================*/
6556  dict_index_t* index)
6558 {
6559  ulint pad;
6560  ulint min_sz;
6561  ulint sz;
6562 
6563  ut_ad(index);
6564 
6566  /* Disabled by user. */
6567  return(UNIV_PAGE_SIZE);
6568  }
6569 
6570  /* We use atomics to read index->zip_pad.pad. Here we use zero
6571  as increment as are not changing the value of the 'pad'. On
6572  platforms where atomics are not available we grab the mutex. */
6573 
6574 #ifdef HAVE_ATOMIC_BUILTINS
6575  pad = os_atomic_increment_ulint(&index->zip_pad.pad, 0);
6576 #else /* HAVE_ATOMIC_BUILTINS */
6577  os_fast_mutex_lock(&index->zip_pad.mutex);
6578  pad = index->zip_pad.pad;
6579  os_fast_mutex_unlock(&index->zip_pad.mutex);
6580 #endif /* HAVE_ATOMIC_BUILTINS */
6581 
6582  ut_ad(pad < UNIV_PAGE_SIZE);
6583  sz = UNIV_PAGE_SIZE - pad;
6584 
6585  /* Min size allowed by user. */
6586  ut_ad(zip_pad_max < 100);
6587  min_sz = (UNIV_PAGE_SIZE * (100 - zip_pad_max)) / 100;
6588 
6589  return(ut_max(sz, min_sz));
6590 }
6591 
6592 /*************************************************************/
6595 UNIV_INTERN
6596 const char*
6598 /*=========================*/
6599  ulint table_flag)
6600 {
6601  switch (dict_tf_get_rec_format(table_flag)) {
6602  case REC_FORMAT_REDUNDANT:
6603  return("ROW_TYPE_REDUNDANT");
6604  case REC_FORMAT_COMPACT:
6605  return("ROW_TYPE_COMPACT");
6606  case REC_FORMAT_COMPRESSED:
6607  return("ROW_TYPE_COMPRESSED");
6608  case REC_FORMAT_DYNAMIC:
6609  return("ROW_TYPE_DYNAMIC");
6610  }
6611 
6612  ut_error;
6613  return(0);
6614 }
6615 #endif /* !UNIV_HOTBACKUP */