~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Padraig O'Sullivan
  • Date: 2009-09-13 01:03:01 UTC
  • mto: (1126.9.2 captain-20090915-01)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: osullivan.padraig@gmail.com-20090913010301-tcvvezipx1124acy
Added calls to the dtrace delete begin/end probes.

Show diffs side-by-side

added added

removed removed

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