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(
193
static_cast<dict_table_info>(DICT_TABLE_LOAD_FROM_CACHE
194
| DICT_TABLE_UPDATE_STATS));
199
dict_table_print_low(table);
201
ut_print_timestamp(stderr);
202
fprintf(stderr, " InnoDB: %s\n", err_msg);
205
mem_heap_empty(heap);
208
rec = dict_getnext_system(&pcur, &mtr);
212
mutex_exit(&(dict_sys->mutex));
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);
222
/********************************************************************//**
223
This function gets the next system table record as it scans the table.
224
@return the next record if found, NULL if end of scan */
227
dict_getnext_system_low(
228
/*====================*/
229
btr_pcur_t* pcur, /*!< in/out: persistent cursor to the
231
mtr_t* mtr) /*!< in: the mini-transaction */
235
while (!rec || rec_get_deleted_flag(rec, 0)) {
236
btr_pcur_move_to_next_user_rec(pcur, mtr);
238
rec = btr_pcur_get_rec(pcur);
240
if (!btr_pcur_is_on_user_rec(pcur)) {
242
btr_pcur_close(pcur);
248
/* Get a record, let's save the position */
249
btr_pcur_store_position(pcur, mtr);
254
/********************************************************************//**
255
This function opens a system table, and return the first record.
256
@return first record of the system table */
259
dict_startscan_system(
260
/*==================*/
261
btr_pcur_t* pcur, /*!< out: persistent cursor to
263
mtr_t* mtr, /*!< in: the mini-transaction */
264
dict_system_id_t system_id) /*!< in: which system table to open */
266
dict_table_t* system_table;
267
dict_index_t* clust_index;
270
ut_a(system_id < SYS_NUM_SYSTEM_TABLES);
272
system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]);
274
clust_index = UT_LIST_GET_FIRST(system_table->indexes);
276
btr_pcur_open_at_index_side(TRUE, clust_index, BTR_SEARCH_LEAF, pcur,
279
rec = dict_getnext_system_low(pcur, mtr);
284
/********************************************************************//**
285
This function gets the next system table record as it scans the table.
286
@return the next record if found, NULL if end of scan */
291
btr_pcur_t* pcur, /*!< in/out: persistent cursor
293
mtr_t* mtr) /*!< in: the mini-transaction */
297
/* Restore the position */
298
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
300
/* Get the next record */
301
rec = dict_getnext_system_low(pcur, mtr);
305
/********************************************************************//**
306
This function processes one SYS_TABLES record and populate the dict_table_t
307
struct for the table. Extracted out of dict_print() to be used by
308
both monitor table output and information schema innodb_sys_tables output.
309
@return error message, or NULL on success */
312
dict_process_sys_tables_rec(
313
/*========================*/
314
mem_heap_t* heap, /*!< in/out: temporary memory heap */
315
const rec_t* rec, /*!< in: SYS_TABLES record */
316
dict_table_t** table, /*!< out: dict_table_t to fill */
317
dict_table_info_t status) /*!< in: status bit controls
318
options such as whether we shall
319
look for dict_table_t from cache
324
const char* err_msg = NULL;
327
field = (const char*) rec_get_nth_field_old(rec, 0, &len);
329
ut_a(!rec_get_deleted_flag(rec, 0));
331
/* Get the table name */
332
table_name = mem_heap_strdupl(heap, (const char*)field, len);
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);
340
err_msg = "Table not found in cache";
343
err_msg = dict_load_table_low(table_name, rec, table);
350
if ((status & DICT_TABLE_UPDATE_STATS)
351
&& dict_table_get_first_index(*table)) {
353
/* Update statistics if DICT_TABLE_UPDATE_STATS
355
dict_update_statistics(*table,
356
FALSE /* update even if
363
/********************************************************************//**
364
This function parses a SYS_INDEXES record and populate a dict_index_t
365
structure with the information from the record. For detail information
366
about SYS_INDEXES fields, please refer to dict_boot() function.
367
@return error message, or NULL on success */
370
dict_process_sys_indexes_rec(
371
/*=========================*/
372
mem_heap_t* heap, /*!< in/out: heap memory */
373
const rec_t* rec, /*!< in: current SYS_INDEXES rec */
374
dict_index_t* index, /*!< out: index to be filled */
375
table_id_t* table_id) /*!< out: index table id */
380
buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
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);
386
*table_id = mach_read_from_8(buf);
390
/********************************************************************//**
391
This function parses a SYS_COLUMNS record and populate a dict_column_t
392
structure with the information from the record.
393
@return error message, or NULL on success */
396
dict_process_sys_columns_rec(
397
/*=========================*/
398
mem_heap_t* heap, /*!< in/out: heap memory */
399
const rec_t* rec, /*!< in: current SYS_COLUMNS rec */
400
dict_col_t* column, /*!< out: dict_col_t to be filled */
401
table_id_t* table_id, /*!< out: table id */
402
const char** col_name) /*!< out: column name */
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);
412
/********************************************************************//**
413
This function parses a SYS_FIELDS record and populates a dict_field_t
414
structure with the information from the record.
415
@return error message, or NULL on success */
418
dict_process_sys_fields_rec(
419
/*========================*/
420
mem_heap_t* heap, /*!< in/out: heap memory */
421
const rec_t* rec, /*!< in: current SYS_FIELDS rec */
422
dict_field_t* sys_field, /*!< out: dict_field_t to be
424
ulint* pos, /*!< out: Field position */
425
index_id_t* index_id, /*!< out: current index id */
426
index_id_t last_id) /*!< in: previous index id */
432
buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
434
last_index_id = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
435
mach_write_to_8(last_index_id, last_id);
437
err_msg = dict_load_field_low(buf, NULL, sys_field,
438
pos, last_index_id, heap, rec);
440
*index_id = mach_read_from_8(buf);
445
/********************************************************************//**
446
This function parses a SYS_FOREIGN record and populate a dict_foreign_t
447
structure with the information from the record. For detail information
448
about SYS_FOREIGN fields, please refer to dict_load_foreign() function
449
@return error message, or NULL on success */
452
dict_process_sys_foreign_rec(
453
/*=========================*/
454
mem_heap_t* heap, /*!< in/out: heap memory */
455
const rec_t* rec, /*!< in: current SYS_FOREIGN rec */
456
dict_foreign_t* foreign) /*!< out: dict_foreign_t struct
461
ulint n_fields_and_type;
463
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
464
return("delete-marked record in SYS_FOREIGN");
467
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
468
return("wrong number of columns in SYS_FOREIGN record");
471
field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
472
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
474
return("incorrect column length in SYS_FOREIGN");
476
foreign->id = mem_heap_strdupl(heap, (const char*) field, len);
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)) {
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)) {
487
field = rec_get_nth_field_old(rec, 3/*FOR_NAME*/, &len);
488
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
491
foreign->foreign_table_name = mem_heap_strdupl(
492
heap, (const char*) field, len);
494
field = rec_get_nth_field_old(rec, 4/*REF_NAME*/, &len);
495
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
498
foreign->referenced_table_name = mem_heap_strdupl(
499
heap, (const char*) field, len);
501
field = rec_get_nth_field_old(rec, 5/*N_COLS*/, &len);
502
if (UNIV_UNLIKELY(len != 4)) {
505
n_fields_and_type = mach_read_from_4(field);
507
foreign->type = (unsigned int) (n_fields_and_type >> 24);
508
foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
512
/********************************************************************//**
513
This function parses a SYS_FOREIGN_COLS record and extract necessary
514
information from the record and return to caller.
515
@return error message, or NULL on success */
518
dict_process_sys_foreign_col_rec(
519
/*=============================*/
520
mem_heap_t* heap, /*!< in/out: heap memory */
521
const rec_t* rec, /*!< in: current SYS_FOREIGN_COLS rec */
522
const char** name, /*!< out: foreign key constraint name */
523
const char** for_col_name, /*!< out: referencing column name */
524
const char** ref_col_name, /*!< out: referenced column name
525
in referenced table */
526
ulint* pos) /*!< out: column position */
531
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
532
return("delete-marked record in SYS_FOREIGN_COLS");
535
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) {
536
return("wrong number of columns in SYS_FOREIGN_COLS record");
539
field = rec_get_nth_field_old(rec, 0/*ID*/, &len);
540
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
542
return("incorrect column length in SYS_FOREIGN_COLS");
544
*name = mem_heap_strdupl(heap, (char*) field, len);
546
field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
547
if (UNIV_UNLIKELY(len != 4)) {
550
*pos = mach_read_from_4(field);
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)) {
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)) {
561
field = rec_get_nth_field_old(rec, 4/*FOR_COL_NAME*/, &len);
562
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
565
*for_col_name = mem_heap_strdupl(heap, (char*) field, len);
567
field = rec_get_nth_field_old(rec, 5/*REF_COL_NAME*/, &len);
568
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
571
*ref_col_name = mem_heap_strdupl(heap, (char*) field, len);
577
Send data to callback function .
580
UNIV_INTERN void dict_print_with_callback(dict_print_callback func, void *func_arg)
582
144
dict_table_t* sys_tables;
583
145
dict_index_t* sys_index;
585
148
const rec_t* rec;
586
149
const byte* field;
860
/********************************************************************//**
861
Loads a table column definition from a SYS_COLUMNS record to
863
@return error message, or NULL on success */
866
dict_load_column_low(
867
/*=================*/
868
dict_table_t* table, /*!< in/out: table, could be NULL
869
if we just populate a dict_column_t
870
struct with information from
871
a SYS_COLUMNS record */
872
mem_heap_t* heap, /*!< in/out: memory heap
873
for temporary storage */
874
dict_col_t* column, /*!< out: dict_column_t to fill,
875
or NULL if table != NULL */
876
table_id_t* table_id, /*!< out: table id */
877
const char** col_name, /*!< out: column name */
878
const rec_t* rec) /*!< in: SYS_COLUMNS record */
414
/************************************************************************
415
Loads definitions for table columns. */
420
dict_table_t* table, /* in: table */
421
mem_heap_t* heap) /* in: memory heap for temporary storage */
423
dict_table_t* sys_columns;
424
dict_index_t* sys_index;
888
ut_ad(table || column);
890
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
891
return("delete-marked record in SYS_COLUMNS");
894
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
895
return("wrong number of columns in SYS_COLUMNS record");
898
field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
899
if (UNIV_UNLIKELY(len != 8)) {
901
return("incorrect column length in SYS_COLUMNS");
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");
910
field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
911
if (UNIV_UNLIKELY(len != 4)) {
916
pos = mach_read_from_4(field);
918
if (UNIV_UNLIKELY(table && table->n_def != pos)) {
919
return("SYS_COLUMNS.POS mismatch");
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)) {
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)) {
931
field = rec_get_nth_field_old(rec, 4/*NAME*/, &len);
932
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
936
name = mem_heap_strdupl(heap, (const char*) field, len);
942
field = rec_get_nth_field_old(rec, 5/*MTYPE*/, &len);
943
if (UNIV_UNLIKELY(len != 4)) {
947
mtype = mach_read_from_4(field);
949
field = rec_get_nth_field_old(rec, 6/*PRTYPE*/, &len);
950
if (UNIV_UNLIKELY(len != 4)) {
953
prtype = mach_read_from_4(field);
955
if (dtype_get_charset_coll(prtype) == 0
956
&& dtype_is_string_type(mtype)) {
957
/* The table was created with < 4.1.2. */
959
if (dtype_is_binary_string_type(mtype, prtype)) {
960
/* Use the binary collation for
961
string columns of binary type. */
963
prtype = dtype_form_prtype(
965
DATA_MYSQL_BINARY_CHARSET_COLL);
967
/* Use the default charset for
968
other than binary columns. */
970
prtype = dtype_form_prtype(
972
data_mysql_default_charset_coll);
976
field = rec_get_nth_field_old(rec, 7/*LEN*/, &len);
977
if (UNIV_UNLIKELY(len != 4)) {
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)) {
987
dict_mem_table_add_col(table, heap, name, mtype,
990
dict_mem_fill_column_struct(column, pos, mtype,
997
/********************************************************************//**
998
Loads definitions for table columns. */
1003
dict_table_t* table, /*!< in/out: table */
1004
mem_heap_t* heap) /*!< in/out: memory heap
1005
for temporary storage */
1007
dict_table_t* sys_columns;
1008
dict_index_t* sys_index;
1037
456
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1038
457
BTR_SEARCH_LEAF, &pcur, &mtr);
1039
458
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
1040
const char* err_msg;
1042
460
rec = btr_pcur_get_rec(&pcur);
1044
462
ut_a(btr_pcur_is_on_user_rec(&pcur));
1046
err_msg = dict_load_column_low(table, heap, NULL, NULL,
1050
fprintf(stderr, "InnoDB: %s\n", err_msg);
464
ut_a(!rec_get_deleted_flag(rec, 0));
466
field = rec_get_nth_field_old(rec, 0, &len);
468
ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0);
470
field = rec_get_nth_field_old(rec, 1, &len);
472
ut_a(i == mach_read_from_4(field));
474
ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
476
field = rec_get_nth_field_old(rec, 4, &len);
477
name = mem_heap_strdupl(heap, (char*) field, len);
479
field = rec_get_nth_field_old(rec, 5, &len);
480
mtype = mach_read_from_4(field);
482
field = rec_get_nth_field_old(rec, 6, &len);
483
prtype = mach_read_from_4(field);
485
if (dtype_get_charset_coll(prtype) == 0
486
&& dtype_is_string_type(mtype)) {
487
/* The table was created with < 4.1.2. */
489
if (dtype_is_binary_string_type(mtype, prtype)) {
490
/* Use the binary collation for
491
string columns of binary type. */
493
prtype = dtype_form_prtype(
495
DATA_MYSQL_BINARY_CHARSET_COLL);
497
/* Use the default charset for
498
other than binary columns. */
500
prtype = dtype_form_prtype(
502
data_mysql_default_charset_coll);
506
field = rec_get_nth_field_old(rec, 7, &len);
507
col_len = mach_read_from_4(field);
509
ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
511
dict_mem_table_add_col(table, heap, name,
512
mtype, prtype, col_len);
1054
513
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1058
517
mtr_commit(&mtr);
1061
/** Error message for a delete-marked record in dict_load_field_low() */
1062
static const char* dict_load_field_del = "delete-marked record in SYS_FIELDS";
1064
/********************************************************************//**
1065
Loads an index field definition from a SYS_FIELDS record to
1067
@return error message, or NULL on success */
1070
dict_load_field_low(
1071
/*================*/
1072
byte* index_id, /*!< in/out: index id (8 bytes)
1073
an "in" value if index != NULL
1074
and "out" if index == NULL */
1075
dict_index_t* index, /*!< in/out: index, could be NULL
1076
if we just populate a dict_field_t
1077
struct with information from
1078
a SYS_FIELDSS record */
1079
dict_field_t* sys_field, /*!< out: dict_field_t to be
1081
ulint* pos, /*!< out: Field position */
1082
byte* last_index_id, /*!< in: last index id */
1083
mem_heap_t* heap, /*!< in/out: memory heap
1084
for temporary storage */
1085
const rec_t* rec) /*!< in: SYS_FIELDS record */
1089
ulint pos_and_prefix_len;
1094
/* Either index or sys_field is supplied, not both */
1095
ut_a((!index) || (!sys_field));
1097
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1098
return(dict_load_field_del);
1101
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) {
1102
return("wrong number of columns in SYS_FIELDS record");
1105
field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len);
1106
if (UNIV_UNLIKELY(len != 8)) {
1108
return("incorrect column length in SYS_FIELDS");
1112
ut_a(last_index_id);
1113
memcpy(index_id, (const char*)field, 8);
1114
first_field = memcmp(index_id, last_index_id, 8);
1116
first_field = (index->n_def == 0);
1117
if (memcmp(field, index_id, 8)) {
1118
return("SYS_FIELDS.INDEX_ID mismatch");
1122
field = rec_get_nth_field_old(rec, 1/*POS*/, &len);
1123
if (UNIV_UNLIKELY(len != 4)) {
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)) {
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)) {
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. */
1144
pos_and_prefix_len = mach_read_from_4(field);
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");
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;
1157
position = pos_and_prefix_len & 0xFFFFUL;
1160
field = rec_get_nth_field_old(rec, 4, &len);
1161
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
1166
dict_mem_index_add_field(
1167
index, mem_heap_strdupl(heap, (const char*) field, len),
1173
sys_field->name = mem_heap_strdupl(
1174
heap, (const char*) field, len);
1175
sys_field->prefix_len = prefix_len;
1182
/********************************************************************//**
1183
Loads definitions for index fields.
1184
@return DB_SUCCESS if ok, DB_CORRUPTION if corruption */
520
/************************************************************************
521
Loads definitions for index fields. */
1187
524
dict_load_fields(
1188
525
/*=============*/
1189
dict_index_t* index, /*!< in/out: index whose fields to load */
1190
mem_heap_t* heap) /*!< in: memory heap for temporary storage */
526
dict_index_t* index, /* in: index whose fields to load */
527
mem_heap_t* heap) /* in: memory heap for temporary storage */
1192
529
dict_table_t* sys_fields;
1193
530
dict_index_t* sys_index;
1194
531
btr_pcur_t pcur;
1195
532
dtuple_t* tuple;
1196
533
dfield_t* dfield;
534
ulint pos_and_prefix_len;
1197
536
const rec_t* rec;
1203
543
ut_ad(mutex_own(&(dict_sys->mutex)));
1221
560
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
1222
561
BTR_SEARCH_LEAF, &pcur, &mtr);
1223
562
for (i = 0; i < index->n_fields; i++) {
1224
const char* err_msg;
1226
564
rec = btr_pcur_get_rec(&pcur);
1228
566
ut_a(btr_pcur_is_on_user_rec(&pcur));
1230
err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL,
568
/* There could be delete marked records in SYS_FIELDS
569
because SYS_FIELDS.INDEX_ID can be updated
570
by ALTER TABLE ADD INDEX. */
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. */
572
if (rec_get_deleted_flag(rec, 0)) {
1239
} else if (err_msg) {
1240
fprintf(stderr, "InnoDB: %s\n", err_msg);
1241
error = DB_CORRUPTION;
577
field = rec_get_nth_field_old(rec, 0, &len);
580
field = rec_get_nth_field_old(rec, 1, &len);
583
/* The next field stores the field position in the index
584
and a possible column prefix length if the index field
585
does not contain the whole column. The storage format is
586
like this: if there is at least one prefix field in the index,
587
then the HIGH 2 bytes contain the field number (== i) and the
588
low 2 bytes the prefix length for the field. Otherwise the
589
field number (== i) is contained in the 2 LOW bytes. */
591
pos_and_prefix_len = mach_read_from_4(field);
593
ut_a((pos_and_prefix_len & 0xFFFFUL) == i
594
|| (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16));
596
if ((i == 0 && pos_and_prefix_len > 0)
597
|| (pos_and_prefix_len & 0xFFFF0000UL) > 0) {
599
prefix_len = pos_and_prefix_len & 0xFFFFUL;
604
ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
606
field = rec_get_nth_field_old(rec, 4, &len);
608
dict_mem_index_add_field(index,
609
mem_heap_strdupl(heap,
1245
614
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
1250
617
btr_pcur_close(&pcur);
1251
618
mtr_commit(&mtr);
1255
/** Error message for a delete-marked record in dict_load_index_low() */
1256
static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES";
1257
/** Error message for table->id mismatch in dict_load_index_low() */
1258
static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch";
1260
/********************************************************************//**
1261
Loads an index definition from a SYS_INDEXES record to dict_index_t.
1262
If allocate=TRUE, we will create a dict_index_t structure and fill it
1263
accordingly. If allocated=FALSE, the dict_index_t will be supplied by
1264
the caller and filled with information read from the record. @return
1265
error message, or NULL on success */
1268
dict_load_index_low(
1269
/*================*/
1270
byte* table_id, /*!< in/out: table id (8 bytes),
1271
an "in" value if allocate=TRUE
1272
and "out" when allocate=FALSE */
1273
const char* table_name, /*!< in: table name */
1274
mem_heap_t* heap, /*!< in/out: temporary memory heap */
1275
const rec_t* rec, /*!< in: SYS_INDEXES record */
1276
ibool allocate, /*!< in: TRUE=allocate *index,
1277
FALSE=fill in a pre-allocated
1279
dict_index_t** index) /*!< out,own: index, or NULL */
621
/************************************************************************
622
Loads definitions for table indexes. Adds them to the data dictionary
628
/* out: DB_SUCCESS if ok, DB_CORRUPTION
629
if corruption of dictionary table or
630
DB_UNSUPPORTED if table has unknown index
632
dict_table_t* table, /* in: table */
633
mem_heap_t* heap) /* in: memory heap for temporary storage */
635
dict_table_t* sys_indexes;
636
dict_index_t* sys_index;
1281
642
const byte* field;
1291
/* If allocate=TRUE, no dict_index_t will
1292
be supplied. Initialize "*index" to NULL */
1296
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1297
return(dict_load_index_del);
1300
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) {
1301
return("wrong number of columns in SYS_INDEXES record");
1304
field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len);
1305
if (UNIV_UNLIKELY(len != 8)) {
1307
return("incorrect column length in SYS_INDEXES");
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);
1319
field = rec_get_nth_field_old(rec, 1/*ID*/, &len);
1320
if (UNIV_UNLIKELY(len != 8)) {
1324
id = mach_read_from_8(field);
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)) {
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)) {
1335
field = rec_get_nth_field_old(rec, 4/*NAME*/, &name_len);
1336
if (UNIV_UNLIKELY(name_len == UNIV_SQL_NULL)) {
1340
name_buf = mem_heap_strdupl(heap, (const char*) field,
1343
field = rec_get_nth_field_old(rec, 5/*N_FIELDS*/, &len);
1344
if (UNIV_UNLIKELY(len != 4)) {
1347
n_fields = mach_read_from_4(field);
1349
field = rec_get_nth_field_old(rec, 6/*TYPE*/, &len);
1350
if (UNIV_UNLIKELY(len != 4)) {
1353
type = mach_read_from_4(field);
1355
field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len);
1356
if (UNIV_UNLIKELY(len != 4)) {
1359
space = mach_read_from_4(field);
1361
field = rec_get_nth_field_old(rec, 8/*PAGE_NO*/, &len);
1362
if (UNIV_UNLIKELY(len != 4)) {
1367
*index = dict_mem_index_create(table_name, name_buf,
1368
space, type, n_fields);
1372
dict_mem_fill_index_struct(*index, NULL, NULL, name_buf,
1373
space, type, n_fields);
1377
(*index)->page = mach_read_from_4(field);
1378
ut_ad((*index)->page);
1383
/********************************************************************//**
1384
Loads definitions for table indexes. Adds them to the data dictionary
1386
@return DB_SUCCESS if ok, DB_CORRUPTION if corruption of dictionary
1387
table or DB_UNSUPPORTED if table has unknown index type */
1392
dict_table_t* table, /*!< in/out: table */
1393
mem_heap_t* heap) /*!< in: memory heap for temporary storage */
1395
dict_table_t* sys_indexes;
1396
dict_index_t* sys_index;
1403
654
ulint error = DB_SUCCESS;
1405
656
ut_ad(mutex_own(&(dict_sys->mutex)));
658
if ((ut_dulint_get_high(table->id) == 0)
659
&& (ut_dulint_get_low(table->id) < DICT_HDR_FIRST_ID)) {
662
is_sys_table = FALSE;
1407
665
mtr_start(&mtr);
1409
667
sys_indexes = dict_table_get_low("SYS_INDEXES");
1410
668
sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
1411
669
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"));
1415
671
tuple = dtuple_create(heap, 1);
1416
672
dfield = dtuple_get_nth_field(tuple, 0);
1418
buf = static_cast<unsigned char *>(mem_heap_alloc(heap, 8));
674
buf = mem_heap_alloc(heap, 8);
1419
675
mach_write_to_8(buf, table->id);
1421
677
dfield_set_data(dfield, buf, 8);
1435
688
rec = btr_pcur_get_rec(&pcur);
1437
err_msg = dict_load_index_low(buf, table->name, heap, rec,
1439
ut_ad((index == NULL) == (err_msg != NULL));
690
field = rec_get_nth_field_old(rec, 0, &len);
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. */
693
if (ut_memcmp(buf, field, len) != 0) {
1445
} else if (err_msg == dict_load_index_del) {
1446
/* Skip delete-marked records. */
695
} else if (rec_get_deleted_flag(rec, 0)) {
696
/* Skip delete marked records */
1448
} else if (err_msg) {
1449
fprintf(stderr, "InnoDB: %s\n", err_msg);
1450
error = DB_CORRUPTION;
700
field = rec_get_nth_field_old(rec, 1, &len);
702
id = mach_read_from_8(field);
704
ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
706
field = rec_get_nth_field_old(rec, 4, &name_len);
707
name_buf = mem_heap_strdupl(heap, (char*) field, name_len);
709
field = rec_get_nth_field_old(rec, 5, &len);
710
n_fields = mach_read_from_4(field);
712
field = rec_get_nth_field_old(rec, 6, &len);
713
type = mach_read_from_4(field);
715
field = rec_get_nth_field_old(rec, 7, &len);
716
space = mach_read_from_4(field);
718
ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
720
field = rec_get_nth_field_old(rec, 8, &len);
721
page_no = mach_read_from_4(field);
1456
723
/* We check for unsupported types first, so that the
1457
724
subsequent checks are relevant for the supported types. */
1458
if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
725
if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
1461
728
"InnoDB: Error: unknown type %lu"
1462
729
" of index %s of table %s\n",
1463
(ulong) index->type, index->name, table->name);
730
(ulong) type, name_buf, table->name);
1465
732
error = DB_UNSUPPORTED;
1466
dict_mem_index_free(index);
1468
} else if (index->page == FIL_NULL) {
734
} else if (page_no == FIL_NULL) {
1471
737
"InnoDB: Error: trying to load index %s"
1472
738
" for table %s\n"
1473
739
"InnoDB: but the index tree has been freed!\n",
1474
index->name, table->name);
740
name_buf, table->name);
1477
dict_mem_index_free(index);
1478
742
error = DB_CORRUPTION;
1480
} else if (!dict_index_is_clust(index)
1481
&& NULL == dict_table_get_first_index(table)) {
744
} else if ((type & DICT_CLUSTERED) == 0
745
&& NULL == dict_table_get_first_index(table)) {
1483
747
fputs("InnoDB: Error: trying to load index ",
1485
ut_print_name(stderr, NULL, FALSE, index->name);
749
ut_print_name(stderr, NULL, FALSE, name_buf);
1486
750
fputs(" for table ", stderr);
1487
751
ut_print_name(stderr, NULL, TRUE, table->name);
1488
752
fputs("\nInnoDB: but the first index"
1489
753
" is not clustered!\n", stderr);
1492
} else if (table->id < DICT_HDR_FIRST_ID
1493
&& (dict_index_is_clust(index)
755
error = DB_CORRUPTION;
757
} else if (is_sys_table
758
&& ((type & DICT_CLUSTERED)
1494
759
|| ((table == dict_sys->sys_tables)
1495
&& !strcmp("ID_IND", index->name)))) {
760
&& (name_len == (sizeof "ID_IND") - 1)
761
&& (0 == ut_memcmp(name_buf,
762
"ID_IND", name_len))))) {
1497
764
/* The index was created in memory already at booting
1498
765
of the database server */
1499
dict_mem_index_free(index);
767
index = dict_mem_index_create(table->name, name_buf,
768
space, type, n_fields);
1501
771
dict_load_fields(index, heap);
1502
error = dict_index_add_to_cache(table, index,
1503
index->page, FALSE);
772
error = dict_index_add_to_cache(table, index, page_no,
1504
774
/* The data dictionary tables should never contain
1505
775
invalid index definitions. If we ignored this error
1506
776
and simply did not load this index definition, the
1526
/********************************************************************//**
1527
Loads a table definition from a SYS_TABLES record to dict_table_t.
1528
Does not load any columns or indexes.
1529
@return error message, or NULL on success */
1532
dict_load_table_low(
1533
/*================*/
1534
const char* name, /*!< in: table name */
1535
const rec_t* rec, /*!< in: SYS_TABLES record */
1536
dict_table_t** table) /*!< out,own: table, or NULL */
1544
if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) {
1545
return("delete-marked record in SYS_TABLES");
1548
if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 10)) {
1549
return("wrong number of columns in SYS_TABLES record");
1552
rec_get_nth_field_offs_old(rec, 0/*NAME*/, &len);
1553
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
1555
return("incorrect column length in SYS_TABLES");
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)) {
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)) {
1566
rec_get_nth_field_offs_old(rec, 3/*ID*/, &len);
1567
if (UNIV_UNLIKELY(len != 8)) {
1571
field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
1572
if (UNIV_UNLIKELY(len != 4)) {
1576
n_cols = mach_read_from_4(field);
1578
rec_get_nth_field_offs_old(rec, 5/*TYPE*/, &len);
1579
if (UNIV_UNLIKELY(len != 4)) {
1583
rec_get_nth_field_offs_old(rec, 6/*MIX_ID*/, &len);
1584
if (UNIV_UNLIKELY(len != 8)) {
1588
rec_get_nth_field_offs_old(rec, 7/*MIX_LEN*/, &len);
1589
if (UNIV_UNLIKELY(len != 4)) {
1593
rec_get_nth_field_offs_old(rec, 8/*CLUSTER_ID*/, &len);
1594
if (UNIV_UNLIKELY(len != UNIV_SQL_NULL)) {
1598
field = rec_get_nth_field_old(rec, 9/*SPACE*/, &len);
1600
if (UNIV_UNLIKELY(len != 4)) {
1604
space = mach_read_from_4(field);
1606
/* Check if the tablespace exists and has the right name */
1608
flags = dict_sys_tables_get_flags(rec);
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);
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",
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) {
1633
flags |= DICT_TF_COMPACT;
1635
field = rec_get_nth_field_old(rec, 7, &len);
1637
if (UNIV_UNLIKELY(len != 4)) {
1642
flags2 = mach_read_from_4(field);
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",
1653
flags2 &= ~(~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT));
1656
flags |= flags2 << DICT_TF2_SHIFT;
1659
/* See if the tablespace is available. */
1660
*table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
1663
field = rec_get_nth_field_old(rec, 3/*ID*/, &len);
1664
ut_ad(len == 8); /* this was checked earlier */
1666
(*table)->id = mach_read_from_8(field);
1668
(*table)->ibd_file_missing = FALSE;
1673
/********************************************************************//**
796
/************************************************************************
1674
797
Loads a table definition and also all its index definitions, and also
1675
798
the cluster definition if the table is a member in a cluster. Also loads
1676
799
all foreign key constraints where the foreign key is in the table or where
1677
800
a foreign key references columns in this table. Adds all these to the data
1679
@return table, NULL if does not exist; if the table is stored in an
1680
.ibd file, but the file does not exist, then we set the
1681
ibd_file_missing flag TRUE in the table object we return */
1684
804
dict_load_table(
1685
805
/*============*/
1686
const char* name, /*!< in: table name in the
806
/* out: table, NULL if does not exist;
807
if the table is stored in an .ibd file,
808
but the file does not exist,
809
then we set the ibd_file_missing flag TRUE
810
in the table object we return */
811
const char* name) /* in: table name in the
1687
812
databasename/tablename format */
1688
ibool cached) /*!< in: TRUE=add to cache, FALSE=do not */
814
ibool ibd_file_missing = FALSE;
1690
815
dict_table_t* table;
1691
816
dict_table_t* sys_tables;
1692
817
btr_pcur_t pcur;
1748
err_msg = dict_load_table_low(name, rec, &table);
1752
ut_print_timestamp(stderr);
1753
fprintf(stderr, " InnoDB: %s\n", err_msg);
1757
if (table->space == 0) {
1758
/* The system tablespace is always available. */
1759
} else if (!fil_space_for_table_exists_in_mem(
1761
(table->flags >> DICT_TF2_SHIFT)
1762
& DICT_TF2_TEMPORARY,
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;
870
ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
872
field = rec_get_nth_field_old(rec, 9, &len);
873
space = mach_read_from_4(field);
875
/* Check if the tablespace exists and has the right name */
877
flags = dict_sys_tables_get_flags(rec);
879
if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
880
field = rec_get_nth_field_old(rec, 5, &len);
881
flags = mach_read_from_4(field);
883
ut_print_timestamp(stderr);
884
fputs(" InnoDB: Error: table ", stderr);
885
ut_print_filename(stderr, name);
887
"InnoDB: in InnoDB data dictionary"
888
" has unknown type %lx.\n",
893
if (fil_space_for_table_exists_in_mem(space, name, FALSE,
895
/* Ok; (if we did a crash recovery then the tablespace
896
can already be in the memory cache) */
898
/* In >= 4.1.9, InnoDB scans the data dictionary also
899
at a normal mysqld startup. It is an error if the
900
space object does not exist in memory. */
1769
902
ut_print_timestamp(stderr);
1771
" InnoDB: error: space object of table ");
1772
ut_print_filename(stderr, name);
1773
fprintf(stderr, ",\n"
904
" InnoDB: error: space object of table %s,\n"
1774
905
"InnoDB: space id %lu did not exist in memory."
1775
906
" Retrying an open.\n",
1776
(ulong) table->space);
1777
908
/* Try to open the tablespace */
1778
909
if (!fil_open_single_table_tablespace(
1780
table->flags == DICT_TF_COMPACT ? 0 :
1781
table->flags & ~(~0 << DICT_TF_BITS), name)) {
1782
/* We failed to find a sensible
910
TRUE, space, flags, name)) {
911
/* We failed to find a sensible tablespace
1785
table->ibd_file_missing = TRUE;
914
ibd_file_missing = TRUE;
921
ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
923
field = rec_get_nth_field_old(rec, 4, &len);
924
n_cols = mach_read_from_4(field);
926
/* The high-order bit of N_COLS is the "compact format" flag. */
927
if (n_cols & 0x80000000UL) {
928
flags |= DICT_TF_COMPACT;
931
table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
934
table->ibd_file_missing = (unsigned int) ibd_file_missing;
936
ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
938
field = rec_get_nth_field_old(rec, 3, &len);
939
table->id = mach_read_from_8(field);
1790
941
btr_pcur_close(&pcur);
1791
942
mtr_commit(&mtr);
1793
944
dict_load_columns(table, heap);
1796
dict_table_add_to_cache(table, heap);
1798
dict_table_add_system_columns(table, heap);
946
dict_table_add_to_cache(table, heap);
1801
948
mem_heap_empty(heap);
1803
950
err = dict_load_indexes(table, heap);
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;
951
#ifndef UNIV_HOTBACKUP
1809
952
/* If the force recovery flag is set, we open the table irrespective
1810
953
of the error condition, since the user may want to dump data from the
1811
954
clustered index. However we load the foreign key information only if
1812
955
all indexes were loaded. */
956
if (err != DB_SUCCESS && !srv_force_recovery) {
957
dict_mem_table_free(table);
1814
959
} else if (err == DB_SUCCESS) {
1815
err = dict_load_foreigns(table->name, TRUE, TRUE);
1817
if (err != DB_SUCCESS) {
1818
dict_table_remove_from_cache(table);
1821
table->fk_max_recusive_level = 0;
1823
} else if (!srv_force_recovery) {
1824
dict_table_remove_from_cache(table);
960
err = dict_load_foreigns(table->name, TRUE);
1828
963
if (err != DB_SUCCESS && table != NULL) {
1830
965
mutex_enter(&dict_foreign_err_mutex);
2152
1283
dict_load_foreign_cols(id, foreign);
2154
ref_table = dict_table_check_if_in_cache_low(
2155
foreign->referenced_table_name);
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
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. */
2182
|| ref_table->fk_max_recusive_level < DICT_FK_MAX_RECURSIVE_LOAD) {
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. */
2188
for_table = dict_table_get_low(foreign->foreign_table_name);
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
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;
1285
/* If the foreign table is not yet in the dictionary cache, we
1286
have to load it so that we are able to make type comparisons
1287
in the next function call. */
1289
dict_table_get_low(foreign->foreign_table_name);
2203
1291
/* Note that there may already be a foreign constraint object in
2204
1292
the dictionary cache for this constraint: then the following