Drizzled Public API Documentation

dict0dict.cc
1 /*****************************************************************************
2 
3 Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /******************************************************************/
26 #include "dict0dict.h"
27 
28 #ifdef UNIV_NONINL
29 #include "dict0dict.ic"
30 #endif
31 
33 UNIV_INTERN dict_index_t* dict_ind_redundant;
35 UNIV_INTERN dict_index_t* dict_ind_compact;
36 
37 #ifndef UNIV_HOTBACKUP
38 #include "buf0buf.h"
39 #include "data0type.h"
40 #include "mach0data.h"
41 #include "dict0boot.h"
42 #include "dict0mem.h"
43 #include "dict0crea.h"
44 #include "trx0undo.h"
45 #include "btr0btr.h"
46 #include "btr0cur.h"
47 #include "btr0sea.h"
48 #include "page0zip.h"
49 #include "page0page.h"
50 #include "pars0pars.h"
51 #include "pars0sym.h"
52 #include "que0que.h"
53 #include "rem0cmp.h"
54 #include "row0merge.h"
55 #include "ha_prototypes.h" /* innobase_strcasecmp() */
56 
57 #include <ctype.h>
58 
59 #include <drizzled/session.h>
60 
62 UNIV_INTERN dict_sys_t* dict_sys = NULL;
63 
72 UNIV_INTERN rw_lock_t dict_operation_lock;
73 
74 /* Keys to register rwlocks and mutexes with performance schema */
75 #ifdef UNIV_PFS_RWLOCK
76 UNIV_INTERN mysql_pfs_key_t dict_operation_lock_key;
77 UNIV_INTERN mysql_pfs_key_t index_tree_rw_lock_key;
78 #endif /* UNIV_PFS_RWLOCK */
79 
80 #ifdef UNIV_PFS_MUTEX
81 UNIV_INTERN mysql_pfs_key_t dict_sys_mutex_key;
82 UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key;
83 #endif /* UNIV_PFS_MUTEX */
84 
85 #define DICT_HEAP_SIZE 100
87 #define DICT_POOL_PER_TABLE_HASH 512
89 #define DICT_POOL_PER_VARYING 4
93 static char dict_ibfk[] = "_ibfk_";
94 
105 #define DICT_TABLE_STATS_LATCHES_SIZE 64
106 static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
107 
108 /*******************************************************************/
112 static
113 ibool
114 dict_index_find_cols(
115 /*=================*/
116  dict_table_t* table,
117  dict_index_t* index);
118 /*******************************************************************/
122 static
124 dict_index_build_internal_clust(
125 /*============================*/
126  const dict_table_t* table,
127  dict_index_t* index);
129 /*******************************************************************/
133 static
135 dict_index_build_internal_non_clust(
136 /*================================*/
137  const dict_table_t* table,
138  dict_index_t* index);
140 /**********************************************************************/
142 static
143 void
144 dict_foreign_remove_from_cache(
145 /*===========================*/
146  dict_foreign_t* foreign);
147 /**********************************************************************/
149 static
150 void
151 dict_col_print_low(
152 /*===============*/
153  const dict_table_t* table,
154  const dict_col_t* col);
155 /**********************************************************************/
157 static
158 void
159 dict_index_print_low(
160 /*=================*/
161  dict_index_t* index);
162 /**********************************************************************/
164 static
165 void
166 dict_field_print_low(
167 /*=================*/
168  const dict_field_t* field);
169 /*********************************************************************/
171 static
172 void
173 dict_foreign_free(
174 /*==============*/
175  dict_foreign_t* foreign);
177 /* Stream for storing detailed information about the latest foreign key
178 and unique key errors */
179 UNIV_INTERN FILE* dict_foreign_err_file = NULL;
180 /* mutex protecting the foreign and unique error buffers */
181 UNIV_INTERN mutex_t dict_foreign_err_mutex;
182 
183 /******************************************************************/
185 UNIV_INTERN
186 void
187 dict_casedn_str(
188 /*============*/
189  char* a)
190 {
192 }
193 
194 /********************************************************************/
197 UNIV_INTERN
198 ibool
199 dict_tables_have_same_db(
200 /*=====================*/
201  const char* name1,
203  const char* name2)
205 {
206  for (; *name1 == *name2; name1++, name2++) {
207  if (*name1 == '/') {
208  return(TRUE);
209  }
210  ut_a(*name1); /* the names must contain '/' */
211  }
212  return(FALSE);
213 }
214 
215 /********************************************************************/
218 UNIV_INTERN
219 const char*
220 dict_remove_db_name(
221 /*================*/
222  const char* name)
224 {
225  const char* s = strchr(name, '/');
226  ut_a(s);
227 
228  return(s + 1);
229 }
230 
231 /********************************************************************/
234 UNIV_INTERN
235 ulint
236 dict_get_db_name_len(
237 /*=================*/
238  const char* name)
240 {
241  const char* s;
242  s = strchr(name, '/');
243  ut_a(s);
244  return(s - name);
245 }
246 
247 /********************************************************************/
249 UNIV_INTERN
250 void
251 dict_mutex_enter_for_mysql(void)
252 /*============================*/
253 {
254  mutex_enter(&(dict_sys->mutex));
255 }
256 
257 /********************************************************************/
259 UNIV_INTERN
260 void
261 dict_mutex_exit_for_mysql(void)
262 /*===========================*/
263 {
264  mutex_exit(&(dict_sys->mutex));
265 }
266 
268 #define GET_TABLE_STATS_LATCH(table) \
269  (&dict_table_stats_latches[ut_fold_ull(table->id) \
270  % DICT_TABLE_STATS_LATCHES_SIZE])
271 
272 /**********************************************************************/
276 UNIV_INTERN
277 void
278 dict_table_stats_lock(
279 /*==================*/
280  const dict_table_t* table,
281  ulint latch_mode)
283 {
284  ut_ad(table != NULL);
285  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
286 
287  switch (latch_mode) {
288  case RW_S_LATCH:
289  rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
290  break;
291  case RW_X_LATCH:
292  rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
293  break;
294  case RW_NO_LATCH:
295  /* fall through */
296  default:
297  ut_error;
298  }
299 }
300 
301 /**********************************************************************/
303 UNIV_INTERN
304 void
305 dict_table_stats_unlock(
306 /*====================*/
307  const dict_table_t* table,
308  ulint latch_mode)
310 {
311  ut_ad(table != NULL);
312  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
313 
314  switch (latch_mode) {
315  case RW_S_LATCH:
316  rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
317  break;
318  case RW_X_LATCH:
319  rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
320  break;
321  case RW_NO_LATCH:
322  /* fall through */
323  default:
324  ut_error;
325  }
326 }
327 
328 /********************************************************************/
330 UNIV_INTERN
331 void
332 dict_table_decrement_handle_count(
333 /*==============================*/
334  dict_table_t* table,
335  ibool dict_locked)
336 {
337  if (!dict_locked) {
338  mutex_enter(&dict_sys->mutex);
339  }
340 
341  ut_ad(mutex_own(&dict_sys->mutex));
342  ut_a(table->n_mysql_handles_opened > 0);
343 
344  table->n_mysql_handles_opened--;
345 
346  if (!dict_locked) {
347  mutex_exit(&dict_sys->mutex);
348  }
349 }
350 #endif /* !UNIV_HOTBACKUP */
351 
352 /**********************************************************************/
356 UNIV_INTERN
357 const char*
358 dict_table_get_col_name(
359 /*====================*/
360  const dict_table_t* table,
361  ulint col_nr)
362 {
363  ulint i;
364  const char* s;
365 
366  ut_ad(table);
367  ut_ad(col_nr < table->n_def);
368  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
369 
370  s = table->col_names;
371  if (s) {
372  for (i = 0; i < col_nr; i++) {
373  s += strlen(s) + 1;
374  }
375  }
376 
377  return(s);
378 }
379 
380 #ifndef UNIV_HOTBACKUP
381 /********************************************************************/
383 UNIV_INTERN
384 void
385 dict_table_autoinc_lock(
386 /*====================*/
387  dict_table_t* table)
388 {
389  mutex_enter(&table->autoinc_mutex);
390 }
391 
392 /********************************************************************/
394 UNIV_INTERN
395 void
396 dict_table_autoinc_initialize(
397 /*==========================*/
398  dict_table_t* table,
399  ib_uint64_t value)
400 {
401  ut_ad(mutex_own(&table->autoinc_mutex));
402 
403  table->autoinc = value;
404 }
405 
406 /********************************************************************/
410 UNIV_INTERN
411 ib_uint64_t
412 dict_table_autoinc_read(
413 /*====================*/
414  const dict_table_t* table)
415 {
416  ut_ad(mutex_own(&table->autoinc_mutex));
417 
418  return(table->autoinc);
419 }
420 
421 /********************************************************************/
424 UNIV_INTERN
425 void
426 dict_table_autoinc_update_if_greater(
427 /*=================================*/
428 
429  dict_table_t* table,
430  ib_uint64_t value)
431 {
432  ut_ad(mutex_own(&table->autoinc_mutex));
433 
434  if (value > table->autoinc) {
435 
436  table->autoinc = value;
437  }
438 }
439 
440 /********************************************************************/
442 UNIV_INTERN
443 void
444 dict_table_autoinc_unlock(
445 /*======================*/
446  dict_table_t* table)
447 {
448  mutex_exit(&table->autoinc_mutex);
449 }
450 
451 /**********************************************************************/
455 UNIV_INTERN
457 dict_index_get_on_id_low(
458 /*=====================*/
459  dict_table_t* table,
460  index_id_t id)
461 {
462  dict_index_t* index;
463 
464  index = dict_table_get_first_index(table);
465 
466  while (index) {
467  if (id == index->id) {
468  /* Found */
469 
470  return(index);
471  }
472 
473  index = dict_table_get_next_index(index);
474  }
475 
476  return(NULL);
477 }
478 #endif /* !UNIV_HOTBACKUP */
479 
480 /********************************************************************/
484 UNIV_INTERN
485 ulint
486 dict_index_get_nth_col_pos(
487 /*=======================*/
488  const dict_index_t* index,
489  ulint n)
490 {
491  const dict_field_t* field;
492  const dict_col_t* col;
493  ulint pos;
494  ulint n_fields;
495 
496  ut_ad(index);
497  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
498 
499  col = dict_table_get_nth_col(index->table, n);
500 
501  if (dict_index_is_clust(index)) {
502 
503  return(dict_col_get_clust_pos(col, index));
504  }
505 
506  n_fields = dict_index_get_n_fields(index);
507 
508  for (pos = 0; pos < n_fields; pos++) {
509  field = dict_index_get_nth_field(index, pos);
510 
511  if (col == field->col && field->prefix_len == 0) {
512 
513  return(pos);
514  }
515  }
516 
517  return(ULINT_UNDEFINED);
518 }
519 
520 #ifndef UNIV_HOTBACKUP
521 /********************************************************************/
524 UNIV_INTERN
525 ibool
526 dict_index_contains_col_or_prefix(
527 /*==============================*/
528  const dict_index_t* index,
529  ulint n)
530 {
531  const dict_field_t* field;
532  const dict_col_t* col;
533  ulint pos;
534  ulint n_fields;
535 
536  ut_ad(index);
537  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
538 
539  if (dict_index_is_clust(index)) {
540 
541  return(TRUE);
542  }
543 
544  col = dict_table_get_nth_col(index->table, n);
545 
546  n_fields = dict_index_get_n_fields(index);
547 
548  for (pos = 0; pos < n_fields; pos++) {
549  field = dict_index_get_nth_field(index, pos);
550 
551  if (col == field->col) {
552 
553  return(TRUE);
554  }
555  }
556 
557  return(FALSE);
558 }
559 
560 /********************************************************************/
567 UNIV_INTERN
568 ulint
569 dict_index_get_nth_field_pos(
570 /*=========================*/
571  const dict_index_t* index,
572  const dict_index_t* index2,
573  ulint n)
574 {
575  const dict_field_t* field;
576  const dict_field_t* field2;
577  ulint n_fields;
578  ulint pos;
579 
580  ut_ad(index);
581  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
582 
583  field2 = dict_index_get_nth_field(index2, n);
584 
585  n_fields = dict_index_get_n_fields(index);
586 
587  for (pos = 0; pos < n_fields; pos++) {
588  field = dict_index_get_nth_field(index, pos);
589 
590  if (field->col == field2->col
591  && (field->prefix_len == 0
592  || (field->prefix_len >= field2->prefix_len
593  && field2->prefix_len != 0))) {
594 
595  return(pos);
596  }
597  }
598 
599  return(ULINT_UNDEFINED);
600 }
601 
602 /**********************************************************************/
605 UNIV_INTERN
607 dict_table_get_on_id(
608 /*=================*/
609  table_id_t table_id,
610  trx_t* trx)
611 {
612  dict_table_t* table;
613 
614  if (trx->dict_operation_lock_mode == RW_X_LATCH) {
615 
616  /* Note: An X latch implies that the transaction
617  already owns the dictionary mutex. */
618 
619  ut_ad(mutex_own(&dict_sys->mutex));
620 
621  return(dict_table_get_on_id_low(table_id));
622  }
623 
624  mutex_enter(&(dict_sys->mutex));
625 
626  table = dict_table_get_on_id_low(table_id);
627 
628  mutex_exit(&(dict_sys->mutex));
629 
630  return(table);
631 }
632 
633 /********************************************************************/
636 UNIV_INTERN
637 ulint
638 dict_table_get_nth_col_pos(
639 /*=======================*/
640  const dict_table_t* table,
641  ulint n)
642 {
643  return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
644  n));
645 }
646 
647 /********************************************************************/
651 UNIV_INTERN
652 ibool
653 dict_table_col_in_clustered_key(
654 /*============================*/
655  const dict_table_t* table,
656  ulint n)
657 {
658  const dict_index_t* index;
659  const dict_field_t* field;
660  const dict_col_t* col;
661  ulint pos;
662  ulint n_fields;
663 
664  ut_ad(table);
665 
666  col = dict_table_get_nth_col(table, n);
667 
668  index = dict_table_get_first_index(table);
669 
670  n_fields = dict_index_get_n_unique(index);
671 
672  for (pos = 0; pos < n_fields; pos++) {
673  field = dict_index_get_nth_field(index, pos);
674 
675  if (col == field->col) {
676 
677  return(TRUE);
678  }
679  }
680 
681  return(FALSE);
682 }
683 
684 /**********************************************************************/
686 UNIV_INTERN
687 void
688 dict_init(void)
689 /*===========*/
690 {
691  int i;
692 
693  dict_sys = static_cast<dict_sys_t *>(mem_alloc(sizeof(dict_sys_t)));
694 
695  mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
696 
697  dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
698  / (DICT_POOL_PER_TABLE_HASH
699  * UNIV_WORD_SIZE));
700  dict_sys->table_id_hash = hash_create(buf_pool_get_curr_size()
701  / (DICT_POOL_PER_TABLE_HASH
702  * UNIV_WORD_SIZE));
703  dict_sys->size = 0;
704 
705  UT_LIST_INIT(dict_sys->table_LRU);
706 
707  rw_lock_create(dict_operation_lock_key,
708  &dict_operation_lock, SYNC_DICT_OPERATION);
709 
710  dict_foreign_err_file = os_file_create_tmpfile();
711  ut_a(dict_foreign_err_file);
712 
713  mutex_create(dict_foreign_err_mutex_key,
714  &dict_foreign_err_mutex, SYNC_ANY_LATCH);
715 
716  for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
717  rw_lock_create(PFS_NOT_INSTRUMENTED,
718  &dict_table_stats_latches[i], SYNC_INDEX_TREE);
719  }
720 }
721 
722 /**********************************************************************/
728 UNIV_INTERN
730 dict_table_get(
731 /*===========*/
732  const char* table_name,
733  ibool inc_mysql_count)
735 {
736  dict_table_t* table;
737 
738  mutex_enter(&(dict_sys->mutex));
739 
740  table = dict_table_get_low(table_name);
741 
742  if (inc_mysql_count && table) {
743  table->n_mysql_handles_opened++;
744  }
745 
746  mutex_exit(&(dict_sys->mutex));
747 
748  if (table != NULL) {
749  /* If table->ibd_file_missing == TRUE, this will
750  print an error message and return without doing
751  anything. */
752  dict_update_statistics(table, TRUE /* only update stats
753  if they have not been initialized */);
754  }
755 
756  return(table);
757 }
758 #endif /* !UNIV_HOTBACKUP */
759 
760 /**********************************************************************/
762 UNIV_INTERN
763 void
764 dict_table_add_system_columns(
765 /*==========================*/
766  dict_table_t* table,
767  mem_heap_t* heap)
768 {
769  ut_ad(table);
770  ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
771  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
772  ut_ad(!table->cached);
773 
774  /* NOTE: the system columns MUST be added in the following order
775  (so that they can be indexed by the numerical value of DATA_ROW_ID,
776  etc.) and as the last columns of the table memory object.
777  The clustered index will not always physically contain all
778  system columns. */
779 
780  dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
781  DATA_ROW_ID | DATA_NOT_NULL,
782  DATA_ROW_ID_LEN);
783 #if DATA_ROW_ID != 0
784 #error "DATA_ROW_ID != 0"
785 #endif
786  dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
787  DATA_TRX_ID | DATA_NOT_NULL,
788  DATA_TRX_ID_LEN);
789 #if DATA_TRX_ID != 1
790 #error "DATA_TRX_ID != 1"
791 #endif
792  dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
793  DATA_ROLL_PTR | DATA_NOT_NULL,
794  DATA_ROLL_PTR_LEN);
795 #if DATA_ROLL_PTR != 2
796 #error "DATA_ROLL_PTR != 2"
797 #endif
798 
799  /* This check reminds that if a new system column is added to
800  the program, it should be dealt with here */
801 #if DATA_N_SYS_COLS != 3
802 #error "DATA_N_SYS_COLS != 3"
803 #endif
804 }
805 
806 #ifndef UNIV_HOTBACKUP
807 /**********************************************************************/
809 UNIV_INTERN
810 void
811 dict_table_add_to_cache(
812 /*====================*/
813  dict_table_t* table,
814  mem_heap_t* heap)
815 {
816  ulint fold;
817  ulint id_fold;
818  ulint i;
819  ulint row_len;
820 
821  /* The lower limit for what we consider a "big" row */
822 #define BIG_ROW_SIZE 1024
823 
824  ut_ad(mutex_own(&(dict_sys->mutex)));
825 
826  dict_table_add_system_columns(table, heap);
827 
828  table->cached = TRUE;
829 
830  fold = ut_fold_string(table->name);
831  id_fold = ut_fold_ull(table->id);
832 
833  row_len = 0;
834  for (i = 0; i < table->n_def; i++) {
835  ulint col_len = dict_col_get_max_size(
836  dict_table_get_nth_col(table, i));
837 
838  row_len += col_len;
839 
840  /* If we have a single unbounded field, or several gigantic
841  fields, mark the maximum row size as BIG_ROW_SIZE. */
842  if (row_len >= BIG_ROW_SIZE || col_len >= BIG_ROW_SIZE) {
843  row_len = BIG_ROW_SIZE;
844 
845  break;
846  }
847  }
848 
849  table->big_rows = row_len >= BIG_ROW_SIZE;
850 
851  /* Look for a table with the same name: error if such exists */
852  {
853  dict_table_t* table2;
854  HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
855  dict_table_t*, table2, ut_ad(table2->cached),
856  ut_strcmp(table2->name, table->name) == 0);
857  ut_a(table2 == NULL);
858 
859 #ifdef UNIV_DEBUG
860  /* Look for the same table pointer with a different name */
861  HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
862  dict_table_t*, table2, ut_ad(table2->cached),
863  table2 == table);
864  ut_ad(table2 == NULL);
865 #endif /* UNIV_DEBUG */
866  }
867 
868  /* Look for a table with the same id: error if such exists */
869  {
870  dict_table_t* table2;
871  HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
872  dict_table_t*, table2, ut_ad(table2->cached),
873  table2->id == table->id);
874  ut_a(table2 == NULL);
875 
876 #ifdef UNIV_DEBUG
877  /* Look for the same table pointer with a different id */
878  HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
879  dict_table_t*, table2, ut_ad(table2->cached),
880  table2 == table);
881  ut_ad(table2 == NULL);
882 #endif /* UNIV_DEBUG */
883  }
884 
885  /* Add table to hash table of tables */
886  HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
887  table);
888 
889  /* Add table to hash table of tables based on table id */
890  HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, id_fold,
891  table);
892  /* Add table to LRU list of tables */
893  UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table);
894 
895  dict_sys->size += mem_heap_get_size(table->heap)
896  + strlen(table->name) + 1;
897 }
898 
899 /**********************************************************************/
904 UNIV_INTERN
906 dict_index_find_on_id_low(
907 /*======================*/
908  index_id_t id)
909 {
910  dict_table_t* table;
911  dict_index_t* index;
912 
913  table = UT_LIST_GET_FIRST(dict_sys->table_LRU);
914 
915  while (table) {
916  index = dict_table_get_first_index(table);
917 
918  while (index) {
919  if (id == index->id) {
920  /* Found */
921 
922  return(index);
923  }
924 
925  index = dict_table_get_next_index(index);
926  }
927 
928  table = UT_LIST_GET_NEXT(table_LRU, table);
929  }
930 
931  return(NULL);
932 }
933 
934 /**********************************************************************/
937 UNIV_INTERN
938 ibool
939 dict_table_rename_in_cache(
940 /*=======================*/
941  dict_table_t* table,
942  const char* new_name,
943  ibool rename_also_foreigns)
946 {
947  dict_foreign_t* foreign;
948  dict_index_t* index;
949  ulint fold;
950  char old_name[MAX_TABLE_NAME_LEN + 1];
951 
952  ut_ad(table);
953  ut_ad(mutex_own(&(dict_sys->mutex)));
954 
955  /* store the old/current name to an automatic variable */
956  if (strlen(table->name) + 1 <= sizeof(old_name)) {
957  memcpy(old_name, table->name, strlen(table->name) + 1);
958  } else {
959  ut_print_timestamp(stderr);
960  fprintf(stderr, "InnoDB: too long table name: '%s', "
961  "max length is %d\n", table->name,
962  MAX_TABLE_NAME_LEN);
963  ut_error;
964  }
965 
966  fold = ut_fold_string(new_name);
967 
968  /* Look for a table with the same name: error if such exists */
969  {
970  dict_table_t* table2;
971  HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
972  dict_table_t*, table2, ut_ad(table2->cached),
973  (ut_strcmp(table2->name, new_name) == 0));
974  if (UNIV_LIKELY_NULL(table2)) {
975  ut_print_timestamp(stderr);
976  fputs(" InnoDB: Error: dictionary cache"
977  " already contains a table ", stderr);
978  ut_print_name(stderr, NULL, TRUE, new_name);
979  fputs("\n"
980  "InnoDB: cannot rename table ", stderr);
981  ut_print_name(stderr, NULL, TRUE, old_name);
982  putc('\n', stderr);
983  return(FALSE);
984  }
985  }
986 
987  /* If the table is stored in a single-table tablespace, rename the
988  .ibd file */
989 
990  if (table->space != 0) {
991  if (table->dir_path_of_temp_table != NULL) {
992  ut_print_timestamp(stderr);
993  fputs(" InnoDB: Error: trying to rename a"
994  " TEMPORARY TABLE ", stderr);
995  ut_print_name(stderr, NULL, TRUE, old_name);
996  fputs(" (", stderr);
997  ut_print_filename(stderr,
998  table->dir_path_of_temp_table);
999  fputs(" )\n", stderr);
1000  return(FALSE);
1001  } else if (!fil_rename_tablespace(old_name, table->space,
1002  new_name)) {
1003  return(FALSE);
1004  }
1005  }
1006 
1007  /* Remove table from the hash tables of tables */
1008  HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1009  ut_fold_string(old_name), table);
1010 
1011  if (strlen(new_name) > strlen(table->name)) {
1012  /* We allocate MAX_TABLE_NAME_LEN+1 bytes here to avoid
1013  memory fragmentation, we assume a repeated calls of
1014  ut_realloc() with the same size do not cause fragmentation */
1015  ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN);
1016  table->name = static_cast<char *>(ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1));
1017  }
1018  memcpy(table->name, new_name, strlen(new_name) + 1);
1019 
1020  /* Add table to hash table of tables */
1021  HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold,
1022  table);
1023 
1024  dict_sys->size += strlen(new_name) - strlen(old_name);
1025  ut_a(dict_sys->size > 0);
1026 
1027  /* Update the table_name field in indexes */
1028  index = dict_table_get_first_index(table);
1029 
1030  while (index != NULL) {
1031  index->table_name = table->name;
1032 
1033  index = dict_table_get_next_index(index);
1034  }
1035 
1036  if (!rename_also_foreigns) {
1037  /* In ALTER TABLE we think of the rename table operation
1038  in the direction table -> temporary table (#sql...)
1039  as dropping the table with the old name and creating
1040  a new with the new name. Thus we kind of drop the
1041  constraints from the dictionary cache here. The foreign key
1042  constraints will be inherited to the new table from the
1043  system tables through a call of dict_load_foreigns. */
1044 
1045  /* Remove the foreign constraints from the cache */
1046  foreign = UT_LIST_GET_LAST(table->foreign_list);
1047 
1048  while (foreign != NULL) {
1049  dict_foreign_remove_from_cache(foreign);
1050  foreign = UT_LIST_GET_LAST(table->foreign_list);
1051  }
1052 
1053  /* Reset table field in referencing constraints */
1054 
1055  foreign = UT_LIST_GET_FIRST(table->referenced_list);
1056 
1057  while (foreign != NULL) {
1058  foreign->referenced_table = NULL;
1059  foreign->referenced_index = NULL;
1060 
1061  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1062  }
1063 
1064  /* Make the list of referencing constraints empty */
1065 
1066  UT_LIST_INIT(table->referenced_list);
1067 
1068  return(TRUE);
1069  }
1070 
1071  /* Update the table name fields in foreign constraints, and update also
1072  the constraint id of new format >= 4.0.18 constraints. Note that at
1073  this point we have already changed table->name to the new name. */
1074 
1075  foreign = UT_LIST_GET_FIRST(table->foreign_list);
1076 
1077  while (foreign != NULL) {
1078  if (ut_strlen(foreign->foreign_table_name)
1079  < ut_strlen(table->name)) {
1080  /* Allocate a longer name buffer;
1081  TODO: store buf len to save memory */
1082 
1083  foreign->foreign_table_name
1084  = static_cast<char *>(mem_heap_alloc(foreign->heap,
1085  ut_strlen(table->name) + 1));
1086  }
1087 
1088  strcpy(foreign->foreign_table_name, table->name);
1089 
1090  if (strchr(foreign->id, '/')) {
1091  ulint db_len;
1092  char* old_id;
1093 
1094  /* This is a >= 4.0.18 format id */
1095 
1096  old_id = mem_strdup(foreign->id);
1097 
1098  if (ut_strlen(foreign->id) > ut_strlen(old_name)
1099  + ((sizeof dict_ibfk) - 1)
1100  && !memcmp(foreign->id, old_name,
1101  ut_strlen(old_name))
1102  && !memcmp(foreign->id + ut_strlen(old_name),
1103  dict_ibfk, (sizeof dict_ibfk) - 1)) {
1104 
1105  /* This is a generated >= 4.0.18 format id */
1106 
1107  if (strlen(table->name) > strlen(old_name)) {
1108  foreign->id = static_cast<char *>(mem_heap_alloc(
1109  foreign->heap,
1110  strlen(table->name)
1111  + strlen(old_id) + 1));
1112  }
1113 
1114  /* Replace the prefix 'databasename/tablename'
1115  with the new names */
1116  strcpy(foreign->id, table->name);
1117  strcat(foreign->id,
1118  old_id + ut_strlen(old_name));
1119  } else {
1120  /* This is a >= 4.0.18 format id where the user
1121  gave the id name */
1122  db_len = dict_get_db_name_len(table->name) + 1;
1123 
1124  if (dict_get_db_name_len(table->name)
1125  > dict_get_db_name_len(foreign->id)) {
1126 
1127  foreign->id = static_cast<char *>(mem_heap_alloc(
1128  foreign->heap,
1129  db_len + strlen(old_id) + 1));
1130  }
1131 
1132  /* Replace the database prefix in id with the
1133  one from table->name */
1134 
1135  ut_memcpy(foreign->id, table->name, db_len);
1136 
1137  strcpy(foreign->id + db_len,
1138  dict_remove_db_name(old_id));
1139  }
1140 
1141  mem_free(old_id);
1142  }
1143 
1144  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
1145  }
1146 
1147  foreign = UT_LIST_GET_FIRST(table->referenced_list);
1148 
1149  while (foreign != NULL) {
1150  if (ut_strlen(foreign->referenced_table_name)
1151  < ut_strlen(table->name)) {
1152  /* Allocate a longer name buffer;
1153  TODO: store buf len to save memory */
1154 
1155  foreign->referenced_table_name = static_cast<char *>(mem_heap_alloc(
1156  foreign->heap, strlen(table->name) + 1));
1157  }
1158 
1159  strcpy(foreign->referenced_table_name, table->name);
1160 
1161  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1162  }
1163 
1164  return(TRUE);
1165 }
1166 
1167 /**********************************************************************/
1170 UNIV_INTERN
1171 void
1172 dict_table_change_id_in_cache(
1173 /*==========================*/
1174  dict_table_t* table,
1175  table_id_t new_id)
1176 {
1177  ut_ad(table);
1178  ut_ad(mutex_own(&(dict_sys->mutex)));
1179  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1180 
1181  /* Remove the table from the hash table of id's */
1182 
1183  HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1184  ut_fold_ull(table->id), table);
1185  table->id = new_id;
1186 
1187  /* Add the table back to the hash table */
1188  HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash,
1189  ut_fold_ull(table->id), table);
1190 }
1191 
1192 /**********************************************************************/
1194 UNIV_INTERN
1195 void
1196 dict_table_remove_from_cache(
1197 /*=========================*/
1198  dict_table_t* table)
1199 {
1200  dict_foreign_t* foreign;
1201  dict_index_t* index;
1202  ulint size;
1203 
1204  ut_ad(table);
1205  ut_ad(mutex_own(&(dict_sys->mutex)));
1206  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1207 
1208 #if 0
1209  fputs("Removing table ", stderr);
1210  ut_print_name(stderr, table->name, ULINT_UNDEFINED);
1211  fputs(" from dictionary cache\n", stderr);
1212 #endif
1213 
1214  /* Remove the foreign constraints from the cache */
1215  foreign = UT_LIST_GET_LAST(table->foreign_list);
1216 
1217  while (foreign != NULL) {
1218  dict_foreign_remove_from_cache(foreign);
1219  foreign = UT_LIST_GET_LAST(table->foreign_list);
1220  }
1221 
1222  /* Reset table field in referencing constraints */
1223 
1224  foreign = UT_LIST_GET_FIRST(table->referenced_list);
1225 
1226  while (foreign != NULL) {
1227  foreign->referenced_table = NULL;
1228  foreign->referenced_index = NULL;
1229 
1230  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1231  }
1232 
1233  /* Remove the indexes from the cache */
1234  index = UT_LIST_GET_LAST(table->indexes);
1235 
1236  while (index != NULL) {
1237  dict_index_remove_from_cache(table, index);
1238  index = UT_LIST_GET_LAST(table->indexes);
1239  }
1240 
1241  /* Remove table from the hash tables of tables */
1242  HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
1243  ut_fold_string(table->name), table);
1244  HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash,
1245  ut_fold_ull(table->id), table);
1246 
1247  /* Remove table from LRU list of tables */
1248  UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table);
1249 
1250  size = mem_heap_get_size(table->heap) + strlen(table->name) + 1;
1251 
1252  ut_ad(dict_sys->size >= size);
1253 
1254  dict_sys->size -= size;
1255 
1256  dict_mem_table_free(table);
1257 }
1258 
1259 /****************************************************************/
1263 UNIV_INTERN
1264 ibool
1265 dict_col_name_is_reserved(
1266 /*======================*/
1267  const char* name)
1268 {
1269  /* This check reminds that if a new system column is added to
1270  the program, it should be dealt with here. */
1271 #if DATA_N_SYS_COLS != 3
1272 #error "DATA_N_SYS_COLS != 3"
1273 #endif
1274 
1275  static const char* reserved_names[] = {
1276  "DB_ROW_ID", "DB_TRX_ID", "DB_ROLL_PTR"
1277  };
1278 
1279  ulint i;
1280 
1281  for (i = 0; i < UT_ARR_SIZE(reserved_names); i++) {
1282  if (innobase_strcasecmp(name, reserved_names[i]) == 0) {
1283 
1284  return(TRUE);
1285  }
1286  }
1287 
1288  return(FALSE);
1289 }
1290 
1291 /****************************************************************/
1295 static
1296 ibool
1297 dict_index_too_big_for_undo(
1298 /*========================*/
1299  const dict_table_t* table,
1300  const dict_index_t* new_index)
1301 {
1302  /* Make sure that all column prefixes will fit in the undo log record
1303  in trx_undo_page_report_modify() right after trx_undo_page_init(). */
1304 
1305  ulint i;
1306  const dict_index_t* clust_index
1307  = dict_table_get_first_index(table);
1308  ulint undo_page_len
1310  + 2 /* next record pointer */
1311  + 1 /* type_cmpl */
1312  + 11 /* trx->undo_no */ + 11 /* table->id */
1313  + 1 /* rec_get_info_bits() */
1314  + 11 /* DB_TRX_ID */
1315  + 11 /* DB_ROLL_PTR */
1316  + 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
1317  + 2/* pointer to previous undo log record */;
1318 
1319  if (UNIV_UNLIKELY(!clust_index)) {
1320  ut_a(dict_index_is_clust(new_index));
1321  clust_index = new_index;
1322  }
1323 
1324  /* Add the size of the ordering columns in the
1325  clustered index. */
1326  for (i = 0; i < clust_index->n_uniq; i++) {
1327  const dict_col_t* col
1328  = dict_index_get_nth_col(clust_index, i);
1329 
1330  /* Use the maximum output size of
1331  mach_write_compressed(), although the encoded
1332  length should always fit in 2 bytes. */
1333  undo_page_len += 5 + dict_col_get_max_size(col);
1334  }
1335 
1336  /* Add the old values of the columns to be updated.
1337  First, the amount and the numbers of the columns.
1338  These are written by mach_write_compressed() whose
1339  maximum output length is 5 bytes. However, given that
1340  the quantities are below REC_MAX_N_FIELDS (10 bits),
1341  the maximum length is 2 bytes per item. */
1342  undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
1343 
1344  for (i = 0; i < clust_index->n_def; i++) {
1345  const dict_col_t* col
1346  = dict_index_get_nth_col(clust_index, i);
1347  ulint max_size
1348  = dict_col_get_max_size(col);
1349  ulint fixed_size
1351  dict_table_is_comp(table));
1352 
1353  if (fixed_size) {
1354  /* Fixed-size columns are stored locally. */
1355  max_size = fixed_size;
1356  } else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
1357  /* Short columns are stored locally. */
1358  } else if (!col->ord_part) {
1359  /* See if col->ord_part would be set
1360  because of new_index. */
1361  ulint j;
1362 
1363  for (j = 0; j < new_index->n_uniq; j++) {
1365  new_index, j) == col) {
1366 
1367  goto is_ord_part;
1368  }
1369  }
1370 
1371  /* This is not an ordering column in any index.
1372  Thus, it can be stored completely externally. */
1373  max_size = BTR_EXTERN_FIELD_REF_SIZE;
1374  } else {
1375 is_ord_part:
1376  /* This is an ordering column in some index.
1377  A long enough prefix must be written to the
1378  undo log. See trx_undo_page_fetch_ext(). */
1379 
1380  if (max_size > REC_MAX_INDEX_COL_LEN) {
1381  max_size = REC_MAX_INDEX_COL_LEN;
1382  }
1383 
1384  max_size += BTR_EXTERN_FIELD_REF_SIZE;
1385  }
1386 
1387  undo_page_len += 5 + max_size;
1388  }
1389 
1390  return(undo_page_len >= UNIV_PAGE_SIZE);
1391 }
1392 
1393 /****************************************************************/
1397 static
1398 ibool
1399 dict_index_too_big_for_tree(
1400 /*========================*/
1401  const dict_table_t* table,
1402  const dict_index_t* new_index)
1403 {
1404  ulint zip_size;
1405  ulint comp;
1406  ulint i;
1407  /* maximum possible storage size of a record */
1408  ulint rec_max_size;
1409  /* maximum allowed size of a record on a leaf page */
1410  ulint page_rec_max;
1411  /* maximum allowed size of a node pointer record */
1412  ulint page_ptr_max;
1413 
1414  comp = dict_table_is_comp(table);
1415  zip_size = dict_table_zip_size(table);
1416 
1417  if (zip_size && zip_size < UNIV_PAGE_SIZE) {
1418  /* On a compressed page, two records must fit in the
1419  uncompressed page modification log. On compressed
1420  pages with zip_size == UNIV_PAGE_SIZE, this limit will
1421  never be reached. */
1422  ut_ad(comp);
1423  /* The maximum allowed record size is the size of
1424  an empty page, minus a byte for recoding the heap
1425  number in the page modification log. The maximum
1426  allowed node pointer size is half that. */
1427  page_rec_max = page_zip_empty_size(new_index->n_fields,
1428  zip_size) - 1;
1429  page_ptr_max = page_rec_max / 2;
1430  /* On a compressed page, there is a two-byte entry in
1431  the dense page directory for every record. But there
1432  is no record header. */
1433  rec_max_size = 2;
1434  } else {
1435  /* The maximum allowed record size is half a B-tree
1436  page. No additional sparse page directory entry will
1437  be generated for the first few user records. */
1438  page_rec_max = page_get_free_space_of_empty(comp) / 2;
1439  page_ptr_max = page_rec_max;
1440  /* Each record has a header. */
1441  rec_max_size = comp
1442  ? REC_N_NEW_EXTRA_BYTES
1443  : REC_N_OLD_EXTRA_BYTES;
1444  }
1445 
1446  if (comp) {
1447  /* Include the "null" flags in the
1448  maximum possible record size. */
1449  rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
1450  } else {
1451  /* For each column, include a 2-byte offset and a
1452  "null" flag. The 1-byte format is only used in short
1453  records that do not contain externally stored columns.
1454  Such records could never exceed the page limit, even
1455  when using the 2-byte format. */
1456  rec_max_size += 2 * new_index->n_fields;
1457  }
1458 
1459  /* Compute the maximum possible record size. */
1460  for (i = 0; i < new_index->n_fields; i++) {
1461  const dict_field_t* field
1462  = dict_index_get_nth_field(new_index, i);
1463  const dict_col_t* col
1464  = dict_field_get_col(field);
1465  ulint field_max_size;
1466  ulint field_ext_max_size;
1467 
1468  /* In dtuple_convert_big_rec(), variable-length columns
1469  that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
1470  may be chosen for external storage.
1471 
1472  Fixed-length columns, and all columns of secondary
1473  index records are always stored inline. */
1474 
1475  /* Determine the maximum length of the index field.
1476  The field_ext_max_size should be computed as the worst
1477  case in rec_get_converted_size_comp() for
1478  REC_STATUS_ORDINARY records. */
1479 
1480  field_max_size = dict_col_get_fixed_size(col, comp);
1481  if (field_max_size) {
1482  /* dict_index_add_col() should guarantee this */
1483  ut_ad(!field->prefix_len
1484  || field->fixed_len == field->prefix_len);
1485  /* Fixed lengths are not encoded
1486  in ROW_FORMAT=COMPACT. */
1487  field_ext_max_size = 0;
1488  goto add_field_size;
1489  }
1490 
1491  field_max_size = dict_col_get_max_size(col);
1492  field_ext_max_size = field_max_size < 256 ? 1 : 2;
1493 
1494  if (field->prefix_len) {
1495  if (field->prefix_len < field_max_size) {
1496  field_max_size = field->prefix_len;
1497  }
1498  } else if (field_max_size > BTR_EXTERN_FIELD_REF_SIZE * 2
1499  && dict_index_is_clust(new_index)) {
1500 
1501  /* In the worst case, we have a locally stored
1502  column of BTR_EXTERN_FIELD_REF_SIZE * 2 bytes.
1503  The length can be stored in one byte. If the
1504  column were stored externally, the lengths in
1505  the clustered index page would be
1506  BTR_EXTERN_FIELD_REF_SIZE and 2. */
1507  field_max_size = BTR_EXTERN_FIELD_REF_SIZE * 2;
1508  field_ext_max_size = 1;
1509  }
1510 
1511  if (comp) {
1512  /* Add the extra size for ROW_FORMAT=COMPACT.
1513  For ROW_FORMAT=REDUNDANT, these bytes were
1514  added to rec_max_size before this loop. */
1515  rec_max_size += field_ext_max_size;
1516  }
1517 add_field_size:
1518  rec_max_size += field_max_size;
1519 
1520  /* Check the size limit on leaf pages. */
1521  if (UNIV_UNLIKELY(rec_max_size >= page_rec_max)) {
1522 
1523  return(TRUE);
1524  }
1525 
1526  /* Check the size limit on non-leaf pages. Records
1527  stored in non-leaf B-tree pages consist of the unique
1528  columns of the record (the key columns of the B-tree)
1529  and a node pointer field. When we have processed the
1530  unique columns, rec_max_size equals the size of the
1531  node pointer record minus the node pointer column. */
1532  if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
1533  && rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {
1534 
1535  return(TRUE);
1536  }
1537  }
1538 
1539  return(FALSE);
1540 }
1541 
1542 /**********************************************************************/
1545 UNIV_INTERN
1546 ulint
1547 dict_index_add_to_cache(
1548 /*====================*/
1549  dict_table_t* table,
1550  dict_index_t* index,
1552  ulint page_no,
1553  ibool strict)
1556 {
1557  dict_index_t* new_index;
1558  ulint n_ord;
1559  ulint i;
1560 
1561  ut_ad(index);
1562  ut_ad(mutex_own(&(dict_sys->mutex)));
1563  ut_ad(index->n_def == index->n_fields);
1564  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1565 
1566  ut_ad(mem_heap_validate(index->heap));
1567  ut_a(!dict_index_is_clust(index)
1568  || UT_LIST_GET_LEN(table->indexes) == 0);
1569 
1570  if (!dict_index_find_cols(table, index)) {
1571 
1572  dict_mem_index_free(index);
1573  return(DB_CORRUPTION);
1574  }
1575 
1576  /* Build the cache internal representation of the index,
1577  containing also the added system fields */
1578 
1579  if (dict_index_is_clust(index)) {
1580  new_index = dict_index_build_internal_clust(table, index);
1581  } else {
1582  new_index = dict_index_build_internal_non_clust(table, index);
1583  }
1584 
1585  /* Set the n_fields value in new_index to the actual defined
1586  number of fields in the cache internal representation */
1587 
1588  new_index->n_fields = new_index->n_def;
1589 
1590  if (strict && dict_index_too_big_for_tree(table, new_index)) {
1591 too_big:
1592  dict_mem_index_free(new_index);
1593  dict_mem_index_free(index);
1594  return(DB_TOO_BIG_RECORD);
1595  }
1596 
1597  if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1598  n_ord = new_index->n_fields;
1599  } else {
1600  n_ord = new_index->n_uniq;
1601  }
1602 
1603  switch (dict_table_get_format(table)) {
1604  case DICT_TF_FORMAT_51:
1605  /* ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT store
1606  prefixes of externally stored columns locally within
1607  the record. There are no special considerations for
1608  the undo log record size. */
1609  goto undo_size_ok;
1610 
1611  case DICT_TF_FORMAT_ZIP:
1612  /* In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED,
1613  column prefix indexes require that prefixes of
1614  externally stored columns are written to the undo log.
1615  This may make the undo log record bigger than the
1616  record on the B-tree page. The maximum size of an
1617  undo log record is the page size. That must be
1618  checked for below. */
1619  break;
1620 
1621 #if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
1622 # error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
1623 #endif
1624  }
1625 
1626  for (i = 0; i < n_ord; i++) {
1627  const dict_field_t* field
1628  = dict_index_get_nth_field(new_index, i);
1629  const dict_col_t* col
1630  = dict_field_get_col(field);
1631 
1632  /* In dtuple_convert_big_rec(), variable-length columns
1633  that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
1634  may be chosen for external storage. If the column appears
1635  in an ordering column of an index, a longer prefix of
1636  REC_MAX_INDEX_COL_LEN will be copied to the undo log
1637  by trx_undo_page_report_modify() and
1638  trx_undo_page_fetch_ext(). It suffices to check the
1639  capacity of the undo log whenever new_index includes
1640  a column prefix on a column that may be stored externally. */
1641 
1642  if (field->prefix_len /* prefix index */
1643  && !col->ord_part /* not yet ordering column */
1644  && !dict_col_get_fixed_size(col, TRUE) /* variable-length */
1645  && dict_col_get_max_size(col)
1646  > BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
1647 
1648  if (dict_index_too_big_for_undo(table, new_index)) {
1649  /* An undo log record might not fit in
1650  a single page. Refuse to create this index. */
1651 
1652  goto too_big;
1653  }
1654 
1655  break;
1656  }
1657  }
1658 
1659 undo_size_ok:
1660  /* Flag the ordering columns */
1661 
1662  for (i = 0; i < n_ord; i++) {
1663 
1664  dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
1665  }
1666 
1667  /* Add the new index as the last index for the table */
1668 
1669  UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
1670  new_index->table = table;
1671  new_index->table_name = table->name;
1672 
1673  new_index->search_info = btr_search_info_create(new_index->heap);
1674 
1675  new_index->stat_index_size = 1;
1676  new_index->stat_n_leaf_pages = 1;
1677 
1678  new_index->page = page_no;
1679  rw_lock_create(index_tree_rw_lock_key, &new_index->lock,
1680  SYNC_INDEX_TREE);
1681 
1682  if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
1683 
1684  new_index->stat_n_diff_key_vals = static_cast<ib_int64_t *>(mem_heap_alloc(
1685  new_index->heap,
1686  (1 + dict_index_get_n_unique(new_index))
1687  * sizeof(ib_int64_t)));
1688  /* Give some sensible values to stat_n_... in case we do
1689  not calculate statistics quickly enough */
1690 
1691  for (i = 0; i <= dict_index_get_n_unique(new_index); i++) {
1692 
1693  new_index->stat_n_diff_key_vals[i] = 100;
1694  }
1695  }
1696 
1697  dict_sys->size += mem_heap_get_size(new_index->heap);
1698 
1699  dict_mem_index_free(index);
1700 
1701  return(DB_SUCCESS);
1702 }
1703 
1704 /**********************************************************************/
1706 UNIV_INTERN
1707 void
1708 dict_index_remove_from_cache(
1709 /*=========================*/
1710  dict_table_t* table,
1711  dict_index_t* index)
1712 {
1713  ulint size;
1714  ulint retries = 0;
1715  btr_search_t* info;
1716 
1717  ut_ad(table && index);
1718  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1719  ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1720  ut_ad(mutex_own(&(dict_sys->mutex)));
1721 
1722  /* We always create search info whether or not adaptive
1723  hash index is enabled or not. */
1724  info = index->search_info;
1725  ut_ad(info);
1726 
1727  /* We are not allowed to free the in-memory index struct
1728  dict_index_t until all entries in the adaptive hash index
1729  that point to any of the page belonging to his b-tree index
1730  are dropped. This is so because dropping of these entries
1731  require access to dict_index_t struct. To avoid such scenario
1732  We keep a count of number of such pages in the search_info and
1733  only free the dict_index_t struct when this count drops to
1734  zero. */
1735 
1736  for (;;) {
1737  ulint ref_count = btr_search_info_get_ref_count(info);
1738  if (ref_count == 0) {
1739  break;
1740  }
1741 
1742  /* Sleep for 10ms before trying again. */
1743  os_thread_sleep(10000);
1744  ++retries;
1745 
1746  if (retries % 500 == 0) {
1747  /* No luck after 5 seconds of wait. */
1748  fprintf(stderr, "InnoDB: Error: Waited for"
1749  " %lu secs for hash index"
1750  " ref_count (%lu) to drop"
1751  " to 0.\n"
1752  "index: \"%s\""
1753  " table: \"%s\"\n",
1754  retries/100,
1755  ref_count,
1756  index->name,
1757  table->name);
1758  }
1759 
1760  /* To avoid a hang here we commit suicide if the
1761  ref_count doesn't drop to zero in 600 seconds. */
1762  if (retries >= 60000) {
1763  ut_error;
1764  }
1765  }
1766 
1767  rw_lock_free(&index->lock);
1768 
1769  /* Remove the index from the list of indexes of the table */
1770  UT_LIST_REMOVE(indexes, table->indexes, index);
1771 
1772  size = mem_heap_get_size(index->heap);
1773 
1774  ut_ad(dict_sys->size >= size);
1775 
1776  dict_sys->size -= size;
1777 
1778  dict_mem_index_free(index);
1779 }
1780 
1781 /*******************************************************************/
1785 static
1786 ibool
1787 dict_index_find_cols(
1788 /*=================*/
1789  dict_table_t* table,
1790  dict_index_t* index)
1791 {
1792  ulint i;
1793 
1794  ut_ad(table && index);
1795  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1796  ut_ad(mutex_own(&(dict_sys->mutex)));
1797 
1798  for (i = 0; i < index->n_fields; i++) {
1799  ulint j;
1800  dict_field_t* field = dict_index_get_nth_field(index, i);
1801 
1802  for (j = 0; j < table->n_cols; j++) {
1803  if (!strcmp(dict_table_get_col_name(table, j),
1804  field->name)) {
1805  field->col = dict_table_get_nth_col(table, j);
1806 
1807  goto found;
1808  }
1809  }
1810 
1811 #ifdef UNIV_DEBUG
1812  /* It is an error not to find a matching column. */
1813  fputs("InnoDB: Error: no matching column for ", stderr);
1814  ut_print_name(stderr, NULL, FALSE, field->name);
1815  fputs(" in ", stderr);
1816  dict_index_name_print(stderr, NULL, index);
1817  fputs("!\n", stderr);
1818 #endif /* UNIV_DEBUG */
1819  return(FALSE);
1820 
1821 found:
1822  ;
1823  }
1824 
1825  return(TRUE);
1826 }
1827 #endif /* !UNIV_HOTBACKUP */
1828 
1829 /*******************************************************************/
1831 UNIV_INTERN
1832 void
1833 dict_index_add_col(
1834 /*===============*/
1835  dict_index_t* index,
1836  const dict_table_t* table,
1837  dict_col_t* col,
1838  ulint prefix_len)
1839 {
1840  dict_field_t* field;
1841  const char* col_name;
1842 
1843  col_name = dict_table_get_col_name(table, dict_col_get_no(col));
1844 
1845  dict_mem_index_add_field(index, col_name, prefix_len);
1846 
1847  field = dict_index_get_nth_field(index, index->n_def - 1);
1848 
1849  field->col = col;
1850  field->fixed_len = (unsigned int) dict_col_get_fixed_size(
1851  col, dict_table_is_comp(table));
1852 
1853  if (prefix_len && field->fixed_len > prefix_len) {
1854  field->fixed_len = (unsigned int) prefix_len;
1855  }
1856 
1857  /* Long fixed-length fields that need external storage are treated as
1858  variable-length fields, so that the extern flag can be embedded in
1859  the length word. */
1860 
1861  if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
1862  field->fixed_len = 0;
1863  }
1864 #if DICT_MAX_INDEX_COL_LEN != 1024
1865  /* The comparison limit above must be constant. If it were
1866  changed, the disk format of some fixed-length columns would
1867  change, which would be a disaster. */
1868 # error "DICT_MAX_INDEX_COL_LEN != 1024"
1869 #endif
1870 
1871  if (!(col->prtype & DATA_NOT_NULL)) {
1872  index->n_nullable++;
1873  }
1874 }
1875 
1876 #ifndef UNIV_HOTBACKUP
1877 /*******************************************************************/
1879 static
1880 void
1881 dict_index_copy(
1882 /*============*/
1883  dict_index_t* index1,
1884  dict_index_t* index2,
1885  const dict_table_t* table,
1886  ulint start,
1887  ulint end)
1888 {
1889  dict_field_t* field;
1890  ulint i;
1891 
1892  /* Copy fields contained in index2 */
1893 
1894  for (i = start; i < end; i++) {
1895 
1896  field = dict_index_get_nth_field(index2, i);
1897  dict_index_add_col(index1, table, field->col,
1898  field->prefix_len);
1899  }
1900 }
1901 
1902 /*******************************************************************/
1904 UNIV_INTERN
1905 void
1906 dict_index_copy_types(
1907 /*==================*/
1908  dtuple_t* tuple,
1909  const dict_index_t* index,
1910  ulint n_fields)
1912 {
1913  ulint i;
1914 
1915  if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1916  dtuple_set_types_binary(tuple, n_fields);
1917 
1918  return;
1919  }
1920 
1921  for (i = 0; i < n_fields; i++) {
1922  const dict_field_t* ifield;
1923  dtype_t* dfield_type;
1924 
1925  ifield = dict_index_get_nth_field(index, i);
1926  dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
1927  dict_col_copy_type(dict_field_get_col(ifield), dfield_type);
1928  }
1929 }
1930 
1931 /*******************************************************************/
1935 UNIV_INTERN
1936 void
1937 dict_table_copy_types(
1938 /*==================*/
1939  dtuple_t* tuple,
1940  const dict_table_t* table)
1941 {
1942  ulint i;
1943 
1944  for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
1945 
1946  dfield_t* dfield = dtuple_get_nth_field(tuple, i);
1947  dtype_t* dtype = dfield_get_type(dfield);
1948 
1949  dfield_set_null(dfield);
1950  dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
1951  }
1952 }
1953 
1954 /*******************************************************************/
1958 static
1959 dict_index_t*
1960 dict_index_build_internal_clust(
1961 /*============================*/
1962  const dict_table_t* table,
1963  dict_index_t* index)
1965 {
1966  dict_index_t* new_index;
1967  dict_field_t* field;
1968  ulint fixed_size;
1969  ulint trx_id_pos;
1970  ulint i;
1971  ibool* indexed;
1972 
1973  ut_ad(table && index);
1974  ut_ad(dict_index_is_clust(index));
1975  ut_ad(mutex_own(&(dict_sys->mutex)));
1976  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1977 
1978  /* Create a new index object with certainly enough fields */
1979  new_index = dict_mem_index_create(table->name,
1980  index->name, table->space,
1981  index->type,
1982  index->n_fields + table->n_cols);
1983 
1984  /* Copy other relevant data from the old index struct to the new
1985  struct: it inherits the values */
1986 
1987  new_index->n_user_defined_cols = index->n_fields;
1988 
1989  new_index->id = index->id;
1990 
1991  /* Copy the fields of index */
1992  dict_index_copy(new_index, index, table, 0, index->n_fields);
1993 
1994  if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
1995  /* No fixed number of fields determines an entry uniquely */
1996 
1997  new_index->n_uniq = REC_MAX_N_FIELDS;
1998 
1999  } else if (dict_index_is_unique(index)) {
2000  /* Only the fields defined so far are needed to identify
2001  the index entry uniquely */
2002 
2003  new_index->n_uniq = new_index->n_def;
2004  } else {
2005  /* Also the row id is needed to identify the entry */
2006  new_index->n_uniq = 1 + new_index->n_def;
2007  }
2008 
2009  new_index->trx_id_offset = 0;
2010 
2011  if (!dict_index_is_ibuf(index)) {
2012  /* Add system columns, trx id first */
2013 
2014  trx_id_pos = new_index->n_def;
2015 
2016 #if DATA_ROW_ID != 0
2017 # error "DATA_ROW_ID != 0"
2018 #endif
2019 #if DATA_TRX_ID != 1
2020 # error "DATA_TRX_ID != 1"
2021 #endif
2022 #if DATA_ROLL_PTR != 2
2023 # error "DATA_ROLL_PTR != 2"
2024 #endif
2025 
2026  if (!dict_index_is_unique(index)) {
2027  dict_index_add_col(new_index, table,
2028  dict_table_get_sys_col(
2029  table, DATA_ROW_ID),
2030  0);
2031  trx_id_pos++;
2032  }
2033 
2034  dict_index_add_col(new_index, table,
2035  dict_table_get_sys_col(table, DATA_TRX_ID),
2036  0);
2037 
2038  dict_index_add_col(new_index, table,
2039  dict_table_get_sys_col(table,
2040  DATA_ROLL_PTR),
2041  0);
2042 
2043  for (i = 0; i < trx_id_pos; i++) {
2044 
2045  fixed_size = dict_col_get_fixed_size(
2046  dict_index_get_nth_col(new_index, i),
2047  dict_table_is_comp(table));
2048 
2049  if (fixed_size == 0) {
2050  new_index->trx_id_offset = 0;
2051 
2052  break;
2053  }
2054 
2055  if (dict_index_get_nth_field(new_index, i)->prefix_len
2056  > 0) {
2057  new_index->trx_id_offset = 0;
2058 
2059  break;
2060  }
2061 
2062  new_index->trx_id_offset += (unsigned int) fixed_size;
2063  }
2064 
2065  }
2066 
2067  /* Remember the table columns already contained in new_index */
2068  void *indexed_ptr= mem_zalloc(table->n_cols * sizeof *indexed);
2069  indexed = static_cast<unsigned long *>(indexed_ptr);
2070 
2071  /* Mark the table columns already contained in new_index */
2072  for (i = 0; i < new_index->n_def; i++) {
2073 
2074  field = dict_index_get_nth_field(new_index, i);
2075 
2076  /* If there is only a prefix of the column in the index
2077  field, do not mark the column as contained in the index */
2078 
2079  if (field->prefix_len == 0) {
2080 
2081  indexed[field->col->ind] = TRUE;
2082  }
2083  }
2084 
2085  /* Add to new_index non-system columns of table not yet included
2086  there */
2087  for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
2088 
2089  dict_col_t* col = dict_table_get_nth_col(table, i);
2090  ut_ad(col->mtype != DATA_SYS);
2091 
2092  if (!indexed[col->ind]) {
2093  dict_index_add_col(new_index, table, col, 0);
2094  }
2095  }
2096 
2097  mem_free(indexed);
2098 
2099  ut_ad(dict_index_is_ibuf(index)
2100  || (UT_LIST_GET_LEN(table->indexes) == 0));
2101 
2102  new_index->cached = TRUE;
2103 
2104  return(new_index);
2105 }
2106 
2107 /*******************************************************************/
2111 static
2112 dict_index_t*
2113 dict_index_build_internal_non_clust(
2114 /*================================*/
2115  const dict_table_t* table,
2116  dict_index_t* index)
2118 {
2119  dict_field_t* field;
2120  dict_index_t* new_index;
2121  dict_index_t* clust_index;
2122  ulint i;
2123  ibool* indexed;
2124 
2125  ut_ad(table && index);
2126  ut_ad(!dict_index_is_clust(index));
2127  ut_ad(mutex_own(&(dict_sys->mutex)));
2128  ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
2129 
2130  /* The clustered index should be the first in the list of indexes */
2131  clust_index = UT_LIST_GET_FIRST(table->indexes);
2132 
2133  ut_ad(clust_index);
2134  ut_ad(dict_index_is_clust(clust_index));
2135  ut_ad(!(clust_index->type & DICT_UNIVERSAL));
2136 
2137  /* Create a new index */
2138  new_index = dict_mem_index_create(
2139  table->name, index->name, index->space, index->type,
2140  index->n_fields + 1 + clust_index->n_uniq);
2141 
2142  /* Copy other relevant data from the old index
2143  struct to the new struct: it inherits the values */
2144 
2145  new_index->n_user_defined_cols = index->n_fields;
2146 
2147  new_index->id = index->id;
2148 
2149  /* Copy fields from index to new_index */
2150  dict_index_copy(new_index, index, table, 0, index->n_fields);
2151 
2152  /* Remember the table columns already contained in new_index */
2153  void *indexed_ptr= mem_zalloc(table->n_cols * sizeof *indexed);
2154  indexed = static_cast<unsigned long *>(indexed_ptr);
2155 
2156  /* Mark the table columns already contained in new_index */
2157  for (i = 0; i < new_index->n_def; i++) {
2158 
2159  field = dict_index_get_nth_field(new_index, i);
2160 
2161  /* If there is only a prefix of the column in the index
2162  field, do not mark the column as contained in the index */
2163 
2164  if (field->prefix_len == 0) {
2165 
2166  indexed[field->col->ind] = TRUE;
2167  }
2168  }
2169 
2170  /* Add to new_index the columns necessary to determine the clustered
2171  index entry uniquely */
2172 
2173  for (i = 0; i < clust_index->n_uniq; i++) {
2174 
2175  field = dict_index_get_nth_field(clust_index, i);
2176 
2177  if (!indexed[field->col->ind]) {
2178  dict_index_add_col(new_index, table, field->col,
2179  field->prefix_len);
2180  }
2181  }
2182 
2183  mem_free(indexed);
2184 
2185  if (dict_index_is_unique(index)) {
2186  new_index->n_uniq = index->n_fields;
2187  } else {
2188  new_index->n_uniq = new_index->n_def;
2189  }
2190 
2191  /* Set the n_fields value in new_index to the actual defined
2192  number of fields */
2193 
2194  new_index->n_fields = new_index->n_def;
2195 
2196  new_index->cached = TRUE;
2197 
2198  return(new_index);
2199 }
2200 
2201 /*====================== FOREIGN KEY PROCESSING ========================*/
2202 
2203 /*********************************************************************/
2206 UNIV_INTERN
2207 ibool
2208 dict_table_is_referenced_by_foreign_key(
2209 /*====================================*/
2210  const dict_table_t* table)
2211 {
2212  return(UT_LIST_GET_LEN(table->referenced_list) > 0);
2213 }
2214 
2215 /*********************************************************************/
2220 UNIV_INTERN
2222 dict_table_get_referenced_constraint(
2223 /*=================================*/
2224  dict_table_t* table,
2225  dict_index_t* index)
2226 {
2227  dict_foreign_t* foreign;
2228 
2229  ut_ad(index != NULL);
2230  ut_ad(table != NULL);
2231 
2232  for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
2233  foreign;
2234  foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
2235 
2236  if (foreign->referenced_index == index) {
2237 
2238  return(foreign);
2239  }
2240  }
2241 
2242  return(NULL);
2243 }
2244 
2245 /*********************************************************************/
2251 UNIV_INTERN
2253 dict_table_get_foreign_constraint(
2254 /*==============================*/
2255  dict_table_t* table,
2256  dict_index_t* index)
2257 {
2258  dict_foreign_t* foreign;
2259 
2260  ut_ad(index != NULL);
2261  ut_ad(table != NULL);
2262 
2263  for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
2264  foreign;
2265  foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
2266 
2267  if (foreign->foreign_index == index
2268  || foreign->referenced_index == index) {
2269 
2270  return(foreign);
2271  }
2272  }
2273 
2274  return(NULL);
2275 }
2276 
2277 /*********************************************************************/
2279 static
2280 void
2281 dict_foreign_free(
2282 /*==============*/
2283  dict_foreign_t* foreign)
2284 {
2285  mem_heap_free(foreign->heap);
2286 }
2287 
2288 /**********************************************************************/
2290 static
2291 void
2292 dict_foreign_remove_from_cache(
2293 /*===========================*/
2294  dict_foreign_t* foreign)
2295 {
2296  ut_ad(mutex_own(&(dict_sys->mutex)));
2297  ut_a(foreign);
2298 
2299  if (foreign->referenced_table) {
2300  UT_LIST_REMOVE(referenced_list,
2302  foreign);
2303  }
2304 
2305  if (foreign->foreign_table) {
2306  UT_LIST_REMOVE(foreign_list,
2307  foreign->foreign_table->foreign_list,
2308  foreign);
2309  }
2310 
2311  dict_foreign_free(foreign);
2312 }
2313 
2314 /**********************************************************************/
2318 static
2320 dict_foreign_find(
2321 /*==============*/
2322  dict_table_t* table,
2323  const char* id)
2324 {
2325  dict_foreign_t* foreign;
2326 
2327  ut_ad(mutex_own(&(dict_sys->mutex)));
2328 
2329  foreign = UT_LIST_GET_FIRST(table->foreign_list);
2330 
2331  while (foreign) {
2332  if (ut_strcmp(id, foreign->id) == 0) {
2333 
2334  return(foreign);
2335  }
2336 
2337  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
2338  }
2339 
2340  foreign = UT_LIST_GET_FIRST(table->referenced_list);
2341 
2342  while (foreign) {
2343  if (ut_strcmp(id, foreign->id) == 0) {
2344 
2345  return(foreign);
2346  }
2347 
2348  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2349  }
2350 
2351  return(NULL);
2352 }
2353 
2354 /*********************************************************************/
2359 static
2360 dict_index_t*
2361 dict_foreign_find_index(
2362 /*====================*/
2363  dict_table_t* table,
2364  const char** columns,
2365  ulint n_cols,
2366  dict_index_t* types_idx,
2368  ibool check_charsets,
2371  ulint check_null)
2374 {
2375  dict_index_t* index;
2376 
2377  index = dict_table_get_first_index(table);
2378 
2379  while (index != NULL) {
2380  /* Ignore matches that refer to the same instance
2381  or the index is to be dropped */
2382  if (index->to_be_dropped || types_idx == index) {
2383 
2384  goto next_rec;
2385 
2386  } else if (dict_index_get_n_fields(index) >= n_cols) {
2387  ulint i;
2388 
2389  for (i = 0; i < n_cols; i++) {
2390  dict_field_t* field;
2391  const char* col_name;
2392 
2393  field = dict_index_get_nth_field(index, i);
2394 
2395  col_name = dict_table_get_col_name(
2396  table, dict_col_get_no(field->col));
2397 
2398  if (field->prefix_len != 0) {
2399  /* We do not accept column prefix
2400  indexes here */
2401 
2402  break;
2403  }
2404 
2405  if (0 != innobase_strcasecmp(columns[i],
2406  col_name)) {
2407  break;
2408  }
2409 
2410  if (check_null
2411  && (field->col->prtype & DATA_NOT_NULL)) {
2412 
2413  return(NULL);
2414  }
2415 
2416  if (types_idx && !cmp_cols_are_equal(
2417  dict_index_get_nth_col(index, i),
2418  dict_index_get_nth_col(types_idx,
2419  i),
2420  check_charsets)) {
2421 
2422  break;
2423  }
2424  }
2425 
2426  if (i == n_cols) {
2427  /* We found a matching index */
2428 
2429  return(index);
2430  }
2431  }
2432 
2433 next_rec:
2434  index = dict_table_get_next_index(index);
2435  }
2436 
2437  return(NULL);
2438 }
2439 
2440 /**********************************************************************/
2444 UNIV_INTERN
2445 dict_index_t*
2446 dict_foreign_find_equiv_index(
2447 /*==========================*/
2448  dict_foreign_t* foreign)
2449 {
2450  ut_a(foreign != NULL);
2451 
2452  /* Try to find an index which contains the columns as the
2453  first fields and in the right order, and the types are the
2454  same as in foreign->foreign_index */
2455 
2456  return(dict_foreign_find_index(
2457  foreign->foreign_table,
2458  foreign->foreign_col_names, foreign->n_fields,
2459  foreign->foreign_index, TRUE, /* check types */
2460  FALSE/* allow columns to be NULL */));
2461 }
2462 
2463 /**********************************************************************/
2467 UNIV_INTERN
2468 dict_index_t*
2469 dict_table_get_index_by_max_id(
2470 /*===========================*/
2471  dict_table_t* table,
2472  const char* name,
2473  const char** columns,
2474  ulint n_cols)
2475 {
2476  dict_index_t* index;
2477  dict_index_t* found;
2478 
2479  found = NULL;
2480  index = dict_table_get_first_index(table);
2481 
2482  while (index != NULL) {
2483  if (ut_strcmp(index->name, name) == 0
2485  == n_cols) {
2486 
2487  ulint i;
2488 
2489  for (i = 0; i < n_cols; i++) {
2490  dict_field_t* field;
2491  const char* col_name;
2492 
2493  field = dict_index_get_nth_field(index, i);
2494 
2495  col_name = dict_table_get_col_name(
2496  table, dict_col_get_no(field->col));
2497 
2498  if (0 != innobase_strcasecmp(
2499  columns[i], col_name)) {
2500 
2501  break;
2502  }
2503  }
2504 
2505  if (i == n_cols) {
2506  /* We found a matching index, select
2507  the index with the higher id*/
2508 
2509  if (!found || index->id > found->id) {
2510 
2511  found = index;
2512  }
2513  }
2514  }
2515 
2516  index = dict_table_get_next_index(index);
2517  }
2518 
2519  return(found);
2520 }
2521 
2522 /**********************************************************************/
2524 static
2525 void
2526 dict_foreign_error_report_low(
2527 /*==========================*/
2528  FILE* file,
2529  const char* name)
2530 {
2531  rewind(file);
2532  ut_print_timestamp(file);
2533  fprintf(file, " Error in foreign key constraint of table %s:\n",
2534  name);
2535 }
2536 
2537 /**********************************************************************/
2539 static
2540 void
2541 dict_foreign_error_report(
2542 /*======================*/
2543  FILE* file,
2544  dict_foreign_t* fk,
2545  const char* msg)
2546 {
2547  mutex_enter(&dict_foreign_err_mutex);
2548  dict_foreign_error_report_low(file, fk->foreign_table_name);
2549  fputs(msg, file);
2550  fputs(" Constraint:\n", file);
2551  dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
2552  putc('\n', file);
2553  if (fk->foreign_index) {
2554  fputs("The index in the foreign key in table is ", file);
2555  ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
2556  fputs("\n"
2557  "See " REFMAN "innodb-foreign-key-constraints.html\n"
2558  "for correct foreign key definition.\n",
2559  file);
2560  }
2561  mutex_exit(&dict_foreign_err_mutex);
2562 }
2563 
2564 /**********************************************************************/
2570 UNIV_INTERN
2571 ulint
2572 dict_foreign_add_to_cache(
2573 /*======================*/
2574  dict_foreign_t* foreign,
2575  ibool check_charsets)
2577 {
2578  dict_table_t* for_table;
2579  dict_table_t* ref_table;
2580  dict_foreign_t* for_in_cache = NULL;
2581  dict_index_t* index;
2582  ibool added_to_referenced_list= FALSE;
2583  FILE* ef = dict_foreign_err_file;
2584 
2585  ut_ad(mutex_own(&(dict_sys->mutex)));
2586 
2588  foreign->foreign_table_name);
2589 
2591  foreign->referenced_table_name);
2592  ut_a(for_table || ref_table);
2593 
2594  if (for_table) {
2595  for_in_cache = dict_foreign_find(for_table, foreign->id);
2596  }
2597 
2598  if (!for_in_cache && ref_table) {
2599  for_in_cache = dict_foreign_find(ref_table, foreign->id);
2600  }
2601 
2602  if (for_in_cache) {
2603  /* Free the foreign object */
2604  mem_heap_free(foreign->heap);
2605  } else {
2606  for_in_cache = foreign;
2607  }
2608 
2609  if (for_in_cache->referenced_table == NULL && ref_table) {
2610  index = dict_foreign_find_index(
2611  ref_table,
2612  for_in_cache->referenced_col_names,
2613  for_in_cache->n_fields, for_in_cache->foreign_index,
2614  check_charsets, FALSE);
2615 
2616  if (index == NULL) {
2617  dict_foreign_error_report(
2618  ef, for_in_cache,
2619  "there is no index in referenced table"
2620  " which would contain\n"
2621  "the columns as the first columns,"
2622  " or the data types in the\n"
2623  "referenced table do not match"
2624  " the ones in table.");
2625 
2626  if (for_in_cache == foreign) {
2627  mem_heap_free(foreign->heap);
2628  }
2629 
2630  return(DB_CANNOT_ADD_CONSTRAINT);
2631  }
2632 
2633  for_in_cache->referenced_table = ref_table;
2634  for_in_cache->referenced_index = index;
2635  UT_LIST_ADD_LAST(referenced_list,
2636  ref_table->referenced_list,
2637  for_in_cache);
2638  added_to_referenced_list = TRUE;
2639  }
2640 
2641  if (for_in_cache->foreign_table == NULL && for_table) {
2642  index = dict_foreign_find_index(
2643  for_table,
2644  for_in_cache->foreign_col_names,
2645  for_in_cache->n_fields,
2646  for_in_cache->referenced_index, check_charsets,
2647  for_in_cache->type
2650 
2651  if (index == NULL) {
2652  dict_foreign_error_report(
2653  ef, for_in_cache,
2654  "there is no index in the table"
2655  " which would contain\n"
2656  "the columns as the first columns,"
2657  " or the data types in the\n"
2658  "table do not match"
2659  " the ones in the referenced table\n"
2660  "or one of the ON ... SET NULL columns"
2661  " is declared NOT NULL.");
2662 
2663  if (for_in_cache == foreign) {
2664  if (added_to_referenced_list) {
2666  referenced_list,
2667  ref_table->referenced_list,
2668  for_in_cache);
2669  }
2670 
2671  mem_heap_free(foreign->heap);
2672  }
2673 
2674  return(DB_CANNOT_ADD_CONSTRAINT);
2675  }
2676 
2677  for_in_cache->foreign_table = for_table;
2678  for_in_cache->foreign_index = index;
2679  UT_LIST_ADD_LAST(foreign_list,
2680  for_table->foreign_list,
2681  for_in_cache);
2682  }
2683 
2684  return(DB_SUCCESS);
2685 }
2686 
2687 /*********************************************************************/
2692 static
2693 const char*
2694 dict_scan_to(
2695 /*=========*/
2696  const char* ptr,
2697  const char* string)
2698 {
2699  char quote = '\0';
2700 
2701  for (; *ptr; ptr++) {
2702  if (*ptr == quote) {
2703  /* Closing quote character: do not look for
2704  starting quote or the keyword. */
2705  quote = '\0';
2706  } else if (quote) {
2707  /* Within quotes: do nothing. */
2708  } else if (*ptr == '`' || *ptr == '"') {
2709  /* Starting quote: remember the quote character. */
2710  quote = *ptr;
2711  } else {
2712  /* Outside quotes: look for the keyword. */
2713  ulint i;
2714  for (i = 0; string[i]; i++) {
2715  if (toupper((int)(unsigned char)(ptr[i]))
2716  != toupper((int)(unsigned char)
2717  (string[i]))) {
2718  goto nomatch;
2719  }
2720  }
2721  break;
2722 nomatch:
2723  ;
2724  }
2725  }
2726 
2727  return(ptr);
2728 }
2729 
2730 /*********************************************************************/
2734 static
2735 const char*
2736 dict_accept(
2737 /*========*/
2738  const void* cs,
2739  const char* ptr,
2740  const char* string,
2742  ibool* success)
2743 {
2744  const char* old_ptr = ptr;
2745  const char* old_ptr2;
2746 
2747  *success = FALSE;
2748 
2749  while (innobase_isspace(cs, *ptr)) {
2750  ptr++;
2751  }
2752 
2753  old_ptr2 = ptr;
2754 
2755  ptr = dict_scan_to(ptr, string);
2756 
2757  if (*ptr == '\0' || old_ptr2 != ptr) {
2758  return(old_ptr);
2759  }
2760 
2761  *success = TRUE;
2762 
2763  return(ptr + ut_strlen(string));
2764 }
2765 
2766 /*********************************************************************/
2770 static
2771 const char*
2772 dict_scan_id(
2773 /*=========*/
2774  const void* cs,
2775  const char* ptr,
2776  mem_heap_t* heap,
2779  const char** id,
2781  ibool table_id,
2783  ibool accept_also_dot)
2787 {
2788  char quote = '\0';
2789  ulint len = 0;
2790  const char* s;
2791  char* str;
2792  char* dst;
2793 
2794  *id = NULL;
2795 
2796  while (innobase_isspace(cs, *ptr)) {
2797  ptr++;
2798  }
2799 
2800  if (*ptr == '\0') {
2801 
2802  return(ptr);
2803  }
2804 
2805  if (*ptr == '`' || *ptr == '"') {
2806  quote = *ptr++;
2807  }
2808 
2809  s = ptr;
2810 
2811  if (quote) {
2812  for (;;) {
2813  if (!*ptr) {
2814  /* Syntax error */
2815  return(ptr);
2816  }
2817  if (*ptr == quote) {
2818  ptr++;
2819  if (*ptr != quote) {
2820  break;
2821  }
2822  }
2823  ptr++;
2824  len++;
2825  }
2826  } else {
2827  while (!innobase_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
2828  && (accept_also_dot || *ptr != '.')
2829  && *ptr != ',' && *ptr != '\0') {
2830 
2831  ptr++;
2832  }
2833 
2834  len = ptr - s;
2835  }
2836 
2837  if (UNIV_UNLIKELY(!heap)) {
2838  /* no heap given: id will point to source string */
2839  *id = s;
2840  return(ptr);
2841  }
2842 
2843  if (quote) {
2844  char* d;
2845  str = d = static_cast<char *>(mem_heap_alloc(heap, len + 1));
2846  while (len--) {
2847  if ((*d++ = *s++) == quote) {
2848  s++;
2849  }
2850  }
2851  *d++ = 0;
2852  len = d - str;
2853  ut_ad(*s == quote);
2854  ut_ad(s + 1 == ptr);
2855  } else {
2856  str = mem_heap_strdupl(heap, s, len);
2857  }
2858 
2859  if (!table_id) {
2860 convert_id:
2861  /* Convert the identifier from connection character set
2862  to UTF-8. */
2863  len = 3 * len + 1;
2864  *id = dst = static_cast<char *>(mem_heap_alloc(heap, len));
2865 
2866  innobase_convert_from_id(cs, dst, str, len);
2867  } else if (!strncmp(str, srv_mysql50_table_name_prefix.c_str(),
2869  /* This is a pre-5.1 table name
2870  containing chars other than [A-Za-z0-9].
2871  Discard the prefix and use raw UTF-8 encoding. */
2872  str += srv_mysql50_table_name_prefix.size();
2873  len -= srv_mysql50_table_name_prefix.size();
2874  goto convert_id;
2875  } else {
2876  /* Encode using filename-safe characters. */
2877  len = 5 * len + 1;
2878  *id = dst = static_cast<char *>(mem_heap_alloc(heap, len));
2879 
2880  innobase_convert_from_table_id(cs, dst, str, len);
2881  }
2882 
2883  return(ptr);
2884 }
2885 
2886 /*********************************************************************/
2889 static
2890 const char*
2891 dict_scan_col(
2892 /*==========*/
2893  const void* cs,
2894  const char* ptr,
2895  ibool* success,
2896  dict_table_t* table,
2897  const dict_col_t** column,
2898  mem_heap_t* heap,
2899  const char** name)
2901 {
2902  ulint i;
2903 
2904  *success = FALSE;
2905 
2906  ptr = dict_scan_id(cs, ptr, heap, name, FALSE, TRUE);
2907 
2908  if (*name == NULL) {
2909 
2910  return(ptr); /* Syntax error */
2911  }
2912 
2913  if (table == NULL) {
2914  *success = TRUE;
2915  *column = NULL;
2916  } else {
2917  for (i = 0; i < dict_table_get_n_cols(table); i++) {
2918 
2919  const char* col_name = dict_table_get_col_name(
2920  table, i);
2921 
2922  if (0 == innobase_strcasecmp(col_name, *name)) {
2923  /* Found */
2924 
2925  *success = TRUE;
2926  *column = dict_table_get_nth_col(table, i);
2927  strcpy((char*) *name, col_name);
2928 
2929  break;
2930  }
2931  }
2932  }
2933 
2934  return(ptr);
2935 }
2936 
2937 /*********************************************************************/
2940 static
2941 const char*
2942 dict_scan_table_name(
2943 /*=================*/
2944  const void* cs,
2945  const char* ptr,
2946  dict_table_t** table,
2947  const char* name,
2948  ibool* success,
2949  mem_heap_t* heap,
2950  const char** ref_name)
2952 {
2953  const char* database_name = NULL;
2954  ulint database_name_len = 0;
2955  const char* table_name = NULL;
2956  ulint table_name_len;
2957  const char* scan_name;
2958  char* ref;
2959 
2960  *success = FALSE;
2961  *table = NULL;
2962 
2963  ptr = dict_scan_id(cs, ptr, heap, &scan_name, TRUE, FALSE);
2964 
2965  if (scan_name == NULL) {
2966 
2967  return(ptr); /* Syntax error */
2968  }
2969 
2970  if (*ptr == '.') {
2971  /* We scanned the database name; scan also the table name */
2972 
2973  ptr++;
2974 
2975  database_name = scan_name;
2976  database_name_len = strlen(database_name);
2977 
2978  ptr = dict_scan_id(cs, ptr, heap, &table_name, TRUE, FALSE);
2979 
2980  if (table_name == NULL) {
2981 
2982  return(ptr); /* Syntax error */
2983  }
2984  } else {
2985  /* To be able to read table dumps made with InnoDB-4.0.17 or
2986  earlier, we must allow the dot separator between the database
2987  name and the table name also to appear within a quoted
2988  identifier! InnoDB used to print a constraint as:
2989  ... REFERENCES `databasename.tablename` ...
2990  starting from 4.0.18 it is
2991  ... REFERENCES `databasename`.`tablename` ... */
2992  const char* s;
2993 
2994  for (s = scan_name; *s; s++) {
2995  if (*s == '.') {
2996  database_name = scan_name;
2997  database_name_len = s - scan_name;
2998  scan_name = ++s;
2999  break;/* to do: multiple dots? */
3000  }
3001  }
3002 
3003  table_name = scan_name;
3004  }
3005 
3006  if (database_name == NULL) {
3007  /* Use the database name of the foreign key table */
3008 
3009  database_name = name;
3010  database_name_len = dict_get_db_name_len(name);
3011  }
3012 
3013  table_name_len = strlen(table_name);
3014 
3015  /* Copy database_name, '/', table_name, '\0' */
3016  ref = static_cast<char *>(mem_heap_alloc(heap, database_name_len + table_name_len + 2));
3017  memcpy(ref, database_name, database_name_len);
3018  ref[database_name_len] = '/';
3019  memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
3020 #ifndef __WIN__
3021  if (srv_lower_case_table_names) {
3022 #endif /* !__WIN__ */
3023  /* The table name is always put to lower case on Windows. */
3024  innobase_casedn_str(ref);
3025 #ifndef __WIN__
3026  }
3027 #endif /* !__WIN__ */
3028 
3029  *success = TRUE;
3030  *ref_name = ref;
3031  *table = dict_table_get_low(ref);
3032 
3033  return(ptr);
3034 }
3035 
3036 /*********************************************************************/
3039 static
3040 const char*
3041 dict_skip_word(
3042 /*===========*/
3043  const void* cs,
3044  const char* ptr,
3045  ibool* success)
3047 {
3048  const char* start;
3049 
3050  *success = FALSE;
3051 
3052  ptr = dict_scan_id(cs, ptr, NULL, &start, FALSE, TRUE);
3053 
3054  if (start) {
3055  *success = TRUE;
3056  }
3057 
3058  return(ptr);
3059 }
3060 
3061 /*********************************************************************/
3069 static
3070 char*
3071 dict_strip_comments(
3072 /*================*/
3073  const char* sql_string,
3074  size_t sql_length)
3075 {
3076  char* str;
3077  const char* sptr;
3078  const char* eptr = sql_string + sql_length;
3079  char* ptr;
3080  /* unclosed quote character (0 if none) */
3081  char quote = 0;
3082 
3083  str = static_cast<char *>(mem_alloc(sql_length + 1));
3084 
3085  sptr = sql_string;
3086  ptr = str;
3087 
3088  for (;;) {
3089 scan_more:
3090  if (sptr >= eptr || *sptr == '\0') {
3091 end_of_string:
3092  *ptr = '\0';
3093 
3094  ut_a(ptr <= str + sql_length);
3095 
3096  return(str);
3097  }
3098 
3099  if (*sptr == quote) {
3100  /* Closing quote character: do not look for
3101  starting quote or comments. */
3102  quote = 0;
3103  } else if (quote) {
3104  /* Within quotes: do not look for
3105  starting quotes or comments. */
3106  } else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
3107  /* Starting quote: remember the quote character. */
3108  quote = *sptr;
3109  } else if (*sptr == '#'
3110  || (sptr[0] == '-' && sptr[1] == '-'
3111  && sptr[2] == ' ')) {
3112  for (;;) {
3113  if (++sptr >= eptr) {
3114  goto end_of_string;
3115  }
3116 
3117  /* In Unix a newline is 0x0A while in Windows
3118  it is 0x0D followed by 0x0A */
3119 
3120  switch (*sptr) {
3121  case (char) 0X0A:
3122  case (char) 0x0D:
3123  case '\0':
3124  goto scan_more;
3125  }
3126  }
3127  } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
3128  sptr += 2;
3129  for (;;) {
3130  if (sptr >= eptr) {
3131  goto end_of_string;
3132  }
3133 
3134  switch (*sptr) {
3135  case '\0':
3136  goto scan_more;
3137  case '*':
3138  if (sptr[1] == '/') {
3139  sptr += 2;
3140  goto scan_more;
3141  }
3142  }
3143 
3144  sptr++;
3145  }
3146  }
3147 
3148  *ptr = *sptr;
3149 
3150  ptr++;
3151  sptr++;
3152  }
3153 }
3154 
3155 /*********************************************************************/
3160 static
3161 ulint
3162 dict_table_get_highest_foreign_id(
3163 /*==============================*/
3164  dict_table_t* table)
3165 {
3166  dict_foreign_t* foreign;
3167  char* endp;
3168  ulint biggest_id = 0;
3169  ulint id;
3170  ulint len;
3171 
3172  ut_a(table);
3173 
3174  len = ut_strlen(table->name);
3175  foreign = UT_LIST_GET_FIRST(table->foreign_list);
3176 
3177  while (foreign) {
3178  if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
3179  && 0 == ut_memcmp(foreign->id, table->name, len)
3180  && 0 == ut_memcmp(foreign->id + len,
3181  dict_ibfk, (sizeof dict_ibfk) - 1)
3182  && foreign->id[len + ((sizeof dict_ibfk) - 1)] != '0') {
3183  /* It is of the >= 4.0.18 format */
3184 
3185  id = strtoul(foreign->id + len
3186  + ((sizeof dict_ibfk) - 1),
3187  &endp, 10);
3188  if (*endp == '\0') {
3189  ut_a(id != biggest_id);
3190 
3191  if (id > biggest_id) {
3192  biggest_id = id;
3193  }
3194  }
3195  }
3196 
3197  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3198  }
3199 
3200  return(biggest_id);
3201 }
3202 
3203 /*********************************************************************/
3205 static
3206 void
3207 dict_foreign_report_syntax_err(
3208 /*===========================*/
3209  const char* name,
3210  const char* start_of_latest_foreign,
3213  const char* ptr)
3214 {
3215  FILE* ef = dict_foreign_err_file;
3216 
3217  mutex_enter(&dict_foreign_err_mutex);
3218  dict_foreign_error_report_low(ef, name);
3219  fprintf(ef, "%s:\nSyntax error close to:\n%s\n",
3220  start_of_latest_foreign, ptr);
3221  mutex_exit(&dict_foreign_err_mutex);
3222 }
3223 
3224 /*********************************************************************/
3231 static
3232 ulint
3233 dict_create_foreign_constraints_low(
3234 /*================================*/
3235  trx_t* trx,
3236  mem_heap_t* heap,
3237  const void* cs,
3238  const char* sql_string,
3245  const char* name,
3247  ibool reject_fks)
3251 {
3252  dict_table_t* table;
3253  dict_table_t* referenced_table;
3254  dict_table_t* table_to_alter;
3255  ulint highest_id_so_far = 0;
3256  dict_index_t* index;
3257  dict_foreign_t* foreign;
3258  const char* ptr = sql_string;
3259  const char* start_of_latest_foreign = sql_string;
3260  FILE* ef = dict_foreign_err_file;
3261  const char* constraint_name;
3262  ibool success;
3263  ulint error;
3264  const char* ptr1;
3265  const char* ptr2;
3266  ulint i;
3267  ulint j;
3268  ibool is_on_delete;
3269  ulint n_on_deletes;
3270  ulint n_on_updates;
3271  const dict_col_t*columns[500];
3272  const char* column_names[500];
3273  const char* referenced_table_name;
3274 
3275  ut_ad(mutex_own(&(dict_sys->mutex)));
3276 
3277  table = dict_table_get_low(name);
3278 
3279  if (table == NULL) {
3280  mutex_enter(&dict_foreign_err_mutex);
3281  dict_foreign_error_report_low(ef, name);
3282  fprintf(ef,
3283  "Cannot find the table in the internal"
3284  " data dictionary of InnoDB.\n"
3285  "Create table statement:\n%s\n", sql_string);
3286  mutex_exit(&dict_foreign_err_mutex);
3287 
3288  return(DB_ERROR);
3289  }
3290 
3291  /* First check if we are actually doing an ALTER TABLE, and in that
3292  case look for the table being altered */
3293 
3294  ptr = dict_accept(cs, ptr, "ALTER", &success);
3295 
3296  if (!success) {
3297 
3298  goto loop;
3299  }
3300 
3301  ptr = dict_accept(cs, ptr, "TABLE", &success);
3302 
3303  if (!success) {
3304 
3305  goto loop;
3306  }
3307 
3308  /* We are doing an ALTER TABLE: scan the table name we are altering */
3309 
3310  ptr = dict_scan_table_name(cs, ptr, &table_to_alter, name,
3311  &success, heap, &referenced_table_name);
3312  if (!success) {
3313  fprintf(stderr,
3314  "InnoDB: Error: could not find"
3315  " the table being ALTERED in:\n%s\n",
3316  sql_string);
3317 
3318  return(DB_ERROR);
3319  }
3320 
3321  /* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
3322  format databasename/tablename_ibfk_[number], where [number] is local
3323  to the table; look for the highest [number] for table_to_alter, so
3324  that we can assign to new constraints higher numbers. */
3325 
3326  /* If we are altering a temporary table, the table name after ALTER
3327  TABLE does not correspond to the internal table name, and
3328  table_to_alter is NULL. TODO: should we fix this somehow? */
3329 
3330  if (table_to_alter == NULL) {
3331  highest_id_so_far = 0;
3332  } else {
3333  highest_id_so_far = dict_table_get_highest_foreign_id(
3334  table_to_alter);
3335  }
3336 
3337  /* Scan for foreign key declarations in a loop */
3338 loop:
3339  /* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
3340 
3341  ptr1 = dict_scan_to(ptr, "CONSTRAINT");
3342  ptr2 = dict_scan_to(ptr, "FOREIGN");
3343 
3344  constraint_name = NULL;
3345 
3346  if (ptr1 < ptr2) {
3347  /* The user may have specified a constraint name. Pick it so
3348  that we can store 'databasename/constraintname' as the id of
3349  of the constraint to system tables. */
3350  ptr = ptr1;
3351 
3352  ptr = dict_accept(cs, ptr, "CONSTRAINT", &success);
3353 
3354  ut_a(success);
3355 
3356  if (!innobase_isspace(cs, *ptr) && *ptr != '"' && *ptr != '`') {
3357  goto loop;
3358  }
3359 
3360  while (innobase_isspace(cs, *ptr)) {
3361  ptr++;
3362  }
3363 
3364  /* read constraint name unless got "CONSTRAINT FOREIGN" */
3365  if (ptr != ptr2) {
3366  ptr = dict_scan_id(cs, ptr, heap,
3367  &constraint_name, FALSE, FALSE);
3368  }
3369  } else {
3370  ptr = ptr2;
3371  }
3372 
3373  if (*ptr == '\0') {
3374  /* The proper way to reject foreign keys for temporary
3375  tables would be to split the lexing and syntactical
3376  analysis of foreign key clauses from the actual adding
3377  of them, so that ha_innodb.cc could first parse the SQL
3378  command, determine if there are any foreign keys, and
3379  if so, immediately reject the command if the table is a
3380  temporary one. For now, this kludge will work. */
3381  if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
3382 
3383  return(DB_CANNOT_ADD_CONSTRAINT);
3384  }
3385 
3386  /**********************************************************/
3387  /* The following call adds the foreign key constraints
3388  to the data dictionary system tables on disk */
3389 
3390  error = dict_create_add_foreigns_to_dictionary(
3391  highest_id_so_far, table, trx);
3392  return(error);
3393  }
3394 
3395  start_of_latest_foreign = ptr;
3396 
3397  ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3398 
3399  if (!success) {
3400  goto loop;
3401  }
3402 
3403  if (!innobase_isspace(cs, *ptr)) {
3404  goto loop;
3405  }
3406 
3407  ptr = dict_accept(cs, ptr, "KEY", &success);
3408 
3409  if (!success) {
3410  goto loop;
3411  }
3412 
3413  ptr = dict_accept(cs, ptr, "(", &success);
3414 
3415  if (!success) {
3416  /* MySQL allows also an index id before the '('; we
3417  skip it */
3418  ptr = dict_skip_word(cs, ptr, &success);
3419 
3420  if (!success) {
3421  dict_foreign_report_syntax_err(
3422  name, start_of_latest_foreign, ptr);
3423 
3424  return(DB_CANNOT_ADD_CONSTRAINT);
3425  }
3426 
3427  ptr = dict_accept(cs, ptr, "(", &success);
3428 
3429  if (!success) {
3430  /* We do not flag a syntax error here because in an
3431  ALTER TABLE we may also have DROP FOREIGN KEY abc */
3432 
3433  goto loop;
3434  }
3435  }
3436 
3437  i = 0;
3438 
3439  /* Scan the columns in the first list */
3440 col_loop1:
3441  ut_a(i < (sizeof column_names) / sizeof *column_names);
3442  ptr = dict_scan_col(cs, ptr, &success, table, columns + i,
3443  heap, column_names + i);
3444  if (!success) {
3445  mutex_enter(&dict_foreign_err_mutex);
3446  dict_foreign_error_report_low(ef, name);
3447  fprintf(ef, "%s:\nCannot resolve column name close to:\n%s\n",
3448  start_of_latest_foreign, ptr);
3449  mutex_exit(&dict_foreign_err_mutex);
3450 
3451  return(DB_CANNOT_ADD_CONSTRAINT);
3452  }
3453 
3454  i++;
3455 
3456  ptr = dict_accept(cs, ptr, ",", &success);
3457 
3458  if (success) {
3459  goto col_loop1;
3460  }
3461 
3462  ptr = dict_accept(cs, ptr, ")", &success);
3463 
3464  if (!success) {
3465  dict_foreign_report_syntax_err(
3466  name, start_of_latest_foreign, ptr);
3467  return(DB_CANNOT_ADD_CONSTRAINT);
3468  }
3469 
3470  /* Try to find an index which contains the columns
3471  as the first fields and in the right order */
3472 
3473  index = dict_foreign_find_index(table, column_names, i,
3474  NULL, TRUE, FALSE);
3475 
3476  if (!index) {
3477  mutex_enter(&dict_foreign_err_mutex);
3478  dict_foreign_error_report_low(ef, name);
3479  fputs("There is no index in table ", ef);
3480  ut_print_name(ef, NULL, TRUE, name);
3481  fprintf(ef, " where the columns appear\n"
3482  "as the first columns. Constraint:\n%s\n"
3483  "See " REFMAN "innodb-foreign-key-constraints.html\n"
3484  "for correct foreign key definition.\n",
3485  start_of_latest_foreign);
3486  mutex_exit(&dict_foreign_err_mutex);
3487 
3488  return(DB_CHILD_NO_INDEX);
3489  }
3490  ptr = dict_accept(cs, ptr, "REFERENCES", &success);
3491 
3492  if (!success || !innobase_isspace(cs, *ptr)) {
3493  dict_foreign_report_syntax_err(
3494  name, start_of_latest_foreign, ptr);
3495  return(DB_CANNOT_ADD_CONSTRAINT);
3496  }
3497 
3498  /* Let us create a constraint struct */
3499 
3500  foreign = dict_mem_foreign_create();
3501 
3502  if (constraint_name) {
3503  ulint db_len;
3504 
3505  /* Catenate 'databasename/' to the constraint name specified
3506  by the user: we conceive the constraint as belonging to the
3507  same MySQL 'database' as the table itself. We store the name
3508  to foreign->id. */
3509 
3510  db_len = dict_get_db_name_len(table->name);
3511 
3512  foreign->id = static_cast<char*>(mem_heap_alloc(
3513  foreign->heap, db_len + strlen(constraint_name) + 2));
3514 
3515  ut_memcpy(foreign->id, table->name, db_len);
3516  foreign->id[db_len] = '/';
3517  strcpy(foreign->id + db_len + 1, constraint_name);
3518  }
3519 
3520  foreign->foreign_table = table;
3521  foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
3522  table->name);
3523  foreign->foreign_index = index;
3524  foreign->n_fields = (unsigned int) i;
3525  foreign->foreign_col_names = static_cast<const char **>(mem_heap_alloc(foreign->heap,
3526  i * sizeof(void*)));
3527  for (i = 0; i < foreign->n_fields; i++) {
3528  foreign->foreign_col_names[i] = mem_heap_strdup(
3529  foreign->heap,
3530  dict_table_get_col_name(table,
3531  dict_col_get_no(columns[i])));
3532  }
3533 
3534  ptr = dict_scan_table_name(cs, ptr, &referenced_table, name,
3535  &success, heap, &referenced_table_name);
3536 
3537  /* Note that referenced_table can be NULL if the user has suppressed
3538  checking of foreign key constraints! */
3539 
3540  if (!success || (!referenced_table && trx->check_foreigns)) {
3541  dict_foreign_free(foreign);
3542 
3543  mutex_enter(&dict_foreign_err_mutex);
3544  dict_foreign_error_report_low(ef, name);
3545  fprintf(ef, "%s:\nCannot resolve table name close to:\n"
3546  "%s\n",
3547  start_of_latest_foreign, ptr);
3548  mutex_exit(&dict_foreign_err_mutex);
3549 
3550  return(DB_CANNOT_ADD_CONSTRAINT);
3551  }
3552 
3553  ptr = dict_accept(cs, ptr, "(", &success);
3554 
3555  if (!success) {
3556  dict_foreign_free(foreign);
3557  dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3558  ptr);
3559  return(DB_CANNOT_ADD_CONSTRAINT);
3560  }
3561 
3562  /* Scan the columns in the second list */
3563  i = 0;
3564 
3565 col_loop2:
3566  ptr = dict_scan_col(cs, ptr, &success, referenced_table, columns + i,
3567  heap, column_names + i);
3568  i++;
3569 
3570  if (!success) {
3571  dict_foreign_free(foreign);
3572 
3573  mutex_enter(&dict_foreign_err_mutex);
3574  dict_foreign_error_report_low(ef, name);
3575  fprintf(ef, "%s:\nCannot resolve column name close to:\n"
3576  "%s\n",
3577  start_of_latest_foreign, ptr);
3578  mutex_exit(&dict_foreign_err_mutex);
3579 
3580  return(DB_CANNOT_ADD_CONSTRAINT);
3581  }
3582 
3583  ptr = dict_accept(cs, ptr, ",", &success);
3584 
3585  if (success) {
3586  goto col_loop2;
3587  }
3588 
3589  ptr = dict_accept(cs, ptr, ")", &success);
3590 
3591  if (!success || foreign->n_fields != i) {
3592  dict_foreign_free(foreign);
3593 
3594  dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3595  ptr);
3596  return(DB_CANNOT_ADD_CONSTRAINT);
3597  }
3598 
3599  n_on_deletes = 0;
3600  n_on_updates = 0;
3601 
3602 scan_on_conditions:
3603  /* Loop here as long as we can find ON ... conditions */
3604 
3605  ptr = dict_accept(cs, ptr, "ON", &success);
3606 
3607  if (!success) {
3608 
3609  goto try_find_index;
3610  }
3611 
3612  ptr = dict_accept(cs, ptr, "DELETE", &success);
3613 
3614  if (!success) {
3615  ptr = dict_accept(cs, ptr, "UPDATE", &success);
3616 
3617  if (!success) {
3618  dict_foreign_free(foreign);
3619 
3620  dict_foreign_report_syntax_err(
3621  name, start_of_latest_foreign, ptr);
3622  return(DB_CANNOT_ADD_CONSTRAINT);
3623  }
3624 
3625  is_on_delete = FALSE;
3626  n_on_updates++;
3627  } else {
3628  is_on_delete = TRUE;
3629  n_on_deletes++;
3630  }
3631 
3632  ptr = dict_accept(cs, ptr, "RESTRICT", &success);
3633 
3634  if (success) {
3635  goto scan_on_conditions;
3636  }
3637 
3638  ptr = dict_accept(cs, ptr, "CASCADE", &success);
3639 
3640  if (success) {
3641  if (is_on_delete) {
3643  } else {
3645  }
3646 
3647  goto scan_on_conditions;
3648  }
3649 
3650  ptr = dict_accept(cs, ptr, "NO", &success);
3651 
3652  if (success) {
3653  ptr = dict_accept(cs, ptr, "ACTION", &success);
3654 
3655  if (!success) {
3656  dict_foreign_free(foreign);
3657  dict_foreign_report_syntax_err(
3658  name, start_of_latest_foreign, ptr);
3659 
3660  return(DB_CANNOT_ADD_CONSTRAINT);
3661  }
3662 
3663  if (is_on_delete) {
3665  } else {
3667  }
3668 
3669  goto scan_on_conditions;
3670  }
3671 
3672  ptr = dict_accept(cs, ptr, "SET", &success);
3673 
3674  if (!success) {
3675  dict_foreign_free(foreign);
3676  dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3677  ptr);
3678  return(DB_CANNOT_ADD_CONSTRAINT);
3679  }
3680 
3681  ptr = dict_accept(cs, ptr, "NULL", &success);
3682 
3683  if (!success) {
3684  dict_foreign_free(foreign);
3685  dict_foreign_report_syntax_err(name, start_of_latest_foreign,
3686  ptr);
3687  return(DB_CANNOT_ADD_CONSTRAINT);
3688  }
3689 
3690  for (j = 0; j < foreign->n_fields; j++) {
3691  if ((dict_index_get_nth_col(foreign->foreign_index, j)->prtype)
3692  & DATA_NOT_NULL) {
3693 
3694  /* It is not sensible to define SET NULL
3695  if the column is not allowed to be NULL! */
3696 
3697  dict_foreign_free(foreign);
3698 
3699  mutex_enter(&dict_foreign_err_mutex);
3700  dict_foreign_error_report_low(ef, name);
3701  fprintf(ef, "%s:\n"
3702  "You have defined a SET NULL condition"
3703  " though some of the\n"
3704  "columns are defined as NOT NULL.\n",
3705  start_of_latest_foreign);
3706  mutex_exit(&dict_foreign_err_mutex);
3707 
3708  return(DB_CANNOT_ADD_CONSTRAINT);
3709  }
3710  }
3711 
3712  if (is_on_delete) {
3714  } else {
3716  }
3717 
3718  goto scan_on_conditions;
3719 
3720 try_find_index:
3721  if (n_on_deletes > 1 || n_on_updates > 1) {
3722  /* It is an error to define more than 1 action */
3723 
3724  dict_foreign_free(foreign);
3725 
3726  mutex_enter(&dict_foreign_err_mutex);
3727  dict_foreign_error_report_low(ef, name);
3728  fprintf(ef, "%s:\n"
3729  "You have twice an ON DELETE clause"
3730  " or twice an ON UPDATE clause.\n",
3731  start_of_latest_foreign);
3732  mutex_exit(&dict_foreign_err_mutex);
3733 
3734  return(DB_CANNOT_ADD_CONSTRAINT);
3735  }
3736 
3737  /* Try to find an index which contains the columns as the first fields
3738  and in the right order, and the types are the same as in
3739  foreign->foreign_index */
3740 
3741  if (referenced_table) {
3742  index = dict_foreign_find_index(referenced_table,
3743  column_names, i,
3744  foreign->foreign_index,
3745  TRUE, FALSE);
3746  if (!index) {
3747  dict_foreign_free(foreign);
3748  mutex_enter(&dict_foreign_err_mutex);
3749  dict_foreign_error_report_low(ef, name);
3750  fprintf(ef, "%s:\n"
3751  "Cannot find an index in the"
3752  " referenced table where the\n"
3753  "referenced columns appear as the"
3754  " first columns, or column types\n"
3755  "in the table and the referenced table"
3756  " do not match for constraint.\n"
3757  "Note that the internal storage type of"
3758  " ENUM and SET changed in\n"
3759  "tables created with >= InnoDB-4.1.12,"
3760  " and such columns in old tables\n"
3761  "cannot be referenced by such columns"
3762  " in new tables.\n"
3763  "See " REFMAN
3764  "innodb-foreign-key-constraints.html\n"
3765  "for correct foreign key definition.\n",
3766  start_of_latest_foreign);
3767  mutex_exit(&dict_foreign_err_mutex);
3768 
3769  return(DB_PARENT_NO_INDEX);
3770  }
3771  } else {
3772  ut_a(trx->check_foreigns == FALSE);
3773  index = NULL;
3774  }
3775 
3776  foreign->referenced_index = index;
3777  foreign->referenced_table = referenced_table;
3778 
3779  foreign->referenced_table_name
3780  = mem_heap_strdup(foreign->heap, referenced_table_name);
3781 
3782  foreign->referenced_col_names = static_cast<const char **>(mem_heap_alloc(foreign->heap,
3783  i * sizeof(void*)));
3784  for (i = 0; i < foreign->n_fields; i++) {
3785  foreign->referenced_col_names[i]
3786  = mem_heap_strdup(foreign->heap, column_names[i]);
3787  }
3788 
3789  /* We found an ok constraint definition: add to the lists */
3790 
3791  UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
3792 
3793  if (referenced_table) {
3794  UT_LIST_ADD_LAST(referenced_list,
3795  referenced_table->referenced_list,
3796  foreign);
3797  }
3798 
3799  goto loop;
3800 }
3801 
3802 /*********************************************************************/
3809 UNIV_INTERN
3810 ulint
3811 dict_create_foreign_constraints(
3812 /*============================*/
3813  trx_t* trx,
3814  const char* sql_string,
3822  size_t sql_length,
3823  const char* name,
3826  ibool reject_fks)
3829 {
3830  char* str;
3831  ulint err;
3832  mem_heap_t* heap;
3833 
3834  ut_a(trx);
3835  ut_a(trx->mysql_thd);
3836 
3837  str = dict_strip_comments(sql_string, sql_length);
3838  heap = mem_heap_create(10000);
3839 
3840  err = dict_create_foreign_constraints_low(
3841  trx, heap, trx->session()->charset(), str, name,
3842  reject_fks);
3843 
3844  mem_heap_free(heap);
3845  mem_free(str);
3846 
3847  return(err);
3848 }
3849 
3850 /**********************************************************************/
3854 UNIV_INTERN
3855 ulint
3856 dict_foreign_parse_drop_constraints(
3857 /*================================*/
3858  mem_heap_t* heap,
3860  trx_t* trx,
3861  dict_table_t* table,
3862  ulint* n,
3864  const char*** constraints_to_drop)
3866 {
3867  dict_foreign_t* foreign;
3868  ibool success;
3869  char* str;
3870  size_t len;
3871  const char* ptr;
3872  const char* id;
3873  FILE* ef = dict_foreign_err_file;
3874  const void* cs;
3875 
3876  ut_a(trx);
3877  ut_a(trx->mysql_thd);
3878 
3879  cs = trx->session()->charset();
3880 
3881  *n = 0;
3882 
3883  *constraints_to_drop = static_cast<const char **>(mem_heap_alloc(heap, 1000 * sizeof(char*)));
3884 
3885  ptr= trx->session()->getQueryStringCopy(len);
3886 
3887  str = dict_strip_comments(ptr, len);
3888 
3889  ptr = str;
3890 
3891  ut_ad(mutex_own(&(dict_sys->mutex)));
3892 loop:
3893  ptr = dict_scan_to(ptr, "DROP");
3894 
3895  if (*ptr == '\0') {
3896  mem_free(str);
3897 
3898  return(DB_SUCCESS);
3899  }
3900 
3901  ptr = dict_accept(cs, ptr, "DROP", &success);
3902 
3903  if (!innobase_isspace(cs, *ptr)) {
3904 
3905  goto loop;
3906  }
3907 
3908  ptr = dict_accept(cs, ptr, "FOREIGN", &success);
3909 
3910  if (!success || !innobase_isspace(cs, *ptr)) {
3911 
3912  goto loop;
3913  }
3914 
3915  ptr = dict_accept(cs, ptr, "KEY", &success);
3916 
3917  if (!success) {
3918 
3919  goto syntax_error;
3920  }
3921 
3922  ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
3923 
3924  if (id == NULL) {
3925 
3926  goto syntax_error;
3927  }
3928 
3929  ut_a(*n < 1000);
3930  (*constraints_to_drop)[*n] = id;
3931  (*n)++;
3932 
3933  /* Look for the given constraint id */
3934 
3935  foreign = UT_LIST_GET_FIRST(table->foreign_list);
3936 
3937  while (foreign != NULL) {
3938  if (0 == strcmp(foreign->id, id)
3939  || (strchr(foreign->id, '/')
3940  && 0 == strcmp(id,
3941  dict_remove_db_name(foreign->id)))) {
3942  /* Found */
3943  break;
3944  }
3945 
3946  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
3947  }
3948 
3949  if (foreign == NULL) {
3950  mutex_enter(&dict_foreign_err_mutex);
3951  rewind(ef);
3952  ut_print_timestamp(ef);
3953  fputs(" Error in dropping of a foreign key constraint"
3954  " of table ", ef);
3955  ut_print_name(ef, NULL, TRUE, table->name);
3956  fputs(",\n"
3957  "in SQL command\n", ef);
3958  fputs(str, ef);
3959  fputs("\nCannot find a constraint with the given id ", ef);
3960  ut_print_name(ef, NULL, FALSE, id);
3961  fputs(".\n", ef);
3962  mutex_exit(&dict_foreign_err_mutex);
3963 
3964  mem_free(str);
3965 
3966  return(DB_CANNOT_DROP_CONSTRAINT);
3967  }
3968 
3969  goto loop;
3970 
3971 syntax_error:
3972  mutex_enter(&dict_foreign_err_mutex);
3973  rewind(ef);
3974  ut_print_timestamp(ef);
3975  fputs(" Syntax error in dropping of a"
3976  " foreign key constraint of table ", ef);
3977  ut_print_name(ef, NULL, TRUE, table->name);
3978  fprintf(ef, ",\n"
3979  "close to:\n%s\n in SQL command\n%s\n", ptr, str);
3980  mutex_exit(&dict_foreign_err_mutex);
3981 
3982  mem_free(str);
3983 
3984  return(DB_CANNOT_DROP_CONSTRAINT);
3985 }
3986 
3987 /*==================== END OF FOREIGN KEY PROCESSING ====================*/
3988 
3989 /**********************************************************************/
3993 UNIV_INTERN
3994 dict_index_t*
3995 dict_index_get_if_in_cache_low(
3996 /*===========================*/
3997  index_id_t index_id)
3998 {
3999  ut_ad(mutex_own(&(dict_sys->mutex)));
4000 
4001  return(dict_index_find_on_id_low(index_id));
4002 }
4003 
4004 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
4005 /**********************************************************************/
4008 UNIV_INTERN
4009 dict_index_t*
4010 dict_index_get_if_in_cache(
4011 /*=======================*/
4012  index_id_t index_id)
4013 {
4014  dict_index_t* index;
4015 
4016  if (dict_sys == NULL) {
4017  return(NULL);
4018  }
4019 
4020  mutex_enter(&(dict_sys->mutex));
4021 
4022  index = dict_index_get_if_in_cache_low(index_id);
4023 
4024  mutex_exit(&(dict_sys->mutex));
4025 
4026  return(index);
4027 }
4028 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
4029 
4030 #ifdef UNIV_DEBUG
4031 /**********************************************************************/
4035 UNIV_INTERN
4036 ibool
4037 dict_index_check_search_tuple(
4038 /*==========================*/
4039  const dict_index_t* index,
4040  const dtuple_t* tuple)
4041 {
4042  ut_a(index);
4045  return(TRUE);
4046 }
4047 #endif /* UNIV_DEBUG */
4048 
4049 /**********************************************************************/
4052 UNIV_INTERN
4053 dtuple_t*
4054 dict_index_build_node_ptr(
4055 /*======================*/
4056  const dict_index_t* index,
4057  const rec_t* rec,
4059  ulint page_no,
4061  mem_heap_t* heap,
4063  ulint level)
4065 {
4066  dtuple_t* tuple;
4067  dfield_t* field;
4068  byte* buf;
4069  ulint n_unique;
4070 
4071  if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
4072  /* In a universal index tree, we take the whole record as
4073  the node pointer if the record is on the leaf level,
4074  on non-leaf levels we remove the last field, which
4075  contains the page number of the child page */
4076 
4077  ut_a(!dict_table_is_comp(index->table));
4078  n_unique = rec_get_n_fields_old(rec);
4079 
4080  if (level > 0) {
4081  ut_a(n_unique > 1);
4082  n_unique--;
4083  }
4084  } else {
4085  n_unique = dict_index_get_n_unique_in_tree(index);
4086  }
4087 
4088  tuple = dtuple_create(heap, n_unique + 1);
4089 
4090  /* When searching in the tree for the node pointer, we must not do
4091  comparison on the last field, the page number field, as on upper
4092  levels in the tree there may be identical node pointers with a
4093  different page number; therefore, we set the n_fields_cmp to one
4094  less: */
4095 
4096  dtuple_set_n_fields_cmp(tuple, n_unique);
4097 
4098  dict_index_copy_types(tuple, index, n_unique);
4099 
4100  buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 4));
4101 
4102  mach_write_to_4(buf, page_no);
4103 
4104  field = dtuple_get_nth_field(tuple, n_unique);
4105  dfield_set_data(field, buf, 4);
4106 
4107  dtype_set(dfield_get_type(field), DATA_SYS_CHILD, DATA_NOT_NULL, 4);
4108 
4109  rec_copy_prefix_to_dtuple(tuple, rec, index, n_unique, heap);
4111  | REC_STATUS_NODE_PTR);
4112 
4113  ut_ad(dtuple_check_typed(tuple));
4114 
4115  return(tuple);
4116 }
4117 
4118 /**********************************************************************/
4122 UNIV_INTERN
4123 rec_t*
4124 dict_index_copy_rec_order_prefix(
4125 /*=============================*/
4126  const dict_index_t* index,
4127  const rec_t* rec,
4129  ulint* n_fields,
4130  byte** buf,
4132  ulint* buf_size)
4133 {
4134  ulint n;
4135 
4136  UNIV_PREFETCH_R(rec);
4137 
4138  if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
4139  ut_a(!dict_table_is_comp(index->table));
4140  n = rec_get_n_fields_old(rec);
4141  } else {
4143  }
4144 
4145  *n_fields = n;
4146  return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
4147 }
4148 
4149 /**********************************************************************/
4152 UNIV_INTERN
4153 dtuple_t*
4154 dict_index_build_data_tuple(
4155 /*========================*/
4156  dict_index_t* index,
4157  rec_t* rec,
4158  ulint n_fields,
4159  mem_heap_t* heap)
4160 {
4161  dtuple_t* tuple;
4162 
4164  || n_fields <= rec_get_n_fields_old(rec));
4165 
4166  tuple = dtuple_create(heap, n_fields);
4167 
4168  dict_index_copy_types(tuple, index, n_fields);
4169 
4170  rec_copy_prefix_to_dtuple(tuple, rec, index, n_fields, heap);
4171 
4172  ut_ad(dtuple_check_typed(tuple));
4173 
4174  return(tuple);
4175 }
4176 
4177 /*********************************************************************/
4179 UNIV_INTERN
4180 ulint
4181 dict_index_calc_min_rec_len(
4182 /*========================*/
4183  const dict_index_t* index)
4184 {
4185  ulint sum = 0;
4186  ulint i;
4187  ulint comp = dict_table_is_comp(index->table);
4188 
4189  if (comp) {
4190  ulint nullable = 0;
4191  sum = REC_N_NEW_EXTRA_BYTES;
4192  for (i = 0; i < dict_index_get_n_fields(index); i++) {
4193  const dict_col_t* col
4194  = dict_index_get_nth_col(index, i);
4195  ulint size = dict_col_get_fixed_size(col, comp);
4196  sum += size;
4197  if (!size) {
4198  size = col->len;
4199  sum += size < 128 ? 1 : 2;
4200  }
4201  if (!(col->prtype & DATA_NOT_NULL)) {
4202  nullable++;
4203  }
4204  }
4205 
4206  /* round the NULL flags up to full bytes */
4207  sum += UT_BITS_IN_BYTES(nullable);
4208 
4209  return(sum);
4210  }
4211 
4212  for (i = 0; i < dict_index_get_n_fields(index); i++) {
4213  sum += dict_col_get_fixed_size(
4214  dict_index_get_nth_col(index, i), comp);
4215  }
4216 
4217  if (sum > 127) {
4218  sum += 2 * dict_index_get_n_fields(index);
4219  } else {
4220  sum += dict_index_get_n_fields(index);
4221  }
4222 
4223  sum += REC_N_OLD_EXTRA_BYTES;
4224 
4225  return(sum);
4226 }
4227 
4228 /*********************************************************************/
4231 UNIV_INTERN
4232 void
4233 dict_update_statistics(
4234 /*===================*/
4235  dict_table_t* table,
4236  ibool only_calc_if_missing_stats)
4240 {
4241  dict_index_t* index;
4242  ulint sum_of_index_sizes = 0;
4243 
4244  if (table->ibd_file_missing) {
4245  ut_print_timestamp(stderr);
4246  fprintf(stderr,
4247  " InnoDB: cannot calculate statistics for table %s\n"
4248  "InnoDB: because the .ibd file is missing. For help,"
4249  " please refer to\n"
4250  "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
4251  table->name);
4252 
4253  return;
4254  }
4255 
4256  /* Find out the sizes of the indexes and how many different values
4257  for the key they approximately have */
4258 
4259  index = dict_table_get_first_index(table);
4260 
4261  if (index == NULL) {
4262  /* Table definition is corrupt */
4263 
4264  return;
4265  }
4266 
4267  dict_table_stats_lock(table, RW_X_LATCH);
4268 
4269  if (only_calc_if_missing_stats && table->stat_initialized) {
4270  dict_table_stats_unlock(table, RW_X_LATCH);
4271  return;
4272  }
4273 
4274  do {
4275  if (UNIV_LIKELY
4276  (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
4277  || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
4278  && dict_index_is_clust(index)))) {
4279  ulint size;
4280  size = btr_get_size(index, BTR_TOTAL_SIZE);
4281 
4282  index->stat_index_size = size;
4283 
4284  sum_of_index_sizes += size;
4285 
4286  size = btr_get_size(index, BTR_N_LEAF_PAGES);
4287 
4288  if (size == 0) {
4289  /* The root node of the tree is a leaf */
4290  size = 1;
4291  }
4292 
4293  index->stat_n_leaf_pages = size;
4294 
4295  btr_estimate_number_of_different_key_vals(index);
4296  } else {
4297  /* If we have set a high innodb_force_recovery
4298  level, do not calculate statistics, as a badly
4299  corrupted index can cause a crash in it.
4300  Initialize some bogus index cardinality
4301  statistics, so that the data can be queried in
4302  various means, also via secondary indexes. */
4303  ulint i;
4304 
4305  sum_of_index_sizes++;
4306  index->stat_index_size = index->stat_n_leaf_pages = 1;
4307 
4308  for (i = dict_index_get_n_unique(index); i; ) {
4309  index->stat_n_diff_key_vals[i--] = 1;
4310  }
4311  }
4312 
4313  index = dict_table_get_next_index(index);
4314  } while (index);
4315 
4316  index = dict_table_get_first_index(table);
4317 
4318  table->stat_n_rows = index->stat_n_diff_key_vals[
4319  dict_index_get_n_unique(index)];
4320 
4322 
4323  table->stat_sum_of_other_index_sizes = sum_of_index_sizes
4324  - index->stat_index_size;
4325 
4326  table->stat_initialized = TRUE;
4327 
4328  table->stat_modified_counter = 0;
4329 
4330  dict_table_stats_unlock(table, RW_X_LATCH);
4331 }
4332 
4333 /**********************************************************************/
4335 static
4336 void
4337 dict_foreign_print_low(
4338 /*===================*/
4339  dict_foreign_t* foreign)
4340 {
4341  ulint i;
4342 
4343  ut_ad(mutex_own(&(dict_sys->mutex)));
4344 
4345  fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
4346  foreign->id, foreign->foreign_table_name);
4347 
4348  for (i = 0; i < foreign->n_fields; i++) {
4349  fprintf(stderr, " %s", foreign->foreign_col_names[i]);
4350  }
4351 
4352  fprintf(stderr, " )\n"
4353  " REFERENCES %s (",
4354  foreign->referenced_table_name);
4355 
4356  for (i = 0; i < foreign->n_fields; i++) {
4357  fprintf(stderr, " %s", foreign->referenced_col_names[i]);
4358  }
4359 
4360  fputs(" )\n", stderr);
4361 }
4362 
4363 /**********************************************************************/
4365 UNIV_INTERN
4366 void
4367 dict_table_print(
4368 /*=============*/
4369  dict_table_t* table)
4370 {
4371  mutex_enter(&(dict_sys->mutex));
4372  dict_table_print_low(table);
4373  mutex_exit(&(dict_sys->mutex));
4374 }
4375 
4376 /**********************************************************************/
4378 UNIV_INTERN
4379 void
4380 dict_table_print_by_name(
4381 /*=====================*/
4382  const char* name)
4383 {
4384  dict_table_t* table;
4385 
4386  mutex_enter(&(dict_sys->mutex));
4387 
4388  table = dict_table_get_low(name);
4389 
4390  ut_a(table);
4391 
4392  dict_table_print_low(table);
4393  mutex_exit(&(dict_sys->mutex));
4394 }
4395 
4396 /**********************************************************************/
4398 UNIV_INTERN
4399 void
4400 dict_table_print_low(
4401 /*=================*/
4402  dict_table_t* table)
4403 {
4404  dict_index_t* index;
4405  dict_foreign_t* foreign;
4406  ulint i;
4407 
4408  ut_ad(mutex_own(&(dict_sys->mutex)));
4409 
4410  dict_update_statistics(table, FALSE /* update even if initialized */);
4411 
4412  dict_table_stats_lock(table, RW_S_LATCH);
4413 
4414  fprintf(stderr,
4415  "--------------------------------------\n"
4416  "TABLE: name %s, id %llu, flags %lx, columns %lu,"
4417  " indexes %lu, appr.rows %lu\n"
4418  " COLUMNS: ",
4419  table->name,
4420  (ullint) table->id,
4421  (ulong) table->flags,
4422  (ulong) table->n_cols,
4423  (ulong) UT_LIST_GET_LEN(table->indexes),
4424  (ulong) table->stat_n_rows);
4425 
4426  for (i = 0; i < (ulint) table->n_cols; i++) {
4427  dict_col_print_low(table, dict_table_get_nth_col(table, i));
4428  fputs("; ", stderr);
4429  }
4430 
4431  putc('\n', stderr);
4432 
4433  index = UT_LIST_GET_FIRST(table->indexes);
4434 
4435  while (index != NULL) {
4436  dict_index_print_low(index);
4437  index = UT_LIST_GET_NEXT(indexes, index);
4438  }
4439 
4440  dict_table_stats_unlock(table, RW_S_LATCH);
4441 
4442  foreign = UT_LIST_GET_FIRST(table->foreign_list);
4443 
4444  while (foreign != NULL) {
4445  dict_foreign_print_low(foreign);
4446  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4447  }
4448 
4449  foreign = UT_LIST_GET_FIRST(table->referenced_list);
4450 
4451  while (foreign != NULL) {
4452  dict_foreign_print_low(foreign);
4453  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
4454  }
4455 }
4456 
4457 /**********************************************************************/
4459 static
4460 void
4461 dict_col_print_low(
4462 /*===============*/
4463  const dict_table_t* table,
4464  const dict_col_t* col)
4465 {
4466  dtype_t type;
4467 
4468  ut_ad(mutex_own(&(dict_sys->mutex)));
4469 
4470  dict_col_copy_type(col, &type);
4471  fprintf(stderr, "%s: ", dict_table_get_col_name(table,
4472  dict_col_get_no(col)));
4473 
4474  dtype_print(&type);
4475 }
4476 
4477 /**********************************************************************/
4479 static
4480 void
4481 dict_index_print_low(
4482 /*=================*/
4483  dict_index_t* index)
4484 {
4485  ib_int64_t n_vals;
4486  ulint i;
4487 
4488  ut_ad(mutex_own(&(dict_sys->mutex)));
4489 
4490  if (index->n_user_defined_cols > 0) {
4491  n_vals = index->stat_n_diff_key_vals[
4492  index->n_user_defined_cols];
4493  } else {
4494  n_vals = index->stat_n_diff_key_vals[1];
4495  }
4496 
4497  fprintf(stderr,
4498  " INDEX: name %s, id %llu, fields %lu/%lu,"
4499  " uniq %lu, type %lu\n"
4500  " root page %lu, appr.key vals %lu,"
4501  " leaf pages %lu, size pages %lu\n"
4502  " FIELDS: ",
4503  index->name,
4504  (ullint) index->id,
4505  (ulong) index->n_user_defined_cols,
4506  (ulong) index->n_fields,
4507  (ulong) index->n_uniq,
4508  (ulong) index->type,
4509  (ulong) index->page,
4510  (ulong) n_vals,
4511  (ulong) index->stat_n_leaf_pages,
4512  (ulong) index->stat_index_size);
4513 
4514  for (i = 0; i < index->n_fields; i++) {
4515  dict_field_print_low(dict_index_get_nth_field(index, i));
4516  }
4517 
4518  putc('\n', stderr);
4519 
4520 #ifdef UNIV_BTR_PRINT
4521  btr_print_size(index);
4522 
4523  btr_print_index(index, 7);
4524 #endif /* UNIV_BTR_PRINT */
4525 }
4526 
4527 /**********************************************************************/
4529 static
4530 void
4531 dict_field_print_low(
4532 /*=================*/
4533  const dict_field_t* field)
4534 {
4535  ut_ad(mutex_own(&(dict_sys->mutex)));
4536 
4537  fprintf(stderr, " %s", field->name);
4538 
4539  if (field->prefix_len != 0) {
4540  fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
4541  }
4542 }
4543 
4544 /**********************************************************************/
4547 UNIV_INTERN
4548 void
4549 dict_print_info_on_foreign_key_in_create_format(
4550 /*============================================*/
4551  FILE* file,
4552  trx_t* trx,
4553  dict_foreign_t* foreign,
4554  ibool add_newline)
4555 {
4556  const char* stripped_id;
4557  ulint i;
4558 
4559  if (strchr(foreign->id, '/')) {
4560  /* Strip the preceding database name from the constraint id */
4561  stripped_id = foreign->id + 1
4562  + dict_get_db_name_len(foreign->id);
4563  } else {
4564  stripped_id = foreign->id;
4565  }
4566 
4567  putc(',', file);
4568 
4569  if (add_newline) {
4570  /* SHOW CREATE TABLE wants constraints each printed nicely
4571  on its own line, while error messages want no newlines
4572  inserted. */
4573  fputs("\n ", file);
4574  }
4575 
4576  fputs(" CONSTRAINT ", file);
4577  ut_print_name(file, trx, FALSE, stripped_id);
4578  fputs(" FOREIGN KEY (", file);
4579 
4580  for (i = 0;;) {
4581  ut_print_name(file, trx, FALSE, foreign->foreign_col_names[i]);
4582  if (++i < foreign->n_fields) {
4583  fputs(", ", file);
4584  } else {
4585  break;
4586  }
4587  }
4588 
4589  fputs(") REFERENCES ", file);
4590 
4591  if (dict_tables_have_same_db(foreign->foreign_table_name,
4592  foreign->referenced_table_name)) {
4593  /* Do not print the database name of the referenced table */
4594  ut_print_name(file, trx, TRUE,
4595  dict_remove_db_name(
4596  foreign->referenced_table_name));
4597  } else {
4598  ut_print_name(file, trx, TRUE,
4599  foreign->referenced_table_name);
4600  }
4601 
4602  putc(' ', file);
4603  putc('(', file);
4604 
4605  for (i = 0;;) {
4606  ut_print_name(file, trx, FALSE,
4607  foreign->referenced_col_names[i]);
4608  if (++i < foreign->n_fields) {
4609  fputs(", ", file);
4610  } else {
4611  break;
4612  }
4613  }
4614 
4615  putc(')', file);
4616 
4617  if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
4618  fputs(" ON DELETE CASCADE", file);
4619  }
4620 
4621  if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
4622  fputs(" ON DELETE SET NULL", file);
4623  }
4624 
4625  if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4626  fputs(" ON DELETE NO ACTION", file);
4627  }
4628 
4629  if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4630  fputs(" ON UPDATE CASCADE", file);
4631  }
4632 
4633  if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4634  fputs(" ON UPDATE SET NULL", file);
4635  }
4636 
4637  if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4638  fputs(" ON UPDATE NO ACTION", file);
4639  }
4640 }
4641 
4642 /**********************************************************************/
4644 UNIV_INTERN
4645 void
4646 dict_print_info_on_foreign_keys(
4647 /*============================*/
4648  ibool create_table_format,
4652  FILE* file,
4653  trx_t* trx,
4654  dict_table_t* table)
4655 {
4656  dict_foreign_t* foreign;
4657 
4658  mutex_enter(&(dict_sys->mutex));
4659 
4660  foreign = UT_LIST_GET_FIRST(table->foreign_list);
4661 
4662  if (foreign == NULL) {
4663  mutex_exit(&(dict_sys->mutex));
4664 
4665  return;
4666  }
4667 
4668  while (foreign != NULL) {
4669  if (create_table_format) {
4670  dict_print_info_on_foreign_key_in_create_format(
4671  file, trx, foreign, TRUE);
4672  } else {
4673  ulint i;
4674  fputs("; (", file);
4675 
4676  for (i = 0; i < foreign->n_fields; i++) {
4677  if (i) {
4678  putc(' ', file);
4679  }
4680 
4681  ut_print_name(file, trx, FALSE,
4682  foreign->foreign_col_names[i]);
4683  }
4684 
4685  fputs(") REFER ", file);
4686  ut_print_name(file, trx, TRUE,
4687  foreign->referenced_table_name);
4688  putc('(', file);
4689 
4690  for (i = 0; i < foreign->n_fields; i++) {
4691  if (i) {
4692  putc(' ', file);
4693  }
4694  ut_print_name(
4695  file, trx, FALSE,
4696  foreign->referenced_col_names[i]);
4697  }
4698 
4699  putc(')', file);
4700 
4701  if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE) {
4702  fputs(" ON DELETE CASCADE", file);
4703  }
4704 
4705  if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
4706  fputs(" ON DELETE SET NULL", file);
4707  }
4708 
4709  if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
4710  fputs(" ON DELETE NO ACTION", file);
4711  }
4712 
4713  if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
4714  fputs(" ON UPDATE CASCADE", file);
4715  }
4716 
4717  if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
4718  fputs(" ON UPDATE SET NULL", file);
4719  }
4720 
4721  if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
4722  fputs(" ON UPDATE NO ACTION", file);
4723  }
4724  }
4725 
4726  foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
4727  }
4728 
4729  mutex_exit(&(dict_sys->mutex));
4730 }
4731 
4732 /********************************************************************/
4734 UNIV_INTERN
4735 void
4736 dict_index_name_print(
4737 /*==================*/
4738  FILE* file,
4739  trx_t* trx,
4740  const dict_index_t* index)
4741 {
4742  fputs("index ", file);
4743  ut_print_name(file, trx, FALSE, index->name);
4744  fputs(" of table ", file);
4745  ut_print_name(file, trx, TRUE, index->table_name);
4746 }
4747 #endif /* !UNIV_HOTBACKUP */
4748 
4749 /**********************************************************************/
4751 UNIV_INTERN
4752 void
4753 dict_ind_init(void)
4754 /*===============*/
4755 {
4756  dict_table_t* table;
4757 
4758  /* create dummy table and index for REDUNDANT infimum and supremum */
4759  table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0);
4760  dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
4761  DATA_ENGLISH | DATA_NOT_NULL, 8);
4762 
4763  dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
4764  DICT_HDR_SPACE, 0, 1);
4765  dict_index_add_col(dict_ind_redundant, table,
4766  dict_table_get_nth_col(table, 0), 0);
4767  dict_ind_redundant->table = table;
4768  /* create dummy table and index for COMPACT infimum and supremum */
4769  table = dict_mem_table_create("SYS_DUMMY2",
4770  DICT_HDR_SPACE, 1, DICT_TF_COMPACT);
4771  dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
4772  DATA_ENGLISH | DATA_NOT_NULL, 8);
4773  dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
4774  DICT_HDR_SPACE, 0, 1);
4775  dict_index_add_col(dict_ind_compact, table,
4776  dict_table_get_nth_col(table, 0), 0);
4777  dict_ind_compact->table = table;
4778 
4779  /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
4780  dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
4781 }
4782 
4783 /**********************************************************************/
4785 static
4786 void
4787 dict_ind_free(void)
4788 /*===============*/
4789 {
4790  dict_table_t* table;
4791 
4792  table = dict_ind_compact->table;
4793  dict_mem_index_free(dict_ind_compact);
4794  dict_ind_compact = NULL;
4795  dict_mem_table_free(table);
4796 
4797  table = dict_ind_redundant->table;
4798  dict_mem_index_free(dict_ind_redundant);
4799  dict_ind_redundant = NULL;
4800  dict_mem_table_free(table);
4801 }
4802 
4803 #ifndef UNIV_HOTBACKUP
4804 /**********************************************************************/
4807 UNIV_INTERN
4808 dict_index_t*
4809 dict_table_get_index_on_name(
4810 /*=========================*/
4811  dict_table_t* table,
4812  const char* name)
4813 {
4814  dict_index_t* index;
4815 
4816  index = dict_table_get_first_index(table);
4817 
4818  while (index != NULL) {
4819  if (ut_strcmp(index->name, name) == 0) {
4820 
4821  return(index);
4822  }
4823 
4824  index = dict_table_get_next_index(index);
4825  }
4826 
4827  return(NULL);
4828 
4829 }
4830 
4831 /**********************************************************************/
4834 UNIV_INTERN
4835 void
4836 dict_table_replace_index_in_foreign_list(
4837 /*=====================================*/
4838  dict_table_t* table,
4839  dict_index_t* index,
4840  const trx_t* trx)
4841 {
4842  dict_foreign_t* foreign;
4843 
4844  for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
4845  foreign;
4846  foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
4847 
4848  if (foreign->foreign_index == index) {
4849  dict_index_t* new_index
4850  = dict_foreign_find_equiv_index(foreign);
4851 
4852  /* There must exist an alternative index if
4853  check_foreigns (FOREIGN_KEY_CHECKS) is on,
4854  since ha_innobase::prepare_drop_index had done
4855  the check before we reach here. */
4856 
4857  ut_a(new_index || !trx->check_foreigns);
4858 
4859  foreign->foreign_index = new_index;
4860  }
4861  }
4862 }
4863 
4864 /**********************************************************************/
4868 UNIV_INTERN
4869 dict_index_t*
4870 dict_table_get_index_on_name_and_min_id(
4871 /*=====================================*/
4872  dict_table_t* table,
4873  const char* name)
4874 {
4875  dict_index_t* index;
4876  dict_index_t* min_index; /* Index with matching name and min(id) */
4877 
4878  min_index = NULL;
4879  index = dict_table_get_first_index(table);
4880 
4881  while (index != NULL) {
4882  if (ut_strcmp(index->name, name) == 0) {
4883  if (!min_index || index->id < min_index->id) {
4884 
4885  min_index = index;
4886  }
4887  }
4888 
4889  index = dict_table_get_next_index(index);
4890  }
4891 
4892  return(min_index);
4893 
4894 }
4895 
4896 #ifdef UNIV_DEBUG
4897 /**********************************************************************/
4899 UNIV_INTERN
4900 void
4901 dict_table_check_for_dup_indexes(
4902 /*=============================*/
4903  const dict_table_t* table,
4905  ibool tmp_ok)
4907 {
4908  /* Check for duplicates, ignoring indexes that are marked
4909  as to be dropped */
4910 
4911  const dict_index_t* index1;
4912  const dict_index_t* index2;
4913 
4914  ut_ad(mutex_own(&dict_sys->mutex));
4915 
4916  /* The primary index _must_ exist */
4917  ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
4918 
4919  index1 = UT_LIST_GET_FIRST(table->indexes);
4920 
4921  do {
4922  ut_ad(tmp_ok || *index1->name != TEMP_INDEX_PREFIX);
4923 
4924  index2 = UT_LIST_GET_NEXT(indexes, index1);
4925 
4926  while (index2) {
4927 
4928  if (!index2->to_be_dropped) {
4929  ut_ad(ut_strcmp(index1->name, index2->name));
4930  }
4931 
4932  index2 = UT_LIST_GET_NEXT(indexes, index2);
4933  }
4934 
4935  index1 = UT_LIST_GET_NEXT(indexes, index1);
4936  } while (index1);
4937 }
4938 #endif /* UNIV_DEBUG */
4939 
4940 /**************************************************************************
4941 Closes the data dictionary module. */
4942 UNIV_INTERN
4943 void
4944 dict_close(void)
4945 /*============*/
4946 {
4947  ulint i;
4948 
4949  /* Free the hash elements. We don't remove them from the table
4950  because we are going to destroy the table anyway. */
4951  for (i = 0; i < hash_get_n_cells(dict_sys->table_hash); i++) {
4952  dict_table_t* table;
4953 
4954  table = static_cast<dict_table_t *>(HASH_GET_FIRST(dict_sys->table_hash, i));
4955 
4956  while (table) {
4957  dict_table_t* prev_table = table;
4958 
4959  table = static_cast<dict_table_t *>(HASH_GET_NEXT(name_hash, prev_table));
4960 #ifdef UNIV_DEBUG
4961  ut_a(prev_table->magic_n == DICT_TABLE_MAGIC_N);
4962 #endif
4963  /* Acquire only because it's a pre-condition. */
4964  mutex_enter(&dict_sys->mutex);
4965 
4966  dict_table_remove_from_cache(prev_table);
4967 
4968  mutex_exit(&dict_sys->mutex);
4969  }
4970  }
4971 
4972  hash_table_free(dict_sys->table_hash);
4973 
4974  /* The elements are the same instance as in dict_sys->table_hash,
4975  therefore we don't delete the individual elements. */
4976  hash_table_free(dict_sys->table_id_hash);
4977 
4978  dict_ind_free();
4979 
4980  mutex_free(&dict_sys->mutex);
4981 
4982  rw_lock_free(&dict_operation_lock);
4983  memset(&dict_operation_lock, 0x0, sizeof(dict_operation_lock));
4984 
4985  mutex_free(&dict_foreign_err_mutex);
4986 
4987  mem_free(dict_sys);
4988  dict_sys = NULL;
4989 
4990  for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
4991  rw_lock_free(&dict_table_stats_latches[i]);
4992  }
4993 }
4994 #endif /* !UNIV_HOTBACKUP */