~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

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