~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Merged vcol stuff.

Show diffs side-by-side

added added

removed removed

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