~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Finished first pass at Protocol cleanup, still some things to remove but they are a bit more involved.

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
 
static 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
 
}