~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/innobase/dict/dict0load.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************
 
2
Loads to the memory cache database object definitions
 
3
from dictionary tables
 
4
 
 
5
(c) 1996 Innobase Oy
 
6
 
 
7
Created 4/24/1996 Heikki Tuuri
 
8
*******************************************************/
 
9
 
 
10
#include "dict0load.h"
 
11
#ifndef UNIV_HOTBACKUP
 
12
#include "mysql_version.h"
 
13
#endif /* !UNIV_HOTBACKUP */
 
14
 
 
15
#ifdef UNIV_NONINL
 
16
#include "dict0load.ic"
 
17
#endif
 
18
 
 
19
#include "btr0pcur.h"
 
20
#include "btr0btr.h"
 
21
#include "page0page.h"
 
22
#include "mach0data.h"
 
23
#include "dict0dict.h"
 
24
#include "dict0boot.h"
 
25
#include "rem0cmp.h"
 
26
#include "srv0start.h"
 
27
#include "srv0srv.h"
 
28
 
 
29
/********************************************************************
 
30
Returns TRUE if index's i'th column's name is 'name' .*/
 
31
static
 
32
ibool
 
33
name_of_col_is(
 
34
/*===========*/
 
35
                                /* out: */
 
36
        dict_table_t*   table,  /* in: table */
 
37
        dict_index_t*   index,  /* in: index */
 
38
        ulint           i,      /* in:  */
 
39
        const char*     name)   /* in: name to compare to */
 
40
{
 
41
        ulint   tmp = dict_col_get_no(dict_field_get_col(
 
42
                                              dict_index_get_nth_field(
 
43
                                                      index, i)));
 
44
 
 
45
        return(strcmp(name, dict_table_get_col_name(table, tmp)) == 0);
 
46
}
 
47
 
 
48
/************************************************************************
 
49
Finds the first table name in the given database. */
 
50
 
 
51
char*
 
52
dict_get_first_table_name_in_db(
 
53
/*============================*/
 
54
                                /* out, own: table name, NULL if
 
55
                                does not exist; the caller must
 
56
                                free the memory in the string! */
 
57
        const char*     name)   /* in: database name which ends in '/' */
 
58
{
 
59
        dict_table_t*   sys_tables;
 
60
        btr_pcur_t      pcur;
 
61
        dict_index_t*   sys_index;
 
62
        dtuple_t*       tuple;
 
63
        mem_heap_t*     heap;
 
64
        dfield_t*       dfield;
 
65
        rec_t*          rec;
 
66
        byte*           field;
 
67
        ulint           len;
 
68
        mtr_t           mtr;
 
69
 
 
70
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
71
 
 
72
        heap = mem_heap_create(1000);
 
73
 
 
74
        mtr_start(&mtr);
 
75
 
 
76
        sys_tables = dict_table_get_low("SYS_TABLES");
 
77
        sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
 
78
        ut_a(!dict_table_is_comp(sys_tables));
 
79
 
 
80
        tuple = dtuple_create(heap, 1);
 
81
        dfield = dtuple_get_nth_field(tuple, 0);
 
82
 
 
83
        dfield_set_data(dfield, name, ut_strlen(name));
 
84
        dict_index_copy_types(tuple, sys_index, 1);
 
85
 
 
86
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 
87
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
88
loop:
 
89
        rec = btr_pcur_get_rec(&pcur);
 
90
 
 
91
        if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
 
92
                /* Not found */
 
93
 
 
94
                btr_pcur_close(&pcur);
 
95
                mtr_commit(&mtr);
 
96
                mem_heap_free(heap);
 
97
 
 
98
                return(NULL);
 
99
        }
 
100
 
 
101
        field = rec_get_nth_field_old(rec, 0, &len);
 
102
 
 
103
        if (len < strlen(name)
 
104
            || ut_memcmp(name, field, strlen(name)) != 0) {
 
105
                /* Not found */
 
106
 
 
107
                btr_pcur_close(&pcur);
 
108
                mtr_commit(&mtr);
 
109
                mem_heap_free(heap);
 
110
 
 
111
                return(NULL);
 
112
        }
 
113
 
 
114
        if (!rec_get_deleted_flag(rec, 0)) {
 
115
 
 
116
                /* We found one */
 
117
 
 
118
                char*   table_name = mem_strdupl((char*) field, len);
 
119
 
 
120
                btr_pcur_close(&pcur);
 
121
                mtr_commit(&mtr);
 
122
                mem_heap_free(heap);
 
123
 
 
124
                return(table_name);
 
125
        }
 
126
 
 
127
        btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
128
 
 
129
        goto loop;
 
130
}
 
131
 
 
132
/************************************************************************
 
133
Prints to the standard output information on all tables found in the data
 
134
dictionary system table. */
 
135
 
 
136
void
 
137
dict_print(void)
 
138
/*============*/
 
139
{
 
140
        dict_table_t*   sys_tables;
 
141
        dict_index_t*   sys_index;
 
142
        dict_table_t*   table;
 
143
        btr_pcur_t      pcur;
 
144
        rec_t*          rec;
 
145
        byte*           field;
 
146
        ulint           len;
 
147
        mtr_t           mtr;
 
148
 
 
149
        /* Enlarge the fatal semaphore wait timeout during the InnoDB table
 
150
        monitor printout */
 
151
 
 
152
        mutex_enter(&kernel_mutex);
 
153
        srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
 
154
        mutex_exit(&kernel_mutex);
 
155
 
 
156
        mutex_enter(&(dict_sys->mutex));
 
157
 
 
158
        mtr_start(&mtr);
 
159
 
 
160
        sys_tables = dict_table_get_low("SYS_TABLES");
 
161
        sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
 
162
 
 
163
        btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
 
164
                                    TRUE, &mtr);
 
165
loop:
 
166
        btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
167
 
 
168
        rec = btr_pcur_get_rec(&pcur);
 
169
 
 
170
        if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
 
171
                /* end of index */
 
172
 
 
173
                btr_pcur_close(&pcur);
 
174
                mtr_commit(&mtr);
 
175
 
 
176
                mutex_exit(&(dict_sys->mutex));
 
177
 
 
178
                /* Restore the fatal semaphore wait timeout */
 
179
 
 
180
                mutex_enter(&kernel_mutex);
 
181
                srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
 
182
                mutex_exit(&kernel_mutex);
 
183
 
 
184
                return;
 
185
        }
 
186
 
 
187
        field = rec_get_nth_field_old(rec, 0, &len);
 
188
 
 
189
        if (!rec_get_deleted_flag(rec, 0)) {
 
190
 
 
191
                /* We found one */
 
192
 
 
193
                char*   table_name = mem_strdupl((char*) field, len);
 
194
 
 
195
                btr_pcur_store_position(&pcur, &mtr);
 
196
 
 
197
                mtr_commit(&mtr);
 
198
 
 
199
                table = dict_table_get_low(table_name);
 
200
                mem_free(table_name);
 
201
 
 
202
                if (table == NULL) {
 
203
                        fputs("InnoDB: Failed to load table ", stderr);
 
204
                        ut_print_namel(stderr, NULL, TRUE, (char*) field, len);
 
205
                        putc('\n', stderr);
 
206
                } else {
 
207
                        /* The table definition was corrupt if there
 
208
                        is no index */
 
209
 
 
210
                        if (dict_table_get_first_index(table)) {
 
211
                                dict_update_statistics_low(table, TRUE);
 
212
                        }
 
213
 
 
214
                        dict_table_print_low(table);
 
215
                }
 
216
 
 
217
                mtr_start(&mtr);
 
218
 
 
219
                btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
 
220
        }
 
221
 
 
222
        goto loop;
 
223
}
 
224
 
 
225
/************************************************************************
 
226
In a crash recovery we already have all the tablespace objects created.
 
227
This function compares the space id information in the InnoDB data dictionary
 
228
to what we already read with fil_load_single_table_tablespaces().
 
229
 
 
230
In a normal startup, we create the tablespace objects for every table in
 
231
InnoDB's data dictionary, if the corresponding .ibd file exists.
 
232
We also scan the biggest space id, and store it to fil_system. */
 
233
 
 
234
void
 
235
dict_check_tablespaces_and_store_max_id(
 
236
/*====================================*/
 
237
        ibool   in_crash_recovery)      /* in: are we doing a crash recovery */
 
238
{
 
239
        dict_table_t*   sys_tables;
 
240
        dict_index_t*   sys_index;
 
241
        btr_pcur_t      pcur;
 
242
        rec_t*          rec;
 
243
        byte*           field;
 
244
        ulint           len;
 
245
        ulint           space_id;
 
246
        ulint           max_space_id    = 0;
 
247
        mtr_t           mtr;
 
248
 
 
249
        mutex_enter(&(dict_sys->mutex));
 
250
 
 
251
        mtr_start(&mtr);
 
252
 
 
253
        sys_tables = dict_table_get_low("SYS_TABLES");
 
254
        sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
 
255
        ut_a(!dict_table_is_comp(sys_tables));
 
256
 
 
257
        btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur,
 
258
                                    TRUE, &mtr);
 
259
loop:
 
260
        btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
261
 
 
262
        rec = btr_pcur_get_rec(&pcur);
 
263
 
 
264
        if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
 
265
                /* end of index */
 
266
 
 
267
                btr_pcur_close(&pcur);
 
268
                mtr_commit(&mtr);
 
269
 
 
270
                /* We must make the tablespace cache aware of the biggest
 
271
                known space id */
 
272
 
 
273
                /* printf("Biggest space id in data dictionary %lu\n",
 
274
                max_space_id); */
 
275
                fil_set_max_space_id_if_bigger(max_space_id);
 
276
 
 
277
                mutex_exit(&(dict_sys->mutex));
 
278
 
 
279
                return;
 
280
        }
 
281
 
 
282
        field = rec_get_nth_field_old(rec, 0, &len);
 
283
 
 
284
        if (!rec_get_deleted_flag(rec, 0)) {
 
285
 
 
286
                /* We found one */
 
287
 
 
288
                char*   name = mem_strdupl((char*) field, len);
 
289
 
 
290
                field = rec_get_nth_field_old(rec, 9, &len);
 
291
                ut_a(len == 4);
 
292
 
 
293
                space_id = mach_read_from_4(field);
 
294
 
 
295
                btr_pcur_store_position(&pcur, &mtr);
 
296
 
 
297
                mtr_commit(&mtr);
 
298
 
 
299
                if (space_id != 0 && in_crash_recovery) {
 
300
                        /* Check that the tablespace (the .ibd file) really
 
301
                        exists; print a warning to the .err log if not */
 
302
 
 
303
                        fil_space_for_table_exists_in_mem(space_id, name,
 
304
                                                          FALSE, TRUE, TRUE);
 
305
                }
 
306
 
 
307
                if (space_id != 0 && !in_crash_recovery) {
 
308
                        /* It is a normal database startup: create the space
 
309
                        object and check that the .ibd file exists. */
 
310
 
 
311
                        fil_open_single_table_tablespace(FALSE, space_id,
 
312
                                                         name);
 
313
                }
 
314
 
 
315
                mem_free(name);
 
316
 
 
317
                if (space_id > max_space_id) {
 
318
                        max_space_id = space_id;
 
319
                }
 
320
 
 
321
                mtr_start(&mtr);
 
322
 
 
323
                btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
 
324
        }
 
325
 
 
326
        goto loop;
 
327
}
 
328
 
 
329
/************************************************************************
 
330
Loads definitions for table columns. */
 
331
static
 
332
void
 
333
dict_load_columns(
 
334
/*==============*/
 
335
        dict_table_t*   table,  /* in: table */
 
336
        mem_heap_t*     heap)   /* in: memory heap for temporary storage */
 
337
{
 
338
        dict_table_t*   sys_columns;
 
339
        dict_index_t*   sys_index;
 
340
        btr_pcur_t      pcur;
 
341
        dtuple_t*       tuple;
 
342
        dfield_t*       dfield;
 
343
        rec_t*          rec;
 
344
        byte*           field;
 
345
        ulint           len;
 
346
        byte*           buf;
 
347
        char*           name;
 
348
        ulint           mtype;
 
349
        ulint           prtype;
 
350
        ulint           col_len;
 
351
        ulint           i;
 
352
        mtr_t           mtr;
 
353
 
 
354
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
355
 
 
356
        mtr_start(&mtr);
 
357
 
 
358
        sys_columns = dict_table_get_low("SYS_COLUMNS");
 
359
        sys_index = UT_LIST_GET_FIRST(sys_columns->indexes);
 
360
        ut_a(!dict_table_is_comp(sys_columns));
 
361
 
 
362
        tuple = dtuple_create(heap, 1);
 
363
        dfield = dtuple_get_nth_field(tuple, 0);
 
364
 
 
365
        buf = mem_heap_alloc(heap, 8);
 
366
        mach_write_to_8(buf, table->id);
 
367
 
 
368
        dfield_set_data(dfield, buf, 8);
 
369
        dict_index_copy_types(tuple, sys_index, 1);
 
370
 
 
371
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 
372
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
373
        for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
 
374
 
 
375
                rec = btr_pcur_get_rec(&pcur);
 
376
 
 
377
                ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
 
378
 
 
379
                ut_a(!rec_get_deleted_flag(rec, 0));
 
380
 
 
381
                field = rec_get_nth_field_old(rec, 0, &len);
 
382
                ut_ad(len == 8);
 
383
                ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0);
 
384
 
 
385
                field = rec_get_nth_field_old(rec, 1, &len);
 
386
                ut_ad(len == 4);
 
387
                ut_a(i == mach_read_from_4(field));
 
388
 
 
389
                ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME"));
 
390
 
 
391
                field = rec_get_nth_field_old(rec, 4, &len);
 
392
                name = mem_heap_strdupl(heap, (char*) field, len);
 
393
 
 
394
                field = rec_get_nth_field_old(rec, 5, &len);
 
395
                mtype = mach_read_from_4(field);
 
396
 
 
397
                field = rec_get_nth_field_old(rec, 6, &len);
 
398
                prtype = mach_read_from_4(field);
 
399
 
 
400
                if (dtype_get_charset_coll(prtype) == 0
 
401
                    && dtype_is_string_type(mtype)) {
 
402
                        /* The table was created with < 4.1.2. */
 
403
 
 
404
                        if (dtype_is_binary_string_type(mtype, prtype)) {
 
405
                                /* Use the binary collation for
 
406
                                string columns of binary type. */
 
407
 
 
408
                                prtype = dtype_form_prtype(
 
409
                                        prtype,
 
410
                                        DATA_MYSQL_BINARY_CHARSET_COLL);
 
411
                        } else {
 
412
                                /* Use the default charset for
 
413
                                other than binary columns. */
 
414
 
 
415
                                prtype = dtype_form_prtype(
 
416
                                        prtype,
 
417
                                        data_mysql_default_charset_coll);
 
418
                        }
 
419
                }
 
420
 
 
421
                field = rec_get_nth_field_old(rec, 7, &len);
 
422
                col_len = mach_read_from_4(field);
 
423
 
 
424
                ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC"));
 
425
 
 
426
                dict_mem_table_add_col(table, heap, name,
 
427
                                       mtype, prtype, col_len);
 
428
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
429
        }
 
430
 
 
431
        btr_pcur_close(&pcur);
 
432
        mtr_commit(&mtr);
 
433
}
 
434
 
 
435
/************************************************************************
 
436
Report that an index field or index for a table has been delete marked. */
 
437
static
 
438
void
 
439
dict_load_report_deleted_index(
 
440
/*===========================*/
 
441
        const char*     name,   /* in: table name */
 
442
        ulint           field)  /* in: index field, or ULINT_UNDEFINED */
 
443
{
 
444
        fprintf(stderr, "InnoDB: Error: data dictionary entry"
 
445
                " for table %s is corrupt!\n", name);
 
446
        if (field != ULINT_UNDEFINED) {
 
447
                fprintf(stderr,
 
448
                        "InnoDB: Index field %lu is delete marked.\n", field);
 
449
        } else {
 
450
                fputs("InnoDB: An index is delete marked.\n", stderr);
 
451
        }
 
452
}
 
453
 
 
454
/************************************************************************
 
455
Loads definitions for index fields. */
 
456
static
 
457
void
 
458
dict_load_fields(
 
459
/*=============*/
 
460
        dict_table_t*   table,  /* in: table */
 
461
        dict_index_t*   index,  /* in: index whose fields to load */
 
462
        mem_heap_t*     heap)   /* in: memory heap for temporary storage */
 
463
{
 
464
        dict_table_t*   sys_fields;
 
465
        dict_index_t*   sys_index;
 
466
        btr_pcur_t      pcur;
 
467
        dtuple_t*       tuple;
 
468
        dfield_t*       dfield;
 
469
        ulint           pos_and_prefix_len;
 
470
        ulint           prefix_len;
 
471
        rec_t*          rec;
 
472
        byte*           field;
 
473
        ulint           len;
 
474
        byte*           buf;
 
475
        ulint           i;
 
476
        mtr_t           mtr;
 
477
 
 
478
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
479
 
 
480
        mtr_start(&mtr);
 
481
 
 
482
        sys_fields = dict_table_get_low("SYS_FIELDS");
 
483
        sys_index = UT_LIST_GET_FIRST(sys_fields->indexes);
 
484
        ut_a(!dict_table_is_comp(sys_fields));
 
485
 
 
486
        tuple = dtuple_create(heap, 1);
 
487
        dfield = dtuple_get_nth_field(tuple, 0);
 
488
 
 
489
        buf = mem_heap_alloc(heap, 8);
 
490
        mach_write_to_8(buf, index->id);
 
491
 
 
492
        dfield_set_data(dfield, buf, 8);
 
493
        dict_index_copy_types(tuple, sys_index, 1);
 
494
 
 
495
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 
496
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
497
        for (i = 0; i < index->n_fields; i++) {
 
498
 
 
499
                rec = btr_pcur_get_rec(&pcur);
 
500
 
 
501
                ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
 
502
                if (rec_get_deleted_flag(rec, 0)) {
 
503
                        dict_load_report_deleted_index(table->name, i);
 
504
                }
 
505
 
 
506
                field = rec_get_nth_field_old(rec, 0, &len);
 
507
                ut_ad(len == 8);
 
508
                ut_a(ut_memcmp(buf, field, len) == 0);
 
509
 
 
510
                field = rec_get_nth_field_old(rec, 1, &len);
 
511
                ut_a(len == 4);
 
512
 
 
513
                /* The next field stores the field position in the index
 
514
                and a possible column prefix length if the index field
 
515
                does not contain the whole column. The storage format is
 
516
                like this: if there is at least one prefix field in the index,
 
517
                then the HIGH 2 bytes contain the field number (== i) and the
 
518
                low 2 bytes the prefix length for the field. Otherwise the
 
519
                field number (== i) is contained in the 2 LOW bytes. */
 
520
 
 
521
                pos_and_prefix_len = mach_read_from_4(field);
 
522
 
 
523
                ut_a((pos_and_prefix_len & 0xFFFFUL) == i
 
524
                     || (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16));
 
525
 
 
526
                if ((i == 0 && pos_and_prefix_len > 0)
 
527
                    || (pos_and_prefix_len & 0xFFFF0000UL) > 0) {
 
528
 
 
529
                        prefix_len = pos_and_prefix_len & 0xFFFFUL;
 
530
                } else {
 
531
                        prefix_len = 0;
 
532
                }
 
533
 
 
534
                ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME"));
 
535
 
 
536
                field = rec_get_nth_field_old(rec, 4, &len);
 
537
 
 
538
                dict_mem_index_add_field(index,
 
539
                                         mem_heap_strdupl(heap,
 
540
                                                          (char*) field, len),
 
541
                                         prefix_len);
 
542
 
 
543
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
544
        }
 
545
 
 
546
        btr_pcur_close(&pcur);
 
547
        mtr_commit(&mtr);
 
548
}
 
549
 
 
550
/************************************************************************
 
551
Loads definitions for table indexes. Adds them to the data dictionary
 
552
cache. */
 
553
static
 
554
ulint
 
555
dict_load_indexes(
 
556
/*==============*/
 
557
                                /* out: DB_SUCCESS if ok, DB_CORRUPTION
 
558
                                if corruption of dictionary table or
 
559
                                DB_UNSUPPORTED if table has unknown index
 
560
                                type */
 
561
        dict_table_t*   table,  /* in: table */
 
562
        mem_heap_t*     heap)   /* in: memory heap for temporary storage */
 
563
{
 
564
        dict_table_t*   sys_indexes;
 
565
        dict_index_t*   sys_index;
 
566
        dict_index_t*   index;
 
567
        btr_pcur_t      pcur;
 
568
        dtuple_t*       tuple;
 
569
        dfield_t*       dfield;
 
570
        rec_t*          rec;
 
571
        byte*           field;
 
572
        ulint           len;
 
573
        ulint           name_len;
 
574
        char*           name_buf;
 
575
        ulint           type;
 
576
        ulint           space;
 
577
        ulint           page_no;
 
578
        ulint           n_fields;
 
579
        byte*           buf;
 
580
        ibool           is_sys_table;
 
581
        dulint          id;
 
582
        mtr_t           mtr;
 
583
        ulint           error = DB_SUCCESS;
 
584
 
 
585
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
586
 
 
587
        if ((ut_dulint_get_high(table->id) == 0)
 
588
            && (ut_dulint_get_low(table->id) < DICT_HDR_FIRST_ID)) {
 
589
                is_sys_table = TRUE;
 
590
        } else {
 
591
                is_sys_table = FALSE;
 
592
        }
 
593
 
 
594
        mtr_start(&mtr);
 
595
 
 
596
        sys_indexes = dict_table_get_low("SYS_INDEXES");
 
597
        sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes);
 
598
        ut_a(!dict_table_is_comp(sys_indexes));
 
599
 
 
600
        tuple = dtuple_create(heap, 1);
 
601
        dfield = dtuple_get_nth_field(tuple, 0);
 
602
 
 
603
        buf = mem_heap_alloc(heap, 8);
 
604
        mach_write_to_8(buf, table->id);
 
605
 
 
606
        dfield_set_data(dfield, buf, 8);
 
607
        dict_index_copy_types(tuple, sys_index, 1);
 
608
 
 
609
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 
610
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
611
        for (;;) {
 
612
                if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
 
613
 
 
614
                        break;
 
615
                }
 
616
 
 
617
                rec = btr_pcur_get_rec(&pcur);
 
618
 
 
619
                field = rec_get_nth_field_old(rec, 0, &len);
 
620
                ut_ad(len == 8);
 
621
 
 
622
                if (ut_memcmp(buf, field, len) != 0) {
 
623
                        break;
 
624
                }
 
625
 
 
626
                if (rec_get_deleted_flag(rec, 0)) {
 
627
                        dict_load_report_deleted_index(table->name,
 
628
                                                       ULINT_UNDEFINED);
 
629
 
 
630
                        error = DB_CORRUPTION;
 
631
                        goto func_exit;
 
632
                }
 
633
 
 
634
                field = rec_get_nth_field_old(rec, 1, &len);
 
635
                ut_ad(len == 8);
 
636
                id = mach_read_from_8(field);
 
637
 
 
638
                ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME"));
 
639
 
 
640
                field = rec_get_nth_field_old(rec, 4, &name_len);
 
641
                name_buf = mem_heap_strdupl(heap, (char*) field, name_len);
 
642
 
 
643
                field = rec_get_nth_field_old(rec, 5, &len);
 
644
                n_fields = mach_read_from_4(field);
 
645
 
 
646
                field = rec_get_nth_field_old(rec, 6, &len);
 
647
                type = mach_read_from_4(field);
 
648
 
 
649
                field = rec_get_nth_field_old(rec, 7, &len);
 
650
                space = mach_read_from_4(field);
 
651
 
 
652
                ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO"));
 
653
 
 
654
                field = rec_get_nth_field_old(rec, 8, &len);
 
655
                page_no = mach_read_from_4(field);
 
656
 
 
657
                /* We check for unsupported types first, so that the
 
658
                subsequent checks are relevant for the supported types. */
 
659
                if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
 
660
 
 
661
                        fprintf(stderr,
 
662
                                "InnoDB: Error: unknown type %lu"
 
663
                                " of index %s of table %s\n",
 
664
                                (ulong) type, name_buf, table->name);
 
665
 
 
666
                        error = DB_UNSUPPORTED;
 
667
                        goto func_exit;
 
668
                } else if (page_no == FIL_NULL) {
 
669
 
 
670
                        fprintf(stderr,
 
671
                                "InnoDB: Error: trying to load index %s"
 
672
                                " for table %s\n"
 
673
                                "InnoDB: but the index tree has been freed!\n",
 
674
                                name_buf, table->name);
 
675
 
 
676
                        error = DB_CORRUPTION;
 
677
                        goto func_exit;
 
678
                } else if ((type & DICT_CLUSTERED) == 0
 
679
                            && NULL == dict_table_get_first_index(table)) {
 
680
 
 
681
                        fprintf(stderr,
 
682
                                "InnoDB: Error: trying to load index %s"
 
683
                                " for table %s\n"
 
684
                                "InnoDB: but the first index"
 
685
                                " is not clustered!\n",
 
686
                                name_buf, table->name);
 
687
 
 
688
                        error = DB_CORRUPTION;
 
689
                        goto func_exit;
 
690
                } else if (is_sys_table
 
691
                           && ((type & DICT_CLUSTERED)
 
692
                               || ((table == dict_sys->sys_tables)
 
693
                                   && (name_len == (sizeof "ID_IND") - 1)
 
694
                                   && (0 == ut_memcmp(name_buf,
 
695
                                                      "ID_IND", name_len))))) {
 
696
 
 
697
                        /* The index was created in memory already at booting
 
698
                        of the database server */
 
699
                } else {
 
700
                        index = dict_mem_index_create(table->name, name_buf,
 
701
                                                      space, type, n_fields);
 
702
                        index->id = id;
 
703
 
 
704
                        dict_load_fields(table, index, heap);
 
705
                        dict_index_add_to_cache(table, index, page_no);
 
706
                }
 
707
 
 
708
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
709
        }
 
710
 
 
711
func_exit:
 
712
        btr_pcur_close(&pcur);
 
713
        mtr_commit(&mtr);
 
714
 
 
715
        return(error);
 
716
}
 
717
 
 
718
/************************************************************************
 
719
Loads a table definition and also all its index definitions, and also
 
720
the cluster definition if the table is a member in a cluster. Also loads
 
721
all foreign key constraints where the foreign key is in the table or where
 
722
a foreign key references columns in this table. Adds all these to the data
 
723
dictionary cache. */
 
724
 
 
725
dict_table_t*
 
726
dict_load_table(
 
727
/*============*/
 
728
                                /* out: table, NULL if does not exist;
 
729
                                if the table is stored in an .ibd file,
 
730
                                but the file does not exist,
 
731
                                then we set the ibd_file_missing flag TRUE
 
732
                                in the table object we return */
 
733
        const char*     name)   /* in: table name in the
 
734
                                databasename/tablename format */
 
735
{
 
736
        ibool           ibd_file_missing        = FALSE;
 
737
        dict_table_t*   table;
 
738
        dict_table_t*   sys_tables;
 
739
        btr_pcur_t      pcur;
 
740
        dict_index_t*   sys_index;
 
741
        dtuple_t*       tuple;
 
742
        mem_heap_t*     heap;
 
743
        dfield_t*       dfield;
 
744
        rec_t*          rec;
 
745
        byte*           field;
 
746
        ulint           len;
 
747
        ulint           space;
 
748
        ulint           n_cols;
 
749
        ulint           flags;
 
750
        ulint           err;
 
751
        mtr_t           mtr;
 
752
 
 
753
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
754
 
 
755
        heap = mem_heap_create(32000);
 
756
 
 
757
        mtr_start(&mtr);
 
758
 
 
759
        sys_tables = dict_table_get_low("SYS_TABLES");
 
760
        sys_index = UT_LIST_GET_FIRST(sys_tables->indexes);
 
761
        ut_a(!dict_table_is_comp(sys_tables));
 
762
 
 
763
        tuple = dtuple_create(heap, 1);
 
764
        dfield = dtuple_get_nth_field(tuple, 0);
 
765
 
 
766
        dfield_set_data(dfield, name, ut_strlen(name));
 
767
        dict_index_copy_types(tuple, sys_index, 1);
 
768
 
 
769
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 
770
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
771
        rec = btr_pcur_get_rec(&pcur);
 
772
 
 
773
        if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
 
774
            || rec_get_deleted_flag(rec, 0)) {
 
775
                /* Not found */
 
776
err_exit:
 
777
                btr_pcur_close(&pcur);
 
778
                mtr_commit(&mtr);
 
779
                mem_heap_free(heap);
 
780
 
 
781
                return(NULL);
 
782
        }
 
783
 
 
784
        field = rec_get_nth_field_old(rec, 0, &len);
 
785
 
 
786
        /* Check if the table name in record is the searched one */
 
787
        if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) {
 
788
 
 
789
                goto err_exit;
 
790
        }
 
791
 
 
792
        ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE"));
 
793
 
 
794
        field = rec_get_nth_field_old(rec, 9, &len);
 
795
        space = mach_read_from_4(field);
 
796
 
 
797
        /* Check if the tablespace exists and has the right name */
 
798
        if (space != 0) {
 
799
                if (fil_space_for_table_exists_in_mem(space, name, FALSE,
 
800
                                                      FALSE, FALSE)) {
 
801
                        /* Ok; (if we did a crash recovery then the tablespace
 
802
                        can already be in the memory cache) */
 
803
                } else {
 
804
                        /* In >= 4.1.9, InnoDB scans the data dictionary also
 
805
                        at a normal mysqld startup. It is an error if the
 
806
                        space object does not exist in memory. */
 
807
 
 
808
                        ut_print_timestamp(stderr);
 
809
                        fprintf(stderr,
 
810
                                "  InnoDB: error: space object of table %s,\n"
 
811
                                "InnoDB: space id %lu did not exist in memory."
 
812
                                " Retrying an open.\n",
 
813
                                name, (ulong)space);
 
814
                        /* Try to open the tablespace */
 
815
                        if (!fil_open_single_table_tablespace(TRUE,
 
816
                                                              space, name)) {
 
817
                                /* We failed to find a sensible tablespace
 
818
                                file */
 
819
 
 
820
                                ibd_file_missing = TRUE;
 
821
                        }
 
822
                }
 
823
        }
 
824
 
 
825
        ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
 
826
 
 
827
        field = rec_get_nth_field_old(rec, 4, &len);
 
828
        n_cols = mach_read_from_4(field);
 
829
 
 
830
        flags = 0;
 
831
 
 
832
        /* The high-order bit of N_COLS is the "compact format" flag. */
 
833
        if (n_cols & 0x80000000UL) {
 
834
                flags |= DICT_TF_COMPACT;
 
835
        }
 
836
 
 
837
        table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL,
 
838
                                      flags);
 
839
 
 
840
        table->ibd_file_missing = (unsigned int) ibd_file_missing;
 
841
 
 
842
        ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID"));
 
843
 
 
844
        field = rec_get_nth_field_old(rec, 3, &len);
 
845
        table->id = mach_read_from_8(field);
 
846
 
 
847
        field = rec_get_nth_field_old(rec, 5, &len);
 
848
        if (UNIV_UNLIKELY(mach_read_from_4(field) != DICT_TABLE_ORDINARY)) {
 
849
                ut_print_timestamp(stderr);
 
850
                fprintf(stderr,
 
851
                        "  InnoDB: table %s: unknown table type %lu\n",
 
852
                        name, (ulong) mach_read_from_4(field));
 
853
                goto err_exit;
 
854
        }
 
855
 
 
856
        btr_pcur_close(&pcur);
 
857
        mtr_commit(&mtr);
 
858
 
 
859
        dict_load_columns(table, heap);
 
860
 
 
861
        dict_table_add_to_cache(table, heap);
 
862
 
 
863
        mem_heap_empty(heap);
 
864
 
 
865
        err = dict_load_indexes(table, heap);
 
866
 
 
867
        /* If the force recovery flag is set, we open the table irrespective
 
868
        of the error condition, since the user may want to dump data from the
 
869
        clustered index. However we load the foreign key information only if
 
870
        all indexes were loaded. */
 
871
        if (err == DB_SUCCESS) {
 
872
                err = dict_load_foreigns(table->name, TRUE);
 
873
        } else if (!srv_force_recovery) {
 
874
                dict_table_remove_from_cache(table);
 
875
                table = NULL;
 
876
        }
 
877
#if 0
 
878
        if (err != DB_SUCCESS && table != NULL) {
 
879
 
 
880
                mutex_enter(&dict_foreign_err_mutex);
 
881
 
 
882
                ut_print_timestamp(stderr);
 
883
 
 
884
                fprintf(stderr,
 
885
                        "  InnoDB: Error: could not make a foreign key"
 
886
                        " definition to match\n"
 
887
                        "InnoDB: the foreign key table"
 
888
                        " or the referenced table!\n"
 
889
                        "InnoDB: The data dictionary of InnoDB is corrupt."
 
890
                        " You may need to drop\n"
 
891
                        "InnoDB: and recreate the foreign key table"
 
892
                        " or the referenced table.\n"
 
893
                        "InnoDB: Submit a detailed bug report"
 
894
                        " to http://bugs.mysql.com\n"
 
895
                        "InnoDB: Latest foreign key error printout:\n%s\n",
 
896
                        dict_foreign_err_buf);
 
897
 
 
898
                mutex_exit(&dict_foreign_err_mutex);
 
899
        }
 
900
#endif /* 0 */
 
901
        mem_heap_free(heap);
 
902
 
 
903
        return(table);
 
904
}
 
905
 
 
906
/***************************************************************************
 
907
Loads a table object based on the table id. */
 
908
 
 
909
dict_table_t*
 
910
dict_load_table_on_id(
 
911
/*==================*/
 
912
                                /* out: table; NULL if table does not exist */
 
913
        dulint  table_id)       /* in: table id */
 
914
{
 
915
        byte            id_buf[8];
 
916
        btr_pcur_t      pcur;
 
917
        mem_heap_t*     heap;
 
918
        dtuple_t*       tuple;
 
919
        dfield_t*       dfield;
 
920
        dict_index_t*   sys_table_ids;
 
921
        dict_table_t*   sys_tables;
 
922
        rec_t*          rec;
 
923
        byte*           field;
 
924
        ulint           len;
 
925
        dict_table_t*   table;
 
926
        mtr_t           mtr;
 
927
 
 
928
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
929
 
 
930
        /* NOTE that the operation of this function is protected by
 
931
        the dictionary mutex, and therefore no deadlocks can occur
 
932
        with other dictionary operations. */
 
933
 
 
934
        mtr_start(&mtr);
 
935
        /*---------------------------------------------------*/
 
936
        /* Get the secondary index based on ID for table SYS_TABLES */
 
937
        sys_tables = dict_sys->sys_tables;
 
938
        sys_table_ids = dict_table_get_next_index(
 
939
                dict_table_get_first_index(sys_tables));
 
940
        ut_a(!dict_table_is_comp(sys_tables));
 
941
        heap = mem_heap_create(256);
 
942
 
 
943
        tuple  = dtuple_create(heap, 1);
 
944
        dfield = dtuple_get_nth_field(tuple, 0);
 
945
 
 
946
        /* Write the table id in byte format to id_buf */
 
947
        mach_write_to_8(id_buf, table_id);
 
948
 
 
949
        dfield_set_data(dfield, id_buf, 8);
 
950
        dict_index_copy_types(tuple, sys_table_ids, 1);
 
951
 
 
952
        btr_pcur_open_on_user_rec(sys_table_ids, tuple, PAGE_CUR_GE,
 
953
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
954
        rec = btr_pcur_get_rec(&pcur);
 
955
 
 
956
        if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
 
957
            || rec_get_deleted_flag(rec, 0)) {
 
958
                /* Not found */
 
959
 
 
960
                btr_pcur_close(&pcur);
 
961
                mtr_commit(&mtr);
 
962
                mem_heap_free(heap);
 
963
 
 
964
                return(NULL);
 
965
        }
 
966
 
 
967
        /*---------------------------------------------------*/
 
968
        /* Now we have the record in the secondary index containing the
 
969
        table ID and NAME */
 
970
 
 
971
        rec = btr_pcur_get_rec(&pcur);
 
972
        field = rec_get_nth_field_old(rec, 0, &len);
 
973
        ut_ad(len == 8);
 
974
 
 
975
        /* Check if the table id in record is the one searched for */
 
976
        if (ut_dulint_cmp(table_id, mach_read_from_8(field)) != 0) {
 
977
 
 
978
                btr_pcur_close(&pcur);
 
979
                mtr_commit(&mtr);
 
980
                mem_heap_free(heap);
 
981
 
 
982
                return(NULL);
 
983
        }
 
984
 
 
985
        /* Now we get the table name from the record */
 
986
        field = rec_get_nth_field_old(rec, 1, &len);
 
987
        /* Load the table definition to memory */
 
988
        table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len));
 
989
 
 
990
        btr_pcur_close(&pcur);
 
991
        mtr_commit(&mtr);
 
992
        mem_heap_free(heap);
 
993
 
 
994
        return(table);
 
995
}
 
996
 
 
997
/************************************************************************
 
998
This function is called when the database is booted. Loads system table
 
999
index definitions except for the clustered index which is added to the
 
1000
dictionary cache at booting before calling this function. */
 
1001
 
 
1002
void
 
1003
dict_load_sys_table(
 
1004
/*================*/
 
1005
        dict_table_t*   table)  /* in: system table */
 
1006
{
 
1007
        mem_heap_t*     heap;
 
1008
 
 
1009
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1010
 
 
1011
        heap = mem_heap_create(1000);
 
1012
 
 
1013
        dict_load_indexes(table, heap);
 
1014
 
 
1015
        mem_heap_free(heap);
 
1016
}
 
1017
 
 
1018
/************************************************************************
 
1019
Loads foreign key constraint col names (also for the referenced table). */
 
1020
static
 
1021
void
 
1022
dict_load_foreign_cols(
 
1023
/*===================*/
 
1024
        const char*     id,     /* in: foreign constraint id as a
 
1025
                                null-terminated string */
 
1026
        dict_foreign_t* foreign)/* in: foreign constraint object */
 
1027
{
 
1028
        dict_table_t*   sys_foreign_cols;
 
1029
        dict_index_t*   sys_index;
 
1030
        btr_pcur_t      pcur;
 
1031
        dtuple_t*       tuple;
 
1032
        dfield_t*       dfield;
 
1033
        rec_t*          rec;
 
1034
        byte*           field;
 
1035
        ulint           len;
 
1036
        ulint           i;
 
1037
        mtr_t           mtr;
 
1038
 
 
1039
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1040
 
 
1041
        foreign->foreign_col_names = mem_heap_alloc(
 
1042
                foreign->heap, foreign->n_fields * sizeof(void*));
 
1043
 
 
1044
        foreign->referenced_col_names = mem_heap_alloc(
 
1045
                foreign->heap, foreign->n_fields * sizeof(void*));
 
1046
        mtr_start(&mtr);
 
1047
 
 
1048
        sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS");
 
1049
        sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes);
 
1050
        ut_a(!dict_table_is_comp(sys_foreign_cols));
 
1051
 
 
1052
        tuple = dtuple_create(foreign->heap, 1);
 
1053
        dfield = dtuple_get_nth_field(tuple, 0);
 
1054
 
 
1055
        dfield_set_data(dfield, id, ut_strlen(id));
 
1056
        dict_index_copy_types(tuple, sys_index, 1);
 
1057
 
 
1058
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 
1059
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
1060
        for (i = 0; i < foreign->n_fields; i++) {
 
1061
 
 
1062
                rec = btr_pcur_get_rec(&pcur);
 
1063
 
 
1064
                ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
 
1065
                ut_a(!rec_get_deleted_flag(rec, 0));
 
1066
 
 
1067
                field = rec_get_nth_field_old(rec, 0, &len);
 
1068
                ut_a(len == ut_strlen(id));
 
1069
                ut_a(ut_memcmp(id, field, len) == 0);
 
1070
 
 
1071
                field = rec_get_nth_field_old(rec, 1, &len);
 
1072
                ut_a(len == 4);
 
1073
                ut_a(i == mach_read_from_4(field));
 
1074
 
 
1075
                field = rec_get_nth_field_old(rec, 4, &len);
 
1076
                foreign->foreign_col_names[i] = mem_heap_strdupl(
 
1077
                        foreign->heap, (char*) field, len);
 
1078
 
 
1079
                field = rec_get_nth_field_old(rec, 5, &len);
 
1080
                foreign->referenced_col_names[i] = mem_heap_strdupl(
 
1081
                        foreign->heap, (char*) field, len);
 
1082
 
 
1083
                btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
1084
        }
 
1085
 
 
1086
        btr_pcur_close(&pcur);
 
1087
        mtr_commit(&mtr);
 
1088
}
 
1089
 
 
1090
/***************************************************************************
 
1091
Loads a foreign key constraint to the dictionary cache. */
 
1092
static
 
1093
ulint
 
1094
dict_load_foreign(
 
1095
/*==============*/
 
1096
                                /* out: DB_SUCCESS or error code */
 
1097
        const char*     id,     /* in: foreign constraint id as a
 
1098
                                null-terminated string */
 
1099
        ibool           check_charsets)
 
1100
                                /* in: TRUE=check charset compatibility */
 
1101
{
 
1102
        dict_foreign_t* foreign;
 
1103
        dict_table_t*   sys_foreign;
 
1104
        btr_pcur_t      pcur;
 
1105
        dict_index_t*   sys_index;
 
1106
        dtuple_t*       tuple;
 
1107
        mem_heap_t*     heap2;
 
1108
        dfield_t*       dfield;
 
1109
        rec_t*          rec;
 
1110
        byte*           field;
 
1111
        ulint           len;
 
1112
        ulint           n_fields_and_type;
 
1113
        mtr_t           mtr;
 
1114
 
 
1115
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1116
 
 
1117
        heap2 = mem_heap_create(1000);
 
1118
 
 
1119
        mtr_start(&mtr);
 
1120
 
 
1121
        sys_foreign = dict_table_get_low("SYS_FOREIGN");
 
1122
        sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes);
 
1123
        ut_a(!dict_table_is_comp(sys_foreign));
 
1124
 
 
1125
        tuple = dtuple_create(heap2, 1);
 
1126
        dfield = dtuple_get_nth_field(tuple, 0);
 
1127
 
 
1128
        dfield_set_data(dfield, id, ut_strlen(id));
 
1129
        dict_index_copy_types(tuple, sys_index, 1);
 
1130
 
 
1131
        btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
 
1132
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
1133
        rec = btr_pcur_get_rec(&pcur);
 
1134
 
 
1135
        if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
 
1136
            || rec_get_deleted_flag(rec, 0)) {
 
1137
                /* Not found */
 
1138
 
 
1139
                fprintf(stderr,
 
1140
                        "InnoDB: Error A: cannot load foreign constraint %s\n",
 
1141
                        id);
 
1142
 
 
1143
                btr_pcur_close(&pcur);
 
1144
                mtr_commit(&mtr);
 
1145
                mem_heap_free(heap2);
 
1146
 
 
1147
                return(DB_ERROR);
 
1148
        }
 
1149
 
 
1150
        field = rec_get_nth_field_old(rec, 0, &len);
 
1151
 
 
1152
        /* Check if the id in record is the searched one */
 
1153
        if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
 
1154
 
 
1155
                fprintf(stderr,
 
1156
                        "InnoDB: Error B: cannot load foreign constraint %s\n",
 
1157
                        id);
 
1158
 
 
1159
                btr_pcur_close(&pcur);
 
1160
                mtr_commit(&mtr);
 
1161
                mem_heap_free(heap2);
 
1162
 
 
1163
                return(DB_ERROR);
 
1164
        }
 
1165
 
 
1166
        /* Read the table names and the number of columns associated
 
1167
        with the constraint */
 
1168
 
 
1169
        mem_heap_free(heap2);
 
1170
 
 
1171
        foreign = dict_mem_foreign_create();
 
1172
 
 
1173
        n_fields_and_type = mach_read_from_4(
 
1174
                rec_get_nth_field_old(rec, 5, &len));
 
1175
 
 
1176
        ut_a(len == 4);
 
1177
 
 
1178
        /* We store the type in the bits 24..29 of n_fields_and_type. */
 
1179
 
 
1180
        foreign->type = (unsigned int) (n_fields_and_type >> 24);
 
1181
        foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
 
1182
 
 
1183
        foreign->id = mem_heap_strdup(foreign->heap, id);
 
1184
 
 
1185
        field = rec_get_nth_field_old(rec, 3, &len);
 
1186
        foreign->foreign_table_name = mem_heap_strdupl(
 
1187
                foreign->heap, (char*) field, len);
 
1188
 
 
1189
        field = rec_get_nth_field_old(rec, 4, &len);
 
1190
        foreign->referenced_table_name = mem_heap_strdupl(
 
1191
                foreign->heap, (char*) field, len);
 
1192
 
 
1193
        btr_pcur_close(&pcur);
 
1194
        mtr_commit(&mtr);
 
1195
 
 
1196
        dict_load_foreign_cols(id, foreign);
 
1197
 
 
1198
        /* If the foreign table is not yet in the dictionary cache, we
 
1199
        have to load it so that we are able to make type comparisons
 
1200
        in the next function call. */
 
1201
 
 
1202
        dict_table_get_low(foreign->foreign_table_name);
 
1203
 
 
1204
        /* Note that there may already be a foreign constraint object in
 
1205
        the dictionary cache for this constraint: then the following
 
1206
        call only sets the pointers in it to point to the appropriate table
 
1207
        and index objects and frees the newly created object foreign.
 
1208
        Adding to the cache should always succeed since we are not creating
 
1209
        a new foreign key constraint but loading one from the data
 
1210
        dictionary. */
 
1211
 
 
1212
        return(dict_foreign_add_to_cache(foreign, check_charsets));
 
1213
}
 
1214
 
 
1215
/***************************************************************************
 
1216
Loads foreign key constraints where the table is either the foreign key
 
1217
holder or where the table is referenced by a foreign key. Adds these
 
1218
constraints to the data dictionary. Note that we know that the dictionary
 
1219
cache already contains all constraints where the other relevant table is
 
1220
already in the dictionary cache. */
 
1221
 
 
1222
ulint
 
1223
dict_load_foreigns(
 
1224
/*===============*/
 
1225
                                        /* out: DB_SUCCESS or error code */
 
1226
        const char*     table_name,     /* in: table name */
 
1227
        ibool           check_charsets) /* in: TRUE=check charset
 
1228
                                        compatibility */
 
1229
{
 
1230
        btr_pcur_t      pcur;
 
1231
        mem_heap_t*     heap;
 
1232
        dtuple_t*       tuple;
 
1233
        dfield_t*       dfield;
 
1234
        dict_index_t*   sec_index;
 
1235
        dict_table_t*   sys_foreign;
 
1236
        rec_t*          rec;
 
1237
        byte*           field;
 
1238
        ulint           len;
 
1239
        char*           id ;
 
1240
        ulint           err;
 
1241
        mtr_t           mtr;
 
1242
 
 
1243
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1244
 
 
1245
        sys_foreign = dict_table_get_low("SYS_FOREIGN");
 
1246
 
 
1247
        if (sys_foreign == NULL) {
 
1248
                /* No foreign keys defined yet in this database */
 
1249
 
 
1250
                fprintf(stderr,
 
1251
                        "InnoDB: Error: no foreign key system tables"
 
1252
                        " in the database\n");
 
1253
 
 
1254
                return(DB_ERROR);
 
1255
        }
 
1256
 
 
1257
        ut_a(!dict_table_is_comp(sys_foreign));
 
1258
        mtr_start(&mtr);
 
1259
 
 
1260
        /* Get the secondary index based on FOR_NAME from table
 
1261
        SYS_FOREIGN */
 
1262
 
 
1263
        sec_index = dict_table_get_next_index(
 
1264
                dict_table_get_first_index(sys_foreign));
 
1265
start_load:
 
1266
        heap = mem_heap_create(256);
 
1267
 
 
1268
        tuple  = dtuple_create(heap, 1);
 
1269
        dfield = dtuple_get_nth_field(tuple, 0);
 
1270
 
 
1271
        dfield_set_data(dfield, table_name, ut_strlen(table_name));
 
1272
        dict_index_copy_types(tuple, sec_index, 1);
 
1273
 
 
1274
        btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE,
 
1275
                                  BTR_SEARCH_LEAF, &pcur, &mtr);
 
1276
loop:
 
1277
        rec = btr_pcur_get_rec(&pcur);
 
1278
 
 
1279
        if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
 
1280
                /* End of index */
 
1281
 
 
1282
                goto load_next_index;
 
1283
        }
 
1284
 
 
1285
        /* Now we have the record in the secondary index containing a table
 
1286
        name and a foreign constraint ID */
 
1287
 
 
1288
        rec = btr_pcur_get_rec(&pcur);
 
1289
        field = rec_get_nth_field_old(rec, 0, &len);
 
1290
 
 
1291
        /* Check if the table name in the record is the one searched for; the
 
1292
        following call does the comparison in the latin1_swedish_ci
 
1293
        charset-collation, in a case-insensitive way. */
 
1294
 
 
1295
        if (0 != cmp_data_data(dfield_get_type(dfield)->mtype,
 
1296
                               dfield_get_type(dfield)->prtype,
 
1297
                               dfield_get_data(dfield), dfield_get_len(dfield),
 
1298
                               field, len)) {
 
1299
 
 
1300
                goto load_next_index;
 
1301
        }
 
1302
 
 
1303
        /* Since table names in SYS_FOREIGN are stored in a case-insensitive
 
1304
        order, we have to check that the table name matches also in a binary
 
1305
        string comparison. On Unix, MySQL allows table names that only differ
 
1306
        in character case. */
 
1307
 
 
1308
        if (0 != ut_memcmp(field, table_name, len)) {
 
1309
 
 
1310
                goto next_rec;
 
1311
        }
 
1312
 
 
1313
        if (rec_get_deleted_flag(rec, 0)) {
 
1314
 
 
1315
                goto next_rec;
 
1316
        }
 
1317
 
 
1318
        /* Now we get a foreign key constraint id */
 
1319
        field = rec_get_nth_field_old(rec, 1, &len);
 
1320
        id = mem_heap_strdupl(heap, (char*) field, len);
 
1321
 
 
1322
        btr_pcur_store_position(&pcur, &mtr);
 
1323
 
 
1324
        mtr_commit(&mtr);
 
1325
 
 
1326
        /* Load the foreign constraint definition to the dictionary cache */
 
1327
 
 
1328
        err = dict_load_foreign(id, check_charsets);
 
1329
 
 
1330
        if (err != DB_SUCCESS) {
 
1331
                btr_pcur_close(&pcur);
 
1332
                mem_heap_free(heap);
 
1333
 
 
1334
                return(err);
 
1335
        }
 
1336
 
 
1337
        mtr_start(&mtr);
 
1338
 
 
1339
        btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
 
1340
next_rec:
 
1341
        btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
1342
 
 
1343
        goto loop;
 
1344
 
 
1345
load_next_index:
 
1346
        btr_pcur_close(&pcur);
 
1347
        mtr_commit(&mtr);
 
1348
        mem_heap_free(heap);
 
1349
 
 
1350
        sec_index = dict_table_get_next_index(sec_index);
 
1351
 
 
1352
        if (sec_index != NULL) {
 
1353
 
 
1354
                mtr_start(&mtr);
 
1355
 
 
1356
                goto start_load;
 
1357
        }
 
1358
 
 
1359
        return(DB_SUCCESS);
 
1360
}