MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
dict0load.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2013, Oracle and/or its affiliates. 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.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
27 #include "dict0load.h"
28 #include "mysql_version.h"
29 
30 #ifdef UNIV_NONINL
31 #include "dict0load.ic"
32 #endif
33 
34 #include "btr0pcur.h"
35 #include "btr0btr.h"
36 #include "page0page.h"
37 #include "mach0data.h"
38 #include "dict0dict.h"
39 #include "dict0boot.h"
40 #include "dict0stats.h"
41 #include "rem0cmp.h"
42 #include "srv0start.h"
43 #include "srv0srv.h"
44 #include "dict0crea.h"
45 #include "dict0priv.h"
46 #include "ha_prototypes.h" /* innobase_casedn_str() */
47 #include "fts0priv.h"
48 
51 static const char* SYSTEM_TABLE_NAME[] = {
52  "SYS_TABLES",
53  "SYS_INDEXES",
54  "SYS_COLUMNS",
55  "SYS_FIELDS",
56  "SYS_FOREIGN",
57  "SYS_FOREIGN_COLS",
58  "SYS_TABLESPACES",
59  "SYS_DATAFILES"
60 };
61 
62 /* If this flag is TRUE, then we will load the cluster index's (and tables')
63 metadata even if it is marked as "corrupted". */
64 UNIV_INTERN my_bool srv_load_corrupted = FALSE;
65 
66 #ifdef UNIV_DEBUG
67 /****************************************************************/
70 static
71 ibool
72 name_of_col_is(
73 /*===========*/
74  const dict_table_t* table,
75  const dict_index_t* index,
76  ulint i,
77  const char* name)
78 {
80  dict_index_get_nth_field(
81  index, i)));
82 
83  return(strcmp(name, dict_table_get_col_name(table, tmp)) == 0);
84 }
85 #endif /* UNIV_DEBUG */
86 
87 /********************************************************************/
91 UNIV_INTERN
92 char*
94 /*============================*/
95  const char* name)
96 {
97  dict_table_t* sys_tables;
99  dict_index_t* sys_index;
100  dtuple_t* tuple;
101  mem_heap_t* heap;
102  dfield_t* dfield;
103  const rec_t* rec;
104  const byte* field;
105  ulint len;
106  mtr_t mtr;
107 
108  ut_ad(mutex_own(&(dict_sys->mutex)));
109 
110  heap = mem_heap_create(1000);
111 
112  mtr_start(&mtr);
113 
114  sys_tables = dict_table_get_low("SYS_TABLES");
115  sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
116  ut_ad(!dict_table_is_comp(sys_tables));
117 
118  tuple = dtuple_create(heap, 1);
119  dfield = dtuple_get_nth_field(tuple, 0);
120 
121  dfield_set_data(dfield, name, ut_strlen(name));
122  dict_index_copy_types(tuple, sys_index, 1);
123 
124  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
125  BTR_SEARCH_LEAF, &pcur, &mtr);
126 loop:
127  rec = btr_pcur_get_rec(&pcur);
128 
129  if (!btr_pcur_is_on_user_rec(&pcur)) {
130  /* Not found */
131 
132  btr_pcur_close(&pcur);
133  mtr_commit(&mtr);
134  mem_heap_free(heap);
135 
136  return(NULL);
137  }
138 
139  field = rec_get_nth_field_old(
140  rec, DICT_FLD__SYS_TABLES__NAME, &len);
141 
142  if (len < strlen(name)
143  || ut_memcmp(name, field, strlen(name)) != 0) {
144  /* Not found */
145 
146  btr_pcur_close(&pcur);
147  mtr_commit(&mtr);
148  mem_heap_free(heap);
149 
150  return(NULL);
151  }
152 
153  if (!rec_get_deleted_flag(rec, 0)) {
154 
155  /* We found one */
156 
157  char* table_name = mem_strdupl((char*) field, len);
158 
159  btr_pcur_close(&pcur);
160  mtr_commit(&mtr);
161  mem_heap_free(heap);
162 
163  return(table_name);
164  }
165 
166  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
167 
168  goto loop;
169 }
170 
171 /********************************************************************/
174 UNIV_INTERN
175 void
177 /*============*/
178 {
181  const rec_t* rec;
182  mem_heap_t* heap;
183  mtr_t mtr;
184 
185  /* Enlarge the fatal semaphore wait timeout during the InnoDB table
186  monitor printout */
187 
189  server_mutex,
190  srv_fatal_semaphore_wait_threshold,
191  SRV_SEMAPHORE_WAIT_EXTENSION);
192 
193  heap = mem_heap_create(1000);
194  mutex_enter(&(dict_sys->mutex));
195  mtr_start(&mtr);
196 
197  rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
198 
199  while (rec) {
200  const char* err_msg;
201 
202  err_msg = static_cast<const char*>(
204  heap, rec, &table, DICT_TABLE_LOAD_FROM_CACHE,
205  &mtr));
206 
207  if (!err_msg) {
208  dict_table_print(table);
209  } else {
210  ut_print_timestamp(stderr);
211  fprintf(stderr, " InnoDB: %s\n", err_msg);
212  }
213 
214  mem_heap_empty(heap);
215 
216  mtr_start(&mtr);
217  rec = dict_getnext_system(&pcur, &mtr);
218  }
219 
220  mtr_commit(&mtr);
221  mutex_exit(&(dict_sys->mutex));
222  mem_heap_free(heap);
223 
224  /* Restore the fatal semaphore wait timeout */
225  os_decrement_counter_by_amount(
226  server_mutex,
227  srv_fatal_semaphore_wait_threshold,
228  SRV_SEMAPHORE_WAIT_EXTENSION);
229 }
230 
231 /********************************************************************/
234 static
235 const rec_t*
236 dict_getnext_system_low(
237 /*====================*/
238  btr_pcur_t* pcur,
240  mtr_t* mtr)
241 {
242  rec_t* rec = NULL;
243 
244  while (!rec || rec_get_deleted_flag(rec, 0)) {
246 
247  rec = btr_pcur_get_rec(pcur);
248 
249  if (!btr_pcur_is_on_user_rec(pcur)) {
250  /* end of index */
251  btr_pcur_close(pcur);
252 
253  return(NULL);
254  }
255  }
256 
257  /* Get a record, let's save the position */
258  btr_pcur_store_position(pcur, mtr);
259 
260  return(rec);
261 }
262 
263 /********************************************************************/
266 UNIV_INTERN
267 const rec_t*
269 /*==================*/
270  btr_pcur_t* pcur,
272  mtr_t* mtr,
273  dict_system_id_t system_id)
274 {
275  dict_table_t* system_table;
276  dict_index_t* clust_index;
277  const rec_t* rec;
278 
279  ut_a(system_id < SYS_NUM_SYSTEM_TABLES);
280 
281  system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]);
282 
283  clust_index = UT_LIST_GET_FIRST(system_table->indexes);
284 
285  btr_pcur_open_at_index_side(true, clust_index, BTR_SEARCH_LEAF, pcur,
286  true, 0, mtr);
287 
288  rec = dict_getnext_system_low(pcur, mtr);
289 
290  return(rec);
291 }
292 
293 /********************************************************************/
296 UNIV_INTERN
297 const rec_t*
299 /*================*/
300  btr_pcur_t* pcur,
302  mtr_t* mtr)
303 {
304  const rec_t* rec;
305 
306  /* Restore the position */
307  btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
308 
309  /* Get the next record */
310  rec = dict_getnext_system_low(pcur, mtr);
311 
312  return(rec);
313 }
314 
315 /********************************************************************/
320 UNIV_INTERN
321 const char*
323 /*=======================================*/
324  mem_heap_t* heap,
325  const rec_t* rec,
326  dict_table_t** table,
327  dict_table_info_t status,
331  mtr_t* mtr)
333 {
334  ulint len;
335  const char* field;
336  const char* err_msg = NULL;
337  char* table_name;
338 
339  field = (const char*) rec_get_nth_field_old(
340  rec, DICT_FLD__SYS_TABLES__NAME, &len);
341 
342  ut_a(!rec_get_deleted_flag(rec, 0));
343 
344  ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_S_FIX));
345 
346  /* Get the table name */
347  table_name = mem_heap_strdupl(heap, field, len);
348 
349  /* If DICT_TABLE_LOAD_FROM_CACHE is set, first check
350  whether there is cached dict_table_t struct */
351  if (status & DICT_TABLE_LOAD_FROM_CACHE) {
352 
353  /* Commit before load the table again */
354  mtr_commit(mtr);
355 
356  *table = dict_table_get_low(table_name);
357 
358  if (!(*table)) {
359  err_msg = "Table not found in cache";
360  }
361  } else {
362  err_msg = dict_load_table_low(table_name, rec, table);
363  mtr_commit(mtr);
364  }
365 
366  if (err_msg) {
367  return(err_msg);
368  }
369 
370  return(NULL);
371 }
372 
373 /********************************************************************/
378 UNIV_INTERN
379 const char*
381 /*=========================*/
382  mem_heap_t* heap,
383  const rec_t* rec,
384  dict_index_t* index,
385  table_id_t* table_id)
386 {
387  const char* err_msg;
388  byte* buf;
389 
390  buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
391 
392  /* Parse the record, and get "dict_index_t" struct filled */
393  err_msg = dict_load_index_low(buf, NULL,
394  heap, rec, FALSE, &index);
395 
396  *table_id = mach_read_from_8(buf);
397 
398  return(err_msg);
399 }
400 
401 /********************************************************************/
405 UNIV_INTERN
406 const char*
408 /*=========================*/
409  mem_heap_t* heap,
410  const rec_t* rec,
411  dict_col_t* column,
412  table_id_t* table_id,
413  const char** col_name)
414 {
415  const char* err_msg;
416 
417  /* Parse the record, and get "dict_col_t" struct filled */
418  err_msg = dict_load_column_low(NULL, heap, column,
419  table_id, col_name, rec);
420 
421  return(err_msg);
422 }
423 
424 /********************************************************************/
428 UNIV_INTERN
429 const char*
431 /*========================*/
432  mem_heap_t* heap,
433  const rec_t* rec,
434  dict_field_t* sys_field,
436  ulint* pos,
437  index_id_t* index_id,
438  index_id_t last_id)
439 {
440  byte* buf;
441  byte* last_index_id;
442  const char* err_msg;
443 
444  buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
445 
446  last_index_id = static_cast<byte*>(mem_heap_alloc(heap, 8));
447  mach_write_to_8(last_index_id, last_id);
448 
449  err_msg = dict_load_field_low(buf, NULL, sys_field,
450  pos, last_index_id, heap, rec);
451 
452  *index_id = mach_read_from_8(buf);
453 
454  return(err_msg);
455 
456 }
457 
458 /********************************************************************/
463 UNIV_INTERN
464 const char*
466 /*=========================*/
467  mem_heap_t* heap,
468  const rec_t* rec,
469  dict_foreign_t* foreign)
471 {
472  ulint len;
473  const byte* field;
474  ulint n_fields_and_type;
475 
476  if (rec_get_deleted_flag(rec, 0)) {
477  return("delete-marked record in SYS_FOREIGN");
478  }
479 
480  if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_FOREIGN) {
481  return("wrong number of columns in SYS_FOREIGN record");
482  }
483 
484  field = rec_get_nth_field_old(
485  rec, DICT_FLD__SYS_FOREIGN__ID, &len);
486  if (len == 0 || len == UNIV_SQL_NULL) {
487 err_len:
488  return("incorrect column length in SYS_FOREIGN");
489  }
490 
491  /* This recieves a dict_foreign_t* that points to a stack variable.
492  So mem_heap_free(foreign->heap) is not used as elsewhere.
493  Since the heap used here is freed elsewhere, foreign->heap
494  is not assigned. */
495  foreign->id = mem_heap_strdupl(heap, (const char*) field, len);
496 
498  rec, DICT_FLD__SYS_FOREIGN__DB_TRX_ID, &len);
499  if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
500  goto err_len;
501  }
503  rec, DICT_FLD__SYS_FOREIGN__DB_ROLL_PTR, &len);
504  if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
505  goto err_len;
506  }
507 
508  /* The _lookup versions of the referenced and foreign table names
509  are not assigned since they are not used in this dict_foreign_t */
510 
511  field = rec_get_nth_field_old(
512  rec, DICT_FLD__SYS_FOREIGN__FOR_NAME, &len);
513  if (len == 0 || len == UNIV_SQL_NULL) {
514  goto err_len;
515  }
517  heap, (const char*) field, len);
518 
519  field = rec_get_nth_field_old(
520  rec, DICT_FLD__SYS_FOREIGN__REF_NAME, &len);
521  if (len == 0 || len == UNIV_SQL_NULL) {
522  goto err_len;
523  }
525  heap, (const char*) field, len);
526 
527  field = rec_get_nth_field_old(
528  rec, DICT_FLD__SYS_FOREIGN__N_COLS, &len);
529  if (len != 4) {
530  goto err_len;
531  }
532  n_fields_and_type = mach_read_from_4(field);
533 
534  foreign->type = (unsigned int) (n_fields_and_type >> 24);
535  foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
536 
537  return(NULL);
538 }
539 
540 /********************************************************************/
544 UNIV_INTERN
545 const char*
547 /*=============================*/
548  mem_heap_t* heap,
549  const rec_t* rec,
550  const char** name,
551  const char** for_col_name,
552  const char** ref_col_name,
554  ulint* pos)
555 {
556  ulint len;
557  const byte* field;
558 
559  if (rec_get_deleted_flag(rec, 0)) {
560  return("delete-marked record in SYS_FOREIGN_COLS");
561  }
562 
563  if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_FOREIGN_COLS) {
564  return("wrong number of columns in SYS_FOREIGN_COLS record");
565  }
566 
567  field = rec_get_nth_field_old(
568  rec, DICT_FLD__SYS_FOREIGN_COLS__ID, &len);
569  if (len == 0 || len == UNIV_SQL_NULL) {
570 err_len:
571  return("incorrect column length in SYS_FOREIGN_COLS");
572  }
573  *name = mem_heap_strdupl(heap, (char*) field, len);
574 
575  field = rec_get_nth_field_old(
576  rec, DICT_FLD__SYS_FOREIGN_COLS__POS, &len);
577  if (len != 4) {
578  goto err_len;
579  }
580  *pos = mach_read_from_4(field);
581 
583  rec, DICT_FLD__SYS_FOREIGN_COLS__DB_TRX_ID, &len);
584  if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
585  goto err_len;
586  }
588  rec, DICT_FLD__SYS_FOREIGN_COLS__DB_ROLL_PTR, &len);
589  if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
590  goto err_len;
591  }
592 
593  field = rec_get_nth_field_old(
594  rec, DICT_FLD__SYS_FOREIGN_COLS__FOR_COL_NAME, &len);
595  if (len == 0 || len == UNIV_SQL_NULL) {
596  goto err_len;
597  }
598  *for_col_name = mem_heap_strdupl(heap, (char*) field, len);
599 
600  field = rec_get_nth_field_old(
601  rec, DICT_FLD__SYS_FOREIGN_COLS__REF_COL_NAME, &len);
602  if (len == 0 || len == UNIV_SQL_NULL) {
603  goto err_len;
604  }
605  *ref_col_name = mem_heap_strdupl(heap, (char*) field, len);
606 
607  return(NULL);
608 }
609 
610 /********************************************************************/
614 UNIV_INTERN
615 const char*
617 /*=========================*/
618  mem_heap_t* heap,
619  const rec_t* rec,
620  ulint* space,
621  const char** name,
622  ulint* flags)
623 {
624  ulint len;
625  const byte* field;
626 
627  /* Initialize the output values */
628  *space = ULINT_UNDEFINED;
629  *name = NULL;
630  *flags = ULINT_UNDEFINED;
631 
632  if (rec_get_deleted_flag(rec, 0)) {
633  return("delete-marked record in SYS_TABLESPACES");
634  }
635 
636  if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_TABLESPACES) {
637  return("wrong number of columns in SYS_TABLESPACES record");
638  }
639 
640  field = rec_get_nth_field_old(
641  rec, DICT_FLD__SYS_TABLESPACES__SPACE, &len);
642  if (len != DICT_FLD_LEN_SPACE) {
643 err_len:
644  return("incorrect column length in SYS_TABLESPACES");
645  }
646  *space = mach_read_from_4(field);
647 
649  rec, DICT_FLD__SYS_TABLESPACES__DB_TRX_ID, &len);
650  if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
651  goto err_len;
652  }
653 
655  rec, DICT_FLD__SYS_TABLESPACES__DB_ROLL_PTR, &len);
656  if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
657  goto err_len;
658  }
659 
660  field = rec_get_nth_field_old(
661  rec, DICT_FLD__SYS_TABLESPACES__NAME, &len);
662  if (len == 0 || len == UNIV_SQL_NULL) {
663  goto err_len;
664  }
665  *name = mem_heap_strdupl(heap, (char*) field, len);
666 
667  field = rec_get_nth_field_old(
668  rec, DICT_FLD__SYS_TABLESPACES__FLAGS, &len);
669  if (len != DICT_FLD_LEN_FLAGS) {
670  goto err_len;
671  }
672  *flags = mach_read_from_4(field);
673 
674  return(NULL);
675 }
676 
677 /********************************************************************/
681 UNIV_INTERN
682 const char*
684 /*=======================*/
685  mem_heap_t* heap,
686  const rec_t* rec,
687  ulint* space,
688  const char** path)
689 {
690  ulint len;
691  const byte* field;
692 
693  if (rec_get_deleted_flag(rec, 0)) {
694  return("delete-marked record in SYS_DATAFILES");
695  }
696 
697  if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_DATAFILES) {
698  return("wrong number of columns in SYS_DATAFILES record");
699  }
700 
701  field = rec_get_nth_field_old(
702  rec, DICT_FLD__SYS_DATAFILES__SPACE, &len);
703  if (len != DICT_FLD_LEN_SPACE) {
704 err_len:
705  return("incorrect column length in SYS_DATAFILES");
706  }
707  *space = mach_read_from_4(field);
708 
710  rec, DICT_FLD__SYS_DATAFILES__DB_TRX_ID, &len);
711  if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
712  goto err_len;
713  }
714 
716  rec, DICT_FLD__SYS_DATAFILES__DB_ROLL_PTR, &len);
717  if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
718  goto err_len;
719  }
720 
721  field = rec_get_nth_field_old(
722  rec, DICT_FLD__SYS_DATAFILES__PATH, &len);
723  if (len == 0 || len == UNIV_SQL_NULL) {
724  goto err_len;
725  }
726  *path = mem_heap_strdupl(heap, (char*) field, len);
727 
728  return(NULL);
729 }
730 
731 /********************************************************************/
734 static
735 ulint
736 dict_sys_tables_get_flags(
737 /*======================*/
738  const rec_t* rec)
739 {
740  const byte* field;
741  ulint len;
742  ulint type;
743  ulint n_cols;
744 
745  /* read the 4 byte flags from the TYPE field */
746  field = rec_get_nth_field_old(
747  rec, DICT_FLD__SYS_TABLES__TYPE, &len);
748  ut_a(len == 4);
749  type = mach_read_from_4(field);
750 
751  /* The low order bit of SYS_TABLES.TYPE is always set to 1. But in
752  dict_table_t::flags the low order bit is used to determine if the
753  row format is Redundant or Compact when the format is Antelope.
754  Read the 4 byte N_COLS field and look at the high order bit. It
755  should be set for COMPACT and later. It should not be set for
756  REDUNDANT. */
757  field = rec_get_nth_field_old(
758  rec, DICT_FLD__SYS_TABLES__N_COLS, &len);
759  ut_a(len == 4);
760  n_cols = mach_read_from_4(field);
761 
762  /* This validation function also combines the DICT_N_COLS_COMPACT
763  flag in n_cols into the type field to effectively make it a
764  dict_table_t::flags. */
765 
766  if (ULINT_UNDEFINED == dict_sys_tables_type_validate(type, n_cols)) {
767  return(ULINT_UNDEFINED);
768  }
769 
770  return(dict_sys_tables_type_to_tf(type, n_cols));
771 }
772 
773 /********************************************************************/
784 UNIV_INTERN
785 char*
787 /*================*/
788  ulint space,
789  const char* name)
790 {
791  mtr_t mtr;
792  dict_table_t* sys_datafiles;
793  dict_index_t* sys_index;
794  dtuple_t* tuple;
795  dfield_t* dfield;
796  byte* buf;
798  const rec_t* rec;
799  const byte* field;
800  ulint len;
801  char* dict_filepath = NULL;
803 
804  ut_ad(mutex_own(&(dict_sys->mutex)));
805 
806  mtr_start(&mtr);
807 
808  sys_datafiles = dict_table_get_low("SYS_DATAFILES");
809  sys_index = UT_LIST_GET_FIRST(sys_datafiles->indexes);
810  ut_ad(!dict_table_is_comp(sys_datafiles));
811  ut_ad(name_of_col_is(sys_datafiles, sys_index,
812  DICT_FLD__SYS_DATAFILES__SPACE, "SPACE"));
813  ut_ad(name_of_col_is(sys_datafiles, sys_index,
814  DICT_FLD__SYS_DATAFILES__PATH, "PATH"));
815 
816  tuple = dtuple_create(heap, 1);
817  dfield = dtuple_get_nth_field(tuple, DICT_FLD__SYS_DATAFILES__SPACE);
818 
819  buf = static_cast<byte*>(mem_heap_alloc(heap, 4));
820  mach_write_to_4(buf, space);
821 
822  dfield_set_data(dfield, buf, 4);
823  dict_index_copy_types(tuple, sys_index, 1);
824 
825  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
826  BTR_SEARCH_LEAF, &pcur, &mtr);
827 
828  rec = btr_pcur_get_rec(&pcur);
829 
830  /* If the file-per-table tablespace was created with
831  an earlier version of InnoDB, then this record is not
832  in SYS_DATAFILES. But a link file still might exist. */
833 
834  if (btr_pcur_is_on_user_rec(&pcur)) {
835  /* A record for this space ID was found. */
836  field = rec_get_nth_field_old(
837  rec, DICT_FLD__SYS_DATAFILES__PATH, &len);
838  ut_a(len > 0 || len == UNIV_SQL_NULL);
839  ut_a(len < OS_FILE_MAX_PATH);
840  dict_filepath = mem_strdupl((char*) field, len);
841  ut_a(dict_filepath);
842  }
843 
844  btr_pcur_close(&pcur);
845  mtr_commit(&mtr);
846  mem_heap_free(heap);
847 
848  return(dict_filepath);
849 }
850 
851 /********************************************************************/
854 UNIV_INTERN
855 dberr_t
857 /*=================*/
858  ulint space_id,
859  const char* filepath)
860 {
861  dberr_t err = DB_SUCCESS;
862  trx_t* trx;
863 
864 #ifdef UNIV_SYNC_DEBUG
865  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
866 #endif /* UNIV_SYNC_DEBUG */
867  ut_ad(mutex_own(&(dict_sys->mutex)));
868 
870  trx->op_info = "update filepath";
871  trx->dict_operation_lock_mode = RW_X_LATCH;
872  trx_start_for_ddl(trx, TRX_DICT_OP_INDEX);
873 
874  pars_info_t* info = pars_info_create();
875 
876  pars_info_add_int4_literal(info, "space", space_id);
877  pars_info_add_str_literal(info, "path", filepath);
878 
879  err = que_eval_sql(info,
880  "PROCEDURE UPDATE_FILEPATH () IS\n"
881  "BEGIN\n"
882  "UPDATE SYS_DATAFILES"
883  " SET PATH = :path\n"
884  " WHERE SPACE = :space;\n"
885  "END;\n", FALSE, trx);
886 
888  trx->dict_operation_lock_mode = 0;
890 
891  if (err == DB_SUCCESS) {
892  /* We just updated SYS_DATAFILES due to the contents in
893  a link file. Make a note that we did this. */
894  ib_logf(IB_LOG_LEVEL_INFO,
895  "The InnoDB data dictionary table SYS_DATAFILES "
896  "for tablespace ID %lu was updated to use file %s.",
897  (ulong) space_id, filepath);
898  } else {
899  ib_logf(IB_LOG_LEVEL_WARN,
900  "Problem updating InnoDB data dictionary table "
901  "SYS_DATAFILES for tablespace ID %lu to file %s.",
902  (ulong) space_id, filepath);
903  }
904 
905  return(err);
906 }
907 
908 /********************************************************************/
911 UNIV_INTERN
912 dberr_t
914 /*================================*/
915  ulint space,
916  const char* name,
917  const char* filepath,
918  ulint fsp_flags)
919 {
920  dberr_t err = DB_SUCCESS;
921  trx_t* trx;
922 
923 #ifdef UNIV_SYNC_DEBUG
924  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
925 #endif /* UNIV_SYNC_DEBUG */
926  ut_ad(mutex_own(&(dict_sys->mutex)));
927  ut_ad(filepath);
928 
930  trx->op_info = "insert tablespace and filepath";
931  trx->dict_operation_lock_mode = RW_X_LATCH;
932  trx_start_for_ddl(trx, TRX_DICT_OP_INDEX);
933 
934  /* A record for this space ID was not found in
935  SYS_DATAFILES. Assume the record is also missing in
936  SYS_TABLESPACES. Insert records onto them both. */
938  space, name, fsp_flags, filepath, trx, false);
939 
941  trx->dict_operation_lock_mode = 0;
943 
944  return(err);
945 }
946 
947 /********************************************************************/
959 UNIV_INTERN
960 void
962 /*====================================*/
963  dict_check_t dict_check)
964 {
965  dict_table_t* sys_tables;
966  dict_index_t* sys_index;
968  const rec_t* rec;
969  ulint max_space_id;
970  mtr_t mtr;
971 
972  rw_lock_x_lock(&dict_operation_lock);
973  mutex_enter(&(dict_sys->mutex));
974 
975  mtr_start(&mtr);
976 
977  sys_tables = dict_table_get_low("SYS_TABLES");
978  sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
979  ut_ad(!dict_table_is_comp(sys_tables));
980 
981  max_space_id = mtr_read_ulint(dict_hdr_get(&mtr)
982  + DICT_HDR_MAX_SPACE_ID,
983  MLOG_4BYTES, &mtr);
984  fil_set_max_space_id_if_bigger(max_space_id);
985 
986  btr_pcur_open_at_index_side(true, sys_index, BTR_SEARCH_LEAF, &pcur,
987  true, 0, &mtr);
988 loop:
989  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
990 
991  rec = btr_pcur_get_rec(&pcur);
992 
993  if (!btr_pcur_is_on_user_rec(&pcur)) {
994  /* end of index */
995 
996  btr_pcur_close(&pcur);
997  mtr_commit(&mtr);
998 
999  /* We must make the tablespace cache aware of the biggest
1000  known space id */
1001 
1002  /* printf("Biggest space id in data dictionary %lu\n",
1003  max_space_id); */
1004  fil_set_max_space_id_if_bigger(max_space_id);
1005 
1006  mutex_exit(&(dict_sys->mutex));
1007  rw_lock_x_unlock(&dict_operation_lock);
1008 
1009  return;
1010  }
1011 
1012  if (!rec_get_deleted_flag(rec, 0)) {
1013 
1014  /* We found one */
1015  const byte* field;
1016  ulint len;
1017  ulint space_id;
1018  ulint flags;
1019  char* name;
1020 
1021  field = rec_get_nth_field_old(
1022  rec, DICT_FLD__SYS_TABLES__NAME, &len);
1023 
1024  name = mem_strdupl((char*) field, len);
1025 
1026  char table_name[MAX_FULL_NAME_LEN + 1];
1027 
1029  table_name, sizeof(table_name), name, FALSE);
1030 
1031  flags = dict_sys_tables_get_flags(rec);
1032  if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
1033  /* Read again the 4 bytes from rec. */
1034  field = rec_get_nth_field_old(
1035  rec, DICT_FLD__SYS_TABLES__TYPE, &len);
1036  ut_ad(len == 4); /* this was checked earlier */
1037  flags = mach_read_from_4(field);
1038 
1039  ib_logf(IB_LOG_LEVEL_ERROR,
1040  "Table '%s' in InnoDB data dictionary"
1041  " has unknown type %lx", table_name, flags);
1042  mem_free(name);
1043  goto loop;
1044  }
1045 
1046  field = rec_get_nth_field_old(
1047  rec, DICT_FLD__SYS_TABLES__SPACE, &len);
1048  ut_a(len == 4);
1049 
1050  space_id = mach_read_from_4(field);
1051 
1052  btr_pcur_store_position(&pcur, &mtr);
1053 
1054  mtr_commit(&mtr);
1055 
1056  /* For tables created with old versions of InnoDB,
1057  SYS_TABLES.MIX_LEN may contain garbage. Such tables
1058  would always be in ROW_FORMAT=REDUNDANT. Pretend that
1059  all such tables are non-temporary. That is, do not
1060  suppress error printouts about temporary or discarded
1061  tablespaces not being found. */
1062 
1063  field = rec_get_nth_field_old(
1064  rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
1065 
1066  bool is_temp = false;
1067  bool discarded = false;
1068  ib_uint32_t flags2 = mach_read_from_4(field);
1069 
1070  /* Check that the tablespace (the .ibd file) really
1071  exists; print a warning to the .err log if not.
1072  Do not print warnings for temporary tables or for
1073  tablespaces that have been discarded. */
1074 
1075  field = rec_get_nth_field_old(
1076  rec, DICT_FLD__SYS_TABLES__N_COLS, &len);
1077 
1078  /* MIX_LEN valid only for ROW_FORMAT > REDUNDANT. */
1079  if (mach_read_from_4(field) & DICT_N_COLS_COMPACT) {
1080 
1081  is_temp = !!(flags2 & DICT_TF2_TEMPORARY);
1082  discarded = !!(flags2 & DICT_TF2_DISCARDED);
1083  }
1084 
1085  if (space_id == 0) {
1086  /* The system tablespace always exists. */
1087  ut_ad(!discarded);
1088  goto next_tablespace;
1089  }
1090 
1091  switch (dict_check) {
1092  case DICT_CHECK_ALL_LOADED:
1093  /* All tablespaces should have been found in
1094  fil_load_single_table_tablespaces(). */
1095 
1097  space_id, name, TRUE, !(is_temp || discarded),
1098  false, NULL, 0);
1099  break;
1100 
1102  /* Some tablespaces may have been opened in
1103  trx_resurrect_table_locks(). */
1105  space_id, name, FALSE, FALSE,
1106  false, NULL, 0)) {
1107  break;
1108  }
1109  /* fall through */
1111  if (discarded) {
1112  ib_logf(IB_LOG_LEVEL_INFO,
1113  "DISCARD flag set for table '%s',"
1114  " ignored.",
1115  table_name);
1116  break;
1117  }
1118 
1119  /* It is a normal database startup: create the
1120  space object and check that the .ibd file exists.
1121  If the table uses a remote tablespace, look for the
1122  space_id in SYS_DATAFILES to find the filepath */
1123 
1124  /* Use the remote filepath if known. */
1125  char* filepath = NULL;
1126  if (DICT_TF_HAS_DATA_DIR(flags)) {
1127  filepath = dict_get_first_path(
1128  space_id, name);
1129  }
1130 
1131  /* We set the 2nd param (fix_dict = true)
1132  here because we already have an x-lock on
1133  dict_operation_lock and dict_sys->mutex. Besides,
1134  this is at startup and we are now single threaded.
1135  If the filepath is not known, it will need to
1136  be discovered. */
1138  false, srv_read_only_mode ? false : true,
1139  space_id, dict_tf_to_fsp_flags(flags),
1140  name, filepath);
1141 
1142  if (err != DB_SUCCESS) {
1143  ib_logf(IB_LOG_LEVEL_ERROR,
1144  "Tablespace open failed for '%s', "
1145  "ignored.", table_name);
1146  }
1147 
1148  if (filepath) {
1149  mem_free(filepath);
1150  }
1151 
1152  break;
1153  }
1154 
1155  if (space_id > max_space_id) {
1156  max_space_id = space_id;
1157  }
1158 
1159 next_tablespace:
1160  mem_free(name);
1161  mtr_start(&mtr);
1162 
1163  btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
1164  }
1165 
1166  goto loop;
1167 }
1168 
1169 /********************************************************************/
1173 UNIV_INTERN
1174 const char*
1176 /*=================*/
1177  dict_table_t* table,
1181  mem_heap_t* heap,
1183  dict_col_t* column,
1185  table_id_t* table_id,
1186  const char** col_name,
1187  const rec_t* rec)
1188 {
1189  char* name;
1190  const byte* field;
1191  ulint len;
1192  ulint mtype;
1193  ulint prtype;
1194  ulint col_len;
1195  ulint pos;
1196 
1197  ut_ad(table || column);
1198 
1199  if (rec_get_deleted_flag(rec, 0)) {
1200  return("delete-marked record in SYS_COLUMNS");
1201  }
1202 
1203  if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_COLUMNS) {
1204  return("wrong number of columns in SYS_COLUMNS record");
1205  }
1206 
1207  field = rec_get_nth_field_old(
1208  rec, DICT_FLD__SYS_COLUMNS__TABLE_ID, &len);
1209  if (len != 8) {
1210 err_len:
1211  return("incorrect column length in SYS_COLUMNS");
1212  }
1213 
1214  if (table_id) {
1215  *table_id = mach_read_from_8(field);
1216  } else if (table->id != mach_read_from_8(field)) {
1217  return("SYS_COLUMNS.TABLE_ID mismatch");
1218  }
1219 
1220  field = rec_get_nth_field_old(
1221  rec, DICT_FLD__SYS_COLUMNS__POS, &len);
1222  if (len != 4) {
1223 
1224  goto err_len;
1225  }
1226 
1227  pos = mach_read_from_4(field);
1228 
1229  if (table && table->n_def != pos) {
1230  return("SYS_COLUMNS.POS mismatch");
1231  }
1232 
1234  rec, DICT_FLD__SYS_COLUMNS__DB_TRX_ID, &len);
1235  if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
1236  goto err_len;
1237  }
1239  rec, DICT_FLD__SYS_COLUMNS__DB_ROLL_PTR, &len);
1240  if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
1241  goto err_len;
1242  }
1243 
1244  field = rec_get_nth_field_old(
1245  rec, DICT_FLD__SYS_COLUMNS__NAME, &len);
1246  if (len == 0 || len == UNIV_SQL_NULL) {
1247  goto err_len;
1248  }
1249 
1250  name = mem_heap_strdupl(heap, (const char*) field, len);
1251 
1252  if (col_name) {
1253  *col_name = name;
1254  }
1255 
1256  field = rec_get_nth_field_old(
1257  rec, DICT_FLD__SYS_COLUMNS__MTYPE, &len);
1258  if (len != 4) {
1259  goto err_len;
1260  }
1261 
1262  mtype = mach_read_from_4(field);
1263 
1264  field = rec_get_nth_field_old(
1265  rec, DICT_FLD__SYS_COLUMNS__PRTYPE, &len);
1266  if (len != 4) {
1267  goto err_len;
1268  }
1269  prtype = mach_read_from_4(field);
1270 
1271  if (dtype_get_charset_coll(prtype) == 0
1272  && dtype_is_string_type(mtype)) {
1273  /* The table was created with < 4.1.2. */
1274 
1275  if (dtype_is_binary_string_type(mtype, prtype)) {
1276  /* Use the binary collation for
1277  string columns of binary type. */
1278 
1279  prtype = dtype_form_prtype(
1280  prtype,
1281  DATA_MYSQL_BINARY_CHARSET_COLL);
1282  } else {
1283  /* Use the default charset for
1284  other than binary columns. */
1285 
1286  prtype = dtype_form_prtype(
1287  prtype,
1288  data_mysql_default_charset_coll);
1289  }
1290  }
1291 
1292  field = rec_get_nth_field_old(
1293  rec, DICT_FLD__SYS_COLUMNS__LEN, &len);
1294  if (len != 4) {
1295  goto err_len;
1296  }
1297  col_len = mach_read_from_4(field);
1298  field = rec_get_nth_field_old(
1299  rec, DICT_FLD__SYS_COLUMNS__PREC, &len);
1300  if (len != 4) {
1301  goto err_len;
1302  }
1303 
1304  if (!column) {
1305  dict_mem_table_add_col(table, heap, name, mtype,
1306  prtype, col_len);
1307  } else {
1308  dict_mem_fill_column_struct(column, pos, mtype,
1309  prtype, col_len);
1310  }
1311 
1312  return(NULL);
1313 }
1314 
1315 /********************************************************************/
1317 static
1318 void
1319 dict_load_columns(
1320 /*==============*/
1321  dict_table_t* table,
1322  mem_heap_t* heap)
1324 {
1325  dict_table_t* sys_columns;
1326  dict_index_t* sys_index;
1327  btr_pcur_t pcur;
1328  dtuple_t* tuple;
1329  dfield_t* dfield;
1330  const rec_t* rec;
1331  byte* buf;
1332  ulint i;
1333  mtr_t mtr;
1334 
1335  ut_ad(mutex_own(&(dict_sys->mutex)));
1336 
1337  mtr_start(&mtr);
1338 
1339  sys_columns = dict_table_get_low("SYS_COLUMNS");
1340  sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
1341  ut_ad(!dict_table_is_comp(sys_columns));
1342 
1343  ut_ad(name_of_col_is(sys_columns, sys_index,
1344  DICT_FLD__SYS_COLUMNS__NAME, "NAME"));
1345  ut_ad(name_of_col_is(sys_columns, sys_index,
1346  DICT_FLD__SYS_COLUMNS__PREC, "PREC"));
1347 
1348  tuple = dtuple_create(heap, 1);
1349  dfield = dtuple_get_nth_field(tuple, 0);
1350 
1351  buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
1352  mach_write_to_8(buf, table->id);
1353 
1354  dfield_set_data(dfield, buf, 8);
1355  dict_index_copy_types(tuple, sys_index, 1);
1356 
1357  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1358  BTR_SEARCH_LEAF, &pcur, &mtr);
1359  for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1360  const char* err_msg;
1361  const char* name;
1362 
1363  rec = btr_pcur_get_rec(&pcur);
1364 
1365  ut_a(btr_pcur_is_on_user_rec(&pcur));
1366 
1367  err_msg = dict_load_column_low(table, heap, NULL, NULL,
1368  &name, rec);
1369 
1370  if (err_msg) {
1371  fprintf(stderr, "InnoDB: %s\n", err_msg);
1372  ut_error;
1373  }
1374 
1375  /* Note: Currently we have one DOC_ID column that is
1376  shared by all FTS indexes on a table. */
1377  if (innobase_strcasecmp(name,
1378  FTS_DOC_ID_COL_NAME) == 0) {
1379  dict_col_t* col;
1380  /* As part of normal loading of tables the
1381  table->flag is not set for tables with FTS
1382  till after the FTS indexes are loaded. So we
1383  create the fts_t instance here if there isn't
1384  one already created.
1385 
1386  This case does not arise for table create as
1387  the flag is set before the table is created. */
1388  if (table->fts == NULL) {
1389  table->fts = fts_create(table);
1390  fts_optimize_add_table(table);
1391  }
1392 
1393  ut_a(table->fts->doc_col == ULINT_UNDEFINED);
1394 
1395  col = dict_table_get_nth_col(table, i);
1396 
1397  ut_ad(col->len == sizeof(doc_id_t));
1398 
1399  if (col->prtype & DATA_FTS_DOC_ID) {
1400  DICT_TF2_FLAG_SET(
1401  table, DICT_TF2_FTS_HAS_DOC_ID);
1402  DICT_TF2_FLAG_UNSET(
1403  table, DICT_TF2_FTS_ADD_DOC_ID);
1404  }
1405 
1406  table->fts->doc_col = i;
1407  }
1408 
1409  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1410  }
1411 
1412  btr_pcur_close(&pcur);
1413  mtr_commit(&mtr);
1414 }
1415 
1417 static const char* dict_load_field_del = "delete-marked record in SYS_FIELDS";
1418 
1419 /********************************************************************/
1423 UNIV_INTERN
1424 const char*
1426 /*================*/
1427  byte* index_id,
1430  dict_index_t* index,
1434  dict_field_t* sys_field,
1436  ulint* pos,
1437  byte* last_index_id,
1438  mem_heap_t* heap,
1440  const rec_t* rec)
1441 {
1442  const byte* field;
1443  ulint len;
1444  ulint pos_and_prefix_len;
1445  ulint prefix_len;
1446  ibool first_field;
1447  ulint position;
1448 
1449  /* Either index or sys_field is supplied, not both */
1450  ut_a((!index) || (!sys_field));
1451 
1452  if (rec_get_deleted_flag(rec, 0)) {
1453  return(dict_load_field_del);
1454  }
1455 
1456  if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_FIELDS) {
1457  return("wrong number of columns in SYS_FIELDS record");
1458  }
1459 
1460  field = rec_get_nth_field_old(
1461  rec, DICT_FLD__SYS_FIELDS__INDEX_ID, &len);
1462  if (len != 8) {
1463 err_len:
1464  return("incorrect column length in SYS_FIELDS");
1465  }
1466 
1467  if (!index) {
1468  ut_a(last_index_id);
1469  memcpy(index_id, (const char*) field, 8);
1470  first_field = memcmp(index_id, last_index_id, 8);
1471  } else {
1472  first_field = (index->n_def == 0);
1473  if (memcmp(field, index_id, 8)) {
1474  return("SYS_FIELDS.INDEX_ID mismatch");
1475  }
1476  }
1477 
1478  /* The next field stores the field position in the index and a
1479  possible column prefix length if the index field does not
1480  contain the whole column. The storage format is like this: if
1481  there is at least one prefix field in the index, then the HIGH
1482  2 bytes contain the field number (index->n_def) and the low 2
1483  bytes the prefix length for the field. Otherwise the field
1484  number (index->n_def) is contained in the 2 LOW bytes. */
1485 
1486  field = rec_get_nth_field_old(
1487  rec, DICT_FLD__SYS_FIELDS__POS, &len);
1488  if (len != 4) {
1489  goto err_len;
1490  }
1491 
1492  pos_and_prefix_len = mach_read_from_4(field);
1493 
1494  if (index && UNIV_UNLIKELY
1495  ((pos_and_prefix_len & 0xFFFFUL) != index->n_def
1496  && (pos_and_prefix_len >> 16 & 0xFFFF) != index->n_def)) {
1497  return("SYS_FIELDS.POS mismatch");
1498  }
1499 
1500  if (first_field || pos_and_prefix_len > 0xFFFFUL) {
1501  prefix_len = pos_and_prefix_len & 0xFFFFUL;
1502  position = (pos_and_prefix_len & 0xFFFF0000UL) >> 16;
1503  } else {
1504  prefix_len = 0;
1505  position = pos_and_prefix_len & 0xFFFFUL;
1506  }
1507 
1509  rec, DICT_FLD__SYS_FIELDS__DB_TRX_ID, &len);
1510  if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
1511  goto err_len;
1512  }
1514  rec, DICT_FLD__SYS_FIELDS__DB_ROLL_PTR, &len);
1515  if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
1516  goto err_len;
1517  }
1518 
1519  field = rec_get_nth_field_old(
1520  rec, DICT_FLD__SYS_FIELDS__COL_NAME, &len);
1521  if (len == 0 || len == UNIV_SQL_NULL) {
1522  goto err_len;
1523  }
1524 
1525  if (index) {
1527  index, mem_heap_strdupl(heap, (const char*) field, len),
1528  prefix_len);
1529  } else {
1530  ut_a(sys_field);
1531  ut_a(pos);
1532 
1533  sys_field->name = mem_heap_strdupl(
1534  heap, (const char*) field, len);
1535  sys_field->prefix_len = prefix_len;
1536  *pos = position;
1537  }
1538 
1539  return(NULL);
1540 }
1541 
1542 /********************************************************************/
1545 static
1546 ulint
1547 dict_load_fields(
1548 /*=============*/
1549  dict_index_t* index,
1550  mem_heap_t* heap)
1551 {
1552  dict_table_t* sys_fields;
1553  dict_index_t* sys_index;
1554  btr_pcur_t pcur;
1555  dtuple_t* tuple;
1556  dfield_t* dfield;
1557  const rec_t* rec;
1558  byte* buf;
1559  ulint i;
1560  mtr_t mtr;
1561  dberr_t error;
1562 
1563  ut_ad(mutex_own(&(dict_sys->mutex)));
1564 
1565  mtr_start(&mtr);
1566 
1567  sys_fields = dict_table_get_low("SYS_FIELDS");
1568  sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
1569  ut_ad(!dict_table_is_comp(sys_fields));
1570  ut_ad(name_of_col_is(sys_fields, sys_index,
1571  DICT_FLD__SYS_FIELDS__COL_NAME, "COL_NAME"));
1572 
1573  tuple = dtuple_create(heap, 1);
1574  dfield = dtuple_get_nth_field(tuple, 0);
1575 
1576  buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
1577  mach_write_to_8(buf, index->id);
1578 
1579  dfield_set_data(dfield, buf, 8);
1580  dict_index_copy_types(tuple, sys_index, 1);
1581 
1582  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1583  BTR_SEARCH_LEAF, &pcur, &mtr);
1584  for (i = 0; i < index->n_fields; i++) {
1585  const char* err_msg;
1586 
1587  rec = btr_pcur_get_rec(&pcur);
1588 
1589  ut_a(btr_pcur_is_on_user_rec(&pcur));
1590 
1591  err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL,
1592  heap, rec);
1593 
1594  if (err_msg == dict_load_field_del) {
1595  /* There could be delete marked records in
1596  SYS_FIELDS because SYS_FIELDS.INDEX_ID can be
1597  updated by ALTER TABLE ADD INDEX. */
1598 
1599  goto next_rec;
1600  } else if (err_msg) {
1601  fprintf(stderr, "InnoDB: %s\n", err_msg);
1602  error = DB_CORRUPTION;
1603  goto func_exit;
1604  }
1605 next_rec:
1606  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1607  }
1608 
1609  error = DB_SUCCESS;
1610 func_exit:
1611  btr_pcur_close(&pcur);
1612  mtr_commit(&mtr);
1613  return(error);
1614 }
1615 
1617 static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES";
1619 static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch";
1620 
1621 /********************************************************************/
1627 UNIV_INTERN
1628 const char*
1630 /*================*/
1631  byte* table_id,
1634  const char* table_name,
1635  mem_heap_t* heap,
1636  const rec_t* rec,
1637  ibool allocate,
1640  dict_index_t** index)
1641 {
1642  const byte* field;
1643  ulint len;
1644  ulint name_len;
1645  char* name_buf;
1646  index_id_t id;
1647  ulint n_fields;
1648  ulint type;
1649  ulint space;
1650 
1651  if (allocate) {
1652  /* If allocate=TRUE, no dict_index_t will
1653  be supplied. Initialize "*index" to NULL */
1654  *index = NULL;
1655  }
1656 
1657  if (rec_get_deleted_flag(rec, 0)) {
1658  return(dict_load_index_del);
1659  }
1660 
1661  if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_INDEXES) {
1662  return("wrong number of columns in SYS_INDEXES record");
1663  }
1664 
1665  field = rec_get_nth_field_old(
1666  rec, DICT_FLD__SYS_INDEXES__TABLE_ID, &len);
1667  if (len != 8) {
1668 err_len:
1669  return("incorrect column length in SYS_INDEXES");
1670  }
1671 
1672  if (!allocate) {
1673  /* We are reading a SYS_INDEXES record. Copy the table_id */
1674  memcpy(table_id, (const char*) field, 8);
1675  } else if (memcmp(field, table_id, 8)) {
1676  /* Caller supplied table_id, verify it is the same
1677  id as on the index record */
1678  return(dict_load_index_id_err);
1679  }
1680 
1681  field = rec_get_nth_field_old(
1682  rec, DICT_FLD__SYS_INDEXES__ID, &len);
1683  if (len != 8) {
1684  goto err_len;
1685  }
1686 
1687  id = mach_read_from_8(field);
1688 
1690  rec, DICT_FLD__SYS_INDEXES__DB_TRX_ID, &len);
1691  if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
1692  goto err_len;
1693  }
1695  rec, DICT_FLD__SYS_INDEXES__DB_ROLL_PTR, &len);
1696  if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
1697  goto err_len;
1698  }
1699 
1700  field = rec_get_nth_field_old(
1701  rec, DICT_FLD__SYS_INDEXES__NAME, &name_len);
1702  if (name_len == UNIV_SQL_NULL) {
1703  goto err_len;
1704  }
1705 
1706  name_buf = mem_heap_strdupl(heap, (const char*) field,
1707  name_len);
1708 
1709  field = rec_get_nth_field_old(
1710  rec, DICT_FLD__SYS_INDEXES__N_FIELDS, &len);
1711  if (len != 4) {
1712  goto err_len;
1713  }
1714  n_fields = mach_read_from_4(field);
1715 
1716  field = rec_get_nth_field_old(
1717  rec, DICT_FLD__SYS_INDEXES__TYPE, &len);
1718  if (len != 4) {
1719  goto err_len;
1720  }
1721  type = mach_read_from_4(field);
1722  if (type & (~0 << DICT_IT_BITS)) {
1723  return("unknown SYS_INDEXES.TYPE bits");
1724  }
1725 
1726  field = rec_get_nth_field_old(
1727  rec, DICT_FLD__SYS_INDEXES__SPACE, &len);
1728  if (len != 4) {
1729  goto err_len;
1730  }
1731  space = mach_read_from_4(field);
1732 
1733  field = rec_get_nth_field_old(
1734  rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
1735  if (len != 4) {
1736  goto err_len;
1737  }
1738 
1739  if (allocate) {
1740  *index = dict_mem_index_create(table_name, name_buf,
1741  space, type, n_fields);
1742  } else {
1743  ut_a(*index);
1744 
1745  dict_mem_fill_index_struct(*index, NULL, NULL, name_buf,
1746  space, type, n_fields);
1747  }
1748 
1749  (*index)->id = id;
1750  (*index)->page = mach_read_from_4(field);
1751  ut_ad((*index)->page);
1752 
1753  return(NULL);
1754 }
1755 
1756 /********************************************************************/
1761 static __attribute__((nonnull))
1762 dberr_t
1763 dict_load_indexes(
1764 /*==============*/
1765  dict_table_t* table,
1766  mem_heap_t* heap,
1767  dict_err_ignore_t ignore_err)
1770 {
1771  dict_table_t* sys_indexes;
1772  dict_index_t* sys_index;
1773  btr_pcur_t pcur;
1774  dtuple_t* tuple;
1775  dfield_t* dfield;
1776  const rec_t* rec;
1777  byte* buf;
1778  mtr_t mtr;
1779  dberr_t error = DB_SUCCESS;
1780 
1781  ut_ad(mutex_own(&(dict_sys->mutex)));
1782 
1783  mtr_start(&mtr);
1784 
1785  sys_indexes = dict_table_get_low("SYS_INDEXES");
1786  sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
1787  ut_ad(!dict_table_is_comp(sys_indexes));
1788  ut_ad(name_of_col_is(sys_indexes, sys_index,
1789  DICT_FLD__SYS_INDEXES__NAME, "NAME"));
1790  ut_ad(name_of_col_is(sys_indexes, sys_index,
1791  DICT_FLD__SYS_INDEXES__PAGE_NO, "PAGE_NO"));
1792 
1793  tuple = dtuple_create(heap, 1);
1794  dfield = dtuple_get_nth_field(tuple, 0);
1795 
1796  buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
1797  mach_write_to_8(buf, table->id);
1798 
1799  dfield_set_data(dfield, buf, 8);
1800  dict_index_copy_types(tuple, sys_index, 1);
1801 
1802  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1803  BTR_SEARCH_LEAF, &pcur, &mtr);
1804  for (;;) {
1805  dict_index_t* index = NULL;
1806  const char* err_msg;
1807 
1808  if (!btr_pcur_is_on_user_rec(&pcur)) {
1809 
1810  /* We should allow the table to open even
1811  without index when DICT_ERR_IGNORE_CORRUPT is set.
1812  DICT_ERR_IGNORE_CORRUPT is currently only set
1813  for drop table */
1814  if (dict_table_get_first_index(table) == NULL
1815  && !(ignore_err & DICT_ERR_IGNORE_CORRUPT)) {
1816  ib_logf(IB_LOG_LEVEL_WARN,
1817  "Cannot load table %s "
1818  "because it has no indexes in "
1819  "InnoDB internal data dictionary.",
1820  table->name);
1821  error = DB_CORRUPTION;
1822  goto func_exit;
1823  }
1824 
1825  break;
1826  }
1827 
1828  rec = btr_pcur_get_rec(&pcur);
1829 
1830  if ((ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)
1831  && rec_get_n_fields_old(rec)
1832  == DICT_NUM_FIELDS__SYS_INDEXES) {
1833  const byte* field;
1834  ulint len;
1835  field = rec_get_nth_field_old(
1836  rec, DICT_FLD__SYS_INDEXES__NAME, &len);
1837 
1838  if (len != UNIV_SQL_NULL
1839  && char(*field) == char(TEMP_INDEX_PREFIX)) {
1840  /* Skip indexes whose name starts with
1841  TEMP_INDEX_PREFIX, because they will
1842  be dropped during crash recovery. */
1843  goto next_rec;
1844  }
1845  }
1846 
1847  err_msg = dict_load_index_low(buf, table->name, heap, rec,
1848  TRUE, &index);
1849  ut_ad((index == NULL && err_msg != NULL)
1850  || (index != NULL && err_msg == NULL));
1851 
1852  if (err_msg == dict_load_index_id_err) {
1853  /* TABLE_ID mismatch means that we have
1854  run out of index definitions for the table. */
1855 
1856  if (dict_table_get_first_index(table) == NULL
1857  && !(ignore_err & DICT_ERR_IGNORE_CORRUPT)) {
1858  ib_logf(IB_LOG_LEVEL_WARN,
1859  "Failed to load the "
1860  "clustered index for table %s "
1861  "because of the following error: %s. "
1862  "Refusing to load the rest of the "
1863  "indexes (if any) and the whole table "
1864  "altogether.", table->name, err_msg);
1865  error = DB_CORRUPTION;
1866  goto func_exit;
1867  }
1868 
1869  break;
1870  } else if (err_msg == dict_load_index_del) {
1871  /* Skip delete-marked records. */
1872  goto next_rec;
1873  } else if (err_msg) {
1874  fprintf(stderr, "InnoDB: %s\n", err_msg);
1875  if (ignore_err & DICT_ERR_IGNORE_CORRUPT) {
1876  goto next_rec;
1877  }
1878  error = DB_CORRUPTION;
1879  goto func_exit;
1880  }
1881 
1882  ut_ad(index);
1883 
1884  /* Check whether the index is corrupted */
1885  if (dict_index_is_corrupted(index)) {
1886  ut_print_timestamp(stderr);
1887  fputs(" InnoDB: ", stderr);
1888  dict_index_name_print(stderr, NULL, index);
1889  fputs(" is corrupted\n", stderr);
1890 
1891  if (!srv_load_corrupted
1892  && !(ignore_err & DICT_ERR_IGNORE_CORRUPT)
1893  && dict_index_is_clust(index)) {
1894  dict_mem_index_free(index);
1895 
1896  error = DB_INDEX_CORRUPT;
1897  goto func_exit;
1898  } else {
1899  /* We will load the index if
1900  1) srv_load_corrupted is TRUE
1901  2) ignore_err is set with
1902  DICT_ERR_IGNORE_CORRUPT
1903  3) if the index corrupted is a secondary
1904  index */
1905  ut_print_timestamp(stderr);
1906  fputs(" InnoDB: load corrupted index ", stderr);
1907  dict_index_name_print(stderr, NULL, index);
1908  putc('\n', stderr);
1909  }
1910  }
1911 
1912  if (index->type & DICT_FTS
1913  && !DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS)) {
1914  /* This should have been created by now. */
1915  ut_a(table->fts != NULL);
1916  DICT_TF2_FLAG_SET(table, DICT_TF2_FTS);
1917  }
1918 
1919  /* We check for unsupported types first, so that the
1920  subsequent checks are relevant for the supported types. */
1921  if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE
1922  | DICT_CORRUPT | DICT_FTS)) {
1923  ib_logf(IB_LOG_LEVEL_ERROR,
1924  "Unknown type %lu of index %s of table %s",
1925  (ulong) index->type, index->name, table->name);
1926 
1927  error = DB_UNSUPPORTED;
1928  dict_mem_index_free(index);
1929  goto func_exit;
1930  } else if (index->page == FIL_NULL
1931  && !table->ibd_file_missing
1932  && (!(index->type & DICT_FTS))) {
1933 
1934  fprintf(stderr,
1935  "InnoDB: Error: trying to load index %s"
1936  " for table %s\n"
1937  "InnoDB: but the index tree has been freed!\n",
1938  index->name, table->name);
1939 
1940  if (ignore_err & DICT_ERR_IGNORE_INDEX_ROOT) {
1941  /* If caller can tolerate this error,
1942  we will continue to load the index and
1943  let caller deal with this error. However
1944  mark the index and table corrupted. We
1945  only need to mark such in the index
1946  dictionary cache for such metadata corruption,
1947  since we would always be able to set it
1948  when loading the dictionary cache */
1950  index, table);
1951 
1952  fprintf(stderr,
1953  "InnoDB: Index is corrupt but forcing"
1954  " load into data dictionary\n");
1955  } else {
1956 corrupted:
1957  dict_mem_index_free(index);
1958  error = DB_CORRUPTION;
1959  goto func_exit;
1960  }
1961  } else if (!dict_index_is_clust(index)
1962  && NULL == dict_table_get_first_index(table)) {
1963 
1964  fputs("InnoDB: Error: trying to load index ",
1965  stderr);
1966  ut_print_name(stderr, NULL, FALSE, index->name);
1967  fputs(" for table ", stderr);
1968  ut_print_name(stderr, NULL, TRUE, table->name);
1969  fputs("\nInnoDB: but the first index"
1970  " is not clustered!\n", stderr);
1971 
1972  goto corrupted;
1973  } else if (dict_is_sys_table(table->id)
1974  && (dict_index_is_clust(index)
1975  || ((table == dict_sys->sys_tables)
1976  && !strcmp("ID_IND", index->name)))) {
1977 
1978  /* The index was created in memory already at booting
1979  of the database server */
1980  dict_mem_index_free(index);
1981  } else {
1982  dict_load_fields(index, heap);
1983 
1984  error = dict_index_add_to_cache(
1985  table, index, index->page, FALSE);
1986 
1987  /* The data dictionary tables should never contain
1988  invalid index definitions. If we ignored this error
1989  and simply did not load this index definition, the
1990  .frm file would disagree with the index definitions
1991  inside InnoDB. */
1992  if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
1993 
1994  goto func_exit;
1995  }
1996  }
1997 next_rec:
1998  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1999  }
2000 
2001  /* If the table contains FTS indexes, populate table->fts->indexes */
2002  if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS)) {
2003  /* table->fts->indexes should have been created. */
2004  ut_a(table->fts->indexes != NULL);
2005  dict_table_get_all_fts_indexes(table, table->fts->indexes);
2006  }
2007 
2008 func_exit:
2009  btr_pcur_close(&pcur);
2010  mtr_commit(&mtr);
2011 
2012  return(error);
2013 }
2014 
2015 /********************************************************************/
2019 UNIV_INTERN
2020 const char*
2022 /*================*/
2023  const char* name,
2024  const rec_t* rec,
2025  dict_table_t** table)
2026 {
2027  const byte* field;
2028  ulint len;
2029  ulint space;
2030  ulint n_cols;
2031  ulint flags = 0;
2032  ulint flags2;
2033 
2034  if (rec_get_deleted_flag(rec, 0)) {
2035  return("delete-marked record in SYS_TABLES");
2036  }
2037 
2038  if (rec_get_n_fields_old(rec) != DICT_NUM_FIELDS__SYS_TABLES) {
2039  return("wrong number of columns in SYS_TABLES record");
2040  }
2041 
2043  rec, DICT_FLD__SYS_TABLES__NAME, &len);
2044  if (len == 0 || len == UNIV_SQL_NULL) {
2045 err_len:
2046  return("incorrect column length in SYS_TABLES");
2047  }
2049  rec, DICT_FLD__SYS_TABLES__DB_TRX_ID, &len);
2050  if (len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL) {
2051  goto err_len;
2052  }
2054  rec, DICT_FLD__SYS_TABLES__DB_ROLL_PTR, &len);
2055  if (len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL) {
2056  goto err_len;
2057  }
2058 
2059  rec_get_nth_field_offs_old(rec, DICT_FLD__SYS_TABLES__ID, &len);
2060  if (len != 8) {
2061  goto err_len;
2062  }
2063 
2064  field = rec_get_nth_field_old(
2065  rec, DICT_FLD__SYS_TABLES__N_COLS, &len);
2066  if (len != 4) {
2067  goto err_len;
2068  }
2069 
2070  n_cols = mach_read_from_4(field);
2071 
2072  rec_get_nth_field_offs_old(rec, DICT_FLD__SYS_TABLES__TYPE, &len);
2073  if (len != 4) {
2074  goto err_len;
2075  }
2076 
2078  rec, DICT_FLD__SYS_TABLES__MIX_ID, &len);
2079  if (len != 8) {
2080  goto err_len;
2081  }
2082 
2083  field = rec_get_nth_field_old(
2084  rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
2085  if (len != 4) {
2086  goto err_len;
2087  }
2088 
2089  /* MIX_LEN may hold additional flags in post-antelope file formats. */
2090  flags2 = mach_read_from_4(field);
2091 
2092  /* DICT_TF2_FTS will be set when indexes is being loaded */
2093  flags2 &= ~DICT_TF2_FTS;
2094 
2096  rec, DICT_FLD__SYS_TABLES__CLUSTER_ID, &len);
2097  if (len != UNIV_SQL_NULL) {
2098  goto err_len;
2099  }
2100 
2101  field = rec_get_nth_field_old(
2102  rec, DICT_FLD__SYS_TABLES__SPACE, &len);
2103  if (len != 4) {
2104  goto err_len;
2105  }
2106 
2107  space = mach_read_from_4(field);
2108 
2109  /* Check if the tablespace exists and has the right name */
2110  flags = dict_sys_tables_get_flags(rec);
2111 
2112  if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
2113  field = rec_get_nth_field_old(
2114  rec, DICT_FLD__SYS_TABLES__TYPE, &len);
2115  ut_ad(len == 4); /* this was checked earlier */
2116  flags = mach_read_from_4(field);
2117 
2118  ut_print_timestamp(stderr);
2119  fputs(" InnoDB: Error: table ", stderr);
2120  ut_print_filename(stderr, name);
2121  fprintf(stderr, "\n"
2122  "InnoDB: in InnoDB data dictionary"
2123  " has unknown type %lx.\n",
2124  (ulong) flags);
2125  return("incorrect flags in SYS_TABLES");
2126  }
2127 
2128  /* The high-order bit of N_COLS is the "compact format" flag.
2129  For tables in that format, MIX_LEN may hold additional flags. */
2130  if (n_cols & DICT_N_COLS_COMPACT) {
2131  ut_ad(flags & DICT_TF_COMPACT);
2132 
2133  if (flags2 & ~DICT_TF2_BIT_MASK) {
2134  ut_print_timestamp(stderr);
2135  fputs(" InnoDB: Warning: table ", stderr);
2136  ut_print_filename(stderr, name);
2137  fprintf(stderr, "\n"
2138  "InnoDB: in InnoDB data dictionary"
2139  " has unknown flags %lx.\n",
2140  (ulong) flags2);
2141 
2142  /* Clean it up and keep going */
2143  flags2 &= DICT_TF2_BIT_MASK;
2144  }
2145  } else {
2146  /* Do not trust the MIX_LEN field when the
2147  row format is Redundant. */
2148  flags2 = 0;
2149  }
2150 
2151  /* See if the tablespace is available. */
2152  *table = dict_mem_table_create(
2153  name, space, n_cols & ~DICT_N_COLS_COMPACT, flags, flags2);
2154 
2155  field = rec_get_nth_field_old(rec, DICT_FLD__SYS_TABLES__ID, &len);
2156  ut_ad(len == 8); /* this was checked earlier */
2157 
2158  (*table)->id = mach_read_from_8(field);
2159 
2160  (*table)->ibd_file_missing = FALSE;
2161 
2162  return(NULL);
2163 }
2164 
2165 /********************************************************************/
2171 UNIV_INTERN
2172 void
2174 /*====================*/
2175  dict_table_t* table,
2176  char* filepath)
2177 {
2178  ut_ad(mutex_own(&(dict_sys->mutex)));
2179  ut_a(DICT_TF_HAS_DATA_DIR(table->flags));
2180 
2181  ut_a(!table->data_dir_path);
2182  ut_a(filepath);
2183 
2184  /* Be sure this filepath is not the default filepath. */
2185  char* default_filepath = fil_make_ibd_name(table->name, false);
2186  if (strcmp(filepath, default_filepath)) {
2187  ulint pathlen = strlen(filepath);
2188  ut_a(pathlen < OS_FILE_MAX_PATH);
2189  ut_a(0 == strcmp(filepath + pathlen - 4, ".ibd"));
2190 
2191  table->data_dir_path = mem_heap_strdup(table->heap, filepath);
2193  } else {
2194  /* This does not change SYS_DATAFILES or SYS_TABLES
2195  or FSP_FLAGS on the header page of the tablespace,
2196  but it makes dict_table_t consistent */
2197  table->flags &= ~DICT_TF_MASK_DATA_DIR;
2198  }
2199  mem_free(default_filepath);
2200 }
2201 
2202 /*****************************************************************/
2205 UNIV_INTERN
2206 void
2208 /*============================*/
2209  dict_table_t* table,
2210  bool dict_mutex_own)
2212 {
2213  if (DICT_TF_HAS_DATA_DIR(table->flags)
2214  && (!table->data_dir_path)) {
2215  char* path = fil_space_get_first_path(table->space);
2216 
2217  if (!dict_mutex_own) {
2219  }
2220  if (!path) {
2221  path = dict_get_first_path(
2222  table->space, table->name);
2223  }
2224 
2225  if (path) {
2226  dict_save_data_dir_path(table, path);
2227  mem_free(path);
2228  }
2229 
2230  if (!dict_mutex_own) {
2232  }
2233  }
2234 }
2235 
2236 /********************************************************************/
2245 UNIV_INTERN
2246 dict_table_t*
2248 /*============*/
2249  const char* name,
2251  ibool cached,
2252  dict_err_ignore_t ignore_err)
2255 {
2256  dberr_t err;
2258  dict_table_t* sys_tables;
2259  btr_pcur_t pcur;
2260  dict_index_t* sys_index;
2261  dtuple_t* tuple;
2262  mem_heap_t* heap;
2263  dfield_t* dfield;
2264  const rec_t* rec;
2265  const byte* field;
2266  ulint len;
2267  char* filepath = NULL;
2268  const char* err_msg;
2269  mtr_t mtr;
2270 
2271  ut_ad(mutex_own(&(dict_sys->mutex)));
2272 
2273  heap = mem_heap_create(32000);
2274 
2275  mtr_start(&mtr);
2276 
2277  sys_tables = dict_table_get_low("SYS_TABLES");
2278  sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
2279  ut_ad(!dict_table_is_comp(sys_tables));
2280  ut_ad(name_of_col_is(sys_tables, sys_index,
2281  DICT_FLD__SYS_TABLES__ID, "ID"));
2282  ut_ad(name_of_col_is(sys_tables, sys_index,
2283  DICT_FLD__SYS_TABLES__N_COLS, "N_COLS"));
2284  ut_ad(name_of_col_is(sys_tables, sys_index,
2285  DICT_FLD__SYS_TABLES__TYPE, "TYPE"));
2286  ut_ad(name_of_col_is(sys_tables, sys_index,
2287  DICT_FLD__SYS_TABLES__MIX_LEN, "MIX_LEN"));
2288  ut_ad(name_of_col_is(sys_tables, sys_index,
2289  DICT_FLD__SYS_TABLES__SPACE, "SPACE"));
2290 
2291  tuple = dtuple_create(heap, 1);
2292  dfield = dtuple_get_nth_field(tuple, 0);
2293 
2294  dfield_set_data(dfield, name, ut_strlen(name));
2295  dict_index_copy_types(tuple, sys_index, 1);
2296 
2297  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2298  BTR_SEARCH_LEAF, &pcur, &mtr);
2299  rec = btr_pcur_get_rec(&pcur);
2300 
2301  if (!btr_pcur_is_on_user_rec(&pcur)
2302  || rec_get_deleted_flag(rec, 0)) {
2303  /* Not found */
2304 err_exit:
2305  btr_pcur_close(&pcur);
2306  mtr_commit(&mtr);
2307  mem_heap_free(heap);
2308 
2309  return(NULL);
2310  }
2311 
2312  field = rec_get_nth_field_old(
2313  rec, DICT_FLD__SYS_TABLES__NAME, &len);
2314 
2315  /* Check if the table name in record is the searched one */
2316  if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
2317 
2318  goto err_exit;
2319  }
2320 
2321  err_msg = dict_load_table_low(name, rec, &table);
2322 
2323  if (err_msg) {
2324 
2325  ut_print_timestamp(stderr);
2326  fprintf(stderr, " InnoDB: %s\n", err_msg);
2327  goto err_exit;
2328  }
2329 
2330  char table_name[MAX_FULL_NAME_LEN + 1];
2331 
2332  innobase_format_name(table_name, sizeof(table_name), name, FALSE);
2333 
2334  btr_pcur_close(&pcur);
2335  mtr_commit(&mtr);
2336 
2337  if (table->space == 0) {
2338  /* The system tablespace is always available. */
2339  } else if (table->flags2 & DICT_TF2_DISCARDED) {
2340 
2341  ib_logf(IB_LOG_LEVEL_WARN,
2342  "Table '%s' tablespace is set as discarded.",
2343  table_name);
2344 
2345  table->ibd_file_missing = TRUE;
2346 
2348  table->space, name, FALSE, FALSE, true, heap,
2349  table->id)) {
2350 
2351  if (DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)) {
2352  /* Do not bother to retry opening temporary tables. */
2353  table->ibd_file_missing = TRUE;
2354 
2355  } else {
2356  if (!(ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)) {
2357  ib_logf(IB_LOG_LEVEL_ERROR,
2358  "Failed to find tablespace for "
2359  "table '%s' in the cache. "
2360  "Attempting to load the tablespace "
2361  "with space id %lu.",
2362  table_name, (ulong) table->space);
2363  }
2364 
2365  /* Use the remote filepath if needed. */
2366  if (DICT_TF_HAS_DATA_DIR(table->flags)) {
2367  /* This needs to be added to the table
2368  from SYS_DATAFILES */
2369  dict_get_and_save_data_dir_path(table, true);
2370 
2371  if (table->data_dir_path) {
2372  filepath = os_file_make_remote_pathname(
2373  table->data_dir_path,
2374  table->name, "ibd");
2375  }
2376  }
2377 
2378  /* Try to open the tablespace. We set the
2379  2nd param (fix_dict = false) here because we
2380  do not have an x-lock on dict_operation_lock */
2382  true, false, table->space,
2383  dict_tf_to_fsp_flags(table->flags),
2384  name, filepath);
2385 
2386  if (err != DB_SUCCESS) {
2387  /* We failed to find a sensible
2388  tablespace file */
2389 
2390  table->ibd_file_missing = TRUE;
2391  }
2392  if (filepath) {
2393  mem_free(filepath);
2394  }
2395  }
2396  }
2397 
2398  dict_load_columns(table, heap);
2399 
2400  if (cached) {
2401  dict_table_add_to_cache(table, TRUE, heap);
2402  } else {
2403  dict_table_add_system_columns(table, heap);
2404  }
2405 
2406  mem_heap_empty(heap);
2407 
2408  /* If there is no tablespace for the table then we only need to
2409  load the index definitions. So that we can IMPORT the tablespace
2410  later. When recovering table locks for resurrected incomplete
2411  transactions, the tablespace should exist, because DDL operations
2412  were not allowed while the table is being locked by a transaction. */
2413  dict_err_ignore_t index_load_err =
2414  !(ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)
2415  && table->ibd_file_missing
2417  : ignore_err;
2418  err = dict_load_indexes(table, heap, index_load_err);
2419 
2420  if (err == DB_INDEX_CORRUPT) {
2421  /* Refuse to load the table if the table has a corrupted
2422  cluster index */
2423  if (!srv_load_corrupted) {
2424  fprintf(stderr, "InnoDB: Error: Load table ");
2425  ut_print_name(stderr, NULL, TRUE, table->name);
2426  fprintf(stderr, " failed, the table has corrupted"
2427  " clustered indexes. Turn on"
2428  " 'innodb_force_load_corrupted'"
2429  " to drop it\n");
2430 
2432  table = NULL;
2433  goto func_exit;
2434  } else {
2435  dict_index_t* clust_index;
2436  clust_index = dict_table_get_first_index(table);
2437 
2438  if (dict_index_is_corrupted(clust_index)) {
2439  table->corrupted = TRUE;
2440  }
2441  }
2442  }
2443 
2444  /* Initialize table foreign_child value. Its value could be
2445  changed when dict_load_foreigns() is called below */
2446  table->fk_max_recusive_level = 0;
2447 
2448  /* If the force recovery flag is set, we open the table irrespective
2449  of the error condition, since the user may want to dump data from the
2450  clustered index. However we load the foreign key information only if
2451  all indexes were loaded. */
2452  if (!cached || table->ibd_file_missing) {
2453  /* Don't attempt to load the indexes from disk. */
2454  } else if (err == DB_SUCCESS) {
2455  err = dict_load_foreigns(table->name, NULL, true, true,
2456  ignore_err);
2457 
2458  if (err != DB_SUCCESS) {
2459  ib_logf(IB_LOG_LEVEL_WARN,
2460  "Load table '%s' failed, the table has missing "
2461  "foreign key indexes. Turn off "
2462  "'foreign_key_checks' and try again.",
2463  table->name);
2464 
2466  table = NULL;
2467  } else {
2468  table->fk_max_recusive_level = 0;
2469  }
2470  } else {
2472 
2473  /* Make sure that at least the clustered index was loaded.
2474  Otherwise refuse to load the table */
2475  index = dict_table_get_first_index(table);
2476 
2477  if (!srv_force_recovery
2478  || !index
2479  || !dict_index_is_clust(index)) {
2480 
2482  table = NULL;
2483 
2484  } else if (dict_index_is_corrupted(index)
2485  && !table->ibd_file_missing) {
2486 
2487  /* It is possible we force to load a corrupted
2488  clustered index if srv_load_corrupted is set.
2489  Mark the table as corrupted in this case */
2490  table->corrupted = TRUE;
2491  }
2492  }
2493 
2494 func_exit:
2495  mem_heap_free(heap);
2496 
2497  ut_ad(!table
2498  || ignore_err != DICT_ERR_IGNORE_NONE
2499  || table->ibd_file_missing
2500  || !table->corrupted);
2501 
2502  if (table && table->fts) {
2503  if (!(dict_table_has_fts_index(table)
2504  || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
2505  || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID))) {
2506  /* the table->fts could be created in dict_load_column
2507  when a user defined FTS_DOC_ID is present, but no
2508  FTS */
2509  fts_free(table);
2510  } else {
2511  fts_optimize_add_table(table);
2512  }
2513  }
2514 
2515  return(table);
2516 }
2517 
2518 /***********************************************************************/
2521 UNIV_INTERN
2522 dict_table_t*
2524 /*==================*/
2525  table_id_t table_id,
2526  dict_err_ignore_t ignore_err)
2528 {
2529  byte id_buf[8];
2530  btr_pcur_t pcur;
2531  mem_heap_t* heap;
2532  dtuple_t* tuple;
2533  dfield_t* dfield;
2534  dict_index_t* sys_table_ids;
2535  dict_table_t* sys_tables;
2536  const rec_t* rec;
2537  const byte* field;
2538  ulint len;
2540  mtr_t mtr;
2541 
2542  ut_ad(mutex_own(&(dict_sys->mutex)));
2543 
2544  table = NULL;
2545 
2546  /* NOTE that the operation of this function is protected by
2547  the dictionary mutex, and therefore no deadlocks can occur
2548  with other dictionary operations. */
2549 
2550  mtr_start(&mtr);
2551  /*---------------------------------------------------*/
2552  /* Get the secondary index based on ID for table SYS_TABLES */
2553  sys_tables = dict_sys->sys_tables;
2554  sys_table_ids = dict_table_get_next_index(
2555  dict_table_get_first_index(sys_tables));
2556  ut_ad(!dict_table_is_comp(sys_tables));
2557  ut_ad(!dict_index_is_clust(sys_table_ids));
2558  heap = mem_heap_create(256);
2559 
2560  tuple = dtuple_create(heap, 1);
2561  dfield = dtuple_get_nth_field(tuple, 0);
2562 
2563  /* Write the table id in byte format to id_buf */
2564  mach_write_to_8(id_buf, table_id);
2565 
2566  dfield_set_data(dfield, id_buf, 8);
2567  dict_index_copy_types(tuple, sys_table_ids, 1);
2568 
2569  btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
2570  BTR_SEARCH_LEAF, &pcur, &mtr);
2571 
2572 check_rec:
2573  rec = btr_pcur_get_rec(&pcur);
2574 
2575  if (page_rec_is_user_rec(rec)) {
2576  /*---------------------------------------------------*/
2577  /* Now we have the record in the secondary index
2578  containing the table ID and NAME */
2579 
2580  field = rec_get_nth_field_old(
2581  rec, DICT_FLD__SYS_TABLE_IDS__ID, &len);
2582  ut_ad(len == 8);
2583 
2584  /* Check if the table id in record is the one searched for */
2585  if (table_id == mach_read_from_8(field)) {
2586  if (rec_get_deleted_flag(rec, 0)) {
2587  /* Until purge has completed, there
2588  may be delete-marked duplicate records
2589  for the same SYS_TABLES.ID.
2590  Due to Bug #60049, some delete-marked
2591  records may survive the purge forever. */
2592  if (btr_pcur_move_to_next(&pcur, &mtr)) {
2593 
2594  goto check_rec;
2595  }
2596  } else {
2597  /* Now we get the table name from the record */
2598  field = rec_get_nth_field_old(rec,
2599  DICT_FLD__SYS_TABLE_IDS__NAME, &len);
2600  /* Load the table definition to memory */
2601  table = dict_load_table(
2603  heap, (char*) field, len),
2604  TRUE, ignore_err);
2605  }
2606  }
2607  }
2608 
2609  btr_pcur_close(&pcur);
2610  mtr_commit(&mtr);
2611  mem_heap_free(heap);
2612 
2613  return(table);
2614 }
2615 
2616 /********************************************************************/
2620 UNIV_INTERN
2621 void
2623 /*================*/
2624  dict_table_t* table)
2625 {
2626  mem_heap_t* heap;
2627 
2628  ut_ad(mutex_own(&(dict_sys->mutex)));
2629 
2630  heap = mem_heap_create(1000);
2631 
2632  dict_load_indexes(table, heap, DICT_ERR_IGNORE_NONE);
2633 
2634  mem_heap_free(heap);
2635 }
2636 
2637 /********************************************************************/
2647 static
2648 void
2649 dict_load_foreign_cols(
2650 /*===================*/
2651  dict_foreign_t* foreign)
2652 {
2653  dict_table_t* sys_foreign_cols;
2654  dict_index_t* sys_index;
2655  btr_pcur_t pcur;
2656  dtuple_t* tuple;
2657  dfield_t* dfield;
2658  const rec_t* rec;
2659  const byte* field;
2660  ulint len;
2661  ulint i;
2662  mtr_t mtr;
2663  size_t id_len;
2664 
2665  ut_ad(mutex_own(&(dict_sys->mutex)));
2666 
2667  id_len = strlen(foreign->id);
2668 
2669  foreign->foreign_col_names = static_cast<const char**>(
2670  mem_heap_alloc(foreign->heap,
2671  foreign->n_fields * sizeof(void*)));
2672 
2673  foreign->referenced_col_names = static_cast<const char**>(
2674  mem_heap_alloc(foreign->heap,
2675  foreign->n_fields * sizeof(void*)));
2676 
2677  mtr_start(&mtr);
2678 
2679  sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
2680 
2681  sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
2682  ut_ad(!dict_table_is_comp(sys_foreign_cols));
2683 
2684  tuple = dtuple_create(foreign->heap, 1);
2685  dfield = dtuple_get_nth_field(tuple, 0);
2686 
2687  dfield_set_data(dfield, foreign->id, id_len);
2688  dict_index_copy_types(tuple, sys_index, 1);
2689 
2690  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2691  BTR_SEARCH_LEAF, &pcur, &mtr);
2692  for (i = 0; i < foreign->n_fields; i++) {
2693 
2694  rec = btr_pcur_get_rec(&pcur);
2695 
2696  ut_a(btr_pcur_is_on_user_rec(&pcur));
2697  ut_a(!rec_get_deleted_flag(rec, 0));
2698 
2699  field = rec_get_nth_field_old(
2700  rec, DICT_FLD__SYS_FOREIGN_COLS__ID, &len);
2701 
2702  if (len != id_len || ut_memcmp(foreign->id, field, len) != 0) {
2703  const rec_t* pos;
2704  ulint pos_len;
2705  const rec_t* for_col_name;
2706  ulint for_col_name_len;
2707  const rec_t* ref_col_name;
2708  ulint ref_col_name_len;
2709 
2710  pos = rec_get_nth_field_old(
2711  rec, DICT_FLD__SYS_FOREIGN_COLS__POS,
2712  &pos_len);
2713 
2714  for_col_name = rec_get_nth_field_old(
2715  rec, DICT_FLD__SYS_FOREIGN_COLS__FOR_COL_NAME,
2716  &for_col_name_len);
2717 
2718  ref_col_name = rec_get_nth_field_old(
2719  rec, DICT_FLD__SYS_FOREIGN_COLS__REF_COL_NAME,
2720  &ref_col_name_len);
2721 
2722  ib_logf(IB_LOG_LEVEL_ERROR,
2723  "Unable to load columns names for foreign "
2724  "key '%s' because it was not found in "
2725  "InnoDB internal table SYS_FOREIGN_COLS. The "
2726  "closest entry we found is: "
2727  "(ID='%.*s', POS=%lu, FOR_COL_NAME='%.*s', "
2728  "REF_COL_NAME='%.*s')",
2729  foreign->id,
2730  (int) len, field,
2731  mach_read_from_4(pos),
2732  (int) for_col_name_len, for_col_name,
2733  (int) ref_col_name_len, ref_col_name);
2734 
2735  ut_error;
2736  }
2737 
2738  field = rec_get_nth_field_old(
2739  rec, DICT_FLD__SYS_FOREIGN_COLS__POS, &len);
2740  ut_a(len == 4);
2741  ut_a(i == mach_read_from_4(field));
2742 
2743  field = rec_get_nth_field_old(
2744  rec, DICT_FLD__SYS_FOREIGN_COLS__FOR_COL_NAME, &len);
2745  foreign->foreign_col_names[i] = mem_heap_strdupl(
2746  foreign->heap, (char*) field, len);
2747 
2748  field = rec_get_nth_field_old(
2749  rec, DICT_FLD__SYS_FOREIGN_COLS__REF_COL_NAME, &len);
2751  foreign->heap, (char*) field, len);
2752 
2753  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2754  }
2755 
2756  btr_pcur_close(&pcur);
2757  mtr_commit(&mtr);
2758 }
2759 
2760 /***********************************************************************/
2763 static __attribute__((nonnull(1), warn_unused_result))
2764 dberr_t
2765 dict_load_foreign(
2766 /*==============*/
2767  const char* id,
2770  const char** col_names,
2773  bool check_recursive,
2777  bool check_charsets,
2780  dict_err_ignore_t ignore_err)
2782 {
2783  dict_foreign_t* foreign;
2784  dict_table_t* sys_foreign;
2785  btr_pcur_t pcur;
2786  dict_index_t* sys_index;
2787  dtuple_t* tuple;
2788  mem_heap_t* heap2;
2789  dfield_t* dfield;
2790  const rec_t* rec;
2791  const byte* field;
2792  ulint len;
2793  ulint n_fields_and_type;
2794  mtr_t mtr;
2795  dict_table_t* for_table;
2796  dict_table_t* ref_table;
2797  size_t id_len;
2798 
2799  ut_ad(mutex_own(&(dict_sys->mutex)));
2800 
2801  id_len = strlen(id);
2802 
2803  heap2 = mem_heap_create(1000);
2804 
2805  mtr_start(&mtr);
2806 
2807  sys_foreign = dict_table_get_low("SYS_FOREIGN");
2808 
2809  sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
2810  ut_ad(!dict_table_is_comp(sys_foreign));
2811 
2812  tuple = dtuple_create(heap2, 1);
2813  dfield = dtuple_get_nth_field(tuple, 0);
2814 
2815  dfield_set_data(dfield, id, id_len);
2816  dict_index_copy_types(tuple, sys_index, 1);
2817 
2818  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2819  BTR_SEARCH_LEAF, &pcur, &mtr);
2820  rec = btr_pcur_get_rec(&pcur);
2821 
2822  if (!btr_pcur_is_on_user_rec(&pcur)
2823  || rec_get_deleted_flag(rec, 0)) {
2824  /* Not found */
2825 
2826  fprintf(stderr,
2827  "InnoDB: Error: cannot load foreign constraint "
2828  "%s: could not find the relevant record in "
2829  "SYS_FOREIGN\n", id);
2830 
2831  btr_pcur_close(&pcur);
2832  mtr_commit(&mtr);
2833  mem_heap_free(heap2);
2834 
2835  return(DB_ERROR);
2836  }
2837 
2838  field = rec_get_nth_field_old(rec, DICT_FLD__SYS_FOREIGN__ID, &len);
2839 
2840  /* Check if the id in record is the searched one */
2841  if (len != id_len || ut_memcmp(id, field, len) != 0) {
2842 
2843  fprintf(stderr,
2844  "InnoDB: Error: cannot load foreign constraint "
2845  "%s: found %.*s instead in SYS_FOREIGN\n",
2846  id, (int) len, field);
2847 
2848  btr_pcur_close(&pcur);
2849  mtr_commit(&mtr);
2850  mem_heap_free(heap2);
2851 
2852  return(DB_ERROR);
2853  }
2854 
2855  /* Read the table names and the number of columns associated
2856  with the constraint */
2857 
2858  mem_heap_free(heap2);
2859 
2860  foreign = dict_mem_foreign_create();
2861 
2862  n_fields_and_type = mach_read_from_4(
2863  rec_get_nth_field_old(
2864  rec, DICT_FLD__SYS_FOREIGN__N_COLS, &len));
2865 
2866  ut_a(len == 4);
2867 
2868  /* We store the type in the bits 24..29 of n_fields_and_type. */
2869 
2870  foreign->type = (unsigned int) (n_fields_and_type >> 24);
2871  foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
2872 
2873  foreign->id = mem_heap_strdupl(foreign->heap, id, id_len);
2874 
2875  field = rec_get_nth_field_old(
2876  rec, DICT_FLD__SYS_FOREIGN__FOR_NAME, &len);
2877 
2879  foreign->heap, (char*) field, len);
2881 
2882  field = rec_get_nth_field_old(
2883  rec, DICT_FLD__SYS_FOREIGN__REF_NAME, &len);
2885  foreign->heap, (char*) field, len);
2887 
2888  btr_pcur_close(&pcur);
2889  mtr_commit(&mtr);
2890 
2891  dict_load_foreign_cols(foreign);
2892 
2894  foreign->referenced_table_name_lookup);
2895 
2896  /* We could possibly wind up in a deep recursive calls if
2897  we call dict_table_get_low() again here if there
2898  is a chain of tables concatenated together with
2899  foreign constraints. In such case, each table is
2900  both a parent and child of the other tables, and
2901  act as a "link" in such table chains.
2902  To avoid such scenario, we would need to check the
2903  number of ancesters the current table has. If that
2904  exceeds DICT_FK_MAX_CHAIN_LEN, we will stop loading
2905  the child table.
2906  Foreign constraints are loaded in a Breath First fashion,
2907  that is, the index on FOR_NAME is scanned first, and then
2908  index on REF_NAME. So foreign constrains in which
2909  current table is a child (foreign table) are loaded first,
2910  and then those constraints where current table is a
2911  parent (referenced) table.
2912  Thus we could check the parent (ref_table) table's
2913  reference count (fk_max_recusive_level) to know how deep the
2914  recursive call is. If the parent table (ref_table) is already
2915  loaded, and its fk_max_recusive_level is larger than
2916  DICT_FK_MAX_CHAIN_LEN, we will stop the recursive loading
2917  by skipping loading the child table. It will not affect foreign
2918  constraint check for DMLs since child table will be loaded
2919  at that time for the constraint check. */
2920  if (!ref_table
2922 
2923  /* If the foreign table is not yet in the dictionary cache, we
2924  have to load it so that we are able to make type comparisons
2925  in the next function call. */
2926 
2927  for_table = dict_table_get_low(foreign->foreign_table_name_lookup);
2928 
2929  if (for_table && ref_table && check_recursive) {
2930  /* This is to record the longest chain of ancesters
2931  this table has, if the parent has more ancesters
2932  than this table has, record it after add 1 (for this
2933  parent */
2934  if (ref_table->fk_max_recusive_level
2935  >= for_table->fk_max_recusive_level) {
2936  for_table->fk_max_recusive_level =
2937  ref_table->fk_max_recusive_level + 1;
2938  }
2939  }
2940  }
2941 
2942  /* Note that there may already be a foreign constraint object in
2943  the dictionary cache for this constraint: then the following
2944  call only sets the pointers in it to point to the appropriate table
2945  and index objects and frees the newly created object foreign.
2946  Adding to the cache should always succeed since we are not creating
2947  a new foreign key constraint but loading one from the data
2948  dictionary. */
2949 
2950  return(dict_foreign_add_to_cache(foreign, col_names, check_charsets,
2951  ignore_err));
2952 }
2953 
2954 /***********************************************************************/
2961 UNIV_INTERN
2962 dberr_t
2964 /*===============*/
2965  const char* table_name,
2966  const char** col_names,
2968  bool check_recursive,
2971  bool check_charsets,
2973  dict_err_ignore_t ignore_err)
2974 {
2975  ulint tuple_buf[(DTUPLE_EST_ALLOC(1) + sizeof(ulint) - 1)
2976  / sizeof(ulint)];
2977  btr_pcur_t pcur;
2978  dtuple_t* tuple;
2979  dfield_t* dfield;
2980  dict_index_t* sec_index;
2981  dict_table_t* sys_foreign;
2982  const rec_t* rec;
2983  const byte* field;
2984  ulint len;
2985  dberr_t err;
2986  mtr_t mtr;
2987 
2988  ut_ad(mutex_own(&(dict_sys->mutex)));
2989 
2990  sys_foreign = dict_table_get_low("SYS_FOREIGN");
2991 
2992  if (sys_foreign == NULL) {
2993  /* No foreign keys defined yet in this database */
2994 
2995  fprintf(stderr,
2996  "InnoDB: Error: no foreign key system tables"
2997  " in the database\n");
2998 
2999  return(DB_ERROR);
3000  }
3001 
3002  ut_ad(!dict_table_is_comp(sys_foreign));
3003  mtr_start(&mtr);
3004 
3005  /* Get the secondary index based on FOR_NAME from table
3006  SYS_FOREIGN */
3007 
3008  sec_index = dict_table_get_next_index(
3009  dict_table_get_first_index(sys_foreign));
3010  ut_ad(!dict_index_is_clust(sec_index));
3011 start_load:
3012 
3013  tuple = dtuple_create_from_mem(tuple_buf, sizeof(tuple_buf), 1);
3014  dfield = dtuple_get_nth_field(tuple, 0);
3015 
3016  dfield_set_data(dfield, table_name, ut_strlen(table_name));
3017  dict_index_copy_types(tuple, sec_index, 1);
3018 
3019  btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE,
3020  BTR_SEARCH_LEAF, &pcur, &mtr);
3021 loop:
3022  rec = btr_pcur_get_rec(&pcur);
3023 
3024  if (!btr_pcur_is_on_user_rec(&pcur)) {
3025  /* End of index */
3026 
3027  goto load_next_index;
3028  }
3029 
3030  /* Now we have the record in the secondary index containing a table
3031  name and a foreign constraint ID */
3032 
3033  field = rec_get_nth_field_old(
3034  rec, DICT_FLD__SYS_FOREIGN_FOR_NAME__NAME, &len);
3035 
3036  /* Check if the table name in the record is the one searched for; the
3037  following call does the comparison in the latin1_swedish_ci
3038  charset-collation, in a case-insensitive way. */
3039 
3040  if (0 != cmp_data_data(dfield_get_type(dfield)->mtype,
3041  dfield_get_type(dfield)->prtype,
3042  static_cast<const byte*>(
3043  dfield_get_data(dfield)),
3044  dfield_get_len(dfield),
3045  field, len)) {
3046 
3047  goto load_next_index;
3048  }
3049 
3050  /* Since table names in SYS_FOREIGN are stored in a case-insensitive
3051  order, we have to check that the table name matches also in a binary
3052  string comparison. On Unix, MySQL allows table names that only differ
3053  in character case. If lower_case_table_names=2 then what is stored
3054  may not be the same case, but the previous comparison showed that they
3055  match with no-case. */
3056 
3057  if (rec_get_deleted_flag(rec, 0)) {
3058  goto next_rec;
3059  }
3060 
3062  && (0 != ut_memcmp(field, table_name, len))) {
3063  goto next_rec;
3064  }
3065 
3066  /* Now we get a foreign key constraint id */
3067  field = rec_get_nth_field_old(
3068  rec, DICT_FLD__SYS_FOREIGN_FOR_NAME__ID, &len);
3069 
3070  /* Copy the string because the page may be modified or evicted
3071  after mtr_commit() below. */
3072  char fk_id[MAX_TABLE_NAME_LEN + 1];
3073 
3074  ut_a(len <= MAX_TABLE_NAME_LEN);
3075  memcpy(fk_id, field, len);
3076  fk_id[len] = '\0';
3077 
3078  btr_pcur_store_position(&pcur, &mtr);
3079 
3080  mtr_commit(&mtr);
3081 
3082  /* Load the foreign constraint definition to the dictionary cache */
3083 
3084  err = dict_load_foreign(fk_id, col_names,
3085  check_recursive, check_charsets, ignore_err);
3086 
3087  if (err != DB_SUCCESS) {
3088  btr_pcur_close(&pcur);
3089 
3090  return(err);
3091  }
3092 
3093  mtr_start(&mtr);
3094 
3095  btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
3096 next_rec:
3097  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
3098 
3099  goto loop;
3100 
3101 load_next_index:
3102  btr_pcur_close(&pcur);
3103  mtr_commit(&mtr);
3104 
3105  sec_index = dict_table_get_next_index(sec_index);
3106 
3107  if (sec_index != NULL) {
3108 
3109  mtr_start(&mtr);
3110 
3111  /* Switch to scan index on REF_NAME, fk_max_recusive_level
3112  already been updated when scanning FOR_NAME index, no need to
3113  update again */
3114  check_recursive = FALSE;
3115 
3116  goto start_load;
3117  }
3118 
3119  return(DB_SUCCESS);
3120 }