1
/*****************************************************************************
3
Copyright (C) 1996, 2010, Innobase Oy. All Rights Reserved.
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.
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.
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
17
*****************************************************************************/
19
/**************************************************//**
20
@file dict/dict0load.c
21
Loads to the memory cache database object definitions
22
from dictionary tables
24
Created 4/24/1996 Heikki Tuuri
25
*******************************************************/
27
#if defined(BUILD_DRIZZLE)
30
# include "mysql_version.h"
31
#endif /* BUILD_DRIZZLE */
32
#include "dict0load.h"
35
#include "dict0load.ic"
40
#include "page0page.h"
41
#include "mach0data.h"
42
#include "dict0dict.h"
43
#include "dict0boot.h"
45
#include "srv0start.h"
49
/** Following are six InnoDB system tables */
50
static const char* SYSTEM_TABLE_NAME[] = {
58
/****************************************************************//**
59
Compare the name of an index column.
60
@return TRUE if the i'th column of index is 'name'. */
65
const dict_table_t* table, /*!< in: table */
66
const dict_index_t* index, /*!< in: index */
67
ulint i, /*!< in: index field offset */
68
const char* name) /*!< in: name to compare to */
70
ulint tmp = dict_col_get_no(dict_field_get_col(
71
dict_index_get_nth_field(
74
return(strcmp(name, dict_table_get_col_name(table, tmp)) == 0);
77
/********************************************************************//**
78
Finds the first table name in the given database.
79
@return own: table name, NULL if does not exist; the caller must free
80
the memory in the string! */
83
dict_get_first_table_name_in_db(
84
/*============================*/
85
const char* name) /*!< in: database name which ends in '/' */
87
dict_table_t* sys_tables;
89
dict_index_t* sys_index;
98
ut_ad(mutex_own(&(dict_sys->mutex)));
100
heap = mem_heap_create(1000);
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));
108
tuple = dtuple_create(heap, 1);
109
dfield = dtuple_get_nth_field(tuple, 0);
111
dfield_set_data(dfield, name, ut_strlen(name));
112
dict_index_copy_types(tuple, sys_index, 1);
114
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
115
BTR_SEARCH_LEAF, &pcur, &mtr);
117
rec = btr_pcur_get_rec(&pcur);
119
if (!btr_pcur_is_on_user_rec(&pcur)) {
122
btr_pcur_close(&pcur);
129
field = rec_get_nth_field_old(rec, 0, &len);
131
if (len < strlen(name)
132
|| ut_memcmp(name, field, strlen(name)) != 0) {
135
btr_pcur_close(&pcur);
142
if (!rec_get_deleted_flag(rec, 0)) {
146
char* table_name = mem_strdupl((char*) field, len);
148
btr_pcur_close(&pcur);
155
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
160
/********************************************************************//**
161
Prints to the standard output information on all tables found in the data
162
dictionary system table. */
174
/* Enlarge the fatal semaphore wait timeout during the InnoDB table
177
mutex_enter(&kernel_mutex);
178
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
179
mutex_exit(&kernel_mutex);
181
heap = mem_heap_create(1000);
182
mutex_enter(&(dict_sys->mutex));
186
rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES);
191
err_msg = dict_process_sys_tables_rec(
192
heap, rec, &table, DICT_TABLE_LOAD_FROM_CACHE
193
| DICT_TABLE_UPDATE_STATS);
198
dict_table_print_low(table);
200
ut_print_timestamp(stderr);
201
fprintf(stderr, " InnoDB: %s\n", err_msg);
204
mem_heap_empty(heap);
207
rec = dict_getnext_system(&pcur, &mtr);
211
mutex_exit(&(dict_sys->mutex));
214
/* Restore the fatal semaphore wait timeout */
215
mutex_enter(&kernel_mutex);
216
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
217
mutex_exit(&kernel_mutex);
221
/********************************************************************//**
222
This function gets the next system table record as it scans the table.
223
@return the next record if found, NULL if end of scan */
226
dict_getnext_system_low(
227
/*====================*/
228
btr_pcur_t* pcur, /*!< in/out: persistent cursor to the
230
mtr_t* mtr) /*!< in: the mini-transaction */
234
while (!rec || rec_get_deleted_flag(rec, 0)) {
235
btr_pcur_move_to_next_user_rec(pcur, mtr);
237
rec = btr_pcur_get_rec(pcur);
239
if (!btr_pcur_is_on_user_rec(pcur)) {
241
btr_pcur_close(pcur);
247
/* Get a record, let's save the position */
248
btr_pcur_store_position(pcur, mtr);
253
/********************************************************************//**
254
This function opens a system table, and return the first record.
255
@return first record of the system table */
258
dict_startscan_system(
259
/*==================*/
260
btr_pcur_t* pcur, /*!< out: persistent cursor to
262
mtr_t* mtr, /*!< in: the mini-transaction */
263
dict_system_id_t system_id) /*!< in: which system table to open */
265
dict_table_t* system_table;
266
dict_index_t* clust_index;
269
ut_a(system_id < SYS_NUM_SYSTEM_TABLES);
271
system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]);
273
clust_index = UT_LIST_GET_FIRST(system_table->indexes);
275
btr_pcur_open_at_index_side(TRUE, clust_index, BTR_SEARCH_LEAF, pcur,
278
rec = dict_getnext_system_low(pcur, mtr);
283
/********************************************************************//**
284
This function gets the next system table record as it scans the table.
285
@return the next record if found, NULL if end of scan */
290
btr_pcur_t* pcur, /*!< in/out: persistent cursor
292
mtr_t* mtr) /*!< in: the mini-transaction */
296
/* Restore the position */
297
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
299
/* Get the next record */
300
rec = dict_getnext_system_low(pcur, mtr);
304
/********************************************************************//**
305
This function processes one SYS_TABLES record and populate the dict_table_t
306
struct for the table. Extracted out of dict_print() to be used by
307
both monitor table output and information schema innodb_sys_tables output.
308
@return error message, or NULL on success */
311
dict_process_sys_tables_rec(
312
/*========================*/
313
mem_heap_t* heap, /*!< in/out: temporary memory heap */
314
const rec_t* rec, /*!< in: SYS_TABLES record */
315
dict_table_t** table, /*!< out: dict_table_t to fill */
316
dict_table_info_t status) /*!< in: status bit controls
317
options such as whether we shall
318
look for dict_table_t from cache
323
const char* err_msg = NULL;
326
field = (const char*) rec_get_nth_field_old(rec, 0, &len);
328
ut_a(!rec_get_deleted_flag(rec, 0));
330
/* Get the table name */
331
table_name = mem_heap_strdupl(heap, (const char*)field, len);
333
/* If DICT_TABLE_LOAD_FROM_CACHE is set, first check
334
whether there is cached dict_table_t struct first */
335
if (status & DICT_TABLE_LOAD_FROM_CACHE) {
336
*table = dict_table_get_low(table_name);
339
err_msg = "Table not found in cache";
342
err_msg = dict_load_table_low(table_name, rec, table);
349
if ((status & DICT_TABLE_UPDATE_STATS)
350
&& dict_table_get_first_index(*table)) {
352
/* Update statistics if DICT_TABLE_UPDATE_STATS
354
dict_update_statistics_low(*table, TRUE);
360
/********************************************************************//**
361
This function parses a SYS_INDEXES record and populate a dict_index_t
362
structure with the information from the record. For detail information
363
about SYS_INDEXES fields, please refer to dict_boot() function.
364
@return error message, or NULL on success */
367
dict_process_sys_indexes_rec(
368
/*=========================*/
369
mem_heap_t* heap, /*!< in/out: heap memory */
370
const rec_t* rec, /*!< in: current SYS_INDEXES rec */
371
dict_index_t* index, /*!< out: index to be filled */
372
table_id_t* table_id) /*!< out: index table id */
377
buf = mem_heap_alloc(heap, 8);
379
/* Parse the record, and get "dict_index_t" struct filled */
380
err_msg = dict_load_index_low(buf, NULL,
381
heap, rec, FALSE, &index);
383
*table_id = mach_read_from_8(buf);
387
/********************************************************************//**
388
This function parses a SYS_COLUMNS record and populate a dict_column_t
389
structure with the information from the record.
390
@return error message, or NULL on success */
393
dict_process_sys_columns_rec(
394
/*=========================*/
395
mem_heap_t* heap, /*!< in/out: heap memory */
396
const rec_t* rec, /*!< in: current SYS_COLUMNS rec */
397
dict_col_t* column, /*!< out: dict_col_t to be filled */
398
table_id_t* table_id, /*!< out: table id */
399
const char** col_name) /*!< out: column name */
403
/* Parse the record, and get "dict_col_t" struct filled */
404
err_msg = dict_load_column_low(NULL, heap, column,
405
table_id, col_name, rec);
409
/********************************************************************//**
410
This function parses a SYS_FIELDS record and populates a dict_field_t
411
structure with the information from the record.
412
@return error message, or NULL on success */
415
dict_process_sys_fields_rec(
416
/*========================*/
417
mem_heap_t* heap, /*!< in/out: heap memory */
418
const rec_t* rec, /*!< in: current SYS_FIELDS rec */
419
dict_field_t* sys_field, /*!< out: dict_field_t to be
421
ulint* pos, /*!< out: Field position */
422
index_id_t* index_id, /*!< out: current index id */
423
index_id_t last_id) /*!< in: previous index id */
429
buf = mem_heap_alloc(heap, 8);
431
last_index_id = mem_heap_alloc(heap, 8);
432
mach_write_to_8(last_index_id, last_id);
434
err_msg = dict_load_field_low(buf, NULL, sys_field,
435
pos, last_index_id, heap, rec);
437
*index_id = mach_read_from_8(buf);
442
/********************************************************************//**
443
This function parses a SYS_FOREIGN record and populate a dict_foreign_t
444
structure with the information from the record. For detail information
445
about SYS_FOREIGN fields, please refer to dict_load_foreign() function
446
@return error message, or NULL on success */
449
dict_process_sys_foreign_rec(
450
/*=========================*/
451
mem_heap_t* heap, /*!< in/out: heap memory */
452
const rec_t* rec, /*!< in: current SYS_FOREIGN rec */
453
dict_foreign_t* foreign) /*!< out: dict_foreign_t struct
458
ulint n_fields_and_type;
460
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
461
return("delete-marked record in SYS_FOREIGN");
464
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
465
return("wrong number of columns in SYS_FOREIGN record");
468
field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
469
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
471
return("incorrect column length in SYS_FOREIGN");
473
foreign->id = mem_heap_strdupl(heap, (const char*) field, len);
475
rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
476
if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
479
rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
480
if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
484
field = rec_get_nth_field_old(rec, 3/*FOR_NAME*/, &len);
485
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
488
foreign->foreign_table_name = mem_heap_strdupl(
489
heap, (const char*) field, len);
491
field = rec_get_nth_field_old(rec, 4/*REF_NAME*/, &len);
492
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
495
foreign->referenced_table_name = mem_heap_strdupl(
496
heap, (const char*) field, len);
498
field = rec_get_nth_field_old(rec, 5/*N_COLS*/, &len);
499
if (UNIV_UNLIKELY(len != 4)) {
502
n_fields_and_type = mach_read_from_4(field);
504
foreign->type = (unsigned int) (n_fields_and_type >> 24);
505
foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
509
/********************************************************************//**
510
This function parses a SYS_FOREIGN_COLS record and extract necessary
511
information from the record and return to caller.
512
@return error message, or NULL on success */
515
dict_process_sys_foreign_col_rec(
516
/*=============================*/
517
mem_heap_t* heap, /*!< in/out: heap memory */
518
const rec_t* rec, /*!< in: current SYS_FOREIGN_COLS rec */
519
const char** name, /*!< out: foreign key constraint name */
520
const char** for_col_name, /*!< out: referencing column name */
521
const char** ref_col_name, /*!< out: referenced column name
522
in referenced table */
523
ulint* pos) /*!< out: column position */
528
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
529
return("delete-marked record in SYS_FOREIGN_COLS");
532
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
533
return("wrong number of columns in SYS_FOREIGN_COLS record");
536
field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
537
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
539
return("incorrect column length in SYS_FOREIGN_COLS");
541
*name = mem_heap_strdupl(heap, (char*) field, len);
543
field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
544
if (UNIV_UNLIKELY(len != 4)) {
547
*pos = mach_read_from_4(field);
549
rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
550
if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
553
rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
554
if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
558
field = rec_get_nth_field_old(rec, 4/*FOR_COL_NAME*/, &len);
559
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
562
*for_col_name = mem_heap_strdupl(heap, (char*) field, len);
564
field = rec_get_nth_field_old(rec, 5/*REF_COL_NAME*/, &len);
565
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
568
*ref_col_name = mem_heap_strdupl(heap, (char*) field, len);
574
Send data to callback function .
577
UNIV_INTERN void dict_print_with_callback(dict_print_callback func, void *func_arg)
579
dict_table_t* sys_tables;
580
dict_index_t* sys_index;
587
/* Enlarge the fatal semaphore wait timeout during the InnoDB table
590
mutex_enter(&kernel_mutex);
591
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
592
mutex_exit(&kernel_mutex);
594
mutex_enter(&(dict_sys->mutex));
598
sys_tables = dict_table_get_low("SYS_TABLES");
599
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
601
btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
604
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
606
rec = btr_pcur_get_rec(&pcur);
608
if (!btr_pcur_is_on_user_rec(&pcur)) {
611
btr_pcur_close(&pcur);
614
mutex_exit(&(dict_sys->mutex));
616
/* Restore the fatal semaphore wait timeout */
618
mutex_enter(&kernel_mutex);
619
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
620
mutex_exit(&kernel_mutex);
625
field = rec_get_nth_field_old(rec, 0, &len);
627
if (!rec_get_deleted_flag(rec, 0)) {
631
char* table_name = mem_strdupl((char*) field, len);
633
btr_pcur_store_position(&pcur, &mtr);
637
func(func_arg, table_name);
638
mem_free(table_name);
642
btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
648
/********************************************************************//**
649
Determine the flags of a table described in SYS_TABLES.
650
@return compressed page size in kilobytes; or 0 if the tablespace is
651
uncompressed, ULINT_UNDEFINED on error */
654
dict_sys_tables_get_flags(
655
/*======================*/
656
const rec_t* rec) /*!< in: a record of SYS_TABLES */
663
field = rec_get_nth_field_old(rec, 5, &len);
666
flags = mach_read_from_4(field);
668
if (UNIV_LIKELY(flags == DICT_TABLE_ORDINARY)) {
672
field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
673
n_cols = mach_read_from_4(field);
675
if (UNIV_UNLIKELY(!(n_cols & 0x80000000UL))) {
676
/* New file formats require ROW_FORMAT=COMPACT. */
677
return(ULINT_UNDEFINED);
680
switch (flags & (DICT_TF_FORMAT_MASK | DICT_TF_COMPACT)) {
682
case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
683
case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT | DICT_TF_COMPACT:
684
/* flags should be DICT_TABLE_ORDINARY,
685
or DICT_TF_FORMAT_MASK should be nonzero. */
686
return(ULINT_UNDEFINED);
688
case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT | DICT_TF_COMPACT:
689
#if DICT_TF_FORMAT_MAX > DICT_TF_FORMAT_ZIP
690
# error "missing case labels for DICT_TF_FORMAT_ZIP .. DICT_TF_FORMAT_MAX"
692
/* We support this format. */
696
if (UNIV_UNLIKELY((flags & DICT_TF_ZSSIZE_MASK)
697
> (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT))) {
698
/* Unsupported compressed page size. */
699
return(ULINT_UNDEFINED);
702
if (UNIV_UNLIKELY(flags & (~0 << DICT_TF_BITS))) {
703
/* Some unused bits are set. */
704
return(ULINT_UNDEFINED);
710
/********************************************************************//**
711
In a crash recovery we already have all the tablespace objects created.
712
This function compares the space id information in the InnoDB data dictionary
713
to what we already read with fil_load_single_table_tablespaces().
715
In a normal startup, we create the tablespace objects for every table in
716
InnoDB's data dictionary, if the corresponding .ibd file exists.
717
We also scan the biggest space id, and store it to fil_system. */
720
dict_check_tablespaces_and_store_max_id(
721
/*====================================*/
722
ibool in_crash_recovery) /*!< in: are we doing a crash recovery */
724
dict_table_t* sys_tables;
725
dict_index_t* sys_index;
731
mutex_enter(&(dict_sys->mutex));
735
sys_tables = dict_table_get_low("SYS_TABLES");
736
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
737
ut_a(!dict_table_is_comp(sys_tables));
739
max_space_id = mtr_read_ulint(dict_hdr_get(&mtr)
740
+ DICT_HDR_MAX_SPACE_ID,
742
fil_set_max_space_id_if_bigger(max_space_id);
744
btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
747
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
749
rec = btr_pcur_get_rec(&pcur);
751
if (!btr_pcur_is_on_user_rec(&pcur)) {
754
btr_pcur_close(&pcur);
757
/* We must make the tablespace cache aware of the biggest
760
/* printf("Biggest space id in data dictionary %lu\n",
762
fil_set_max_space_id_if_bigger(max_space_id);
764
mutex_exit(&(dict_sys->mutex));
769
if (!rec_get_deleted_flag(rec, 0)) {
778
field = rec_get_nth_field_old(rec, 0, &len);
779
name = mem_strdupl((char*) field, len);
781
flags = dict_sys_tables_get_flags(rec);
782
if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
784
field = rec_get_nth_field_old(rec, 5, &len);
785
flags = mach_read_from_4(field);
787
ut_print_timestamp(stderr);
788
fputs(" InnoDB: Error: table ", stderr);
789
ut_print_filename(stderr, name);
791
"InnoDB: in InnoDB data dictionary"
792
" has unknown type %lx.\n",
798
field = rec_get_nth_field_old(rec, 9, &len);
801
space_id = mach_read_from_4(field);
803
btr_pcur_store_position(&pcur, &mtr);
808
/* The system tablespace always exists. */
809
} else if (in_crash_recovery) {
810
/* Check that the tablespace (the .ibd file) really
811
exists; print a warning to the .err log if not.
812
Do not print warnings for temporary tables. */
815
field = rec_get_nth_field_old(rec, 4, &len);
816
if (0x80000000UL & mach_read_from_4(field)) {
817
/* ROW_FORMAT=COMPACT: read the is_temp
818
flag from SYS_TABLES.MIX_LEN. */
819
field = rec_get_nth_field_old(rec, 7, &len);
820
is_temp = mach_read_from_4(field)
821
& DICT_TF2_TEMPORARY;
823
/* For tables created with old versions
824
of InnoDB, SYS_TABLES.MIX_LEN may contain
825
garbage. Such tables would always be
826
in ROW_FORMAT=REDUNDANT. Pretend that
827
all such tables are non-temporary. That is,
828
do not suppress error printouts about
829
temporary tables not being found. */
833
fil_space_for_table_exists_in_mem(
834
space_id, name, is_temp, TRUE, !is_temp);
836
/* It is a normal database startup: create the space
837
object and check that the .ibd file exists. */
839
fil_open_single_table_tablespace(FALSE, space_id,
845
if (space_id > max_space_id) {
846
max_space_id = space_id;
851
btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
857
/********************************************************************//**
858
Loads a table column definition from a SYS_COLUMNS record to
860
@return error message, or NULL on success */
863
dict_load_column_low(
864
/*=================*/
865
dict_table_t* table, /*!< in/out: table, could be NULL
866
if we just populate a dict_column_t
867
struct with information from
868
a SYS_COLUMNS record */
869
mem_heap_t* heap, /*!< in/out: memory heap
870
for temporary storage */
871
dict_col_t* column, /*!< out: dict_column_t to fill,
872
or NULL if table != NULL */
873
table_id_t* table_id, /*!< out: table id */
874
const char** col_name, /*!< out: column name */
875
const rec_t* rec) /*!< in: SYS_COLUMNS record */
885
ut_ad(table || column);
887
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
888
return("delete-marked record in SYS_COLUMNS");
891
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
892
return("wrong number of columns in SYS_COLUMNS record");
895
field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
896
if (UNIV_UNLIKELY(len != 8)) {
898
return("incorrect column length in SYS_COLUMNS");
902
*table_id = mach_read_from_8(field);
903
} else if (UNIV_UNLIKELY(table->id != mach_read_from_8(field))) {
904
return("SYS_COLUMNS.TABLE_ID mismatch");
907
field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
908
if (UNIV_UNLIKELY(len != 4)) {
913
pos = mach_read_from_4(field);
915
if (UNIV_UNLIKELY(table && table->n_def != pos)) {
916
return("SYS_COLUMNS.POS mismatch");
919
rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
920
if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
923
rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
924
if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
928
field = rec_get_nth_field_old(rec, 4/*NAME*/, &len);
929
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
933
name = mem_heap_strdupl(heap, (const char*) field, len);
939
field = rec_get_nth_field_old(rec, 5/*MTYPE*/, &len);
940
if (UNIV_UNLIKELY(len != 4)) {
944
mtype = mach_read_from_4(field);
946
field = rec_get_nth_field_old(rec, 6/*PRTYPE*/, &len);
947
if (UNIV_UNLIKELY(len != 4)) {
950
prtype = mach_read_from_4(field);
952
if (dtype_get_charset_coll(prtype) == 0
953
&& dtype_is_string_type(mtype)) {
954
/* The table was created with < 4.1.2. */
956
if (dtype_is_binary_string_type(mtype, prtype)) {
957
/* Use the binary collation for
958
string columns of binary type. */
960
prtype = dtype_form_prtype(
962
DATA_MYSQL_BINARY_CHARSET_COLL);
964
/* Use the default charset for
965
other than binary columns. */
967
prtype = dtype_form_prtype(
969
data_mysql_default_charset_coll);
973
field = rec_get_nth_field_old(rec, 7/*LEN*/, &len);
974
if (UNIV_UNLIKELY(len != 4)) {
977
col_len = mach_read_from_4(field);
978
field = rec_get_nth_field_old(rec, 8/*PREC*/, &len);
979
if (UNIV_UNLIKELY(len != 4)) {
984
dict_mem_table_add_col(table, heap, name, mtype,
987
dict_mem_fill_column_struct(column, pos, mtype,
994
/********************************************************************//**
995
Loads definitions for table columns. */
1000
dict_table_t* table, /*!< in/out: table */
1001
mem_heap_t* heap) /*!< in/out: memory heap
1002
for temporary storage */
1004
dict_table_t* sys_columns;
1005
dict_index_t* sys_index;
1014
ut_ad(mutex_own(&(dict_sys->mutex)));
1018
sys_columns = dict_table_get_low("SYS_COLUMNS");
1019
sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
1020
ut_a(!dict_table_is_comp(sys_columns));
1022
ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
1023
ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
1025
tuple = dtuple_create(heap, 1);
1026
dfield = dtuple_get_nth_field(tuple, 0);
1028
buf = mem_heap_alloc(heap, 8);
1029
mach_write_to_8(buf, table->id);
1031
dfield_set_data(dfield, buf, 8);
1032
dict_index_copy_types(tuple, sys_index, 1);
1034
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1035
BTR_SEARCH_LEAF, &pcur, &mtr);
1036
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1037
const char* err_msg;
1039
rec = btr_pcur_get_rec(&pcur);
1041
ut_a(btr_pcur_is_on_user_rec(&pcur));
1043
err_msg = dict_load_column_low(table, heap, NULL, NULL,
1047
fprintf(stderr, "InnoDB: %s\n", err_msg);
1051
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1054
btr_pcur_close(&pcur);
1058
/** Error message for a delete-marked record in dict_load_field_low() */
1059
static const char* dict_load_field_del = "delete-marked record in SYS_FIELDS";
1061
/********************************************************************//**
1062
Loads an index field definition from a SYS_FIELDS record to
1064
@return error message, or NULL on success */
1067
dict_load_field_low(
1068
/*================*/
1069
byte* index_id, /*!< in/out: index id (8 bytes)
1070
an "in" value if index != NULL
1071
and "out" if index == NULL */
1072
dict_index_t* index, /*!< in/out: index, could be NULL
1073
if we just populate a dict_field_t
1074
struct with information from
1075
a SYS_FIELDSS record */
1076
dict_field_t* sys_field, /*!< out: dict_field_t to be
1078
ulint* pos, /*!< out: Field position */
1079
byte* last_index_id, /*!< in: last index id */
1080
mem_heap_t* heap, /*!< in/out: memory heap
1081
for temporary storage */
1082
const rec_t* rec) /*!< in: SYS_FIELDS record */
1086
ulint pos_and_prefix_len;
1091
/* Either index or sys_field is supplied, not both */
1092
ut_a((!index) || (!sys_field));
1094
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1095
return(dict_load_field_del);
1098
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
1099
return("wrong number of columns in SYS_FIELDS record");
1102
field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
1103
if (UNIV_UNLIKELY(len != 8)) {
1105
return("incorrect column length in SYS_FIELDS");
1109
ut_a(last_index_id);
1110
memcpy(index_id, (const char*)field, 8);
1111
first_field = memcmp(index_id, last_index_id, 8);
1113
first_field = (index->n_def == 0);
1114
if (memcmp(field, index_id, 8)) {
1115
return("SYS_FIELDS.INDEX_ID mismatch");
1119
field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
1120
if (UNIV_UNLIKELY(len != 4)) {
1124
rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
1125
if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
1128
rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
1129
if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
1133
/* The next field stores the field position in the index and a
1134
possible column prefix length if the index field does not
1135
contain the whole column. The storage format is like this: if
1136
there is at least one prefix field in the index, then the HIGH
1137
2 bytes contain the field number (index->n_def) and the low 2
1138
bytes the prefix length for the field. Otherwise the field
1139
number (index->n_def) is contained in the 2 LOW bytes. */
1141
pos_and_prefix_len = mach_read_from_4(field);
1143
if (index && UNIV_UNLIKELY
1144
((pos_and_prefix_len & 0xFFFFUL) != index->n_def
1145
&& (pos_and_prefix_len >> 16 & 0xFFFF) != index->n_def)) {
1146
return("SYS_FIELDS.POS mismatch");
1149
if (first_field || pos_and_prefix_len > 0xFFFFUL) {
1150
prefix_len = pos_and_prefix_len & 0xFFFFUL;
1151
position = (pos_and_prefix_len & 0xFFFF0000UL) >> 16;
1154
position = pos_and_prefix_len & 0xFFFFUL;
1157
field = rec_get_nth_field_old(rec, 4, &len);
1158
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
1163
dict_mem_index_add_field(
1164
index, mem_heap_strdupl(heap, (const char*) field, len),
1170
sys_field->name = mem_heap_strdupl(
1171
heap, (const char*) field, len);
1172
sys_field->prefix_len = prefix_len;
1179
/********************************************************************//**
1180
Loads definitions for index fields.
1181
@return DB_SUCCESS if ok, DB_CORRUPTION if corruption */
1186
dict_index_t* index, /*!< in/out: index whose fields to load */
1187
mem_heap_t* heap) /*!< in: memory heap for temporary storage */
1189
dict_table_t* sys_fields;
1190
dict_index_t* sys_index;
1200
ut_ad(mutex_own(&(dict_sys->mutex)));
1204
sys_fields = dict_table_get_low("SYS_FIELDS");
1205
sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
1206
ut_a(!dict_table_is_comp(sys_fields));
1207
ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
1209
tuple = dtuple_create(heap, 1);
1210
dfield = dtuple_get_nth_field(tuple, 0);
1212
buf = mem_heap_alloc(heap, 8);
1213
mach_write_to_8(buf, index->id);
1215
dfield_set_data(dfield, buf, 8);
1216
dict_index_copy_types(tuple, sys_index, 1);
1218
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1219
BTR_SEARCH_LEAF, &pcur, &mtr);
1220
for (i = 0; i < index->n_fields; i++) {
1221
const char* err_msg;
1223
rec = btr_pcur_get_rec(&pcur);
1225
ut_a(btr_pcur_is_on_user_rec(&pcur));
1227
err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL,
1230
if (err_msg == dict_load_field_del) {
1231
/* There could be delete marked records in
1232
SYS_FIELDS because SYS_FIELDS.INDEX_ID can be
1233
updated by ALTER TABLE ADD INDEX. */
1236
} else if (err_msg) {
1237
fprintf(stderr, "InnoDB: %s\n", err_msg);
1238
error = DB_CORRUPTION;
1242
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1247
btr_pcur_close(&pcur);
1252
/** Error message for a delete-marked record in dict_load_index_low() */
1253
static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES";
1254
/** Error message for table->id mismatch in dict_load_index_low() */
1255
static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch";
1257
/********************************************************************//**
1258
Loads an index definition from a SYS_INDEXES record to dict_index_t.
1259
If allocate=TRUE, we will create a dict_index_t structure and fill it
1260
accordingly. If allocated=FALSE, the dict_index_t will be supplied by
1261
the caller and filled with information read from the record. @return
1262
error message, or NULL on success */
1265
dict_load_index_low(
1266
/*================*/
1267
byte* table_id, /*!< in/out: table id (8 bytes),
1268
an "in" value if allocate=TRUE
1269
and "out" when allocate=FALSE */
1270
const char* table_name, /*!< in: table name */
1271
mem_heap_t* heap, /*!< in/out: temporary memory heap */
1272
const rec_t* rec, /*!< in: SYS_INDEXES record */
1273
ibool allocate, /*!< in: TRUE=allocate *index,
1274
FALSE=fill in a pre-allocated
1276
dict_index_t** index) /*!< out,own: index, or NULL */
1288
/* If allocate=TRUE, no dict_index_t will
1289
be supplied. Initialize "*index" to NULL */
1293
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1294
return(dict_load_index_del);
1297
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
1298
return("wrong number of columns in SYS_INDEXES record");
1301
field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
1302
if (UNIV_UNLIKELY(len != 8)) {
1304
return("incorrect column length in SYS_INDEXES");
1308
/* We are reading a SYS_INDEXES record. Copy the table_id */
1309
memcpy(table_id, (const char*)field, 8);
1310
} else if (memcmp(field, table_id, 8)) {
1311
/* Caller supplied table_id, verify it is the same
1312
id as on the index record */
1313
return(dict_load_index_id_err);
1316
field = rec_get_nth_field_old(rec, 1/*ID*/, &len);
1317
if (UNIV_UNLIKELY(len != 8)) {
1321
id = mach_read_from_8(field);
1323
rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len);
1324
if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
1327
rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len);
1328
if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
1332
field = rec_get_nth_field_old(rec, 4/*NAME*/, &name_len);
1333
if (UNIV_UNLIKELY(name_len == UNIV_SQL_NULL)) {
1337
name_buf = mem_heap_strdupl(heap, (const char*) field,
1340
field = rec_get_nth_field_old(rec, 5/*N_FIELDS*/, &len);
1341
if (UNIV_UNLIKELY(len != 4)) {
1344
n_fields = mach_read_from_4(field);
1346
field = rec_get_nth_field_old(rec, 6/*TYPE*/, &len);
1347
if (UNIV_UNLIKELY(len != 4)) {
1350
type = mach_read_from_4(field);
1352
field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len);
1353
if (UNIV_UNLIKELY(len != 4)) {
1356
space = mach_read_from_4(field);
1358
field = rec_get_nth_field_old(rec, 8/*PAGE_NO*/, &len);
1359
if (UNIV_UNLIKELY(len != 4)) {
1364
*index = dict_mem_index_create(table_name, name_buf,
1365
space, type, n_fields);
1369
dict_mem_fill_index_struct(*index, NULL, NULL, name_buf,
1370
space, type, n_fields);
1374
(*index)->page = mach_read_from_4(field);
1375
ut_ad((*index)->page);
1380
/********************************************************************//**
1381
Loads definitions for table indexes. Adds them to the data dictionary
1383
@return DB_SUCCESS if ok, DB_CORRUPTION if corruption of dictionary
1384
table or DB_UNSUPPORTED if table has unknown index type */
1389
dict_table_t* table, /*!< in/out: table */
1390
mem_heap_t* heap) /*!< in: memory heap for temporary storage */
1392
dict_table_t* sys_indexes;
1393
dict_index_t* sys_index;
1400
ulint error = DB_SUCCESS;
1402
ut_ad(mutex_own(&(dict_sys->mutex)));
1406
sys_indexes = dict_table_get_low("SYS_INDEXES");
1407
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
1408
ut_a(!dict_table_is_comp(sys_indexes));
1409
ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
1410
ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
1412
tuple = dtuple_create(heap, 1);
1413
dfield = dtuple_get_nth_field(tuple, 0);
1415
buf = mem_heap_alloc(heap, 8);
1416
mach_write_to_8(buf, table->id);
1418
dfield_set_data(dfield, buf, 8);
1419
dict_index_copy_types(tuple, sys_index, 1);
1421
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1422
BTR_SEARCH_LEAF, &pcur, &mtr);
1424
dict_index_t* index = NULL;
1425
const char* err_msg;
1427
if (!btr_pcur_is_on_user_rec(&pcur)) {
1432
rec = btr_pcur_get_rec(&pcur);
1434
err_msg = dict_load_index_low(buf, table->name, heap, rec,
1436
ut_ad((index == NULL) == (err_msg != NULL));
1438
if (err_msg == dict_load_index_id_err) {
1439
/* TABLE_ID mismatch means that we have
1440
run out of index definitions for the table. */
1442
} else if (err_msg == dict_load_index_del) {
1443
/* Skip delete-marked records. */
1445
} else if (err_msg) {
1446
fprintf(stderr, "InnoDB: %s\n", err_msg);
1447
error = DB_CORRUPTION;
1453
/* We check for unsupported types first, so that the
1454
subsequent checks are relevant for the supported types. */
1455
if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
1458
"InnoDB: Error: unknown type %lu"
1459
" of index %s of table %s\n",
1460
(ulong) index->type, index->name, table->name);
1462
error = DB_UNSUPPORTED;
1463
dict_mem_index_free(index);
1465
} else if (index->page == FIL_NULL) {
1468
"InnoDB: Error: trying to load index %s"
1470
"InnoDB: but the index tree has been freed!\n",
1471
index->name, table->name);
1474
dict_mem_index_free(index);
1475
error = DB_CORRUPTION;
1477
} else if (!dict_index_is_clust(index)
1478
&& NULL == dict_table_get_first_index(table)) {
1480
fputs("InnoDB: Error: trying to load index ",
1482
ut_print_name(stderr, NULL, FALSE, index->name);
1483
fputs(" for table ", stderr);
1484
ut_print_name(stderr, NULL, TRUE, table->name);
1485
fputs("\nInnoDB: but the first index"
1486
" is not clustered!\n", stderr);
1489
} else if (table->id < DICT_HDR_FIRST_ID
1490
&& (dict_index_is_clust(index)
1491
|| ((table == dict_sys->sys_tables)
1492
&& !strcmp("ID_IND", index->name)))) {
1494
/* The index was created in memory already at booting
1495
of the database server */
1496
dict_mem_index_free(index);
1498
dict_load_fields(index, heap);
1499
error = dict_index_add_to_cache(table, index,
1500
index->page, FALSE);
1501
/* The data dictionary tables should never contain
1502
invalid index definitions. If we ignored this error
1503
and simply did not load this index definition, the
1504
.frm file would disagree with the index definitions
1506
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
1513
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1517
btr_pcur_close(&pcur);
1523
/********************************************************************//**
1524
Loads a table definition from a SYS_TABLES record to dict_table_t.
1525
Does not load any columns or indexes.
1526
@return error message, or NULL on success */
1529
dict_load_table_low(
1530
/*================*/
1531
const char* name, /*!< in: table name */
1532
const rec_t* rec, /*!< in: SYS_TABLES record */
1533
dict_table_t** table) /*!< out,own: table, or NULL */
1541
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1542
return("delete-marked record in SYS_TABLES");
1545
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 10)) {
1546
return("wrong number of columns in SYS_TABLES record");
1549
rec_get_nth_field_offs_old(rec, 0/*NAME*/, &len);
1550
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
1552
return("incorrect column length in SYS_TABLES");
1554
rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len);
1555
if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) {
1558
rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len);
1559
if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) {
1563
rec_get_nth_field_offs_old(rec, 3/*ID*/, &len);
1564
if (UNIV_UNLIKELY(len != 8)) {
1568
field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
1569
if (UNIV_UNLIKELY(len != 4)) {
1573
n_cols = mach_read_from_4(field);
1575
rec_get_nth_field_offs_old(rec, 5/*TYPE*/, &len);
1576
if (UNIV_UNLIKELY(len != 4)) {
1580
rec_get_nth_field_offs_old(rec, 6/*MIX_ID*/, &len);
1581
if (UNIV_UNLIKELY(len != 8)) {
1585
rec_get_nth_field_offs_old(rec, 7/*MIX_LEN*/, &len);
1586
if (UNIV_UNLIKELY(len != 4)) {
1590
rec_get_nth_field_offs_old(rec, 8/*CLUSTER_ID*/, &len);
1591
if (UNIV_UNLIKELY(len != UNIV_SQL_NULL)) {
1595
field = rec_get_nth_field_old(rec, 9/*SPACE*/, &len);
1597
if (UNIV_UNLIKELY(len != 4)) {
1601
space = mach_read_from_4(field);
1603
/* Check if the tablespace exists and has the right name */
1605
flags = dict_sys_tables_get_flags(rec);
1607
if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
1608
field = rec_get_nth_field_old(rec, 5/*TYPE*/, &len);
1609
ut_ad(len == 4); /* this was checked earlier */
1610
flags = mach_read_from_4(field);
1612
ut_print_timestamp(stderr);
1613
fputs(" InnoDB: Error: table ", stderr);
1614
ut_print_filename(stderr, name);
1615
fprintf(stderr, "\n"
1616
"InnoDB: in InnoDB data dictionary"
1617
" has unknown type %lx.\n",
1625
/* The high-order bit of N_COLS is the "compact format" flag.
1626
For tables in that format, MIX_LEN may hold additional flags. */
1627
if (n_cols & 0x80000000UL) {
1630
flags |= DICT_TF_COMPACT;
1632
field = rec_get_nth_field_old(rec, 7, &len);
1634
if (UNIV_UNLIKELY(len != 4)) {
1639
flags2 = mach_read_from_4(field);
1641
if (flags2 & (~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT))) {
1642
ut_print_timestamp(stderr);
1643
fputs(" InnoDB: Warning: table ", stderr);
1644
ut_print_filename(stderr, name);
1645
fprintf(stderr, "\n"
1646
"InnoDB: in InnoDB data dictionary"
1647
" has unknown flags %lx.\n",
1650
flags2 &= ~(~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT));
1653
flags |= flags2 << DICT_TF2_SHIFT;
1656
/* See if the tablespace is available. */
1657
*table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
1660
field = rec_get_nth_field_old(rec, 3/*ID*/, &len);
1661
ut_ad(len == 8); /* this was checked earlier */
1663
(*table)->id = mach_read_from_8(field);
1665
(*table)->ibd_file_missing = FALSE;
1670
/********************************************************************//**
1671
Loads a table definition and also all its index definitions, and also
1672
the cluster definition if the table is a member in a cluster. Also loads
1673
all foreign key constraints where the foreign key is in the table or where
1674
a foreign key references columns in this table. Adds all these to the data
1676
@return table, NULL if does not exist; if the table is stored in an
1677
.ibd file, but the file does not exist, then we set the
1678
ibd_file_missing flag TRUE in the table object we return */
1683
const char* name, /*!< in: table name in the
1684
databasename/tablename format */
1685
ibool cached) /*!< in: TRUE=add to cache, FALSE=do not */
1687
dict_table_t* table;
1688
dict_table_t* sys_tables;
1690
dict_index_t* sys_index;
1698
const char* err_msg;
1701
ut_ad(mutex_own(&(dict_sys->mutex)));
1703
heap = mem_heap_create(32000);
1707
sys_tables = dict_table_get_low("SYS_TABLES");
1708
sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
1709
ut_a(!dict_table_is_comp(sys_tables));
1710
ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
1711
ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
1712
ut_a(name_of_col_is(sys_tables, sys_index, 5, "TYPE"));
1713
ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN"));
1714
ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
1716
tuple = dtuple_create(heap, 1);
1717
dfield = dtuple_get_nth_field(tuple, 0);
1719
dfield_set_data(dfield, name, ut_strlen(name));
1720
dict_index_copy_types(tuple, sys_index, 1);
1722
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1723
BTR_SEARCH_LEAF, &pcur, &mtr);
1724
rec = btr_pcur_get_rec(&pcur);
1726
if (!btr_pcur_is_on_user_rec(&pcur)
1727
|| rec_get_deleted_flag(rec, 0)) {
1730
btr_pcur_close(&pcur);
1732
mem_heap_free(heap);
1737
field = rec_get_nth_field_old(rec, 0, &len);
1739
/* Check if the table name in record is the searched one */
1740
if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
1745
err_msg = dict_load_table_low(name, rec, &table);
1749
ut_print_timestamp(stderr);
1750
fprintf(stderr, " InnoDB: %s\n", err_msg);
1754
if (table->space == 0) {
1755
/* The system tablespace is always available. */
1756
} else if (!fil_space_for_table_exists_in_mem(
1758
(table->flags >> DICT_TF2_SHIFT)
1759
& DICT_TF2_TEMPORARY,
1762
if (table->flags & (DICT_TF2_TEMPORARY << DICT_TF2_SHIFT)) {
1763
/* Do not bother to retry opening temporary tables. */
1764
table->ibd_file_missing = TRUE;
1766
ut_print_timestamp(stderr);
1768
" InnoDB: error: space object of table ");
1769
ut_print_filename(stderr, name);
1770
fprintf(stderr, ",\n"
1771
"InnoDB: space id %lu did not exist in memory."
1772
" Retrying an open.\n",
1773
(ulong) table->space);
1774
/* Try to open the tablespace */
1775
if (!fil_open_single_table_tablespace(
1777
table->flags == DICT_TF_COMPACT ? 0 :
1778
table->flags & ~(~0 << DICT_TF_BITS), name)) {
1779
/* We failed to find a sensible
1782
table->ibd_file_missing = TRUE;
1787
btr_pcur_close(&pcur);
1790
dict_load_columns(table, heap);
1793
dict_table_add_to_cache(table, heap);
1795
dict_table_add_system_columns(table, heap);
1798
mem_heap_empty(heap);
1800
err = dict_load_indexes(table, heap);
1802
/* Initialize table foreign_child value. Its value could be
1803
changed when dict_load_foreigns() is called below */
1804
table->fk_max_recusive_level = 0;
1806
/* If the force recovery flag is set, we open the table irrespective
1807
of the error condition, since the user may want to dump data from the
1808
clustered index. However we load the foreign key information only if
1809
all indexes were loaded. */
1811
} else if (err == DB_SUCCESS) {
1812
err = dict_load_foreigns(table->name, TRUE, TRUE);
1814
if (err != DB_SUCCESS) {
1815
dict_table_remove_from_cache(table);
1818
} else if (!srv_force_recovery) {
1819
dict_table_remove_from_cache(table);
1823
table->fk_max_recusive_level = 0;
1825
if (err != DB_SUCCESS && table != NULL) {
1827
mutex_enter(&dict_foreign_err_mutex);
1829
ut_print_timestamp(stderr);
1832
" InnoDB: Error: could not make a foreign key"
1833
" definition to match\n"
1834
"InnoDB: the foreign key table"
1835
" or the referenced table!\n"
1836
"InnoDB: The data dictionary of InnoDB is corrupt."
1837
" You may need to drop\n"
1838
"InnoDB: and recreate the foreign key table"
1839
" or the referenced table.\n"
1840
"InnoDB: Submit a detailed bug report"
1841
" to http://bugs.mysql.com\n"
1842
"InnoDB: Latest foreign key error printout:\n%s\n",
1843
dict_foreign_err_buf);
1845
mutex_exit(&dict_foreign_err_mutex);
1848
mem_heap_free(heap);
1853
/***********************************************************************//**
1854
Loads a table object based on the table id.
1855
@return table; NULL if table does not exist */
1858
dict_load_table_on_id(
1859
/*==================*/
1860
table_id_t table_id) /*!< in: table id */
1867
dict_index_t* sys_table_ids;
1868
dict_table_t* sys_tables;
1872
dict_table_t* table;
1875
ut_ad(mutex_own(&(dict_sys->mutex)));
1879
/* NOTE that the operation of this function is protected by
1880
the dictionary mutex, and therefore no deadlocks can occur
1881
with other dictionary operations. */
1884
/*---------------------------------------------------*/
1885
/* Get the secondary index based on ID for table SYS_TABLES */
1886
sys_tables = dict_sys->sys_tables;
1887
sys_table_ids = dict_table_get_next_index(
1888
dict_table_get_first_index(sys_tables));
1889
ut_a(!dict_table_is_comp(sys_tables));
1890
heap = mem_heap_create(256);
1892
tuple = dtuple_create(heap, 1);
1893
dfield = dtuple_get_nth_field(tuple, 0);
1895
/* Write the table id in byte format to id_buf */
1896
mach_write_to_8(id_buf, table_id);
1898
dfield_set_data(dfield, id_buf, 8);
1899
dict_index_copy_types(tuple, sys_table_ids, 1);
1901
btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
1902
BTR_SEARCH_LEAF, &pcur, &mtr);
1903
rec = btr_pcur_get_rec(&pcur);
1905
if (!btr_pcur_is_on_user_rec(&pcur)) {
1910
/* Find the first record that is not delete marked */
1911
while (rec_get_deleted_flag(rec, 0)) {
1912
if (!btr_pcur_move_to_next_user_rec(&pcur, &mtr)) {
1915
rec = btr_pcur_get_rec(&pcur);
1918
/*---------------------------------------------------*/
1919
/* Now we have the record in the secondary index containing the
1920
table ID and NAME */
1922
rec = btr_pcur_get_rec(&pcur);
1923
field = rec_get_nth_field_old(rec, 0, &len);
1926
/* Check if the table id in record is the one searched for */
1927
if (table_id != mach_read_from_8(field)) {
1931
/* Now we get the table name from the record */
1932
field = rec_get_nth_field_old(rec, 1, &len);
1933
/* Load the table definition to memory */
1934
table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len),
1937
btr_pcur_close(&pcur);
1939
mem_heap_free(heap);
1944
/********************************************************************//**
1945
This function is called when the database is booted. Loads system table
1946
index definitions except for the clustered index which is added to the
1947
dictionary cache at booting before calling this function. */
1950
dict_load_sys_table(
1951
/*================*/
1952
dict_table_t* table) /*!< in: system table */
1956
ut_ad(mutex_own(&(dict_sys->mutex)));
1958
heap = mem_heap_create(1000);
1960
dict_load_indexes(table, heap);
1962
mem_heap_free(heap);
1965
/********************************************************************//**
1966
Loads foreign key constraint col names (also for the referenced table). */
1969
dict_load_foreign_cols(
1970
/*===================*/
1971
const char* id, /*!< in: foreign constraint id as a
1972
null-terminated string */
1973
dict_foreign_t* foreign)/*!< in: foreign constraint object */
1975
dict_table_t* sys_foreign_cols;
1976
dict_index_t* sys_index;
1986
ut_ad(mutex_own(&(dict_sys->mutex)));
1988
foreign->foreign_col_names = mem_heap_alloc(
1989
foreign->heap, foreign->n_fields * sizeof(void*));
1991
foreign->referenced_col_names = mem_heap_alloc(
1992
foreign->heap, foreign->n_fields * sizeof(void*));
1995
sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
1996
sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
1997
ut_a(!dict_table_is_comp(sys_foreign_cols));
1999
tuple = dtuple_create(foreign->heap, 1);
2000
dfield = dtuple_get_nth_field(tuple, 0);
2002
dfield_set_data(dfield, id, ut_strlen(id));
2003
dict_index_copy_types(tuple, sys_index, 1);
2005
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2006
BTR_SEARCH_LEAF, &pcur, &mtr);
2007
for (i = 0; i < foreign->n_fields; i++) {
2009
rec = btr_pcur_get_rec(&pcur);
2011
ut_a(btr_pcur_is_on_user_rec(&pcur));
2012
ut_a(!rec_get_deleted_flag(rec, 0));
2014
field = rec_get_nth_field_old(rec, 0, &len);
2015
ut_a(len == ut_strlen(id));
2016
ut_a(ut_memcmp(id, field, len) == 0);
2018
field = rec_get_nth_field_old(rec, 1, &len);
2020
ut_a(i == mach_read_from_4(field));
2022
field = rec_get_nth_field_old(rec, 4, &len);
2023
foreign->foreign_col_names[i] = mem_heap_strdupl(
2024
foreign->heap, (char*) field, len);
2026
field = rec_get_nth_field_old(rec, 5, &len);
2027
foreign->referenced_col_names[i] = mem_heap_strdupl(
2028
foreign->heap, (char*) field, len);
2030
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2033
btr_pcur_close(&pcur);
2037
/***********************************************************************//**
2038
Loads a foreign key constraint to the dictionary cache.
2039
@return DB_SUCCESS or error code */
2044
const char* id, /*!< in: foreign constraint id as a
2045
null-terminated string */
2046
ibool check_charsets,
2047
/*!< in: TRUE=check charset compatibility */
2048
ibool check_recursive)
2049
/*!< in: Whether to record the foreign table
2050
parent count to avoid unlimited recursive
2051
load of chained foreign tables */
2053
dict_foreign_t* foreign;
2054
dict_table_t* sys_foreign;
2056
dict_index_t* sys_index;
2063
ulint n_fields_and_type;
2065
dict_table_t* for_table;
2066
dict_table_t* ref_table;
2068
ut_ad(mutex_own(&(dict_sys->mutex)));
2070
heap2 = mem_heap_create(1000);
2074
sys_foreign = dict_table_get_low("SYS_FOREIGN");
2075
sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
2076
ut_a(!dict_table_is_comp(sys_foreign));
2078
tuple = dtuple_create(heap2, 1);
2079
dfield = dtuple_get_nth_field(tuple, 0);
2081
dfield_set_data(dfield, id, ut_strlen(id));
2082
dict_index_copy_types(tuple, sys_index, 1);
2084
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2085
BTR_SEARCH_LEAF, &pcur, &mtr);
2086
rec = btr_pcur_get_rec(&pcur);
2088
if (!btr_pcur_is_on_user_rec(&pcur)
2089
|| rec_get_deleted_flag(rec, 0)) {
2093
"InnoDB: Error A: cannot load foreign constraint %s\n",
2096
btr_pcur_close(&pcur);
2098
mem_heap_free(heap2);
2103
field = rec_get_nth_field_old(rec, 0, &len);
2105
/* Check if the id in record is the searched one */
2106
if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
2109
"InnoDB: Error B: cannot load foreign constraint %s\n",
2112
btr_pcur_close(&pcur);
2114
mem_heap_free(heap2);
2119
/* Read the table names and the number of columns associated
2120
with the constraint */
2122
mem_heap_free(heap2);
2124
foreign = dict_mem_foreign_create();
2126
n_fields_and_type = mach_read_from_4(
2127
rec_get_nth_field_old(rec, 5, &len));
2131
/* We store the type in the bits 24..29 of n_fields_and_type. */
2133
foreign->type = (unsigned int) (n_fields_and_type >> 24);
2134
foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
2136
foreign->id = mem_heap_strdup(foreign->heap, id);
2138
field = rec_get_nth_field_old(rec, 3, &len);
2139
foreign->foreign_table_name = mem_heap_strdupl(
2140
foreign->heap, (char*) field, len);
2142
field = rec_get_nth_field_old(rec, 4, &len);
2143
foreign->referenced_table_name = mem_heap_strdupl(
2144
foreign->heap, (char*) field, len);
2146
btr_pcur_close(&pcur);
2149
dict_load_foreign_cols(id, foreign);
2151
ref_table = dict_table_check_if_in_cache_low(
2152
foreign->referenced_table_name);
2154
/* We could possibly wind up in a deep recursive calls if
2155
we call dict_table_get_low() again here if there
2156
is a chain of tables concatenated together with
2157
foreign constraints. In such case, each table is
2158
both a parent and child of the other tables, and
2159
act as a "link" in such table chains.
2160
To avoid such scenario, we would need to check the
2161
number of ancesters the current table has. If that
2162
exceeds DICT_FK_MAX_CHAIN_LEN, we will stop loading
2164
Foreign constraints are loaded in a Breath First fashion,
2165
that is, the index on FOR_NAME is scanned first, and then
2166
index on REF_NAME. So foreign constrains in which
2167
current table is a child (foreign table) are loaded first,
2168
and then those constraints where current table is a
2169
parent (referenced) table.
2170
Thus we could check the parent (ref_table) table's
2171
reference count (fk_max_recusive_level) to know how deep the
2172
recursive call is. If the parent table (ref_table) is already
2173
loaded, and its fk_max_recusive_level is larger than
2174
DICT_FK_MAX_CHAIN_LEN, we will stop the recursive loading
2175
by skipping loading the child table. It will not affect foreign
2176
constraint check for DMLs since child table will be loaded
2177
at that time for the constraint check. */
2179
|| ref_table->fk_max_recusive_level < DICT_FK_MAX_RECURSIVE_LOAD) {
2181
/* If the foreign table is not yet in the dictionary cache, we
2182
have to load it so that we are able to make type comparisons
2183
in the next function call. */
2185
for_table = dict_table_get_low(foreign->foreign_table_name);
2187
if (for_table && ref_table && check_recursive) {
2188
/* This is to record the longest chain of ancesters
2189
this table has, if the parent has more ancesters
2190
than this table has, record it after add 1 (for this
2192
if (ref_table->fk_max_recusive_level
2193
>= for_table->fk_max_recusive_level) {
2194
for_table->fk_max_recusive_level =
2195
ref_table->fk_max_recusive_level + 1;
2200
/* Note that there may already be a foreign constraint object in
2201
the dictionary cache for this constraint: then the following
2202
call only sets the pointers in it to point to the appropriate table
2203
and index objects and frees the newly created object foreign.
2204
Adding to the cache should always succeed since we are not creating
2205
a new foreign key constraint but loading one from the data
2208
return(dict_foreign_add_to_cache(foreign, check_charsets));
2211
/***********************************************************************//**
2212
Loads foreign key constraints where the table is either the foreign key
2213
holder or where the table is referenced by a foreign key. Adds these
2214
constraints to the data dictionary. Note that we know that the dictionary
2215
cache already contains all constraints where the other relevant table is
2216
already in the dictionary cache.
2217
@return DB_SUCCESS or error code */
2222
const char* table_name, /*!< in: table name */
2223
ibool check_recursive,/*!< in: Whether to check recursive
2224
load of tables chained by FK */
2225
ibool check_charsets) /*!< in: TRUE=check charset
2232
dict_index_t* sec_index;
2233
dict_table_t* sys_foreign;
2241
ut_ad(mutex_own(&(dict_sys->mutex)));
2243
sys_foreign = dict_table_get_low("SYS_FOREIGN");
2245
if (sys_foreign == NULL) {
2246
/* No foreign keys defined yet in this database */
2249
"InnoDB: Error: no foreign key system tables"
2250
" in the database\n");
2255
ut_a(!dict_table_is_comp(sys_foreign));
2258
/* Get the secondary index based on FOR_NAME from table
2261
sec_index = dict_table_get_next_index(
2262
dict_table_get_first_index(sys_foreign));
2264
heap = mem_heap_create(256);
2266
tuple = dtuple_create(heap, 1);
2267
dfield = dtuple_get_nth_field(tuple, 0);
2269
dfield_set_data(dfield, table_name, ut_strlen(table_name));
2270
dict_index_copy_types(tuple, sec_index, 1);
2272
btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE,
2273
BTR_SEARCH_LEAF, &pcur, &mtr);
2275
rec = btr_pcur_get_rec(&pcur);
2277
if (!btr_pcur_is_on_user_rec(&pcur)) {
2280
goto load_next_index;
2283
/* Now we have the record in the secondary index containing a table
2284
name and a foreign constraint ID */
2286
rec = btr_pcur_get_rec(&pcur);
2287
field = rec_get_nth_field_old(rec, 0, &len);
2289
/* Check if the table name in the record is the one searched for; the
2290
following call does the comparison in the latin1_swedish_ci
2291
charset-collation, in a case-insensitive way. */
2293
if (0 != cmp_data_data(dfield_get_type(dfield)->mtype,
2294
dfield_get_type(dfield)->prtype,
2295
dfield_get_data(dfield), dfield_get_len(dfield),
2298
goto load_next_index;
2301
/* Since table names in SYS_FOREIGN are stored in a case-insensitive
2302
order, we have to check that the table name matches also in a binary
2303
string comparison. On Unix, MySQL allows table names that only differ
2304
in character case. */
2306
if (0 != ut_memcmp(field, table_name, len)) {
2311
if (rec_get_deleted_flag(rec, 0)) {
2316
/* Now we get a foreign key constraint id */
2317
field = rec_get_nth_field_old(rec, 1, &len);
2318
id = mem_heap_strdupl(heap, (char*) field, len);
2320
btr_pcur_store_position(&pcur, &mtr);
2324
/* Load the foreign constraint definition to the dictionary cache */
2326
err = dict_load_foreign(id, check_charsets, check_recursive);
2328
if (err != DB_SUCCESS) {
2329
btr_pcur_close(&pcur);
2330
mem_heap_free(heap);
2337
btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
2339
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2344
btr_pcur_close(&pcur);
2346
mem_heap_free(heap);
2348
sec_index = dict_table_get_next_index(sec_index);
2350
if (sec_index != NULL) {
2354
/* Switch to scan index on REF_NAME, fk_max_recusive_level
2355
already been updated when scanning FOR_NAME index, no need to
2357
check_recursive = FALSE;