~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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