~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

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
}