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