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

« back to all changes in this revision

Viewing changes to storage/innodb_plugin/dict/dict0crea.c

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
 
4
 
 
5
This program is free software; you can redistribute it and/or modify it under
 
6
the terms of the GNU General Public License as published by the Free Software
 
7
Foundation; version 2 of the License.
 
8
 
 
9
This program is distributed in the hope that it will be useful, but WITHOUT
 
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
12
 
 
13
You should have received a copy of the GNU General Public License along with
 
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
15
Place, Suite 330, Boston, MA 02111-1307 USA
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/**************************************************//**
 
20
@file dict/dict0crea.c
 
21
Database object creation
 
22
 
 
23
Created 1/8/1996 Heikki Tuuri
 
24
*******************************************************/
 
25
 
 
26
#include "dict0crea.h"
 
27
 
 
28
#ifdef UNIV_NONINL
 
29
#include "dict0crea.ic"
 
30
#endif
 
31
 
 
32
#include "btr0pcur.h"
 
33
#include "btr0btr.h"
 
34
#include "page0page.h"
 
35
#include "mach0data.h"
 
36
#include "dict0boot.h"
 
37
#include "dict0dict.h"
 
38
#include "que0que.h"
 
39
#include "row0ins.h"
 
40
#include "row0mysql.h"
 
41
#include "pars0pars.h"
 
42
#include "trx0roll.h"
 
43
#include "usr0sess.h"
 
44
#include "ut0vec.h"
 
45
 
 
46
/*****************************************************************//**
 
47
Based on a table object, this function builds the entry to be inserted
 
48
in the SYS_TABLES system table.
 
49
@return the tuple which should be inserted */
 
50
static
 
51
dtuple_t*
 
52
dict_create_sys_tables_tuple(
 
53
/*=========================*/
 
54
        dict_table_t*   table,  /*!< in: table */
 
55
        mem_heap_t*     heap)   /*!< in: memory heap from which the memory for
 
56
                                the built tuple is allocated */
 
57
{
 
58
        dict_table_t*   sys_tables;
 
59
        dtuple_t*       entry;
 
60
        dfield_t*       dfield;
 
61
        byte*           ptr;
 
62
 
 
63
        ut_ad(table && heap);
 
64
 
 
65
        sys_tables = dict_sys->sys_tables;
 
66
 
 
67
        entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS);
 
68
 
 
69
        dict_table_copy_types(entry, sys_tables);
 
70
 
 
71
        /* 0: NAME -----------------------------*/
 
72
        dfield = dtuple_get_nth_field(entry, 0);
 
73
 
 
74
        dfield_set_data(dfield, table->name, ut_strlen(table->name));
 
75
        /* 3: ID -------------------------------*/
 
76
        dfield = dtuple_get_nth_field(entry, 1);
 
77
 
 
78
        ptr = mem_heap_alloc(heap, 8);
 
79
        mach_write_to_8(ptr, table->id);
 
80
 
 
81
        dfield_set_data(dfield, ptr, 8);
 
82
        /* 4: N_COLS ---------------------------*/
 
83
        dfield = dtuple_get_nth_field(entry, 2);
 
84
 
 
85
#if DICT_TF_COMPACT != 1
 
86
#error
 
87
#endif
 
88
 
 
89
        ptr = mem_heap_alloc(heap, 4);
 
90
        mach_write_to_4(ptr, table->n_def
 
91
                        | ((table->flags & DICT_TF_COMPACT) << 31));
 
92
        dfield_set_data(dfield, ptr, 4);
 
93
        /* 5: TYPE -----------------------------*/
 
94
        dfield = dtuple_get_nth_field(entry, 3);
 
95
 
 
96
        ptr = mem_heap_alloc(heap, 4);
 
97
        if (table->flags & ~DICT_TF_COMPACT) {
 
98
                ut_a(table->flags & DICT_TF_COMPACT);
 
99
                ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
 
100
                ut_a((table->flags & DICT_TF_ZSSIZE_MASK)
 
101
                     <= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT));
 
102
                ut_a(!(table->flags & (~0 << DICT_TF_BITS)));
 
103
                mach_write_to_4(ptr, table->flags);
 
104
        } else {
 
105
                mach_write_to_4(ptr, DICT_TABLE_ORDINARY);
 
106
        }
 
107
 
 
108
        dfield_set_data(dfield, ptr, 4);
 
109
        /* 6: MIX_ID (obsolete) ---------------------------*/
 
110
        dfield = dtuple_get_nth_field(entry, 4);
 
111
 
 
112
        ptr = mem_heap_zalloc(heap, 8);
 
113
 
 
114
        dfield_set_data(dfield, ptr, 8);
 
115
        /* 7: MIX_LEN (obsolete) --------------------------*/
 
116
 
 
117
        dfield = dtuple_get_nth_field(entry, 5);
 
118
 
 
119
        ptr = mem_heap_zalloc(heap, 4);
 
120
 
 
121
        dfield_set_data(dfield, ptr, 4);
 
122
        /* 8: CLUSTER_NAME ---------------------*/
 
123
        dfield = dtuple_get_nth_field(entry, 6);
 
124
        dfield_set_null(dfield); /* not supported */
 
125
 
 
126
        /* 9: SPACE ----------------------------*/
 
127
        dfield = dtuple_get_nth_field(entry, 7);
 
128
 
 
129
        ptr = mem_heap_alloc(heap, 4);
 
130
        mach_write_to_4(ptr, table->space);
 
131
 
 
132
        dfield_set_data(dfield, ptr, 4);
 
133
        /*----------------------------------*/
 
134
 
 
135
        return(entry);
 
136
}
 
137
 
 
138
/*****************************************************************//**
 
139
Based on a table object, this function builds the entry to be inserted
 
140
in the SYS_COLUMNS system table.
 
141
@return the tuple which should be inserted */
 
142
static
 
143
dtuple_t*
 
144
dict_create_sys_columns_tuple(
 
145
/*==========================*/
 
146
        dict_table_t*   table,  /*!< in: table */
 
147
        ulint           i,      /*!< in: column number */
 
148
        mem_heap_t*     heap)   /*!< in: memory heap from which the memory for
 
149
                                the built tuple is allocated */
 
150
{
 
151
        dict_table_t*           sys_columns;
 
152
        dtuple_t*               entry;
 
153
        const dict_col_t*       column;
 
154
        dfield_t*               dfield;
 
155
        byte*                   ptr;
 
156
        const char*     col_name;
 
157
 
 
158
        ut_ad(table && heap);
 
159
 
 
160
        column = dict_table_get_nth_col(table, i);
 
161
 
 
162
        sys_columns = dict_sys->sys_columns;
 
163
 
 
164
        entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
 
165
 
 
166
        dict_table_copy_types(entry, sys_columns);
 
167
 
 
168
        /* 0: TABLE_ID -----------------------*/
 
169
        dfield = dtuple_get_nth_field(entry, 0);
 
170
 
 
171
        ptr = mem_heap_alloc(heap, 8);
 
172
        mach_write_to_8(ptr, table->id);
 
173
 
 
174
        dfield_set_data(dfield, ptr, 8);
 
175
        /* 1: POS ----------------------------*/
 
176
        dfield = dtuple_get_nth_field(entry, 1);
 
177
 
 
178
        ptr = mem_heap_alloc(heap, 4);
 
179
        mach_write_to_4(ptr, i);
 
180
 
 
181
        dfield_set_data(dfield, ptr, 4);
 
182
        /* 4: NAME ---------------------------*/
 
183
        dfield = dtuple_get_nth_field(entry, 2);
 
184
 
 
185
        col_name = dict_table_get_col_name(table, i);
 
186
        dfield_set_data(dfield, col_name, ut_strlen(col_name));
 
187
        /* 5: MTYPE --------------------------*/
 
188
        dfield = dtuple_get_nth_field(entry, 3);
 
189
 
 
190
        ptr = mem_heap_alloc(heap, 4);
 
191
        mach_write_to_4(ptr, column->mtype);
 
192
 
 
193
        dfield_set_data(dfield, ptr, 4);
 
194
        /* 6: PRTYPE -------------------------*/
 
195
        dfield = dtuple_get_nth_field(entry, 4);
 
196
 
 
197
        ptr = mem_heap_alloc(heap, 4);
 
198
        mach_write_to_4(ptr, column->prtype);
 
199
 
 
200
        dfield_set_data(dfield, ptr, 4);
 
201
        /* 7: LEN ----------------------------*/
 
202
        dfield = dtuple_get_nth_field(entry, 5);
 
203
 
 
204
        ptr = mem_heap_alloc(heap, 4);
 
205
        mach_write_to_4(ptr, column->len);
 
206
 
 
207
        dfield_set_data(dfield, ptr, 4);
 
208
        /* 8: PREC ---------------------------*/
 
209
        dfield = dtuple_get_nth_field(entry, 6);
 
210
 
 
211
        ptr = mem_heap_alloc(heap, 4);
 
212
        mach_write_to_4(ptr, 0/* unused */);
 
213
 
 
214
        dfield_set_data(dfield, ptr, 4);
 
215
        /*---------------------------------*/
 
216
 
 
217
        return(entry);
 
218
}
 
219
 
 
220
/***************************************************************//**
 
221
Builds a table definition to insert.
 
222
@return DB_SUCCESS or error code */
 
223
static
 
224
ulint
 
225
dict_build_table_def_step(
 
226
/*======================*/
 
227
        que_thr_t*      thr,    /*!< in: query thread */
 
228
        tab_node_t*     node)   /*!< in: table create node */
 
229
{
 
230
        dict_table_t*   table;
 
231
        dtuple_t*       row;
 
232
        ulint           error;
 
233
        const char*     path_or_name;
 
234
        ibool           is_path;
 
235
        mtr_t           mtr;
 
236
 
 
237
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
238
 
 
239
        table = node->table;
 
240
 
 
241
        table->id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
 
242
 
 
243
        thr_get_trx(thr)->table_id = table->id;
 
244
 
 
245
        if (srv_file_per_table) {
 
246
                /* We create a new single-table tablespace for the table.
 
247
                We initially let it be 4 pages:
 
248
                - page 0 is the fsp header and an extent descriptor page,
 
249
                - page 1 is an ibuf bitmap page,
 
250
                - page 2 is the first inode page,
 
251
                - page 3 will contain the root of the clustered index of the
 
252
                table we create here. */
 
253
 
 
254
                ulint   space = 0;      /* reset to zero for the call below */
 
255
 
 
256
                if (table->dir_path_of_temp_table) {
 
257
                        /* We place tables created with CREATE TEMPORARY
 
258
                        TABLE in the tmp dir of mysqld server */
 
259
 
 
260
                        path_or_name = table->dir_path_of_temp_table;
 
261
                        is_path = TRUE;
 
262
                } else {
 
263
                        path_or_name = table->name;
 
264
                        is_path = FALSE;
 
265
                }
 
266
 
 
267
                ut_ad(dict_table_get_format(table) <= DICT_TF_FORMAT_MAX);
 
268
                ut_ad(!dict_table_zip_size(table)
 
269
                      || dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
 
270
 
 
271
                error = fil_create_new_single_table_tablespace(
 
272
                        &space, path_or_name, is_path,
 
273
                        table->flags == DICT_TF_COMPACT ? 0 : table->flags,
 
274
                        FIL_IBD_FILE_INITIAL_SIZE);
 
275
                table->space = (unsigned int) space;
 
276
 
 
277
                if (error != DB_SUCCESS) {
 
278
 
 
279
                        return(error);
 
280
                }
 
281
 
 
282
                mtr_start(&mtr);
 
283
 
 
284
                fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
 
285
 
 
286
                mtr_commit(&mtr);
 
287
        } else {
 
288
                /* Create in the system tablespace: disallow new features */
 
289
                table->flags &= DICT_TF_COMPACT;
 
290
        }
 
291
 
 
292
        row = dict_create_sys_tables_tuple(table, node->heap);
 
293
 
 
294
        ins_node_set_new_row(node->tab_def, row);
 
295
 
 
296
        return(DB_SUCCESS);
 
297
}
 
298
 
 
299
/***************************************************************//**
 
300
Builds a column definition to insert.
 
301
@return DB_SUCCESS */
 
302
static
 
303
ulint
 
304
dict_build_col_def_step(
 
305
/*====================*/
 
306
        tab_node_t*     node)   /*!< in: table create node */
 
307
{
 
308
        dtuple_t*       row;
 
309
 
 
310
        row = dict_create_sys_columns_tuple(node->table, node->col_no,
 
311
                                            node->heap);
 
312
        ins_node_set_new_row(node->col_def, row);
 
313
 
 
314
        return(DB_SUCCESS);
 
315
}
 
316
 
 
317
/*****************************************************************//**
 
318
Based on an index object, this function builds the entry to be inserted
 
319
in the SYS_INDEXES system table.
 
320
@return the tuple which should be inserted */
 
321
static
 
322
dtuple_t*
 
323
dict_create_sys_indexes_tuple(
 
324
/*==========================*/
 
325
        dict_index_t*   index,  /*!< in: index */
 
326
        mem_heap_t*     heap)   /*!< in: memory heap from which the memory for
 
327
                                the built tuple is allocated */
 
328
{
 
329
        dict_table_t*   sys_indexes;
 
330
        dict_table_t*   table;
 
331
        dtuple_t*       entry;
 
332
        dfield_t*       dfield;
 
333
        byte*           ptr;
 
334
 
 
335
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
336
        ut_ad(index && heap);
 
337
 
 
338
        sys_indexes = dict_sys->sys_indexes;
 
339
 
 
340
        table = dict_table_get_low(index->table_name);
 
341
 
 
342
        entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
 
343
 
 
344
        dict_table_copy_types(entry, sys_indexes);
 
345
 
 
346
        /* 0: TABLE_ID -----------------------*/
 
347
        dfield = dtuple_get_nth_field(entry, 0);
 
348
 
 
349
        ptr = mem_heap_alloc(heap, 8);
 
350
        mach_write_to_8(ptr, table->id);
 
351
 
 
352
        dfield_set_data(dfield, ptr, 8);
 
353
        /* 1: ID ----------------------------*/
 
354
        dfield = dtuple_get_nth_field(entry, 1);
 
355
 
 
356
        ptr = mem_heap_alloc(heap, 8);
 
357
        mach_write_to_8(ptr, index->id);
 
358
 
 
359
        dfield_set_data(dfield, ptr, 8);
 
360
        /* 4: NAME --------------------------*/
 
361
        dfield = dtuple_get_nth_field(entry, 2);
 
362
 
 
363
        dfield_set_data(dfield, index->name, ut_strlen(index->name));
 
364
        /* 5: N_FIELDS ----------------------*/
 
365
        dfield = dtuple_get_nth_field(entry, 3);
 
366
 
 
367
        ptr = mem_heap_alloc(heap, 4);
 
368
        mach_write_to_4(ptr, index->n_fields);
 
369
 
 
370
        dfield_set_data(dfield, ptr, 4);
 
371
        /* 6: TYPE --------------------------*/
 
372
        dfield = dtuple_get_nth_field(entry, 4);
 
373
 
 
374
        ptr = mem_heap_alloc(heap, 4);
 
375
        mach_write_to_4(ptr, index->type);
 
376
 
 
377
        dfield_set_data(dfield, ptr, 4);
 
378
        /* 7: SPACE --------------------------*/
 
379
 
 
380
#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 7
 
381
#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 7"
 
382
#endif
 
383
 
 
384
        dfield = dtuple_get_nth_field(entry, 5);
 
385
 
 
386
        ptr = mem_heap_alloc(heap, 4);
 
387
        mach_write_to_4(ptr, index->space);
 
388
 
 
389
        dfield_set_data(dfield, ptr, 4);
 
390
        /* 8: PAGE_NO --------------------------*/
 
391
 
 
392
#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 8
 
393
#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 8"
 
394
#endif
 
395
 
 
396
        dfield = dtuple_get_nth_field(entry, 6);
 
397
 
 
398
        ptr = mem_heap_alloc(heap, 4);
 
399
        mach_write_to_4(ptr, FIL_NULL);
 
400
 
 
401
        dfield_set_data(dfield, ptr, 4);
 
402
        /*--------------------------------*/
 
403
 
 
404
        return(entry);
 
405
}
 
406
 
 
407
/*****************************************************************//**
 
408
Based on an index object, this function builds the entry to be inserted
 
409
in the SYS_FIELDS system table.
 
410
@return the tuple which should be inserted */
 
411
static
 
412
dtuple_t*
 
413
dict_create_sys_fields_tuple(
 
414
/*=========================*/
 
415
        dict_index_t*   index,  /*!< in: index */
 
416
        ulint           i,      /*!< in: field number */
 
417
        mem_heap_t*     heap)   /*!< in: memory heap from which the memory for
 
418
                                the built tuple is allocated */
 
419
{
 
420
        dict_table_t*   sys_fields;
 
421
        dtuple_t*       entry;
 
422
        dict_field_t*   field;
 
423
        dfield_t*       dfield;
 
424
        byte*           ptr;
 
425
        ibool           index_contains_column_prefix_field      = FALSE;
 
426
        ulint           j;
 
427
 
 
428
        ut_ad(index && heap);
 
429
 
 
430
        for (j = 0; j < index->n_fields; j++) {
 
431
                if (dict_index_get_nth_field(index, j)->prefix_len > 0) {
 
432
                        index_contains_column_prefix_field = TRUE;
 
433
                        break;
 
434
                }
 
435
        }
 
436
 
 
437
        field = dict_index_get_nth_field(index, i);
 
438
 
 
439
        sys_fields = dict_sys->sys_fields;
 
440
 
 
441
        entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
 
442
 
 
443
        dict_table_copy_types(entry, sys_fields);
 
444
 
 
445
        /* 0: INDEX_ID -----------------------*/
 
446
        dfield = dtuple_get_nth_field(entry, 0);
 
447
 
 
448
        ptr = mem_heap_alloc(heap, 8);
 
449
        mach_write_to_8(ptr, index->id);
 
450
 
 
451
        dfield_set_data(dfield, ptr, 8);
 
452
        /* 1: POS + PREFIX LENGTH ----------------------------*/
 
453
 
 
454
        dfield = dtuple_get_nth_field(entry, 1);
 
455
 
 
456
        ptr = mem_heap_alloc(heap, 4);
 
457
 
 
458
        if (index_contains_column_prefix_field) {
 
459
                /* If there are column prefix fields in the index, then
 
460
                we store the number of the field to the 2 HIGH bytes
 
461
                and the prefix length to the 2 low bytes, */
 
462
 
 
463
                mach_write_to_4(ptr, (i << 16) + field->prefix_len);
 
464
        } else {
 
465
                /* Else we store the number of the field to the 2 LOW bytes.
 
466
                This is to keep the storage format compatible with
 
467
                InnoDB versions < 4.0.14. */
 
468
 
 
469
                mach_write_to_4(ptr, i);
 
470
        }
 
471
 
 
472
        dfield_set_data(dfield, ptr, 4);
 
473
        /* 4: COL_NAME -------------------------*/
 
474
        dfield = dtuple_get_nth_field(entry, 2);
 
475
 
 
476
        dfield_set_data(dfield, field->name,
 
477
                        ut_strlen(field->name));
 
478
        /*---------------------------------*/
 
479
 
 
480
        return(entry);
 
481
}
 
482
 
 
483
/*****************************************************************//**
 
484
Creates the tuple with which the index entry is searched for writing the index
 
485
tree root page number, if such a tree is created.
 
486
@return the tuple for search */
 
487
static
 
488
dtuple_t*
 
489
dict_create_search_tuple(
 
490
/*=====================*/
 
491
        const dtuple_t* tuple,  /*!< in: the tuple inserted in the SYS_INDEXES
 
492
                                table */
 
493
        mem_heap_t*     heap)   /*!< in: memory heap from which the memory for
 
494
                                the built tuple is allocated */
 
495
{
 
496
        dtuple_t*       search_tuple;
 
497
        const dfield_t* field1;
 
498
        dfield_t*       field2;
 
499
 
 
500
        ut_ad(tuple && heap);
 
501
 
 
502
        search_tuple = dtuple_create(heap, 2);
 
503
 
 
504
        field1 = dtuple_get_nth_field(tuple, 0);
 
505
        field2 = dtuple_get_nth_field(search_tuple, 0);
 
506
 
 
507
        dfield_copy(field2, field1);
 
508
 
 
509
        field1 = dtuple_get_nth_field(tuple, 1);
 
510
        field2 = dtuple_get_nth_field(search_tuple, 1);
 
511
 
 
512
        dfield_copy(field2, field1);
 
513
 
 
514
        ut_ad(dtuple_validate(search_tuple));
 
515
 
 
516
        return(search_tuple);
 
517
}
 
518
 
 
519
/***************************************************************//**
 
520
Builds an index definition row to insert.
 
521
@return DB_SUCCESS or error code */
 
522
static
 
523
ulint
 
524
dict_build_index_def_step(
 
525
/*======================*/
 
526
        que_thr_t*      thr,    /*!< in: query thread */
 
527
        ind_node_t*     node)   /*!< in: index create node */
 
528
{
 
529
        dict_table_t*   table;
 
530
        dict_index_t*   index;
 
531
        dtuple_t*       row;
 
532
        trx_t*          trx;
 
533
 
 
534
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
535
 
 
536
        trx = thr_get_trx(thr);
 
537
 
 
538
        index = node->index;
 
539
 
 
540
        table = dict_table_get_low(index->table_name);
 
541
 
 
542
        if (table == NULL) {
 
543
                return(DB_TABLE_NOT_FOUND);
 
544
        }
 
545
 
 
546
        trx->table_id = table->id;
 
547
 
 
548
        node->table = table;
 
549
 
 
550
        ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
 
551
              || dict_index_is_clust(index));
 
552
 
 
553
        index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID);
 
554
 
 
555
        /* Inherit the space id from the table; we store all indexes of a
 
556
        table in the same tablespace */
 
557
 
 
558
        index->space = table->space;
 
559
        node->page_no = FIL_NULL;
 
560
        row = dict_create_sys_indexes_tuple(index, node->heap);
 
561
        node->ind_row = row;
 
562
 
 
563
        ins_node_set_new_row(node->ind_def, row);
 
564
 
 
565
        /* Note that the index was created by this transaction. */
 
566
        index->trx_id = (ib_uint64_t) ut_conv_dulint_to_longlong(trx->id);
 
567
 
 
568
        return(DB_SUCCESS);
 
569
}
 
570
 
 
571
/***************************************************************//**
 
572
Builds a field definition row to insert.
 
573
@return DB_SUCCESS */
 
574
static
 
575
ulint
 
576
dict_build_field_def_step(
 
577
/*======================*/
 
578
        ind_node_t*     node)   /*!< in: index create node */
 
579
{
 
580
        dict_index_t*   index;
 
581
        dtuple_t*       row;
 
582
 
 
583
        index = node->index;
 
584
 
 
585
        row = dict_create_sys_fields_tuple(index, node->field_no, node->heap);
 
586
 
 
587
        ins_node_set_new_row(node->field_def, row);
 
588
 
 
589
        return(DB_SUCCESS);
 
590
}
 
591
 
 
592
/***************************************************************//**
 
593
Creates an index tree for the index if it is not a member of a cluster.
 
594
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
 
595
static
 
596
ulint
 
597
dict_create_index_tree_step(
 
598
/*========================*/
 
599
        ind_node_t*     node)   /*!< in: index create node */
 
600
{
 
601
        dict_index_t*   index;
 
602
        dict_table_t*   sys_indexes;
 
603
        dict_table_t*   table;
 
604
        dtuple_t*       search_tuple;
 
605
        btr_pcur_t      pcur;
 
606
        mtr_t           mtr;
 
607
 
 
608
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
609
 
 
610
        index = node->index;
 
611
        table = node->table;
 
612
 
 
613
        sys_indexes = dict_sys->sys_indexes;
 
614
 
 
615
        /* Run a mini-transaction in which the index tree is allocated for
 
616
        the index and its root address is written to the index entry in
 
617
        sys_indexes */
 
618
 
 
619
        mtr_start(&mtr);
 
620
 
 
621
        search_tuple = dict_create_search_tuple(node->ind_row, node->heap);
 
622
 
 
623
        btr_pcur_open(UT_LIST_GET_FIRST(sys_indexes->indexes),
 
624
                      search_tuple, PAGE_CUR_L, BTR_MODIFY_LEAF,
 
625
                      &pcur, &mtr);
 
626
 
 
627
        btr_pcur_move_to_next_user_rec(&pcur, &mtr);
 
628
 
 
629
        node->page_no = btr_create(index->type, index->space,
 
630
                                   dict_table_zip_size(index->table),
 
631
                                   index->id, index, &mtr);
 
632
        /* printf("Created a new index tree in space %lu root page %lu\n",
 
633
        index->space, index->page_no); */
 
634
 
 
635
        page_rec_write_index_page_no(btr_pcur_get_rec(&pcur),
 
636
                                     DICT_SYS_INDEXES_PAGE_NO_FIELD,
 
637
                                     node->page_no, &mtr);
 
638
        btr_pcur_close(&pcur);
 
639
        mtr_commit(&mtr);
 
640
 
 
641
        if (node->page_no == FIL_NULL) {
 
642
 
 
643
                return(DB_OUT_OF_FILE_SPACE);
 
644
        }
 
645
 
 
646
        return(DB_SUCCESS);
 
647
}
 
648
 
 
649
/*******************************************************************//**
 
650
Drops the index tree associated with a row in SYS_INDEXES table. */
 
651
UNIV_INTERN
 
652
void
 
653
dict_drop_index_tree(
 
654
/*=================*/
 
655
        rec_t*  rec,    /*!< in/out: record in the clustered index
 
656
                        of SYS_INDEXES table */
 
657
        mtr_t*  mtr)    /*!< in: mtr having the latch on the record page */
 
658
{
 
659
        ulint           root_page_no;
 
660
        ulint           space;
 
661
        ulint           zip_size;
 
662
        const byte*     ptr;
 
663
        ulint           len;
 
664
 
 
665
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
666
        ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
 
667
        ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
 
668
 
 
669
        ut_ad(len == 4);
 
670
 
 
671
        root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
 
672
 
 
673
        if (root_page_no == FIL_NULL) {
 
674
                /* The tree has already been freed */
 
675
 
 
676
                return;
 
677
        }
 
678
 
 
679
        ptr = rec_get_nth_field_old(rec,
 
680
                                    DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
 
681
 
 
682
        ut_ad(len == 4);
 
683
 
 
684
        space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
 
685
        zip_size = fil_space_get_zip_size(space);
 
686
 
 
687
        if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
 
688
                /* It is a single table tablespace and the .ibd file is
 
689
                missing: do nothing */
 
690
 
 
691
                return;
 
692
        }
 
693
 
 
694
        /* We free all the pages but the root page first; this operation
 
695
        may span several mini-transactions */
 
696
 
 
697
        btr_free_but_not_root(space, zip_size, root_page_no);
 
698
 
 
699
        /* Then we free the root page in the same mini-transaction where
 
700
        we write FIL_NULL to the appropriate field in the SYS_INDEXES
 
701
        record: this mini-transaction marks the B-tree totally freed */
 
702
 
 
703
        /* printf("Dropping index tree in space %lu root page %lu\n", space,
 
704
        root_page_no); */
 
705
        btr_free_root(space, zip_size, root_page_no, mtr);
 
706
 
 
707
        page_rec_write_index_page_no(rec,
 
708
                                     DICT_SYS_INDEXES_PAGE_NO_FIELD,
 
709
                                     FIL_NULL, mtr);
 
710
}
 
711
 
 
712
/*******************************************************************//**
 
713
Truncates the index tree associated with a row in SYS_INDEXES table.
 
714
@return new root page number, or FIL_NULL on failure */
 
715
UNIV_INTERN
 
716
ulint
 
717
dict_truncate_index_tree(
 
718
/*=====================*/
 
719
        dict_table_t*   table,  /*!< in: the table the index belongs to */
 
720
        ulint           space,  /*!< in: 0=truncate,
 
721
                                nonzero=create the index tree in the
 
722
                                given tablespace */
 
723
        btr_pcur_t*     pcur,   /*!< in/out: persistent cursor pointing to
 
724
                                record in the clustered index of
 
725
                                SYS_INDEXES table. The cursor may be
 
726
                                repositioned in this call. */
 
727
        mtr_t*          mtr)    /*!< in: mtr having the latch
 
728
                                on the record page. The mtr may be
 
729
                                committed and restarted in this call. */
 
730
{
 
731
        ulint           root_page_no;
 
732
        ibool           drop = !space;
 
733
        ulint           zip_size;
 
734
        ulint           type;
 
735
        dulint          index_id;
 
736
        rec_t*          rec;
 
737
        const byte*     ptr;
 
738
        ulint           len;
 
739
        dict_index_t*   index;
 
740
 
 
741
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
742
        ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
 
743
        rec = btr_pcur_get_rec(pcur);
 
744
        ptr = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD, &len);
 
745
 
 
746
        ut_ad(len == 4);
 
747
 
 
748
        root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
 
749
 
 
750
        if (drop && root_page_no == FIL_NULL) {
 
751
                /* The tree has been freed. */
 
752
 
 
753
                ut_print_timestamp(stderr);
 
754
                fprintf(stderr, "  InnoDB: Trying to TRUNCATE"
 
755
                        " a missing index of table %s!\n", table->name);
 
756
                drop = FALSE;
 
757
        }
 
758
 
 
759
        ptr = rec_get_nth_field_old(rec,
 
760
                                    DICT_SYS_INDEXES_SPACE_NO_FIELD, &len);
 
761
 
 
762
        ut_ad(len == 4);
 
763
 
 
764
        if (drop) {
 
765
                space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
 
766
        }
 
767
 
 
768
        zip_size = fil_space_get_zip_size(space);
 
769
 
 
770
        if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
 
771
                /* It is a single table tablespace and the .ibd file is
 
772
                missing: do nothing */
 
773
 
 
774
                ut_print_timestamp(stderr);
 
775
                fprintf(stderr, "  InnoDB: Trying to TRUNCATE"
 
776
                        " a missing .ibd file of table %s!\n", table->name);
 
777
                return(FIL_NULL);
 
778
        }
 
779
 
 
780
        ptr = rec_get_nth_field_old(rec,
 
781
                                    DICT_SYS_INDEXES_TYPE_FIELD, &len);
 
782
        ut_ad(len == 4);
 
783
        type = mach_read_from_4(ptr);
 
784
 
 
785
        ptr = rec_get_nth_field_old(rec, 1, &len);
 
786
        ut_ad(len == 8);
 
787
        index_id = mach_read_from_8(ptr);
 
788
 
 
789
        if (!drop) {
 
790
 
 
791
                goto create;
 
792
        }
 
793
 
 
794
        /* We free all the pages but the root page first; this operation
 
795
        may span several mini-transactions */
 
796
 
 
797
        btr_free_but_not_root(space, zip_size, root_page_no);
 
798
 
 
799
        /* Then we free the root page in the same mini-transaction where
 
800
        we create the b-tree and write its new root page number to the
 
801
        appropriate field in the SYS_INDEXES record: this mini-transaction
 
802
        marks the B-tree totally truncated */
 
803
 
 
804
        btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
 
805
 
 
806
        btr_free_root(space, zip_size, root_page_no, mtr);
 
807
create:
 
808
        /* We will temporarily write FIL_NULL to the PAGE_NO field
 
809
        in SYS_INDEXES, so that the database will not get into an
 
810
        inconsistent state in case it crashes between the mtr_commit()
 
811
        below and the following mtr_commit() call. */
 
812
        page_rec_write_index_page_no(rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
 
813
                                     FIL_NULL, mtr);
 
814
 
 
815
        /* We will need to commit the mini-transaction in order to avoid
 
816
        deadlocks in the btr_create() call, because otherwise we would
 
817
        be freeing and allocating pages in the same mini-transaction. */
 
818
        btr_pcur_store_position(pcur, mtr);
 
819
        mtr_commit(mtr);
 
820
 
 
821
        mtr_start(mtr);
 
822
        btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr);
 
823
 
 
824
        /* Find the index corresponding to this SYS_INDEXES record. */
 
825
        for (index = UT_LIST_GET_FIRST(table->indexes);
 
826
             index;
 
827
             index = UT_LIST_GET_NEXT(indexes, index)) {
 
828
                if (!ut_dulint_cmp(index->id, index_id)) {
 
829
                        root_page_no = btr_create(type, space, zip_size,
 
830
                                                  index_id, index, mtr);
 
831
                        index->page = (unsigned int) root_page_no;
 
832
                        return(root_page_no);
 
833
                }
 
834
        }
 
835
 
 
836
        ut_print_timestamp(stderr);
 
837
        fprintf(stderr,
 
838
                "  InnoDB: Index %lu %lu of table %s is missing\n"
 
839
                "InnoDB: from the data dictionary during TRUNCATE!\n",
 
840
                ut_dulint_get_high(index_id),
 
841
                ut_dulint_get_low(index_id),
 
842
                table->name);
 
843
 
 
844
        return(FIL_NULL);
 
845
}
 
846
 
 
847
/*********************************************************************//**
 
848
Creates a table create graph.
 
849
@return own: table create node */
 
850
UNIV_INTERN
 
851
tab_node_t*
 
852
tab_create_graph_create(
 
853
/*====================*/
 
854
        dict_table_t*   table,  /*!< in: table to create, built as a memory data
 
855
                                structure */
 
856
        mem_heap_t*     heap)   /*!< in: heap where created */
 
857
{
 
858
        tab_node_t*     node;
 
859
 
 
860
        node = mem_heap_alloc(heap, sizeof(tab_node_t));
 
861
 
 
862
        node->common.type = QUE_NODE_CREATE_TABLE;
 
863
 
 
864
        node->table = table;
 
865
 
 
866
        node->state = TABLE_BUILD_TABLE_DEF;
 
867
        node->heap = mem_heap_create(256);
 
868
 
 
869
        node->tab_def = ins_node_create(INS_DIRECT, dict_sys->sys_tables,
 
870
                                        heap);
 
871
        node->tab_def->common.parent = node;
 
872
 
 
873
        node->col_def = ins_node_create(INS_DIRECT, dict_sys->sys_columns,
 
874
                                        heap);
 
875
        node->col_def->common.parent = node;
 
876
 
 
877
        node->commit_node = commit_node_create(heap);
 
878
        node->commit_node->common.parent = node;
 
879
 
 
880
        return(node);
 
881
}
 
882
 
 
883
/*********************************************************************//**
 
884
Creates an index create graph.
 
885
@return own: index create node */
 
886
UNIV_INTERN
 
887
ind_node_t*
 
888
ind_create_graph_create(
 
889
/*====================*/
 
890
        dict_index_t*   index,  /*!< in: index to create, built as a memory data
 
891
                                structure */
 
892
        mem_heap_t*     heap)   /*!< in: heap where created */
 
893
{
 
894
        ind_node_t*     node;
 
895
 
 
896
        node = mem_heap_alloc(heap, sizeof(ind_node_t));
 
897
 
 
898
        node->common.type = QUE_NODE_CREATE_INDEX;
 
899
 
 
900
        node->index = index;
 
901
 
 
902
        node->state = INDEX_BUILD_INDEX_DEF;
 
903
        node->page_no = FIL_NULL;
 
904
        node->heap = mem_heap_create(256);
 
905
 
 
906
        node->ind_def = ins_node_create(INS_DIRECT,
 
907
                                        dict_sys->sys_indexes, heap);
 
908
        node->ind_def->common.parent = node;
 
909
 
 
910
        node->field_def = ins_node_create(INS_DIRECT,
 
911
                                          dict_sys->sys_fields, heap);
 
912
        node->field_def->common.parent = node;
 
913
 
 
914
        node->commit_node = commit_node_create(heap);
 
915
        node->commit_node->common.parent = node;
 
916
 
 
917
        return(node);
 
918
}
 
919
 
 
920
/***********************************************************//**
 
921
Creates a table. This is a high-level function used in SQL execution graphs.
 
922
@return query thread to run next or NULL */
 
923
UNIV_INTERN
 
924
que_thr_t*
 
925
dict_create_table_step(
 
926
/*===================*/
 
927
        que_thr_t*      thr)    /*!< in: query thread */
 
928
{
 
929
        tab_node_t*     node;
 
930
        ulint           err     = DB_ERROR;
 
931
        trx_t*          trx;
 
932
 
 
933
        ut_ad(thr);
 
934
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
935
 
 
936
        trx = thr_get_trx(thr);
 
937
 
 
938
        node = thr->run_node;
 
939
 
 
940
        ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_TABLE);
 
941
 
 
942
        if (thr->prev_node == que_node_get_parent(node)) {
 
943
                node->state = TABLE_BUILD_TABLE_DEF;
 
944
        }
 
945
 
 
946
        if (node->state == TABLE_BUILD_TABLE_DEF) {
 
947
 
 
948
                /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
 
949
 
 
950
                err = dict_build_table_def_step(thr, node);
 
951
 
 
952
                if (err != DB_SUCCESS) {
 
953
 
 
954
                        goto function_exit;
 
955
                }
 
956
 
 
957
                node->state = TABLE_BUILD_COL_DEF;
 
958
                node->col_no = 0;
 
959
 
 
960
                thr->run_node = node->tab_def;
 
961
 
 
962
                return(thr);
 
963
        }
 
964
 
 
965
        if (node->state == TABLE_BUILD_COL_DEF) {
 
966
 
 
967
                if (node->col_no < (node->table)->n_def) {
 
968
 
 
969
                        err = dict_build_col_def_step(node);
 
970
 
 
971
                        if (err != DB_SUCCESS) {
 
972
 
 
973
                                goto function_exit;
 
974
                        }
 
975
 
 
976
                        node->col_no++;
 
977
 
 
978
                        thr->run_node = node->col_def;
 
979
 
 
980
                        return(thr);
 
981
                } else {
 
982
                        node->state = TABLE_COMMIT_WORK;
 
983
                }
 
984
        }
 
985
 
 
986
        if (node->state == TABLE_COMMIT_WORK) {
 
987
 
 
988
                /* Table was correctly defined: do NOT commit the transaction
 
989
                (CREATE TABLE does NOT do an implicit commit of the current
 
990
                transaction) */
 
991
 
 
992
                node->state = TABLE_ADD_TO_CACHE;
 
993
 
 
994
                /* thr->run_node = node->commit_node;
 
995
 
 
996
                return(thr); */
 
997
        }
 
998
 
 
999
        if (node->state == TABLE_ADD_TO_CACHE) {
 
1000
 
 
1001
                dict_table_add_to_cache(node->table, node->heap);
 
1002
 
 
1003
                err = DB_SUCCESS;
 
1004
        }
 
1005
 
 
1006
function_exit:
 
1007
        trx->error_state = err;
 
1008
 
 
1009
        if (err == DB_SUCCESS) {
 
1010
                /* Ok: do nothing */
 
1011
 
 
1012
        } else if (err == DB_LOCK_WAIT) {
 
1013
 
 
1014
                return(NULL);
 
1015
        } else {
 
1016
                /* SQL error detected */
 
1017
 
 
1018
                return(NULL);
 
1019
        }
 
1020
 
 
1021
        thr->run_node = que_node_get_parent(node);
 
1022
 
 
1023
        return(thr);
 
1024
}
 
1025
 
 
1026
/***********************************************************//**
 
1027
Creates an index. This is a high-level function used in SQL execution
 
1028
graphs.
 
1029
@return query thread to run next or NULL */
 
1030
UNIV_INTERN
 
1031
que_thr_t*
 
1032
dict_create_index_step(
 
1033
/*===================*/
 
1034
        que_thr_t*      thr)    /*!< in: query thread */
 
1035
{
 
1036
        ind_node_t*     node;
 
1037
        ulint           err     = DB_ERROR;
 
1038
        trx_t*          trx;
 
1039
 
 
1040
        ut_ad(thr);
 
1041
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1042
 
 
1043
        trx = thr_get_trx(thr);
 
1044
 
 
1045
        node = thr->run_node;
 
1046
 
 
1047
        ut_ad(que_node_get_type(node) == QUE_NODE_CREATE_INDEX);
 
1048
 
 
1049
        if (thr->prev_node == que_node_get_parent(node)) {
 
1050
                node->state = INDEX_BUILD_INDEX_DEF;
 
1051
        }
 
1052
 
 
1053
        if (node->state == INDEX_BUILD_INDEX_DEF) {
 
1054
                /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */
 
1055
                err = dict_build_index_def_step(thr, node);
 
1056
 
 
1057
                if (err != DB_SUCCESS) {
 
1058
 
 
1059
                        goto function_exit;
 
1060
                }
 
1061
 
 
1062
                node->state = INDEX_BUILD_FIELD_DEF;
 
1063
                node->field_no = 0;
 
1064
 
 
1065
                thr->run_node = node->ind_def;
 
1066
 
 
1067
                return(thr);
 
1068
        }
 
1069
 
 
1070
        if (node->state == INDEX_BUILD_FIELD_DEF) {
 
1071
 
 
1072
                if (node->field_no < (node->index)->n_fields) {
 
1073
 
 
1074
                        err = dict_build_field_def_step(node);
 
1075
 
 
1076
                        if (err != DB_SUCCESS) {
 
1077
 
 
1078
                                goto function_exit;
 
1079
                        }
 
1080
 
 
1081
                        node->field_no++;
 
1082
 
 
1083
                        thr->run_node = node->field_def;
 
1084
 
 
1085
                        return(thr);
 
1086
                } else {
 
1087
                        node->state = INDEX_ADD_TO_CACHE;
 
1088
                }
 
1089
        }
 
1090
 
 
1091
        if (node->state == INDEX_ADD_TO_CACHE) {
 
1092
 
 
1093
                dulint  index_id = node->index->id;
 
1094
 
 
1095
                err = dict_index_add_to_cache(node->table, node->index,
 
1096
                                              FIL_NULL, TRUE);
 
1097
 
 
1098
                node->index = dict_index_get_if_in_cache_low(index_id);
 
1099
                ut_a(!node->index == (err != DB_SUCCESS));
 
1100
 
 
1101
                if (err != DB_SUCCESS) {
 
1102
 
 
1103
                        goto function_exit;
 
1104
                }
 
1105
 
 
1106
                node->state = INDEX_CREATE_INDEX_TREE;
 
1107
        }
 
1108
 
 
1109
        if (node->state == INDEX_CREATE_INDEX_TREE) {
 
1110
 
 
1111
                err = dict_create_index_tree_step(node);
 
1112
 
 
1113
                if (err != DB_SUCCESS) {
 
1114
                        dict_index_remove_from_cache(node->table, node->index);
 
1115
                        node->index = NULL;
 
1116
 
 
1117
                        goto function_exit;
 
1118
                }
 
1119
 
 
1120
                node->index->page = node->page_no;
 
1121
                node->state = INDEX_COMMIT_WORK;
 
1122
        }
 
1123
 
 
1124
        if (node->state == INDEX_COMMIT_WORK) {
 
1125
 
 
1126
                /* Index was correctly defined: do NOT commit the transaction
 
1127
                (CREATE INDEX does NOT currently do an implicit commit of
 
1128
                the current transaction) */
 
1129
 
 
1130
                node->state = INDEX_CREATE_INDEX_TREE;
 
1131
 
 
1132
                /* thr->run_node = node->commit_node;
 
1133
 
 
1134
                return(thr); */
 
1135
        }
 
1136
 
 
1137
function_exit:
 
1138
        trx->error_state = err;
 
1139
 
 
1140
        if (err == DB_SUCCESS) {
 
1141
                /* Ok: do nothing */
 
1142
 
 
1143
        } else if (err == DB_LOCK_WAIT) {
 
1144
 
 
1145
                return(NULL);
 
1146
        } else {
 
1147
                /* SQL error detected */
 
1148
 
 
1149
                return(NULL);
 
1150
        }
 
1151
 
 
1152
        thr->run_node = que_node_get_parent(node);
 
1153
 
 
1154
        return(thr);
 
1155
}
 
1156
 
 
1157
/****************************************************************//**
 
1158
Creates the foreign key constraints system tables inside InnoDB
 
1159
at database creation or database start if they are not found or are
 
1160
not of the right form.
 
1161
@return DB_SUCCESS or error code */
 
1162
UNIV_INTERN
 
1163
ulint
 
1164
dict_create_or_check_foreign_constraint_tables(void)
 
1165
/*================================================*/
 
1166
{
 
1167
        dict_table_t*   table1;
 
1168
        dict_table_t*   table2;
 
1169
        ulint           error;
 
1170
        trx_t*          trx;
 
1171
 
 
1172
        mutex_enter(&(dict_sys->mutex));
 
1173
 
 
1174
        table1 = dict_table_get_low("SYS_FOREIGN");
 
1175
        table2 = dict_table_get_low("SYS_FOREIGN_COLS");
 
1176
 
 
1177
        if (table1 && table2
 
1178
            && UT_LIST_GET_LEN(table1->indexes) == 3
 
1179
            && UT_LIST_GET_LEN(table2->indexes) == 1) {
 
1180
 
 
1181
                /* Foreign constraint system tables have already been
 
1182
                created, and they are ok */
 
1183
 
 
1184
                mutex_exit(&(dict_sys->mutex));
 
1185
 
 
1186
                return(DB_SUCCESS);
 
1187
        }
 
1188
 
 
1189
        mutex_exit(&(dict_sys->mutex));
 
1190
 
 
1191
        trx = trx_allocate_for_mysql();
 
1192
 
 
1193
        trx->op_info = "creating foreign key sys tables";
 
1194
 
 
1195
        row_mysql_lock_data_dictionary(trx);
 
1196
 
 
1197
        if (table1) {
 
1198
                fprintf(stderr,
 
1199
                        "InnoDB: dropping incompletely created"
 
1200
                        " SYS_FOREIGN table\n");
 
1201
                row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
 
1202
        }
 
1203
 
 
1204
        if (table2) {
 
1205
                fprintf(stderr,
 
1206
                        "InnoDB: dropping incompletely created"
 
1207
                        " SYS_FOREIGN_COLS table\n");
 
1208
                row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
 
1209
        }
 
1210
 
 
1211
        fprintf(stderr,
 
1212
                "InnoDB: Creating foreign key constraint system tables\n");
 
1213
 
 
1214
        /* NOTE: in dict_load_foreigns we use the fact that
 
1215
        there are 2 secondary indexes on SYS_FOREIGN, and they
 
1216
        are defined just like below */
 
1217
 
 
1218
        /* NOTE: when designing InnoDB's foreign key support in 2001, we made
 
1219
        an error and made the table names and the foreign key id of type
 
1220
        'CHAR' (internally, really a VARCHAR). We should have made the type
 
1221
        VARBINARY, like in other InnoDB system tables, to get a clean
 
1222
        design. */
 
1223
 
 
1224
        error = que_eval_sql(NULL,
 
1225
                             "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
 
1226
                             "BEGIN\n"
 
1227
                             "CREATE TABLE\n"
 
1228
                             "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
 
1229
                             " REF_NAME CHAR, N_COLS INT);\n"
 
1230
                             "CREATE UNIQUE CLUSTERED INDEX ID_IND"
 
1231
                             " ON SYS_FOREIGN (ID);\n"
 
1232
                             "CREATE INDEX FOR_IND"
 
1233
                             " ON SYS_FOREIGN (FOR_NAME);\n"
 
1234
                             "CREATE INDEX REF_IND"
 
1235
                             " ON SYS_FOREIGN (REF_NAME);\n"
 
1236
                             "CREATE TABLE\n"
 
1237
                             "SYS_FOREIGN_COLS(ID CHAR, POS INT,"
 
1238
                             " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
 
1239
                             "CREATE UNIQUE CLUSTERED INDEX ID_IND"
 
1240
                             " ON SYS_FOREIGN_COLS (ID, POS);\n"
 
1241
                             "END;\n"
 
1242
                             , FALSE, trx);
 
1243
 
 
1244
        if (error != DB_SUCCESS) {
 
1245
                fprintf(stderr, "InnoDB: error %lu in creation\n",
 
1246
                        (ulong) error);
 
1247
 
 
1248
                ut_a(error == DB_OUT_OF_FILE_SPACE
 
1249
                     || error == DB_TOO_MANY_CONCURRENT_TRXS);
 
1250
 
 
1251
                fprintf(stderr,
 
1252
                        "InnoDB: creation failed\n"
 
1253
                        "InnoDB: tablespace is full\n"
 
1254
                        "InnoDB: dropping incompletely created"
 
1255
                        " SYS_FOREIGN tables\n");
 
1256
 
 
1257
                row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
 
1258
                row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
 
1259
 
 
1260
                error = DB_MUST_GET_MORE_FILE_SPACE;
 
1261
        }
 
1262
 
 
1263
        trx_commit_for_mysql(trx);
 
1264
 
 
1265
        row_mysql_unlock_data_dictionary(trx);
 
1266
 
 
1267
        trx_free_for_mysql(trx);
 
1268
 
 
1269
        if (error == DB_SUCCESS) {
 
1270
                fprintf(stderr,
 
1271
                        "InnoDB: Foreign key constraint system tables"
 
1272
                        " created\n");
 
1273
        }
 
1274
 
 
1275
        return(error);
 
1276
}
 
1277
 
 
1278
/****************************************************************//**
 
1279
Evaluate the given foreign key SQL statement.
 
1280
@return error code or DB_SUCCESS */
 
1281
static
 
1282
ulint
 
1283
dict_foreign_eval_sql(
 
1284
/*==================*/
 
1285
        pars_info_t*    info,   /*!< in: info struct, or NULL */
 
1286
        const char*     sql,    /*!< in: SQL string to evaluate */
 
1287
        dict_table_t*   table,  /*!< in: table */
 
1288
        dict_foreign_t* foreign,/*!< in: foreign */
 
1289
        trx_t*          trx)    /*!< in: transaction */
 
1290
{
 
1291
        ulint           error;
 
1292
        FILE*           ef      = dict_foreign_err_file;
 
1293
 
 
1294
        error = que_eval_sql(info, sql, FALSE, trx);
 
1295
 
 
1296
        if (error == DB_DUPLICATE_KEY) {
 
1297
                mutex_enter(&dict_foreign_err_mutex);
 
1298
                rewind(ef);
 
1299
                ut_print_timestamp(ef);
 
1300
                fputs(" Error in foreign key constraint creation for table ",
 
1301
                      ef);
 
1302
                ut_print_name(ef, trx, TRUE, table->name);
 
1303
                fputs(".\nA foreign key constraint of name ", ef);
 
1304
                ut_print_name(ef, trx, TRUE, foreign->id);
 
1305
                fputs("\nalready exists."
 
1306
                      " (Note that internally InnoDB adds 'databasename'\n"
 
1307
                      "in front of the user-defined constraint name.)\n"
 
1308
                      "Note that InnoDB's FOREIGN KEY system tables store\n"
 
1309
                      "constraint names as case-insensitive, with the\n"
 
1310
                      "MySQL standard latin1_swedish_ci collation. If you\n"
 
1311
                      "create tables or databases whose names differ only in\n"
 
1312
                      "the character case, then collisions in constraint\n"
 
1313
                      "names can occur. Workaround: name your constraints\n"
 
1314
                      "explicitly with unique names.\n",
 
1315
                      ef);
 
1316
 
 
1317
                mutex_exit(&dict_foreign_err_mutex);
 
1318
 
 
1319
                return(error);
 
1320
        }
 
1321
 
 
1322
        if (error != DB_SUCCESS) {
 
1323
                fprintf(stderr,
 
1324
                        "InnoDB: Foreign key constraint creation failed:\n"
 
1325
                        "InnoDB: internal error number %lu\n", (ulong) error);
 
1326
 
 
1327
                mutex_enter(&dict_foreign_err_mutex);
 
1328
                ut_print_timestamp(ef);
 
1329
                fputs(" Internal error in foreign key constraint creation"
 
1330
                      " for table ", ef);
 
1331
                ut_print_name(ef, trx, TRUE, table->name);
 
1332
                fputs(".\n"
 
1333
                      "See the MySQL .err log in the datadir"
 
1334
                      " for more information.\n", ef);
 
1335
                mutex_exit(&dict_foreign_err_mutex);
 
1336
 
 
1337
                return(error);
 
1338
        }
 
1339
 
 
1340
        return(DB_SUCCESS);
 
1341
}
 
1342
 
 
1343
/********************************************************************//**
 
1344
Add a single foreign key field definition to the data dictionary tables in
 
1345
the database.
 
1346
@return error code or DB_SUCCESS */
 
1347
static
 
1348
ulint
 
1349
dict_create_add_foreign_field_to_dictionary(
 
1350
/*========================================*/
 
1351
        ulint           field_nr,       /*!< in: foreign field number */
 
1352
        dict_table_t*   table,          /*!< in: table */
 
1353
        dict_foreign_t* foreign,        /*!< in: foreign */
 
1354
        trx_t*          trx)            /*!< in: transaction */
 
1355
{
 
1356
        pars_info_t*    info = pars_info_create();
 
1357
 
 
1358
        pars_info_add_str_literal(info, "id", foreign->id);
 
1359
 
 
1360
        pars_info_add_int4_literal(info, "pos", field_nr);
 
1361
 
 
1362
        pars_info_add_str_literal(info, "for_col_name",
 
1363
                                  foreign->foreign_col_names[field_nr]);
 
1364
 
 
1365
        pars_info_add_str_literal(info, "ref_col_name",
 
1366
                                  foreign->referenced_col_names[field_nr]);
 
1367
 
 
1368
        return(dict_foreign_eval_sql(
 
1369
                       info,
 
1370
                       "PROCEDURE P () IS\n"
 
1371
                       "BEGIN\n"
 
1372
                       "INSERT INTO SYS_FOREIGN_COLS VALUES"
 
1373
                       "(:id, :pos, :for_col_name, :ref_col_name);\n"
 
1374
                       "END;\n",
 
1375
                       table, foreign, trx));
 
1376
}
 
1377
 
 
1378
/********************************************************************//**
 
1379
Add a single foreign key definition to the data dictionary tables in the
 
1380
database. We also generate names to constraints that were not named by the
 
1381
user. A generated constraint has a name of the format
 
1382
databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and
 
1383
are given locally for this table, that is, the number is not global, as in
 
1384
the old format constraints < 4.0.18 it used to be.
 
1385
@return error code or DB_SUCCESS */
 
1386
static
 
1387
ulint
 
1388
dict_create_add_foreign_to_dictionary(
 
1389
/*==================================*/
 
1390
        ulint*          id_nr,  /*!< in/out: number to use in id generation;
 
1391
                                incremented if used */
 
1392
        dict_table_t*   table,  /*!< in: table */
 
1393
        dict_foreign_t* foreign,/*!< in: foreign */
 
1394
        trx_t*          trx)    /*!< in: transaction */
 
1395
{
 
1396
        ulint           error;
 
1397
        ulint           i;
 
1398
 
 
1399
        pars_info_t*    info = pars_info_create();
 
1400
 
 
1401
        if (foreign->id == NULL) {
 
1402
                /* Generate a new constraint id */
 
1403
                ulint   namelen = strlen(table->name);
 
1404
                char*   id      = mem_heap_alloc(foreign->heap, namelen + 20);
 
1405
                /* no overflow if number < 1e13 */
 
1406
                sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++);
 
1407
                foreign->id = id;
 
1408
        }
 
1409
 
 
1410
        pars_info_add_str_literal(info, "id", foreign->id);
 
1411
 
 
1412
        pars_info_add_str_literal(info, "for_name", table->name);
 
1413
 
 
1414
        pars_info_add_str_literal(info, "ref_name",
 
1415
                                  foreign->referenced_table_name);
 
1416
 
 
1417
        pars_info_add_int4_literal(info, "n_cols",
 
1418
                                   foreign->n_fields + (foreign->type << 24));
 
1419
 
 
1420
        error = dict_foreign_eval_sql(info,
 
1421
                                      "PROCEDURE P () IS\n"
 
1422
                                      "BEGIN\n"
 
1423
                                      "INSERT INTO SYS_FOREIGN VALUES"
 
1424
                                      "(:id, :for_name, :ref_name, :n_cols);\n"
 
1425
                                      "END;\n"
 
1426
                                      , table, foreign, trx);
 
1427
 
 
1428
        if (error != DB_SUCCESS) {
 
1429
 
 
1430
                return(error);
 
1431
        }
 
1432
 
 
1433
        for (i = 0; i < foreign->n_fields; i++) {
 
1434
                error = dict_create_add_foreign_field_to_dictionary(
 
1435
                        i, table, foreign, trx);
 
1436
 
 
1437
                if (error != DB_SUCCESS) {
 
1438
 
 
1439
                        return(error);
 
1440
                }
 
1441
        }
 
1442
 
 
1443
        error = dict_foreign_eval_sql(NULL,
 
1444
                                      "PROCEDURE P () IS\n"
 
1445
                                      "BEGIN\n"
 
1446
                                      "COMMIT WORK;\n"
 
1447
                                      "END;\n"
 
1448
                                      , table, foreign, trx);
 
1449
 
 
1450
        return(error);
 
1451
}
 
1452
 
 
1453
/********************************************************************//**
 
1454
Adds foreign key definitions to data dictionary tables in the database.
 
1455
@return error code or DB_SUCCESS */
 
1456
UNIV_INTERN
 
1457
ulint
 
1458
dict_create_add_foreigns_to_dictionary(
 
1459
/*===================================*/
 
1460
        ulint           start_id,/*!< in: if we are actually doing ALTER TABLE
 
1461
                                ADD CONSTRAINT, we want to generate constraint
 
1462
                                numbers which are bigger than in the table so
 
1463
                                far; we number the constraints from
 
1464
                                start_id + 1 up; start_id should be set to 0 if
 
1465
                                we are creating a new table, or if the table
 
1466
                                so far has no constraints for which the name
 
1467
                                was generated here */
 
1468
        dict_table_t*   table,  /*!< in: table */
 
1469
        trx_t*          trx)    /*!< in: transaction */
 
1470
{
 
1471
        dict_foreign_t* foreign;
 
1472
        ulint           number  = start_id + 1;
 
1473
        ulint           error;
 
1474
 
 
1475
        ut_ad(mutex_own(&(dict_sys->mutex)));
 
1476
 
 
1477
        if (NULL == dict_table_get_low("SYS_FOREIGN")) {
 
1478
                fprintf(stderr,
 
1479
                        "InnoDB: table SYS_FOREIGN not found"
 
1480
                        " in internal data dictionary\n");
 
1481
 
 
1482
                return(DB_ERROR);
 
1483
        }
 
1484
 
 
1485
        for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
 
1486
             foreign;
 
1487
             foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
 
1488
 
 
1489
                error = dict_create_add_foreign_to_dictionary(&number, table,
 
1490
                                                              foreign, trx);
 
1491
 
 
1492
                if (error != DB_SUCCESS) {
 
1493
 
 
1494
                        return(error);
 
1495
                }
 
1496
        }
 
1497
 
 
1498
        return(DB_SUCCESS);
 
1499
}