Drizzled Public API Documentation

dict0load.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 /**************************************************/
27 #if defined(BUILD_DRIZZLE)
28 # include "config.h"
29 #else
30 # include "mysql_version.h"
31 #endif /* BUILD_DRIZZLE */
32 #include "dict0load.h"
33 
34 #ifdef UNIV_NONINL
35 #include "dict0load.ic"
36 #endif
37 
38 #include "btr0pcur.h"
39 #include "btr0btr.h"
40 #include "page0page.h"
41 #include "mach0data.h"
42 #include "dict0dict.h"
43 #include "dict0boot.h"
44 #include "rem0cmp.h"
45 #include "srv0start.h"
46 #include "srv0srv.h"
47 
48 
50 static const char* SYSTEM_TABLE_NAME[] = {
51  "SYS_TABLES",
52  "SYS_INDEXES",
53  "SYS_COLUMNS",
54  "SYS_FIELDS",
55  "SYS_FOREIGN",
56  "SYS_FOREIGN_COLS"
57 };
58 /****************************************************************/
61 static
62 ibool
63 name_of_col_is(
64 /*===========*/
65  const dict_table_t* table,
66  const dict_index_t* index,
67  ulint i,
68  const char* name)
69 {
71  dict_index_get_nth_field(
72  index, i)));
73 
74  return(strcmp(name, dict_table_get_col_name(table, tmp)) == 0);
75 }
76 
77 /********************************************************************/
81 UNIV_INTERN
82 char*
83 dict_get_first_table_name_in_db(
84 /*============================*/
85  const char* name)
86 {
87  dict_table_t* sys_tables;
88  btr_pcur_t pcur;
89  dict_index_t* sys_index;
90  dtuple_t* tuple;
91  mem_heap_t* heap;
92  dfield_t* dfield;
93  const rec_t* rec;
94  const byte* field;
95  ulint len;
96  mtr_t mtr;
97 
98  ut_ad(mutex_own(&(dict_sys->mutex)));
99 
100  heap = mem_heap_create(1000);
101 
102  mtr_start(&mtr);
103 
104  sys_tables = dict_table_get_low("SYS_TABLES");
105  sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
106  ut_a(!dict_table_is_comp(sys_tables));
107 
108  tuple = dtuple_create(heap, 1);
109  dfield = dtuple_get_nth_field(tuple, 0);
110 
111  dfield_set_data(dfield, name, ut_strlen(name));
112  dict_index_copy_types(tuple, sys_index, 1);
113 
114  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
115  BTR_SEARCH_LEAF, &pcur, &mtr);
116 loop:
117  rec = btr_pcur_get_rec(&pcur);
118 
119  if (!btr_pcur_is_on_user_rec(&pcur)) {
120  /* Not found */
121 
122  btr_pcur_close(&pcur);
123  mtr_commit(&mtr);
124  mem_heap_free(heap);
125 
126  return(NULL);
127  }
128 
129  field = rec_get_nth_field_old(rec, 0, &len);
130 
131  if (len < strlen(name)
132  || ut_memcmp(name, field, strlen(name)) != 0) {
133  /* Not found */
134 
135  btr_pcur_close(&pcur);
136  mtr_commit(&mtr);
137  mem_heap_free(heap);
138 
139  return(NULL);
140  }
141 
142  if (!rec_get_deleted_flag(rec, 0)) {
143 
144  /* We found one */
145 
146  char* table_name = mem_strdupl((char*) field, len);
147 
148  btr_pcur_close(&pcur);
149  mtr_commit(&mtr);
150  mem_heap_free(heap);
151 
152  return(table_name);
153  }
154 
155  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
156 
157  goto loop;
158 }
159 
160 /********************************************************************/
163 UNIV_INTERN
164 void
165 dict_print(void)
166 /*============*/
167 {
168  dict_table_t* table;
169  btr_pcur_t pcur;
170  const rec_t* rec;
171  mem_heap_t* heap;
172  mtr_t mtr;
173 
174  /* Enlarge the fatal semaphore wait timeout during the InnoDB table
175  monitor printout */
176 
177  mutex_enter(&kernel_mutex);
178  srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
179  mutex_exit(&kernel_mutex);
180 
181  heap = mem_heap_create(1000);
182  mutex_enter(&(dict_sys->mutex));
183 
184  mtr_start(&mtr);
185 
186  rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
187 
188  while (rec) {
189  const char* err_msg;
190 
191  err_msg = dict_process_sys_tables_rec(
192  heap, rec, &table,
193  static_cast<dict_table_info>(DICT_TABLE_LOAD_FROM_CACHE
195 
196  mtr_commit(&mtr);
197 
198  if (!err_msg) {
199  dict_table_print_low(table);
200  } else {
201  ut_print_timestamp(stderr);
202  fprintf(stderr, " InnoDB: %s\n", err_msg);
203  }
204 
205  mem_heap_empty(heap);
206 
207  mtr_start(&mtr);
208  rec = dict_getnext_system(&pcur, &mtr);
209  }
210 
211  mtr_commit(&mtr);
212  mutex_exit(&(dict_sys->mutex));
213  mem_heap_free(heap);
214 
215  /* Restore the fatal semaphore wait timeout */
216  mutex_enter(&kernel_mutex);
217  srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
218  mutex_exit(&kernel_mutex);
219 }
220 
221 
222 /********************************************************************/
225 static
226 const rec_t*
227 dict_getnext_system_low(
228 /*====================*/
229  btr_pcur_t* pcur,
231  mtr_t* mtr)
232 {
233  rec_t* rec = NULL;
234 
235  while (!rec || rec_get_deleted_flag(rec, 0)) {
237 
238  rec = btr_pcur_get_rec(pcur);
239 
240  if (!btr_pcur_is_on_user_rec(pcur)) {
241  /* end of index */
242  btr_pcur_close(pcur);
243 
244  return(NULL);
245  }
246  }
247 
248  /* Get a record, let's save the position */
249  btr_pcur_store_position(pcur, mtr);
250 
251  return(rec);
252 }
253 
254 /********************************************************************/
257 UNIV_INTERN
258 const rec_t*
259 dict_startscan_system(
260 /*==================*/
261  btr_pcur_t* pcur,
263  mtr_t* mtr,
264  dict_system_id_t system_id)
265 {
266  dict_table_t* system_table;
267  dict_index_t* clust_index;
268  const rec_t* rec;
269 
270  ut_a(system_id < SYS_NUM_SYSTEM_TABLES);
271 
272  system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]);
273 
274  clust_index = UT_LIST_GET_FIRST(system_table->indexes);
275 
276  btr_pcur_open_at_index_side(TRUE, clust_index, BTR_SEARCH_LEAF, pcur,
277  TRUE, mtr);
278 
279  rec = dict_getnext_system_low(pcur, mtr);
280 
281  return(rec);
282 }
283 
284 /********************************************************************/
287 UNIV_INTERN
288 const rec_t*
289 dict_getnext_system(
290 /*================*/
291  btr_pcur_t* pcur,
293  mtr_t* mtr)
294 {
295  const rec_t* rec;
296 
297  /* Restore the position */
298  btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
299 
300  /* Get the next record */
301  rec = dict_getnext_system_low(pcur, mtr);
302 
303  return(rec);
304 }
305 /********************************************************************/
310 UNIV_INTERN
311 const char*
312 dict_process_sys_tables_rec(
313 /*========================*/
314  mem_heap_t* heap,
315  const rec_t* rec,
316  dict_table_t** table,
317  dict_table_info_t status)
321 {
322  ulint len;
323  const char* field;
324  const char* err_msg = NULL;
325  char* table_name;
326 
327  field = (const char*) rec_get_nth_field_old(rec, 0, &len);
328 
329  ut_a(!rec_get_deleted_flag(rec, 0));
330 
331  /* Get the table name */
332  table_name = mem_heap_strdupl(heap, (const char*)field, len);
333 
334  /* If DICT_TABLE_LOAD_FROM_CACHE is set, first check
335  whether there is cached dict_table_t struct first */
336  if (status & DICT_TABLE_LOAD_FROM_CACHE) {
337  *table = dict_table_get_low(table_name);
338 
339  if (!(*table)) {
340  err_msg = "Table not found in cache";
341  }
342  } else {
343  err_msg = dict_load_table_low(table_name, rec, table);
344  }
345 
346  if (err_msg) {
347  return(err_msg);
348  }
349 
350  if ((status & DICT_TABLE_UPDATE_STATS)
351  && dict_table_get_first_index(*table)) {
352 
353  /* Update statistics if DICT_TABLE_UPDATE_STATS
354  is set */
355  dict_update_statistics(*table,
356  FALSE /* update even if
357  initialized */);
358  }
359 
360  return(NULL);
361 }
362 
363 /********************************************************************/
368 UNIV_INTERN
369 const char*
370 dict_process_sys_indexes_rec(
371 /*=========================*/
372  mem_heap_t* heap,
373  const rec_t* rec,
374  dict_index_t* index,
375  table_id_t* table_id)
376 {
377  const char* err_msg;
378  byte* buf;
379 
380  buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
381 
382  /* Parse the record, and get "dict_index_t" struct filled */
383  err_msg = dict_load_index_low(buf, NULL,
384  heap, rec, FALSE, &index);
385 
386  *table_id = mach_read_from_8(buf);
387 
388  return(err_msg);
389 }
390 /********************************************************************/
394 UNIV_INTERN
395 const char*
396 dict_process_sys_columns_rec(
397 /*=========================*/
398  mem_heap_t* heap,
399  const rec_t* rec,
400  dict_col_t* column,
401  table_id_t* table_id,
402  const char** col_name)
403 {
404  const char* err_msg;
405 
406  /* Parse the record, and get "dict_col_t" struct filled */
407  err_msg = dict_load_column_low(NULL, heap, column,
408  table_id, col_name, rec);
409 
410  return(err_msg);
411 }
412 /********************************************************************/
416 UNIV_INTERN
417 const char*
418 dict_process_sys_fields_rec(
419 /*========================*/
420  mem_heap_t* heap,
421  const rec_t* rec,
422  dict_field_t* sys_field,
424  ulint* pos,
425  index_id_t* index_id,
426  index_id_t last_id)
427 {
428  byte* buf;
429  byte* last_index_id;
430  const char* err_msg;
431 
432  buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
433 
434  last_index_id = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
435  mach_write_to_8(last_index_id, last_id);
436 
437  err_msg = dict_load_field_low(buf, NULL, sys_field,
438  pos, last_index_id, heap, rec);
439 
440  *index_id = mach_read_from_8(buf);
441 
442  return(err_msg);
443 
444 }
445 /********************************************************************/
450 UNIV_INTERN
451 const char*
452 dict_process_sys_foreign_rec(
453 /*=========================*/
454  mem_heap_t* heap,
455  const rec_t* rec,
456  dict_foreign_t* foreign)
458 {
459  ulint len;
460  const byte* field;
461  ulint n_fields_and_type;
462 
463  if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
464  return("delete-marked record in SYS_FOREIGN");
465  }
466 
467  if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
468  return("wrong number of columns in SYS_FOREIGN record");
469  }
470 
471  field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
472  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
473 err_len:
474  return("incorrect column length in SYS_FOREIGN");
475  }
476  foreign->id = mem_heap_strdupl(heap, (const char*) field, len);
477 
478  rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
479  if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
480  goto err_len;
481  }
482  rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
483  if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
484  goto err_len;
485  }
486 
487  field = rec_get_nth_field_old(rec, 3/*FOR_NAME*/, &len);
488  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
489  goto err_len;
490  }
492  heap, (const char*) field, len);
493 
494  field = rec_get_nth_field_old(rec, 4/*REF_NAME*/, &len);
495  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
496  goto err_len;
497  }
499  heap, (const char*) field, len);
500 
501  field = rec_get_nth_field_old(rec, 5/*N_COLS*/, &len);
502  if (UNIV_UNLIKELY(len != 4)) {
503  goto err_len;
504  }
505  n_fields_and_type = mach_read_from_4(field);
506 
507  foreign->type = (unsigned int) (n_fields_and_type >> 24);
508  foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
509 
510  return(NULL);
511 }
512 /********************************************************************/
516 UNIV_INTERN
517 const char*
518 dict_process_sys_foreign_col_rec(
519 /*=============================*/
520  mem_heap_t* heap,
521  const rec_t* rec,
522  const char** name,
523  const char** for_col_name,
524  const char** ref_col_name,
526  ulint* pos)
527 {
528  ulint len;
529  const byte* field;
530 
531  if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
532  return("delete-marked record in SYS_FOREIGN_COLS");
533  }
534 
535  if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
536  return("wrong number of columns in SYS_FOREIGN_COLS record");
537  }
538 
539  field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
540  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
541 err_len:
542  return("incorrect column length in SYS_FOREIGN_COLS");
543  }
544  *name = mem_heap_strdupl(heap, (char*) field, len);
545 
546  field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
547  if (UNIV_UNLIKELY(len != 4)) {
548  goto err_len;
549  }
550  *pos = mach_read_from_4(field);
551 
552  rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
553  if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
554  goto err_len;
555  }
556  rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
557  if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
558  goto err_len;
559  }
560 
561  field = rec_get_nth_field_old(rec, 4/*FOR_COL_NAME*/, &len);
562  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
563  goto err_len;
564  }
565  *for_col_name = mem_heap_strdupl(heap, (char*) field, len);
566 
567  field = rec_get_nth_field_old(rec, 5/*REF_COL_NAME*/, &len);
568  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
569  goto err_len;
570  }
571  *ref_col_name = mem_heap_strdupl(heap, (char*) field, len);
572 
573  return(NULL);
574 }
575 
576 /*
577  Send data to callback function .
578 */
579 
580 UNIV_INTERN void dict_print_with_callback(dict_print_callback func, void *func_arg)
581 {
582  dict_table_t* sys_tables;
583  dict_index_t* sys_index;
584  btr_pcur_t pcur;
585  const rec_t* rec;
586  const byte* field;
587  ulint len;
588  mtr_t mtr;
589 
590  /* Enlarge the fatal semaphore wait timeout during the InnoDB table
591  monitor printout */
592 
593  mutex_enter(&kernel_mutex);
594  srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
595  mutex_exit(&kernel_mutex);
596 
597  mutex_enter(&(dict_sys->mutex));
598 
599  mtr_start(&mtr);
600 
601  sys_tables = dict_table_get_low("SYS_TABLES");
602  sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
603 
604  btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
605  TRUE, &mtr);
606 loop:
607  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
608 
609  rec = btr_pcur_get_rec(&pcur);
610 
611  if (!btr_pcur_is_on_user_rec(&pcur)) {
612  /* end of index */
613 
614  btr_pcur_close(&pcur);
615  mtr_commit(&mtr);
616 
617  mutex_exit(&(dict_sys->mutex));
618 
619  /* Restore the fatal semaphore wait timeout */
620 
621  mutex_enter(&kernel_mutex);
622  srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
623  mutex_exit(&kernel_mutex);
624 
625  return;
626  }
627 
628  field = rec_get_nth_field_old(rec, 0, &len);
629 
630  if (!rec_get_deleted_flag(rec, 0)) {
631 
632  /* We found one */
633 
634  char* table_name = mem_strdupl((char*) field, len);
635 
636  btr_pcur_store_position(&pcur, &mtr);
637 
638  mtr_commit(&mtr);
639 
640  func(func_arg, table_name);
641  mem_free(table_name);
642 
643  mtr_start(&mtr);
644 
645  btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
646  }
647 
648  goto loop;
649 }
650 
651 /********************************************************************/
655 static
656 ulint
657 dict_sys_tables_get_flags(
658 /*======================*/
659  const rec_t* rec)
660 {
661  const byte* field;
662  ulint len;
663  ulint n_cols;
664  ulint flags;
665 
666  field = rec_get_nth_field_old(rec, 5, &len);
667  ut_a(len == 4);
668 
669  flags = mach_read_from_4(field);
670 
671  if (UNIV_LIKELY(flags == DICT_TABLE_ORDINARY)) {
672  return(0);
673  }
674 
675  field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
676  n_cols = mach_read_from_4(field);
677 
678  if (UNIV_UNLIKELY(!(n_cols & 0x80000000UL))) {
679  /* New file formats require ROW_FORMAT=COMPACT. */
680  return(ULINT_UNDEFINED);
681  }
682 
683  switch (flags & (DICT_TF_FORMAT_MASK | DICT_TF_COMPACT)) {
684  default:
687  /* flags should be DICT_TABLE_ORDINARY,
688  or DICT_TF_FORMAT_MASK should be nonzero. */
689  return(ULINT_UNDEFINED);
690 
692 #if DICT_TF_FORMAT_MAX > DICT_TF_FORMAT_ZIP
693 # error "missing case labels for DICT_TF_FORMAT_ZIP .. DICT_TF_FORMAT_MAX"
694 #endif
695  /* We support this format. */
696  break;
697  }
698 
699  if (UNIV_UNLIKELY((flags & DICT_TF_ZSSIZE_MASK)
700  > (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT))) {
701  /* Unsupported compressed page size. */
702  return(ULINT_UNDEFINED);
703  }
704 
705  if (UNIV_UNLIKELY(flags & (SIZE_MAX << DICT_TF_BITS))) {
706  /* Some unused bits are set. */
707  return(ULINT_UNDEFINED);
708  }
709 
710  return(flags);
711 }
712 
713 /********************************************************************/
721 UNIV_INTERN
722 void
723 dict_check_tablespaces_and_store_max_id(
724 /*====================================*/
725  ibool in_crash_recovery)
726 {
727  dict_table_t* sys_tables;
728  dict_index_t* sys_index;
729  btr_pcur_t pcur;
730  const rec_t* rec;
731  ulint max_space_id;
732  mtr_t mtr;
733 
734  mutex_enter(&(dict_sys->mutex));
735 
736  mtr_start(&mtr);
737 
738  sys_tables = dict_table_get_low("SYS_TABLES");
739  sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
740  ut_a(!dict_table_is_comp(sys_tables));
741 
742  max_space_id = mtr_read_ulint(dict_hdr_get(&mtr)
743  + DICT_HDR_MAX_SPACE_ID,
744  MLOG_4BYTES, &mtr);
745  fil_set_max_space_id_if_bigger(max_space_id);
746 
747  btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
748  TRUE, &mtr);
749 loop:
750  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
751 
752  rec = btr_pcur_get_rec(&pcur);
753 
754  if (!btr_pcur_is_on_user_rec(&pcur)) {
755  /* end of index */
756 
757  btr_pcur_close(&pcur);
758  mtr_commit(&mtr);
759 
760  /* We must make the tablespace cache aware of the biggest
761  known space id */
762 
763  /* printf("Biggest space id in data dictionary %lu\n",
764  max_space_id); */
765  fil_set_max_space_id_if_bigger(max_space_id);
766 
767  mutex_exit(&(dict_sys->mutex));
768 
769  return;
770  }
771 
772  if (!rec_get_deleted_flag(rec, 0)) {
773 
774  /* We found one */
775  const byte* field;
776  ulint len;
777  ulint space_id;
778  ulint flags;
779  char* name;
780 
781  field = rec_get_nth_field_old(rec, 0, &len);
782  name = mem_strdupl((char*) field, len);
783 
784  flags = dict_sys_tables_get_flags(rec);
785  if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
786 
787  field = rec_get_nth_field_old(rec, 5, &len);
788  flags = mach_read_from_4(field);
789 
790  ut_print_timestamp(stderr);
791  fputs(" InnoDB: Error: table ", stderr);
792  ut_print_filename(stderr, name);
793  fprintf(stderr, "\n"
794  "InnoDB: in InnoDB data dictionary"
795  " has unknown type %lx.\n",
796  (ulong) flags);
797 
798  goto loop;
799  }
800 
801  field = rec_get_nth_field_old(rec, 9, &len);
802  ut_a(len == 4);
803 
804  space_id = mach_read_from_4(field);
805 
806  btr_pcur_store_position(&pcur, &mtr);
807 
808  mtr_commit(&mtr);
809 
810  if (space_id == 0) {
811  /* The system tablespace always exists. */
812  } else if (in_crash_recovery) {
813  /* Check that the tablespace (the .ibd file) really
814  exists; print a warning to the .err log if not.
815  Do not print warnings for temporary tables. */
816  ibool is_temp;
817 
818  field = rec_get_nth_field_old(rec, 4, &len);
819  if (0x80000000UL & mach_read_from_4(field)) {
820  /* ROW_FORMAT=COMPACT: read the is_temp
821  flag from SYS_TABLES.MIX_LEN. */
822  field = rec_get_nth_field_old(rec, 7, &len);
823  is_temp = mach_read_from_4(field)
825  } else {
826  /* For tables created with old versions
827  of InnoDB, SYS_TABLES.MIX_LEN may contain
828  garbage. Such tables would always be
829  in ROW_FORMAT=REDUNDANT. Pretend that
830  all such tables are non-temporary. That is,
831  do not suppress error printouts about
832  temporary tables not being found. */
833  is_temp = FALSE;
834  }
835 
836  fil_space_for_table_exists_in_mem(
837  space_id, name, is_temp, TRUE, !is_temp);
838  } else {
839  /* It is a normal database startup: create the space
840  object and check that the .ibd file exists. */
841 
842  fil_open_single_table_tablespace(FALSE, space_id,
843  flags, name);
844  }
845 
846  mem_free(name);
847 
848  if (space_id > max_space_id) {
849  max_space_id = space_id;
850  }
851 
852  mtr_start(&mtr);
853 
854  btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
855  }
856 
857  goto loop;
858 }
859 
860 /********************************************************************/
864 UNIV_INTERN
865 const char*
866 dict_load_column_low(
867 /*=================*/
868  dict_table_t* table,
872  mem_heap_t* heap,
874  dict_col_t* column,
876  table_id_t* table_id,
877  const char** col_name,
878  const rec_t* rec)
879 {
880  char* name;
881  const byte* field;
882  ulint len;
883  ulint mtype;
884  ulint prtype;
885  ulint col_len;
886  ulint pos = 0;
887 
888  ut_ad(table || column);
889 
890  if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
891  return("delete-marked record in SYS_COLUMNS");
892  }
893 
894  if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
895  return("wrong number of columns in SYS_COLUMNS record");
896  }
897 
898  field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
899  if (UNIV_UNLIKELY(len != 8)) {
900 err_len:
901  return("incorrect column length in SYS_COLUMNS");
902  }
903 
904  if (table_id) {
905  *table_id = mach_read_from_8(field);
906  } else if (UNIV_UNLIKELY(table->id != mach_read_from_8(field))) {
907  return("SYS_COLUMNS.TABLE_ID mismatch");
908  }
909 
910  field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
911  if (UNIV_UNLIKELY(len != 4)) {
912 
913  goto err_len;
914  }
915 
916  pos = mach_read_from_4(field);
917 
918  if (UNIV_UNLIKELY(table && table->n_def != pos)) {
919  return("SYS_COLUMNS.POS mismatch");
920  }
921 
922  rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
923  if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
924  goto err_len;
925  }
926  rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
927  if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
928  goto err_len;
929  }
930 
931  field = rec_get_nth_field_old(rec, 4/*NAME*/, &len);
932  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
933  goto err_len;
934  }
935 
936  name = mem_heap_strdupl(heap, (const char*) field, len);
937 
938  if (col_name) {
939  *col_name = name;
940  }
941 
942  field = rec_get_nth_field_old(rec, 5/*MTYPE*/, &len);
943  if (UNIV_UNLIKELY(len != 4)) {
944  goto err_len;
945  }
946 
947  mtype = mach_read_from_4(field);
948 
949  field = rec_get_nth_field_old(rec, 6/*PRTYPE*/, &len);
950  if (UNIV_UNLIKELY(len != 4)) {
951  goto err_len;
952  }
953  prtype = mach_read_from_4(field);
954 
955  if (dtype_get_charset_coll(prtype) == 0
956  && dtype_is_string_type(mtype)) {
957  /* The table was created with < 4.1.2. */
958 
959  if (dtype_is_binary_string_type(mtype, prtype)) {
960  /* Use the binary collation for
961  string columns of binary type. */
962 
963  prtype = dtype_form_prtype(
964  prtype,
965  DATA_MYSQL_BINARY_CHARSET_COLL);
966  } else {
967  /* Use the default charset for
968  other than binary columns. */
969 
970  prtype = dtype_form_prtype(
971  prtype,
972  data_mysql_default_charset_coll);
973  }
974  }
975 
976  field = rec_get_nth_field_old(rec, 7/*LEN*/, &len);
977  if (UNIV_UNLIKELY(len != 4)) {
978  goto err_len;
979  }
980  col_len = mach_read_from_4(field);
981  field = rec_get_nth_field_old(rec, 8/*PREC*/, &len);
982  if (UNIV_UNLIKELY(len != 4)) {
983  goto err_len;
984  }
985 
986  if (!column) {
987  dict_mem_table_add_col(table, heap, name, mtype,
988  prtype, col_len);
989  } else {
990  dict_mem_fill_column_struct(column, pos, mtype,
991  prtype, col_len);
992  }
993 
994  return(NULL);
995 }
996 
997 /********************************************************************/
999 static
1000 void
1001 dict_load_columns(
1002 /*==============*/
1003  dict_table_t* table,
1004  mem_heap_t* heap)
1006 {
1007  dict_table_t* sys_columns;
1008  dict_index_t* sys_index;
1009  btr_pcur_t pcur;
1010  dtuple_t* tuple;
1011  dfield_t* dfield;
1012  const rec_t* rec;
1013  byte* buf;
1014  ulint i;
1015  mtr_t mtr;
1016 
1017  ut_ad(mutex_own(&(dict_sys->mutex)));
1018 
1019  mtr_start(&mtr);
1020 
1021  sys_columns = dict_table_get_low("SYS_COLUMNS");
1022  sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
1023  ut_a(!dict_table_is_comp(sys_columns));
1024 
1025  ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
1026  ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
1027 
1028  tuple = dtuple_create(heap, 1);
1029  dfield = dtuple_get_nth_field(tuple, 0);
1030 
1031  buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
1032  mach_write_to_8(buf, table->id);
1033 
1034  dfield_set_data(dfield, buf, 8);
1035  dict_index_copy_types(tuple, sys_index, 1);
1036 
1037  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1038  BTR_SEARCH_LEAF, &pcur, &mtr);
1039  for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1040  const char* err_msg;
1041 
1042  rec = btr_pcur_get_rec(&pcur);
1043 
1044  ut_a(btr_pcur_is_on_user_rec(&pcur));
1045 
1046  err_msg = dict_load_column_low(table, heap, NULL, NULL,
1047  NULL, rec);
1048 
1049  if (err_msg) {
1050  fprintf(stderr, "InnoDB: %s\n", err_msg);
1051  ut_error;
1052  }
1053 
1054  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1055  }
1056 
1057  btr_pcur_close(&pcur);
1058  mtr_commit(&mtr);
1059 }
1060 
1062 static const char* dict_load_field_del = "delete-marked record in SYS_FIELDS";
1063 
1064 /********************************************************************/
1068 UNIV_INTERN
1069 const char*
1070 dict_load_field_low(
1071 /*================*/
1072  byte* index_id,
1075  dict_index_t* index,
1079  dict_field_t* sys_field,
1081  ulint* pos,
1082  byte* last_index_id,
1083  mem_heap_t* heap,
1085  const rec_t* rec)
1086 {
1087  const byte* field;
1088  ulint len;
1089  ulint pos_and_prefix_len;
1090  ulint prefix_len;
1091  ibool first_field;
1092  ulint position;
1093 
1094  /* Either index or sys_field is supplied, not both */
1095  ut_a((!index) || (!sys_field));
1096 
1097  if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1098  return(dict_load_field_del);
1099  }
1100 
1101  if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
1102  return("wrong number of columns in SYS_FIELDS record");
1103  }
1104 
1105  field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
1106  if (UNIV_UNLIKELY(len != 8)) {
1107 err_len:
1108  return("incorrect column length in SYS_FIELDS");
1109  }
1110 
1111  if (!index) {
1112  ut_a(last_index_id);
1113  memcpy(index_id, (const char*)field, 8);
1114  first_field = memcmp(index_id, last_index_id, 8);
1115  } else {
1116  first_field = (index->n_def == 0);
1117  if (memcmp(field, index_id, 8)) {
1118  return("SYS_FIELDS.INDEX_ID mismatch");
1119  }
1120  }
1121 
1122  field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
1123  if (UNIV_UNLIKELY(len != 4)) {
1124  goto err_len;
1125  }
1126 
1127  rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
1128  if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
1129  goto err_len;
1130  }
1131  rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
1132  if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
1133  goto err_len;
1134  }
1135 
1136  /* The next field stores the field position in the index and a
1137  possible column prefix length if the index field does not
1138  contain the whole column. The storage format is like this: if
1139  there is at least one prefix field in the index, then the HIGH
1140  2 bytes contain the field number (index->n_def) and the low 2
1141  bytes the prefix length for the field. Otherwise the field
1142  number (index->n_def) is contained in the 2 LOW bytes. */
1143 
1144  pos_and_prefix_len = mach_read_from_4(field);
1145 
1146  if (index && UNIV_UNLIKELY
1147  ((pos_and_prefix_len & 0xFFFFUL) != index->n_def
1148  && (pos_and_prefix_len >> 16 & 0xFFFF) != index->n_def)) {
1149  return("SYS_FIELDS.POS mismatch");
1150  }
1151 
1152  if (first_field || pos_and_prefix_len > 0xFFFFUL) {
1153  prefix_len = pos_and_prefix_len & 0xFFFFUL;
1154  position = (pos_and_prefix_len & 0xFFFF0000UL) >> 16;
1155  } else {
1156  prefix_len = 0;
1157  position = pos_and_prefix_len & 0xFFFFUL;
1158  }
1159 
1160  field = rec_get_nth_field_old(rec, 4, &len);
1161  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
1162  goto err_len;
1163  }
1164 
1165  if (index) {
1166  dict_mem_index_add_field(
1167  index, mem_heap_strdupl(heap, (const char*) field, len),
1168  prefix_len);
1169  } else {
1170  ut_a(sys_field);
1171  ut_a(pos);
1172 
1173  sys_field->name = mem_heap_strdupl(
1174  heap, (const char*) field, len);
1175  sys_field->prefix_len = prefix_len;
1176  *pos = position;
1177  }
1178 
1179  return(NULL);
1180 }
1181 
1182 /********************************************************************/
1185 static
1186 ulint
1187 dict_load_fields(
1188 /*=============*/
1189  dict_index_t* index,
1190  mem_heap_t* heap)
1191 {
1192  dict_table_t* sys_fields;
1193  dict_index_t* sys_index;
1194  btr_pcur_t pcur;
1195  dtuple_t* tuple;
1196  dfield_t* dfield;
1197  const rec_t* rec;
1198  byte* buf;
1199  ulint i;
1200  mtr_t mtr;
1201  ulint error;
1202 
1203  ut_ad(mutex_own(&(dict_sys->mutex)));
1204 
1205  mtr_start(&mtr);
1206 
1207  sys_fields = dict_table_get_low("SYS_FIELDS");
1208  sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
1209  ut_a(!dict_table_is_comp(sys_fields));
1210  ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
1211 
1212  tuple = dtuple_create(heap, 1);
1213  dfield = dtuple_get_nth_field(tuple, 0);
1214 
1215  buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
1216  mach_write_to_8(buf, index->id);
1217 
1218  dfield_set_data(dfield, buf, 8);
1219  dict_index_copy_types(tuple, sys_index, 1);
1220 
1221  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1222  BTR_SEARCH_LEAF, &pcur, &mtr);
1223  for (i = 0; i < index->n_fields; i++) {
1224  const char* err_msg;
1225 
1226  rec = btr_pcur_get_rec(&pcur);
1227 
1228  ut_a(btr_pcur_is_on_user_rec(&pcur));
1229 
1230  err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL,
1231  heap, rec);
1232 
1233  if (err_msg == dict_load_field_del) {
1234  /* There could be delete marked records in
1235  SYS_FIELDS because SYS_FIELDS.INDEX_ID can be
1236  updated by ALTER TABLE ADD INDEX. */
1237 
1238  goto next_rec;
1239  } else if (err_msg) {
1240  fprintf(stderr, "InnoDB: %s\n", err_msg);
1241  error = DB_CORRUPTION;
1242  goto func_exit;
1243  }
1244 next_rec:
1245  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1246  }
1247 
1248  error = DB_SUCCESS;
1249 func_exit:
1250  btr_pcur_close(&pcur);
1251  mtr_commit(&mtr);
1252  return(error);
1253 }
1254 
1256 static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES";
1258 static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch";
1259 
1260 /********************************************************************/
1266 UNIV_INTERN
1267 const char*
1268 dict_load_index_low(
1269 /*================*/
1270  byte* table_id,
1273  const char* table_name,
1274  mem_heap_t* heap,
1275  const rec_t* rec,
1276  ibool allocate,
1279  dict_index_t** index)
1280 {
1281  const byte* field;
1282  ulint len;
1283  ulint name_len;
1284  char* name_buf;
1285  index_id_t id;
1286  ulint n_fields;
1287  ulint type;
1288  ulint space;
1289 
1290  if (allocate) {
1291  /* If allocate=TRUE, no dict_index_t will
1292  be supplied. Initialize "*index" to NULL */
1293  *index = NULL;
1294  }
1295 
1296  if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1297  return(dict_load_index_del);
1298  }
1299 
1300  if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
1301  return("wrong number of columns in SYS_INDEXES record");
1302  }
1303 
1304  field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
1305  if (UNIV_UNLIKELY(len != 8)) {
1306 err_len:
1307  return("incorrect column length in SYS_INDEXES");
1308  }
1309 
1310  if (!allocate) {
1311  /* We are reading a SYS_INDEXES record. Copy the table_id */
1312  memcpy(table_id, (const char*)field, 8);
1313  } else if (memcmp(field, table_id, 8)) {
1314  /* Caller supplied table_id, verify it is the same
1315  id as on the index record */
1316  return(dict_load_index_id_err);
1317  }
1318 
1319  field = rec_get_nth_field_old(rec, 1/*ID*/, &len);
1320  if (UNIV_UNLIKELY(len != 8)) {
1321  goto err_len;
1322  }
1323 
1324  id = mach_read_from_8(field);
1325 
1326  rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
1327  if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
1328  goto err_len;
1329  }
1330  rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
1331  if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
1332  goto err_len;
1333  }
1334 
1335  field = rec_get_nth_field_old(rec, 4/*NAME*/, &name_len);
1336  if (UNIV_UNLIKELY(name_len == UNIV_SQL_NULL)) {
1337  goto err_len;
1338  }
1339 
1340  name_buf = mem_heap_strdupl(heap, (const char*) field,
1341  name_len);
1342 
1343  field = rec_get_nth_field_old(rec, 5/*N_FIELDS*/, &len);
1344  if (UNIV_UNLIKELY(len != 4)) {
1345  goto err_len;
1346  }
1347  n_fields = mach_read_from_4(field);
1348 
1349  field = rec_get_nth_field_old(rec, 6/*TYPE*/, &len);
1350  if (UNIV_UNLIKELY(len != 4)) {
1351  goto err_len;
1352  }
1353  type = mach_read_from_4(field);
1354 
1355  field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len);
1356  if (UNIV_UNLIKELY(len != 4)) {
1357  goto err_len;
1358  }
1359  space = mach_read_from_4(field);
1360 
1361  field = rec_get_nth_field_old(rec, 8/*PAGE_NO*/, &len);
1362  if (UNIV_UNLIKELY(len != 4)) {
1363  goto err_len;
1364  }
1365 
1366  if (allocate) {
1367  *index = dict_mem_index_create(table_name, name_buf,
1368  space, type, n_fields);
1369  } else {
1370  ut_a(*index);
1371 
1372  dict_mem_fill_index_struct(*index, NULL, NULL, name_buf,
1373  space, type, n_fields);
1374  }
1375 
1376  (*index)->id = id;
1377  (*index)->page = mach_read_from_4(field);
1378  ut_ad((*index)->page);
1379 
1380  return(NULL);
1381 }
1382 
1383 /********************************************************************/
1388 static
1389 ulint
1390 dict_load_indexes(
1391 /*==============*/
1392  dict_table_t* table,
1393  mem_heap_t* heap)
1394 {
1395  dict_table_t* sys_indexes;
1396  dict_index_t* sys_index;
1397  btr_pcur_t pcur;
1398  dtuple_t* tuple;
1399  dfield_t* dfield;
1400  const rec_t* rec;
1401  byte* buf;
1402  mtr_t mtr;
1403  ulint error = DB_SUCCESS;
1404 
1405  ut_ad(mutex_own(&(dict_sys->mutex)));
1406 
1407  mtr_start(&mtr);
1408 
1409  sys_indexes = dict_table_get_low("SYS_INDEXES");
1410  sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
1411  ut_a(!dict_table_is_comp(sys_indexes));
1412  ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
1413  ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
1414 
1415  tuple = dtuple_create(heap, 1);
1416  dfield = dtuple_get_nth_field(tuple, 0);
1417 
1418  buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
1419  mach_write_to_8(buf, table->id);
1420 
1421  dfield_set_data(dfield, buf, 8);
1422  dict_index_copy_types(tuple, sys_index, 1);
1423 
1424  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1425  BTR_SEARCH_LEAF, &pcur, &mtr);
1426  for (;;) {
1427  dict_index_t* index = NULL;
1428  const char* err_msg;
1429 
1430  if (!btr_pcur_is_on_user_rec(&pcur)) {
1431 
1432  break;
1433  }
1434 
1435  rec = btr_pcur_get_rec(&pcur);
1436 
1437  err_msg = dict_load_index_low(buf, table->name, heap, rec,
1438  TRUE, &index);
1439  ut_ad((index == NULL) == (err_msg != NULL));
1440 
1441  if (err_msg == dict_load_index_id_err) {
1442  /* TABLE_ID mismatch means that we have
1443  run out of index definitions for the table. */
1444  break;
1445  } else if (err_msg == dict_load_index_del) {
1446  /* Skip delete-marked records. */
1447  goto next_rec;
1448  } else if (err_msg) {
1449  fprintf(stderr, "InnoDB: %s\n", err_msg);
1450  error = DB_CORRUPTION;
1451  goto func_exit;
1452  }
1453 
1454  ut_ad(index);
1455 
1456  /* We check for unsupported types first, so that the
1457  subsequent checks are relevant for the supported types. */
1458  if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
1459 
1460  fprintf(stderr,
1461  "InnoDB: Error: unknown type %lu"
1462  " of index %s of table %s\n",
1463  (ulong) index->type, index->name, table->name);
1464 
1465  error = DB_UNSUPPORTED;
1466  dict_mem_index_free(index);
1467  goto func_exit;
1468  } else if (index->page == FIL_NULL) {
1469 
1470  fprintf(stderr,
1471  "InnoDB: Error: trying to load index %s"
1472  " for table %s\n"
1473  "InnoDB: but the index tree has been freed!\n",
1474  index->name, table->name);
1475 
1476 corrupted:
1477  dict_mem_index_free(index);
1478  error = DB_CORRUPTION;
1479  goto func_exit;
1480  } else if (!dict_index_is_clust(index)
1481  && NULL == dict_table_get_first_index(table)) {
1482 
1483  fputs("InnoDB: Error: trying to load index ",
1484  stderr);
1485  ut_print_name(stderr, NULL, FALSE, index->name);
1486  fputs(" for table ", stderr);
1487  ut_print_name(stderr, NULL, TRUE, table->name);
1488  fputs("\nInnoDB: but the first index"
1489  " is not clustered!\n", stderr);
1490 
1491  goto corrupted;
1492  } else if (table->id < DICT_HDR_FIRST_ID
1493  && (dict_index_is_clust(index)
1494  || ((table == dict_sys->sys_tables)
1495  && !strcmp("ID_IND", index->name)))) {
1496 
1497  /* The index was created in memory already at booting
1498  of the database server */
1499  dict_mem_index_free(index);
1500  } else {
1501  dict_load_fields(index, heap);
1502  error = dict_index_add_to_cache(table, index,
1503  index->page, FALSE);
1504  /* The data dictionary tables should never contain
1505  invalid index definitions. If we ignored this error
1506  and simply did not load this index definition, the
1507  .frm file would disagree with the index definitions
1508  inside InnoDB. */
1509  if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
1510 
1511  goto func_exit;
1512  }
1513  }
1514 
1515 next_rec:
1516  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1517  }
1518 
1519 func_exit:
1520  btr_pcur_close(&pcur);
1521  mtr_commit(&mtr);
1522 
1523  return(error);
1524 }
1525 
1526 /********************************************************************/
1530 UNIV_INTERN
1531 const char*
1532 dict_load_table_low(
1533 /*================*/
1534  const char* name,
1535  const rec_t* rec,
1536  dict_table_t** table)
1537 {
1538  const byte* field;
1539  ulint len;
1540  ulint space;
1541  ulint n_cols;
1542  ulint flags;
1543 
1544  if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1545  return("delete-marked record in SYS_TABLES");
1546  }
1547 
1548  if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 10)) {
1549  return("wrong number of columns in SYS_TABLES record");
1550  }
1551 
1552  rec_get_nth_field_offs_old(rec, 0/*NAME*/, &len);
1553  if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
1554 err_len:
1555  return("incorrect column length in SYS_TABLES");
1556  }
1557  rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
1558  if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
1559  goto err_len;
1560  }
1561  rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
1562  if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
1563  goto err_len;
1564  }
1565 
1566  rec_get_nth_field_offs_old(rec, 3/*ID*/, &len);
1567  if (UNIV_UNLIKELY(len != 8)) {
1568  goto err_len;
1569  }
1570 
1571  field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
1572  if (UNIV_UNLIKELY(len != 4)) {
1573  goto err_len;
1574  }
1575 
1576  n_cols = mach_read_from_4(field);
1577 
1578  rec_get_nth_field_offs_old(rec, 5/*TYPE*/, &len);
1579  if (UNIV_UNLIKELY(len != 4)) {
1580  goto err_len;
1581  }
1582 
1583  rec_get_nth_field_offs_old(rec, 6/*MIX_ID*/, &len);
1584  if (UNIV_UNLIKELY(len != 8)) {
1585  goto err_len;
1586  }
1587 
1588  rec_get_nth_field_offs_old(rec, 7/*MIX_LEN*/, &len);
1589  if (UNIV_UNLIKELY(len != 4)) {
1590  goto err_len;
1591  }
1592 
1593  rec_get_nth_field_offs_old(rec, 8/*CLUSTER_ID*/, &len);
1594  if (UNIV_UNLIKELY(len != UNIV_SQL_NULL)) {
1595  goto err_len;
1596  }
1597 
1598  field = rec_get_nth_field_old(rec, 9/*SPACE*/, &len);
1599 
1600  if (UNIV_UNLIKELY(len != 4)) {
1601  goto err_len;
1602  }
1603 
1604  space = mach_read_from_4(field);
1605 
1606  /* Check if the tablespace exists and has the right name */
1607  if (space != 0) {
1608  flags = dict_sys_tables_get_flags(rec);
1609 
1610  if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
1611  field = rec_get_nth_field_old(rec, 5/*TYPE*/, &len);
1612  ut_ad(len == 4); /* this was checked earlier */
1613  flags = mach_read_from_4(field);
1614 
1615  ut_print_timestamp(stderr);
1616  fputs(" InnoDB: Error: table ", stderr);
1617  ut_print_filename(stderr, name);
1618  fprintf(stderr, "\n"
1619  "InnoDB: in InnoDB data dictionary"
1620  " has unknown type %lx.\n",
1621  (ulong) flags);
1622  return(NULL);
1623  }
1624  } else {
1625  flags = 0;
1626  }
1627 
1628  /* The high-order bit of N_COLS is the "compact format" flag.
1629  For tables in that format, MIX_LEN may hold additional flags. */
1630  if (n_cols & 0x80000000UL) {
1631  ulint flags2;
1632 
1633  flags |= DICT_TF_COMPACT;
1634 
1635  field = rec_get_nth_field_old(rec, 7, &len);
1636 
1637  if (UNIV_UNLIKELY(len != 4)) {
1638 
1639  goto err_len;
1640  }
1641 
1642  flags2 = mach_read_from_4(field);
1643 
1644  if (flags2 & (SIZE_MAX << (DICT_TF2_BITS - DICT_TF2_SHIFT))) {
1645  ut_print_timestamp(stderr);
1646  fputs(" InnoDB: Warning: table ", stderr);
1647  ut_print_filename(stderr, name);
1648  fprintf(stderr, "\n"
1649  "InnoDB: in InnoDB data dictionary"
1650  " has unknown flags %lx.\n",
1651  (ulong) flags2);
1652 
1653  flags2 &= ~(~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT));
1654  }
1655 
1656  flags |= flags2 << DICT_TF2_SHIFT;
1657  }
1658 
1659  /* See if the tablespace is available. */
1660  *table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
1661  flags);
1662 
1663  field = rec_get_nth_field_old(rec, 3/*ID*/, &len);
1664  ut_ad(len == 8); /* this was checked earlier */
1665 
1666  (*table)->id = mach_read_from_8(field);
1667 
1668  (*table)->ibd_file_missing = FALSE;
1669 
1670  return(NULL);
1671 }
1672 
1673 /********************************************************************/
1682 UNIV_INTERN
1683 dict_table_t*
1684 dict_load_table(
1685 /*============*/
1686  const char* name,
1688  ibool cached)
1689 {
1690  dict_table_t* table;
1691  dict_table_t* sys_tables;
1692  btr_pcur_t pcur;
1693  dict_index_t* sys_index;
1694  dtuple_t* tuple;
1695  mem_heap_t* heap;
1696  dfield_t* dfield;
1697  const rec_t* rec;
1698  const byte* field;
1699  ulint len;
1700  ulint err;
1701  const char* err_msg;
1702  mtr_t mtr;
1703 
1704  ut_ad(mutex_own(&(dict_sys->mutex)));
1705 
1706  heap = mem_heap_create(32000);
1707 
1708  mtr_start(&mtr);
1709 
1710  sys_tables = dict_table_get_low("SYS_TABLES");
1711  sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
1712  ut_a(!dict_table_is_comp(sys_tables));
1713  ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
1714  ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
1715  ut_a(name_of_col_is(sys_tables, sys_index, 5, "TYPE"));
1716  ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN"));
1717  ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
1718 
1719  tuple = dtuple_create(heap, 1);
1720  dfield = dtuple_get_nth_field(tuple, 0);
1721 
1722  dfield_set_data(dfield, name, ut_strlen(name));
1723  dict_index_copy_types(tuple, sys_index, 1);
1724 
1725  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1726  BTR_SEARCH_LEAF, &pcur, &mtr);
1727  rec = btr_pcur_get_rec(&pcur);
1728 
1729  if (!btr_pcur_is_on_user_rec(&pcur)
1730  || rec_get_deleted_flag(rec, 0)) {
1731  /* Not found */
1732 err_exit:
1733  btr_pcur_close(&pcur);
1734  mtr_commit(&mtr);
1735  mem_heap_free(heap);
1736 
1737  return(NULL);
1738  }
1739 
1740  field = rec_get_nth_field_old(rec, 0, &len);
1741 
1742  /* Check if the table name in record is the searched one */
1743  if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
1744 
1745  goto err_exit;
1746  }
1747 
1748  err_msg = dict_load_table_low(name, rec, &table);
1749 
1750  if (err_msg) {
1751 
1752  ut_print_timestamp(stderr);
1753  fprintf(stderr, " InnoDB: %s\n", err_msg);
1754  goto err_exit;
1755  }
1756 
1757  if (table->space == 0) {
1758  /* The system tablespace is always available. */
1759  } else if (!fil_space_for_table_exists_in_mem(
1760  table->space, name,
1761  (table->flags >> DICT_TF2_SHIFT)
1763  FALSE, FALSE)) {
1764 
1765  if (table->flags & (DICT_TF2_TEMPORARY << DICT_TF2_SHIFT)) {
1766  /* Do not bother to retry opening temporary tables. */
1767  table->ibd_file_missing = TRUE;
1768  } else {
1769  ut_print_timestamp(stderr);
1770  fprintf(stderr,
1771  " InnoDB: error: space object of table ");
1772  ut_print_filename(stderr, name);
1773  fprintf(stderr, ",\n"
1774  "InnoDB: space id %lu did not exist in memory."
1775  " Retrying an open.\n",
1776  (ulong) table->space);
1777  /* Try to open the tablespace */
1778  if (!fil_open_single_table_tablespace(
1779  TRUE, table->space,
1780  table->flags == DICT_TF_COMPACT ? 0 :
1781  table->flags & ~(~0 << DICT_TF_BITS), name)) {
1782  /* We failed to find a sensible
1783  tablespace file */
1784 
1785  table->ibd_file_missing = TRUE;
1786  }
1787  }
1788  }
1789 
1790  btr_pcur_close(&pcur);
1791  mtr_commit(&mtr);
1792 
1793  dict_load_columns(table, heap);
1794 
1795  if (cached) {
1796  dict_table_add_to_cache(table, heap);
1797  } else {
1798  dict_table_add_system_columns(table, heap);
1799  }
1800 
1801  mem_heap_empty(heap);
1802 
1803  err = dict_load_indexes(table, heap);
1804 
1805  /* Initialize table foreign_child value. Its value could be
1806  changed when dict_load_foreigns() is called below */
1807  table->fk_max_recusive_level = 0;
1808 
1809  /* If the force recovery flag is set, we open the table irrespective
1810  of the error condition, since the user may want to dump data from the
1811  clustered index. However we load the foreign key information only if
1812  all indexes were loaded. */
1813  if (!cached) {
1814  } else if (err == DB_SUCCESS) {
1815  err = dict_load_foreigns(table->name, TRUE, TRUE);
1816 
1817  if (err != DB_SUCCESS) {
1818  dict_table_remove_from_cache(table);
1819  table = NULL;
1820  } else {
1821  table->fk_max_recusive_level = 0;
1822  }
1823  } else if (!srv_force_recovery) {
1824  dict_table_remove_from_cache(table);
1825  table = NULL;
1826  }
1827 #if 0
1828  if (err != DB_SUCCESS && table != NULL) {
1829 
1830  mutex_enter(&dict_foreign_err_mutex);
1831 
1832  ut_print_timestamp(stderr);
1833 
1834  fprintf(stderr,
1835  " InnoDB: Error: could not make a foreign key"
1836  " definition to match\n"
1837  "InnoDB: the foreign key table"
1838  " or the referenced table!\n"
1839  "InnoDB: The data dictionary of InnoDB is corrupt."
1840  " You may need to drop\n"
1841  "InnoDB: and recreate the foreign key table"
1842  " or the referenced table.\n"
1843  "InnoDB: Submit a detailed bug report"
1844  " to http://bugs.mysql.com\n"
1845  "InnoDB: Latest foreign key error printout:\n%s\n",
1846  dict_foreign_err_buf);
1847 
1848  mutex_exit(&dict_foreign_err_mutex);
1849  }
1850 #endif /* 0 */
1851  mem_heap_free(heap);
1852 
1853  return(table);
1854 }
1855 
1856 /***********************************************************************/
1859 UNIV_INTERN
1860 dict_table_t*
1861 dict_load_table_on_id(
1862 /*==================*/
1863  table_id_t table_id)
1864 {
1865  byte id_buf[8];
1866  btr_pcur_t pcur;
1867  mem_heap_t* heap;
1868  dtuple_t* tuple;
1869  dfield_t* dfield;
1870  dict_index_t* sys_table_ids;
1871  dict_table_t* sys_tables;
1872  const rec_t* rec;
1873  const byte* field;
1874  ulint len;
1875  dict_table_t* table;
1876  mtr_t mtr;
1877 
1878  ut_ad(mutex_own(&(dict_sys->mutex)));
1879 
1880  table = NULL;
1881 
1882  /* NOTE that the operation of this function is protected by
1883  the dictionary mutex, and therefore no deadlocks can occur
1884  with other dictionary operations. */
1885 
1886  mtr_start(&mtr);
1887  /*---------------------------------------------------*/
1888  /* Get the secondary index based on ID for table SYS_TABLES */
1889  sys_tables = dict_sys->sys_tables;
1890  sys_table_ids = dict_table_get_next_index(
1891  dict_table_get_first_index(sys_tables));
1892  ut_a(!dict_table_is_comp(sys_tables));
1893  heap = mem_heap_create(256);
1894 
1895  tuple = dtuple_create(heap, 1);
1896  dfield = dtuple_get_nth_field(tuple, 0);
1897 
1898  /* Write the table id in byte format to id_buf */
1899  mach_write_to_8(id_buf, table_id);
1900 
1901  dfield_set_data(dfield, id_buf, 8);
1902  dict_index_copy_types(tuple, sys_table_ids, 1);
1903 
1904  btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
1905  BTR_SEARCH_LEAF, &pcur, &mtr);
1906  rec = btr_pcur_get_rec(&pcur);
1907 
1908  if (!btr_pcur_is_on_user_rec(&pcur)) {
1909  /* Not found */
1910  goto func_exit;
1911  }
1912 
1913  /* Find the first record that is not delete marked */
1914  while (rec_get_deleted_flag(rec, 0)) {
1915  if (!btr_pcur_move_to_next_user_rec(&pcur, &mtr)) {
1916  goto func_exit;
1917  }
1918  rec = btr_pcur_get_rec(&pcur);
1919  }
1920 
1921  /*---------------------------------------------------*/
1922  /* Now we have the record in the secondary index containing the
1923  table ID and NAME */
1924 
1925  rec = btr_pcur_get_rec(&pcur);
1926  field = rec_get_nth_field_old(rec, 0, &len);
1927  ut_ad(len == 8);
1928 
1929  /* Check if the table id in record is the one searched for */
1930  if (table_id != mach_read_from_8(field)) {
1931  goto func_exit;
1932  }
1933 
1934  /* Now we get the table name from the record */
1935  field = rec_get_nth_field_old(rec, 1, &len);
1936  /* Load the table definition to memory */
1937  table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len),
1938  TRUE);
1939 func_exit:
1940  btr_pcur_close(&pcur);
1941  mtr_commit(&mtr);
1942  mem_heap_free(heap);
1943 
1944  return(table);
1945 }
1946 
1947 /********************************************************************/
1951 UNIV_INTERN
1952 void
1953 dict_load_sys_table(
1954 /*================*/
1955  dict_table_t* table)
1956 {
1957  mem_heap_t* heap;
1958 
1959  ut_ad(mutex_own(&(dict_sys->mutex)));
1960 
1961  heap = mem_heap_create(1000);
1962 
1963  dict_load_indexes(table, heap);
1964 
1965  mem_heap_free(heap);
1966 }
1967 
1968 /********************************************************************/
1970 static
1971 void
1972 dict_load_foreign_cols(
1973 /*===================*/
1974  const char* id,
1976  dict_foreign_t* foreign)
1977 {
1978  dict_table_t* sys_foreign_cols;
1979  dict_index_t* sys_index;
1980  btr_pcur_t pcur;
1981  dtuple_t* tuple;
1982  dfield_t* dfield;
1983  const rec_t* rec;
1984  const byte* field;
1985  ulint len;
1986  ulint i;
1987  mtr_t mtr;
1988 
1989  ut_ad(mutex_own(&(dict_sys->mutex)));
1990 
1991  foreign->foreign_col_names = static_cast<const char **>(mem_heap_alloc(
1992  foreign->heap, foreign->n_fields * sizeof(void*)));
1993 
1994  foreign->referenced_col_names = static_cast<const char **>(mem_heap_alloc(
1995  foreign->heap, foreign->n_fields * sizeof(void*)));
1996  mtr_start(&mtr);
1997 
1998  sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
1999  sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
2000  ut_a(!dict_table_is_comp(sys_foreign_cols));
2001 
2002  tuple = dtuple_create(foreign->heap, 1);
2003  dfield = dtuple_get_nth_field(tuple, 0);
2004 
2005  dfield_set_data(dfield, id, ut_strlen(id));
2006  dict_index_copy_types(tuple, sys_index, 1);
2007 
2008  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2009  BTR_SEARCH_LEAF, &pcur, &mtr);
2010  for (i = 0; i < foreign->n_fields; i++) {
2011 
2012  rec = btr_pcur_get_rec(&pcur);
2013 
2014  ut_a(btr_pcur_is_on_user_rec(&pcur));
2015  ut_a(!rec_get_deleted_flag(rec, 0));
2016 
2017  field = rec_get_nth_field_old(rec, 0, &len);
2018  ut_a(len == ut_strlen(id));
2019  ut_a(ut_memcmp(id, field, len) == 0);
2020 
2021  field = rec_get_nth_field_old(rec, 1, &len);
2022  ut_a(len == 4);
2023  ut_a(i == mach_read_from_4(field));
2024 
2025  field = rec_get_nth_field_old(rec, 4, &len);
2026  foreign->foreign_col_names[i] = mem_heap_strdupl(
2027  foreign->heap, (char*) field, len);
2028 
2029  field = rec_get_nth_field_old(rec, 5, &len);
2030  foreign->referenced_col_names[i] = mem_heap_strdupl(
2031  foreign->heap, (char*) field, len);
2032 
2033  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2034  }
2035 
2036  btr_pcur_close(&pcur);
2037  mtr_commit(&mtr);
2038 }
2039 
2040 /***********************************************************************/
2043 static
2044 ulint
2045 dict_load_foreign(
2046 /*==============*/
2047  const char* id,
2049  ibool check_charsets,
2051  ibool check_recursive)
2055 {
2056  dict_foreign_t* foreign;
2057  dict_table_t* sys_foreign;
2058  btr_pcur_t pcur;
2059  dict_index_t* sys_index;
2060  dtuple_t* tuple;
2061  mem_heap_t* heap2;
2062  dfield_t* dfield;
2063  const rec_t* rec;
2064  const byte* field;
2065  ulint len;
2066  ulint n_fields_and_type;
2067  mtr_t mtr;
2068  dict_table_t* for_table;
2069  dict_table_t* ref_table;
2070 
2071  ut_ad(mutex_own(&(dict_sys->mutex)));
2072 
2073  heap2 = mem_heap_create(1000);
2074 
2075  mtr_start(&mtr);
2076 
2077  sys_foreign = dict_table_get_low("SYS_FOREIGN");
2078  sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
2079  ut_a(!dict_table_is_comp(sys_foreign));
2080 
2081  tuple = dtuple_create(heap2, 1);
2082  dfield = dtuple_get_nth_field(tuple, 0);
2083 
2084  dfield_set_data(dfield, id, ut_strlen(id));
2085  dict_index_copy_types(tuple, sys_index, 1);
2086 
2087  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2088  BTR_SEARCH_LEAF, &pcur, &mtr);
2089  rec = btr_pcur_get_rec(&pcur);
2090 
2091  if (!btr_pcur_is_on_user_rec(&pcur)
2092  || rec_get_deleted_flag(rec, 0)) {
2093  /* Not found */
2094 
2095  fprintf(stderr,
2096  "InnoDB: Error A: cannot load foreign constraint %s\n",
2097  id);
2098 
2099  btr_pcur_close(&pcur);
2100  mtr_commit(&mtr);
2101  mem_heap_free(heap2);
2102 
2103  return(DB_ERROR);
2104  }
2105 
2106  field = rec_get_nth_field_old(rec, 0, &len);
2107 
2108  /* Check if the id in record is the searched one */
2109  if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
2110 
2111  fprintf(stderr,
2112  "InnoDB: Error B: cannot load foreign constraint %s\n",
2113  id);
2114 
2115  btr_pcur_close(&pcur);
2116  mtr_commit(&mtr);
2117  mem_heap_free(heap2);
2118 
2119  return(DB_ERROR);
2120  }
2121 
2122  /* Read the table names and the number of columns associated
2123  with the constraint */
2124 
2125  mem_heap_free(heap2);
2126 
2127  foreign = dict_mem_foreign_create();
2128 
2129  n_fields_and_type = mach_read_from_4(
2130  rec_get_nth_field_old(rec, 5, &len));
2131 
2132  ut_a(len == 4);
2133 
2134  /* We store the type in the bits 24..29 of n_fields_and_type. */
2135 
2136  foreign->type = (unsigned int) (n_fields_and_type >> 24);
2137  foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
2138 
2139  foreign->id = mem_heap_strdup(foreign->heap, id);
2140 
2141  field = rec_get_nth_field_old(rec, 3, &len);
2143  foreign->heap, (char*) field, len);
2144 
2145  field = rec_get_nth_field_old(rec, 4, &len);
2147  foreign->heap, (char*) field, len);
2148 
2149  btr_pcur_close(&pcur);
2150  mtr_commit(&mtr);
2151 
2152  dict_load_foreign_cols(id, foreign);
2153 
2155  foreign->referenced_table_name);
2156 
2157  /* We could possibly wind up in a deep recursive calls if
2158  we call dict_table_get_low() again here if there
2159  is a chain of tables concatenated together with
2160  foreign constraints. In such case, each table is
2161  both a parent and child of the other tables, and
2162  act as a "link" in such table chains.
2163  To avoid such scenario, we would need to check the
2164  number of ancesters the current table has. If that
2165  exceeds DICT_FK_MAX_CHAIN_LEN, we will stop loading
2166  the child table.
2167  Foreign constraints are loaded in a Breath First fashion,
2168  that is, the index on FOR_NAME is scanned first, and then
2169  index on REF_NAME. So foreign constrains in which
2170  current table is a child (foreign table) are loaded first,
2171  and then those constraints where current table is a
2172  parent (referenced) table.
2173  Thus we could check the parent (ref_table) table's
2174  reference count (fk_max_recusive_level) to know how deep the
2175  recursive call is. If the parent table (ref_table) is already
2176  loaded, and its fk_max_recusive_level is larger than
2177  DICT_FK_MAX_CHAIN_LEN, we will stop the recursive loading
2178  by skipping loading the child table. It will not affect foreign
2179  constraint check for DMLs since child table will be loaded
2180  at that time for the constraint check. */
2181  if (!ref_table
2183 
2184  /* If the foreign table is not yet in the dictionary cache, we
2185  have to load it so that we are able to make type comparisons
2186  in the next function call. */
2187 
2188  for_table = dict_table_get_low(foreign->foreign_table_name);
2189 
2190  if (for_table && ref_table && check_recursive) {
2191  /* This is to record the longest chain of ancesters
2192  this table has, if the parent has more ancesters
2193  than this table has, record it after add 1 (for this
2194  parent */
2195  if (ref_table->fk_max_recusive_level
2196  >= for_table->fk_max_recusive_level) {
2197  for_table->fk_max_recusive_level =
2198  ref_table->fk_max_recusive_level + 1;
2199  }
2200  }
2201  }
2202 
2203  /* Note that there may already be a foreign constraint object in
2204  the dictionary cache for this constraint: then the following
2205  call only sets the pointers in it to point to the appropriate table
2206  and index objects and frees the newly created object foreign.
2207  Adding to the cache should always succeed since we are not creating
2208  a new foreign key constraint but loading one from the data
2209  dictionary. */
2210 
2211  return(dict_foreign_add_to_cache(foreign, check_charsets));
2212 }
2213 
2214 /***********************************************************************/
2221 UNIV_INTERN
2222 ulint
2223 dict_load_foreigns(
2224 /*===============*/
2225  const char* table_name,
2226  ibool check_recursive,
2228  ibool check_charsets)
2230 {
2231  btr_pcur_t pcur;
2232  mem_heap_t* heap;
2233  dtuple_t* tuple;
2234  dfield_t* dfield;
2235  dict_index_t* sec_index;
2236  dict_table_t* sys_foreign;
2237  const rec_t* rec;
2238  const byte* field;
2239  ulint len;
2240  char* id ;
2241  ulint err;
2242  mtr_t mtr;
2243 
2244  ut_ad(mutex_own(&(dict_sys->mutex)));
2245 
2246  sys_foreign = dict_table_get_low("SYS_FOREIGN");
2247 
2248  if (sys_foreign == NULL) {
2249  /* No foreign keys defined yet in this database */
2250 
2251  fprintf(stderr,
2252  "InnoDB: Error: no foreign key system tables"
2253  " in the database\n");
2254 
2255  return(DB_ERROR);
2256  }
2257 
2258  ut_a(!dict_table_is_comp(sys_foreign));
2259  mtr_start(&mtr);
2260 
2261  /* Get the secondary index based on FOR_NAME from table
2262  SYS_FOREIGN */
2263 
2264  sec_index = dict_table_get_next_index(
2265  dict_table_get_first_index(sys_foreign));
2266 start_load:
2267  heap = mem_heap_create(256);
2268 
2269  tuple = dtuple_create(heap, 1);
2270  dfield = dtuple_get_nth_field(tuple, 0);
2271 
2272  dfield_set_data(dfield, table_name, ut_strlen(table_name));
2273  dict_index_copy_types(tuple, sec_index, 1);
2274 
2275  btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE,
2276  BTR_SEARCH_LEAF, &pcur, &mtr);
2277 loop:
2278  rec = btr_pcur_get_rec(&pcur);
2279 
2280  if (!btr_pcur_is_on_user_rec(&pcur)) {
2281  /* End of index */
2282 
2283  goto load_next_index;
2284  }
2285 
2286  /* Now we have the record in the secondary index containing a table
2287  name and a foreign constraint ID */
2288 
2289  rec = btr_pcur_get_rec(&pcur);
2290  field = rec_get_nth_field_old(rec, 0, &len);
2291 
2292  /* Check if the table name in the record is the one searched for; the
2293  following call does the comparison in the latin1_swedish_ci
2294  charset-collation, in a case-insensitive way. */
2295 
2296  if (0 != cmp_data_data(dfield_get_type(dfield)->mtype,
2297  dfield_get_type(dfield)->prtype,
2298  static_cast<const unsigned char *>(dfield_get_data(dfield)),
2299  dfield_get_len(dfield),
2300  field, len)) {
2301 
2302  goto load_next_index;
2303  }
2304 
2305  /* Since table names in SYS_FOREIGN are stored in a case-insensitive
2306  order, we have to check that the table name matches also in a binary
2307  string comparison. On Unix, MySQL allows table names that only differ
2308  in character case. */
2309 
2310  if (0 != ut_memcmp(field, table_name, len)) {
2311 
2312  goto next_rec;
2313  }
2314 
2315  if (rec_get_deleted_flag(rec, 0)) {
2316 
2317  goto next_rec;
2318  }
2319 
2320  /* Now we get a foreign key constraint id */
2321  field = rec_get_nth_field_old(rec, 1, &len);
2322  id = mem_heap_strdupl(heap, (char*) field, len);
2323 
2324  btr_pcur_store_position(&pcur, &mtr);
2325 
2326  mtr_commit(&mtr);
2327 
2328  /* Load the foreign constraint definition to the dictionary cache */
2329 
2330  err = dict_load_foreign(id, check_charsets, check_recursive);
2331 
2332  if (err != DB_SUCCESS) {
2333  btr_pcur_close(&pcur);
2334  mem_heap_free(heap);
2335 
2336  return(err);
2337  }
2338 
2339  mtr_start(&mtr);
2340 
2341  btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
2342 next_rec:
2343  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2344 
2345  goto loop;
2346 
2347 load_next_index:
2348  btr_pcur_close(&pcur);
2349  mtr_commit(&mtr);
2350  mem_heap_free(heap);
2351 
2352  sec_index = dict_table_get_next_index(sec_index);
2353 
2354  if (sec_index != NULL) {
2355 
2356  mtr_start(&mtr);
2357 
2358  /* Switch to scan index on REF_NAME, fk_max_recusive_level
2359  already been updated when scanning FOR_NAME index, no need to
2360  update again */
2361  check_recursive = FALSE;
2362 
2363  goto start_load;
2364  }
2365 
2366  return(DB_SUCCESS);
2367 }