~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
 
Place, Suite 330, Boston, MA 02111-1307 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file dict/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
 
        pars_info_t *info = pars_info_create();
1225
 
        error = que_eval_sql(info,
1226
 
                             "PROCEDURE CREATE_FOREIGN_SYS_TABLES_PROC () IS\n"
1227
 
                             "BEGIN\n"
1228
 
                             "CREATE TABLE\n"
1229
 
                             "SYS_FOREIGN(ID CHAR, FOR_NAME CHAR,"
1230
 
                             " REF_NAME CHAR, N_COLS INT);\n"
1231
 
                             "CREATE UNIQUE CLUSTERED INDEX ID_IND"
1232
 
                             " ON SYS_FOREIGN (ID);\n"
1233
 
                             "CREATE INDEX FOR_IND"
1234
 
                             " ON SYS_FOREIGN (FOR_NAME);\n"
1235
 
                             "CREATE INDEX REF_IND"
1236
 
                             " ON SYS_FOREIGN (REF_NAME);\n"
1237
 
                             "CREATE TABLE\n"
1238
 
                             "SYS_FOREIGN_COLS(ID CHAR, POS INT,"
1239
 
                             " FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
1240
 
                             "CREATE UNIQUE CLUSTERED INDEX ID_IND"
1241
 
                             " ON SYS_FOREIGN_COLS (ID, POS);\n"
1242
 
                             "END;\n"
1243
 
                             , FALSE, trx);
1244
 
 
1245
 
        if (error != DB_SUCCESS) {
1246
 
                fprintf(stderr, "InnoDB: error %lu in creation\n",
1247
 
                        (ulong) error);
1248
 
 
1249
 
                ut_a(error == DB_OUT_OF_FILE_SPACE
1250
 
                     || error == DB_TOO_MANY_CONCURRENT_TRXS);
1251
 
 
1252
 
                fprintf(stderr,
1253
 
                        "InnoDB: creation failed\n"
1254
 
                        "InnoDB: tablespace is full\n"
1255
 
                        "InnoDB: dropping incompletely created"
1256
 
                        " SYS_FOREIGN tables\n");
1257
 
 
1258
 
                row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE);
1259
 
                row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE);
1260
 
 
1261
 
                error = DB_MUST_GET_MORE_FILE_SPACE;
1262
 
        }
1263
 
 
1264
 
        trx_commit_for_mysql(trx);
1265
 
 
1266
 
        row_mysql_unlock_data_dictionary(trx);
1267
 
 
1268
 
        trx_free_for_mysql(trx);
1269
 
 
1270
 
        if (error == DB_SUCCESS) {
1271
 
                fprintf(stderr,
1272
 
                        "InnoDB: Foreign key constraint system tables"
1273
 
                        " created\n");
1274
 
        }
1275
 
 
1276
 
        return(error);
1277
 
}
1278
 
 
1279
 
/****************************************************************//**
1280
 
Evaluate the given foreign key SQL statement.
1281
 
@return error code or DB_SUCCESS */
1282
 
static
1283
 
ulint
1284
 
dict_foreign_eval_sql(
1285
 
/*==================*/
1286
 
        pars_info_t*    info,   /*!< in: info struct, or NULL */
1287
 
        const char*     sql,    /*!< in: SQL string to evaluate */
1288
 
        dict_table_t*   table,  /*!< in: table */
1289
 
        dict_foreign_t* foreign,/*!< in: foreign */
1290
 
        trx_t*          trx)    /*!< in: transaction */
1291
 
{
1292
 
        ulint           error;
1293
 
        FILE*           ef      = dict_foreign_err_file;
1294
 
 
1295
 
        error = que_eval_sql(info, sql, FALSE, trx);
1296
 
 
1297
 
        if (error == DB_DUPLICATE_KEY) {
1298
 
                mutex_enter(&dict_foreign_err_mutex);
1299
 
                rewind(ef);
1300
 
                ut_print_timestamp(ef);
1301
 
                fputs(" Error in foreign key constraint creation for table ",
1302
 
                      ef);
1303
 
                ut_print_name(ef, trx, TRUE, table->name);
1304
 
                fputs(".\nA foreign key constraint of name ", ef);
1305
 
                ut_print_name(ef, trx, TRUE, foreign->id);
1306
 
                fputs("\nalready exists."
1307
 
                      " (Note that internally InnoDB adds 'databasename'\n"
1308
 
                      "in front of the user-defined constraint name.)\n"
1309
 
                      "Note that InnoDB's FOREIGN KEY system tables store\n"
1310
 
                      "constraint names as case-insensitive, with the\n"
1311
 
                      "MySQL standard latin1_swedish_ci collation. If you\n"
1312
 
                      "create tables or databases whose names differ only in\n"
1313
 
                      "the character case, then collisions in constraint\n"
1314
 
                      "names can occur. Workaround: name your constraints\n"
1315
 
                      "explicitly with unique names.\n",
1316
 
                      ef);
1317
 
 
1318
 
                mutex_exit(&dict_foreign_err_mutex);
1319
 
 
1320
 
                return(error);
1321
 
        }
1322
 
 
1323
 
        if (error != DB_SUCCESS) {
1324
 
                fprintf(stderr,
1325
 
                        "InnoDB: Foreign key constraint creation failed:\n"
1326
 
                        "InnoDB: internal error number %lu\n", (ulong) error);
1327
 
 
1328
 
                mutex_enter(&dict_foreign_err_mutex);
1329
 
                ut_print_timestamp(ef);
1330
 
                fputs(" Internal error in foreign key constraint creation"
1331
 
                      " for table ", ef);
1332
 
                ut_print_name(ef, trx, TRUE, table->name);
1333
 
                fputs(".\n"
1334
 
                      "See the MySQL .err log in the datadir"
1335
 
                      " for more information.\n", ef);
1336
 
                mutex_exit(&dict_foreign_err_mutex);
1337
 
 
1338
 
                return(error);
1339
 
        }
1340
 
 
1341
 
        return(DB_SUCCESS);
1342
 
}
1343
 
 
1344
 
/********************************************************************//**
1345
 
Add a single foreign key field definition to the data dictionary tables in
1346
 
the database.
1347
 
@return error code or DB_SUCCESS */
1348
 
static
1349
 
ulint
1350
 
dict_create_add_foreign_field_to_dictionary(
1351
 
/*========================================*/
1352
 
        ulint           field_nr,       /*!< in: foreign field number */
1353
 
        dict_table_t*   table,          /*!< in: table */
1354
 
        dict_foreign_t* foreign,        /*!< in: foreign */
1355
 
        trx_t*          trx)            /*!< in: transaction */
1356
 
{
1357
 
        pars_info_t*    info = pars_info_create();
1358
 
 
1359
 
        pars_info_add_str_literal(info, "id", foreign->id);
1360
 
 
1361
 
        pars_info_add_int4_literal(info, "pos", field_nr);
1362
 
 
1363
 
        pars_info_add_str_literal(info, "for_col_name",
1364
 
                                  foreign->foreign_col_names[field_nr]);
1365
 
 
1366
 
        pars_info_add_str_literal(info, "ref_col_name",
1367
 
                                  foreign->referenced_col_names[field_nr]);
1368
 
 
1369
 
        return(dict_foreign_eval_sql(
1370
 
                       info,
1371
 
                       "PROCEDURE P () IS\n"
1372
 
                       "BEGIN\n"
1373
 
                       "INSERT INTO SYS_FOREIGN_COLS VALUES"
1374
 
                       "(:id, :pos, :for_col_name, :ref_col_name);\n"
1375
 
                       "END;\n",
1376
 
                       table, foreign, trx));
1377
 
}
1378
 
 
1379
 
/********************************************************************//**
1380
 
Add a single foreign key definition to the data dictionary tables in the
1381
 
database. We also generate names to constraints that were not named by the
1382
 
user. A generated constraint has a name of the format
1383
 
databasename/tablename_ibfk_<number>, where the numbers start from 1, and
1384
 
are given locally for this table, that is, the number is not global, as in
1385
 
the old format constraints < 4.0.18 it used to be.
1386
 
@return error code or DB_SUCCESS */
1387
 
static
1388
 
ulint
1389
 
dict_create_add_foreign_to_dictionary(
1390
 
/*==================================*/
1391
 
        ulint*          id_nr,  /*!< in/out: number to use in id generation;
1392
 
                                incremented if used */
1393
 
        dict_table_t*   table,  /*!< in: table */
1394
 
        dict_foreign_t* foreign,/*!< in: foreign */
1395
 
        trx_t*          trx)    /*!< in: transaction */
1396
 
{
1397
 
        ulint           error;
1398
 
        ulint           i;
1399
 
 
1400
 
        pars_info_t*    info = pars_info_create();
1401
 
 
1402
 
        if (foreign->id == NULL) {
1403
 
                /* Generate a new constraint id */
1404
 
                ulint   namelen = strlen(table->name);
1405
 
                char*   id      = mem_heap_alloc(foreign->heap, namelen + 20);
1406
 
                /* no overflow if number < 1e13 */
1407
 
                sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++);
1408
 
                foreign->id = id;
1409
 
        }
1410
 
 
1411
 
        pars_info_add_str_literal(info, "id", foreign->id);
1412
 
 
1413
 
        pars_info_add_str_literal(info, "for_name", table->name);
1414
 
 
1415
 
        pars_info_add_str_literal(info, "ref_name",
1416
 
                                  foreign->referenced_table_name);
1417
 
 
1418
 
        pars_info_add_int4_literal(info, "n_cols",
1419
 
                                   foreign->n_fields + (foreign->type << 24));
1420
 
 
1421
 
        error = dict_foreign_eval_sql(info,
1422
 
                                      "PROCEDURE P () IS\n"
1423
 
                                      "BEGIN\n"
1424
 
                                      "INSERT INTO SYS_FOREIGN VALUES"
1425
 
                                      "(:id, :for_name, :ref_name, :n_cols);\n"
1426
 
                                      "END;\n"
1427
 
                                      , table, foreign, trx);
1428
 
 
1429
 
        if (error != DB_SUCCESS) {
1430
 
 
1431
 
                return(error);
1432
 
        }
1433
 
 
1434
 
        for (i = 0; i < foreign->n_fields; i++) {
1435
 
                error = dict_create_add_foreign_field_to_dictionary(
1436
 
                        i, table, foreign, trx);
1437
 
 
1438
 
                if (error != DB_SUCCESS) {
1439
 
 
1440
 
                        return(error);
1441
 
                }
1442
 
        }
1443
 
 
1444
 
        error = dict_foreign_eval_sql(NULL,
1445
 
                                      "PROCEDURE P () IS\n"
1446
 
                                      "BEGIN\n"
1447
 
                                      "COMMIT WORK;\n"
1448
 
                                      "END;\n"
1449
 
                                      , table, foreign, trx);
1450
 
 
1451
 
        return(error);
1452
 
}
1453
 
 
1454
 
/********************************************************************//**
1455
 
Adds foreign key definitions to data dictionary tables in the database.
1456
 
@return error code or DB_SUCCESS */
1457
 
UNIV_INTERN
1458
 
ulint
1459
 
dict_create_add_foreigns_to_dictionary(
1460
 
/*===================================*/
1461
 
        ulint           start_id,/*!< in: if we are actually doing ALTER TABLE
1462
 
                                ADD CONSTRAINT, we want to generate constraint
1463
 
                                numbers which are bigger than in the table so
1464
 
                                far; we number the constraints from
1465
 
                                start_id + 1 up; start_id should be set to 0 if
1466
 
                                we are creating a new table, or if the table
1467
 
                                so far has no constraints for which the name
1468
 
                                was generated here */
1469
 
        dict_table_t*   table,  /*!< in: table */
1470
 
        trx_t*          trx)    /*!< in: transaction */
1471
 
{
1472
 
        dict_foreign_t* foreign;
1473
 
        ulint           number  = start_id + 1;
1474
 
        ulint           error;
1475
 
 
1476
 
        ut_ad(mutex_own(&(dict_sys->mutex)));
1477
 
 
1478
 
        if (NULL == dict_table_get_low("SYS_FOREIGN")) {
1479
 
                fprintf(stderr,
1480
 
                        "InnoDB: table SYS_FOREIGN not found"
1481
 
                        " in internal data dictionary\n");
1482
 
 
1483
 
                return(DB_ERROR);
1484
 
        }
1485
 
 
1486
 
        for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
1487
 
             foreign;
1488
 
             foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
1489
 
 
1490
 
                error = dict_create_add_foreign_to_dictionary(&number, table,
1491
 
                                                              foreign, trx);
1492
 
 
1493
 
                if (error != DB_SUCCESS) {
1494
 
 
1495
 
                        return(error);
1496
 
                }
1497
 
        }
1498
 
 
1499
 
        return(DB_SUCCESS);
1500
 
}