~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/handler/handler0alter.cc

Cleanup around SAFEMALLOC

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15
 
Place, Suite 330, Boston, MA 02111-1307 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/**************************************************//**
20
 
@file handler/handler0alter.cc
21
 
Smart ALTER TABLE
22
 
*******************************************************/
23
 
 
24
 
#include "config.h"
25
 
#include <drizzled/error.h>
26
 
#include "drizzled/charset_info.h"
27
 
#include <drizzled/field.h>
28
 
#include <drizzled/table.h>
29
 
#include <drizzled/field/varstring.h>
30
 
#include "drizzled/internal/my_sys.h"
31
 
 
32
 
extern "C" {
33
 
#include "log0log.h"
34
 
#include "row0merge.h"
35
 
#include "srv0srv.h"
36
 
#include "trx0trx.h"
37
 
#include "trx0roll.h"
38
 
#include "ha_prototypes.h"
39
 
#include "handler0alter.h"
40
 
}
41
 
 
42
 
#include "ha_innodb.h"
43
 
#include "handler0vars.h"
44
 
 
45
 
/*************************************************************//**
46
 
Copies an InnoDB column to a MySQL field.  This function is
47
 
adapted from row_sel_field_store_in_mysql_format(). */
48
 
static
49
 
void
50
 
innobase_col_to_mysql(
51
 
/*==================*/
52
 
        const dict_col_t*       col,    /*!< in: InnoDB column */
53
 
        const unsigned char*    data,   /*!< in: InnoDB column data */
54
 
        ulint                   len,    /*!< in: length of data, in bytes */
55
 
        Field*                  field)  /*!< in/out: MySQL field */
56
 
{
57
 
        unsigned char*  ptr;
58
 
        unsigned char*  dest    = field->ptr;
59
 
        ulint   flen    = field->pack_length();
60
 
 
61
 
        switch (col->mtype) {
62
 
        case DATA_INT:
63
 
                ut_ad(len == flen);
64
 
 
65
 
                /* Convert integer data from Innobase to little-endian
66
 
                format, sign bit restored to normal */
67
 
 
68
 
                for (ptr = dest + len; ptr != dest; ) {
69
 
                        *--ptr = *data++;
70
 
                }
71
 
 
72
 
                if (!(field->flags & UNSIGNED_FLAG)) {
73
 
                        ((byte*) dest)[len - 1] ^= 0x80;
74
 
                }
75
 
 
76
 
                break;
77
 
 
78
 
        case DATA_VARCHAR:
79
 
        case DATA_VARMYSQL:
80
 
        case DATA_BINARY:
81
 
                field->reset();
82
 
 
83
 
                if (field->type() == DRIZZLE_TYPE_VARCHAR) {
84
 
                        /* This is a >= 5.0.3 type true VARCHAR. Store the
85
 
                        length of the data to the first byte or the first
86
 
                        two bytes of dest. */
87
 
 
88
 
                        dest = row_mysql_store_true_var_len(
89
 
                                dest, len, flen - field->key_length());
90
 
                }
91
 
 
92
 
                /* Copy the actual data */
93
 
                memcpy(dest, data, len);
94
 
                break;
95
 
 
96
 
        case DATA_BLOB:
97
 
                /* Store a pointer to the BLOB buffer to dest: the BLOB was
98
 
                already copied to the buffer in row_sel_store_mysql_rec */
99
 
 
100
 
                row_mysql_store_blob_ref(dest, flen, data, len);
101
 
                break;
102
 
 
103
 
#ifdef UNIV_DEBUG
104
 
        case DATA_MYSQL:
105
 
                ut_ad(flen >= len);
106
 
                ut_ad(col->mbmaxlen >= col->mbminlen);
107
 
                ut_ad(col->mbmaxlen > col->mbminlen || flen == len);
108
 
                memcpy(dest, data, len);
109
 
                break;
110
 
 
111
 
        default:
112
 
        case DATA_SYS_CHILD:
113
 
        case DATA_SYS:
114
 
                /* These column types should never be shipped to MySQL. */
115
 
                ut_ad(0);
116
 
 
117
 
        case DATA_CHAR:
118
 
        case DATA_FIXBINARY:
119
 
        case DATA_FLOAT:
120
 
        case DATA_DOUBLE:
121
 
        case DATA_DECIMAL:
122
 
                /* Above are the valid column types for MySQL data. */
123
 
                ut_ad(flen == len);
124
 
#else /* UNIV_DEBUG */
125
 
        default:
126
 
#endif /* UNIV_DEBUG */
127
 
                memcpy(dest, data, len);
128
 
        }
129
 
}
130
 
 
131
 
/*************************************************************//**
132
 
Copies an InnoDB record to table->record[0]. */
133
 
extern "C" UNIV_INTERN
134
 
void
135
 
innobase_rec_to_mysql(
136
 
/*==================*/
137
 
        Table*                  table,          /*!< in/out: MySQL table */
138
 
        const rec_t*            rec,            /*!< in: record */
139
 
        const dict_index_t*     index,          /*!< in: index */
140
 
        const ulint*            offsets)        /*!< in: rec_get_offsets(
141
 
                                                rec, index, ...) */
142
 
{
143
 
        uint    n_fields        = table->s->fields;
144
 
        uint    i;
145
 
 
146
 
        ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
147
 
 
148
 
        for (i = 0; i < n_fields; i++) {
149
 
                Field*          field   = table->field[i];
150
 
                ulint           ipos;
151
 
                ulint           ilen;
152
 
                const unsigned char*    ifield;
153
 
 
154
 
                field->reset();
155
 
 
156
 
                ipos = dict_index_get_nth_col_pos(index, i);
157
 
 
158
 
                if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
159
 
null_field:
160
 
                        field->set_null();
161
 
                        continue;
162
 
                }
163
 
 
164
 
                ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
165
 
 
166
 
                /* Assign the NULL flag */
167
 
                if (ilen == UNIV_SQL_NULL) {
168
 
                        ut_ad(field->real_maybe_null());
169
 
                        goto null_field;
170
 
                }
171
 
 
172
 
                field->set_notnull();
173
 
 
174
 
                innobase_col_to_mysql(
175
 
                        dict_field_get_col(
176
 
                                dict_index_get_nth_field(index, ipos)),
177
 
                        ifield, ilen, field);
178
 
        }
179
 
}
180
 
 
181
 
/*************************************************************//**
182
 
Resets table->record[0]. */
183
 
extern "C" UNIV_INTERN
184
 
void
185
 
innobase_rec_reset(
186
 
/*===============*/
187
 
        Table*                  table)          /*!< in/out: MySQL table */
188
 
{
189
 
        uint    n_fields        = table->s->fields;
190
 
        uint    i;
191
 
 
192
 
        for (i = 0; i < n_fields; i++) {
193
 
                table->field[i]->set_default();
194
 
        }
195
 
}
196
 
 
197
 
/******************************************************************//**
198
 
Removes the filename encoding of a database and table name. */
199
 
static
200
 
void
201
 
innobase_convert_tablename(
202
 
/*=======================*/
203
 
        char*   s)      /*!< in: identifier; out: decoded identifier */
204
 
{
205
 
 
206
 
        char*   slash = strchr(s, '/');
207
 
 
208
 
        if (slash) {
209
 
                char*   t;
210
 
                /* Temporarily replace the '/' with NUL. */
211
 
                *slash = 0;
212
 
                strncpy(s, s, slash - s + 1);
213
 
 
214
 
                t = s + strlen(s);
215
 
                ut_ad(slash >= t);
216
 
                /* Append a  '.' after the database name. */
217
 
                *t++ = '.';
218
 
                slash++;
219
 
                /* Convert the table name. */
220
 
                strncpy(t, slash, slash - t + strlen(slash));
221
 
        }
222
 
}
223
 
 
224
 
/*******************************************************************//**
225
 
This function checks that index keys are sensible.
226
 
@return 0 or error number */
227
 
static
228
 
int
229
 
innobase_check_index_keys(
230
 
/*======================*/
231
 
        const KEY*      key_info,       /*!< in: Indexes to be created */
232
 
        ulint           num_of_keys)    /*!< in: Number of indexes to
233
 
                                        be created */
234
 
{
235
 
        ulint           key_num;
236
 
 
237
 
        ut_ad(key_info);
238
 
        ut_ad(num_of_keys);
239
 
 
240
 
        for (key_num = 0; key_num < num_of_keys; key_num++) {
241
 
                const KEY&      key = key_info[key_num];
242
 
 
243
 
                /* Check that the same index name does not appear
244
 
                twice in indexes to be created. */
245
 
 
246
 
                for (ulint i = 0; i < key_num; i++) {
247
 
                        const KEY&      key2 = key_info[i];
248
 
 
249
 
                        if (0 == strcmp(key.name, key2.name)) {
250
 
                                errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: key name `%s` appears"
251
 
                                                " twice in CREATE INDEX\n",
252
 
                                                key.name);
253
 
 
254
 
                                return(ER_WRONG_NAME_FOR_INDEX);
255
 
                        }
256
 
                }
257
 
 
258
 
                /* Check that MySQL does not try to create a column
259
 
                prefix index field on an inappropriate data type and
260
 
                that the same colum does not appear twice in the index. */
261
 
 
262
 
                for (ulint i = 0; i < key.key_parts; i++) {
263
 
                        const KEY_PART_INFO&    key_part1
264
 
                                = key.key_part[i];
265
 
                        const Field*            field
266
 
                                = key_part1.field;
267
 
                        ibool                   is_unsigned;
268
 
 
269
 
                        switch (get_innobase_type_from_mysql_type(
270
 
                                        &is_unsigned, field)) {
271
 
                        default:
272
 
                                break;
273
 
                        case DATA_INT:
274
 
                        case DATA_FLOAT:
275
 
                        case DATA_DOUBLE:
276
 
                        case DATA_DECIMAL:
277
 
                                if (field->type() == DRIZZLE_TYPE_VARCHAR) {
278
 
                                        if (key_part1.length
279
 
                                            >= field->pack_length()
280
 
                                            - ((Field_varstring*) field)
281
 
                                            ->length_bytes) {
282
 
                                                break;
283
 
                                        }
284
 
                                } else {
285
 
                                        if (key_part1.length
286
 
                                            >= field->pack_length()) {
287
 
                                                break;
288
 
                                        }
289
 
                                }
290
 
 
291
 
                                errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: MySQL is trying to"
292
 
                                                " create a column prefix"
293
 
                                                " index field on an"
294
 
                                                " inappropriate data type."
295
 
                                                " column `%s`,"
296
 
                                                " index `%s`.\n",
297
 
                                                field->field_name,
298
 
                                                key.name);
299
 
                                return(ER_WRONG_KEY_COLUMN);
300
 
                        }
301
 
 
302
 
                        for (ulint j = 0; j < i; j++) {
303
 
                                const KEY_PART_INFO&    key_part2
304
 
                                        = key.key_part[j];
305
 
 
306
 
                                if (strcmp(key_part1.field->field_name,
307
 
                                           key_part2.field->field_name)) {
308
 
                                        continue;
309
 
                                }
310
 
 
311
 
                                errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: column `%s`"
312
 
                                                " is not allowed to occur"
313
 
                                                " twice in index `%s`.\n",
314
 
                                                key_part1.field->field_name,
315
 
                                                key.name);
316
 
                                return(ER_WRONG_KEY_COLUMN);
317
 
                        }
318
 
                }
319
 
        }
320
 
 
321
 
        return(0);
322
 
}
323
 
 
324
 
/*******************************************************************//**
325
 
Create index field definition for key part */
326
 
static
327
 
void
328
 
innobase_create_index_field_def(
329
 
/*============================*/
330
 
        KEY_PART_INFO*          key_part,       /*!< in: MySQL key definition */
331
 
        mem_heap_t*             heap,           /*!< in: memory heap */
332
 
        merge_index_field_t*    index_field)    /*!< out: index field
333
 
                                                definition for key_part */
334
 
{
335
 
        Field*          field;
336
 
        ibool           is_unsigned;
337
 
        ulint           col_type;
338
 
 
339
 
        ut_ad(key_part);
340
 
        ut_ad(index_field);
341
 
 
342
 
        field = key_part->field;
343
 
        ut_a(field);
344
 
 
345
 
        col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
346
 
 
347
 
        if (DATA_BLOB == col_type
348
 
            || (key_part->length < field->pack_length()
349
 
                && field->type() != DRIZZLE_TYPE_VARCHAR)
350
 
            || (field->type() == DRIZZLE_TYPE_VARCHAR
351
 
                && key_part->length < field->pack_length()
352
 
                        - ((Field_varstring*)field)->length_bytes)) {
353
 
 
354
 
                index_field->prefix_len = key_part->length;
355
 
        } else {
356
 
                index_field->prefix_len = 0;
357
 
        }
358
 
 
359
 
        index_field->field_name = mem_heap_strdup(heap, field->field_name);
360
 
 
361
 
        return;
362
 
}
363
 
 
364
 
/*******************************************************************//**
365
 
Create index definition for key */
366
 
static
367
 
void
368
 
innobase_create_index_def(
369
 
/*======================*/
370
 
        KEY*                    key,            /*!< in: key definition */
371
 
        bool                    new_primary,    /*!< in: TRUE=generating
372
 
                                                a new primary key
373
 
                                                on the table */
374
 
        bool                    key_primary,    /*!< in: TRUE if this key
375
 
                                                is a primary key */
376
 
        merge_index_def_t*      index,          /*!< out: index definition */
377
 
        mem_heap_t*             heap)           /*!< in: heap where memory
378
 
                                                is allocated */
379
 
{
380
 
        ulint   i;
381
 
        ulint   len;
382
 
        ulint   n_fields = key->key_parts;
383
 
        char*   index_name;
384
 
 
385
 
        index->fields = (merge_index_field_t*) mem_heap_alloc(
386
 
                heap, n_fields * sizeof *index->fields);
387
 
 
388
 
        index->ind_type = 0;
389
 
        index->n_fields = n_fields;
390
 
        len = strlen(key->name) + 1;
391
 
        index->name = index_name = (char*) mem_heap_alloc(heap,
392
 
                                                          len + !new_primary);
393
 
 
394
 
        if (UNIV_LIKELY(!new_primary)) {
395
 
                *index_name++ = TEMP_INDEX_PREFIX;
396
 
        }
397
 
 
398
 
        memcpy(index_name, key->name, len);
399
 
 
400
 
        if (key->flags & HA_NOSAME) {
401
 
                index->ind_type |= DICT_UNIQUE;
402
 
        }
403
 
 
404
 
        if (key_primary) {
405
 
                index->ind_type |= DICT_CLUSTERED;
406
 
        }
407
 
 
408
 
        for (i = 0; i < n_fields; i++) {
409
 
                innobase_create_index_field_def(&key->key_part[i], heap,
410
 
                                                &index->fields[i]);
411
 
        }
412
 
 
413
 
        return;
414
 
}
415
 
 
416
 
/*******************************************************************//**
417
 
Copy index field definition */
418
 
static
419
 
void
420
 
innobase_copy_index_field_def(
421
 
/*==========================*/
422
 
        const dict_field_t*     field,          /*!< in: definition to copy */
423
 
        merge_index_field_t*    index_field)    /*!< out: copied definition */
424
 
{
425
 
        assert(field != NULL);
426
 
        assert(index_field != NULL);
427
 
 
428
 
        index_field->field_name = field->name;
429
 
        index_field->prefix_len = field->prefix_len;
430
 
 
431
 
        return;
432
 
}
433
 
 
434
 
/*******************************************************************//**
435
 
Copy index definition for the index */
436
 
static
437
 
void
438
 
innobase_copy_index_def(
439
 
/*====================*/
440
 
        const dict_index_t*     index,  /*!< in: index definition to copy */
441
 
        merge_index_def_t*      new_index,/*!< out: Index definition */
442
 
        mem_heap_t*             heap)   /*!< in: heap where allocated */
443
 
{
444
 
        ulint   n_fields;
445
 
        ulint   i;
446
 
 
447
 
        /* Note that we take only those fields that user defined to be
448
 
        in the index.  In the internal representation more colums were
449
 
        added and those colums are not copied .*/
450
 
 
451
 
        n_fields = index->n_user_defined_cols;
452
 
 
453
 
        new_index->fields = (merge_index_field_t*) mem_heap_alloc(
454
 
                heap, n_fields * sizeof *new_index->fields);
455
 
 
456
 
        /* When adding a PRIMARY KEY, we may convert a previous
457
 
        clustered index to a secondary index (UNIQUE NOT NULL). */
458
 
        new_index->ind_type = index->type & ~DICT_CLUSTERED;
459
 
        new_index->n_fields = n_fields;
460
 
        new_index->name = index->name;
461
 
 
462
 
        for (i = 0; i < n_fields; i++) {
463
 
                innobase_copy_index_field_def(&index->fields[i],
464
 
                                              &new_index->fields[i]);
465
 
        }
466
 
 
467
 
        return;
468
 
}
469
 
 
470
 
/*******************************************************************//**
471
 
Create an index table where indexes are ordered as follows:
472
 
 
473
 
IF a new primary key is defined for the table THEN
474
 
 
475
 
        1) New primary key
476
 
        2) Original secondary indexes
477
 
        3) New secondary indexes
478
 
 
479
 
ELSE
480
 
 
481
 
        1) All new indexes in the order they arrive from MySQL
482
 
 
483
 
ENDIF
484
 
 
485
 
 
486
 
@return key definitions or NULL */
487
 
static
488
 
merge_index_def_t*
489
 
innobase_create_key_def(
490
 
/*====================*/
491
 
        trx_t*          trx,            /*!< in: trx */
492
 
        const dict_table_t*table,               /*!< in: table definition */
493
 
        mem_heap_t*     heap,           /*!< in: heap where space for key
494
 
                                        definitions are allocated */
495
 
        KEY*            key_info,       /*!< in: Indexes to be created */
496
 
        ulint&          n_keys)         /*!< in/out: Number of indexes to
497
 
                                        be created */
498
 
{
499
 
        ulint                   i = 0;
500
 
        merge_index_def_t*      indexdef;
501
 
        merge_index_def_t*      indexdefs;
502
 
        bool                    new_primary;
503
 
 
504
 
        indexdef = indexdefs = (merge_index_def_t*)
505
 
                mem_heap_alloc(heap, sizeof *indexdef
506
 
                               * (n_keys + UT_LIST_GET_LEN(table->indexes)));
507
 
 
508
 
        /* If there is a primary key, it is always the first index
509
 
        defined for the table. */
510
 
 
511
 
        new_primary = !my_strcasecmp(system_charset_info,
512
 
                                     key_info->name, "PRIMARY");
513
 
 
514
 
        /* If there is a UNIQUE INDEX consisting entirely of NOT NULL
515
 
        columns, MySQL will treat it as a PRIMARY KEY unless the
516
 
        table already has one. */
517
 
 
518
 
        if (!new_primary && (key_info->flags & HA_NOSAME)
519
 
            && row_table_got_default_clust_index(table)) {
520
 
                uint    key_part = key_info->key_parts;
521
 
 
522
 
                new_primary = TRUE;
523
 
 
524
 
                while (key_part--) {
525
 
                        if (key_info->key_part[key_part].null_bit == 0) {
526
 
                                new_primary = FALSE;
527
 
                                break;
528
 
                        }
529
 
                }
530
 
        }
531
 
 
532
 
        if (new_primary) {
533
 
                const dict_index_t*     index;
534
 
 
535
 
                /* Create the PRIMARY key index definition */
536
 
                innobase_create_index_def(&key_info[i++], TRUE, TRUE,
537
 
                                          indexdef++, heap);
538
 
 
539
 
                row_mysql_lock_data_dictionary(trx);
540
 
 
541
 
                index = dict_table_get_first_index(table);
542
 
 
543
 
                /* Copy the index definitions of the old table.  Skip
544
 
                the old clustered index if it is a generated clustered
545
 
                index or a PRIMARY KEY.  If the clustered index is a
546
 
                UNIQUE INDEX, it must be converted to a secondary index. */
547
 
 
548
 
                if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
549
 
                    || !my_strcasecmp(system_charset_info,
550
 
                                      index->name, "PRIMARY")) {
551
 
                        index = dict_table_get_next_index(index);
552
 
                }
553
 
 
554
 
                while (index) {
555
 
                        innobase_copy_index_def(index, indexdef++, heap);
556
 
                        index = dict_table_get_next_index(index);
557
 
                }
558
 
 
559
 
                row_mysql_unlock_data_dictionary(trx);
560
 
        }
561
 
 
562
 
        /* Create definitions for added secondary indexes. */
563
 
 
564
 
        while (i < n_keys) {
565
 
                innobase_create_index_def(&key_info[i++], new_primary, FALSE,
566
 
                                          indexdef++, heap);
567
 
        }
568
 
 
569
 
        n_keys = indexdef - indexdefs;
570
 
 
571
 
        return(indexdefs);
572
 
}
573
 
 
574
 
/*******************************************************************//**
575
 
Create a temporary tablename using query id, thread id, and id
576
 
@return temporary tablename */
577
 
static
578
 
char*
579
 
innobase_create_temporary_tablename(
580
 
/*================================*/
581
 
        mem_heap_t*     heap,           /*!< in: memory heap */
582
 
        char            id,             /*!< in: identifier [0-9a-zA-Z] */
583
 
        const char*     table_name)     /*!< in: table name */
584
 
{
585
 
        char*                   name;
586
 
        ulint                   len;
587
 
        static const char       suffix[] = "@0023 "; /* "# " */
588
 
 
589
 
        len = strlen(table_name);
590
 
 
591
 
        name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
592
 
        memcpy(name, table_name, len);
593
 
        memcpy(name + len, suffix, sizeof suffix);
594
 
        name[len + (sizeof suffix - 2)] = id;
595
 
 
596
 
        return(name);
597
 
}
598
 
 
599
 
/*******************************************************************//**
600
 
Create indexes.
601
 
@return 0 or error number */
602
 
UNIV_INTERN
603
 
int
604
 
ha_innobase::add_index(
605
 
/*===================*/
606
 
        Table*  i_table,        /*!< in: Table where indexes are created */
607
 
        KEY*    key_info,       /*!< in: Indexes to be created */
608
 
        uint    num_of_keys)    /*!< in: Number of indexes to be created */
609
 
{
610
 
        dict_index_t**  index;          /*!< Index to be created */
611
 
        dict_table_t*   innodb_table;   /*!< InnoDB table in dictionary */
612
 
        dict_table_t*   indexed_table;  /*!< Table where indexes are created */
613
 
        merge_index_def_t* index_defs;  /*!< Index definitions */
614
 
        mem_heap_t*     heap;           /*!< Heap for index definitions */
615
 
        trx_t*          trx;            /*!< Transaction */
616
 
        ulint           num_of_idx;
617
 
        ulint           num_created     = 0;
618
 
        ibool           dict_locked     = FALSE;
619
 
        ulint           new_primary;
620
 
        ulint           error;
621
 
 
622
 
        ut_a(i_table);
623
 
        ut_a(key_info);
624
 
        ut_a(num_of_keys);
625
 
 
626
 
        if (srv_created_new_raw || srv_force_recovery) {
627
 
                return(HA_ERR_WRONG_COMMAND);
628
 
        }
629
 
 
630
 
        update_session();
631
 
 
632
 
        heap = mem_heap_create(1024);
633
 
 
634
 
        /* In case MySQL calls this in the middle of a SELECT query, release
635
 
        possible adaptive hash latch to avoid deadlocks of threads. */
636
 
        trx_search_latch_release_if_reserved(prebuilt->trx);
637
 
        trx_start_if_not_started(prebuilt->trx);
638
 
 
639
 
        /* Create a background transaction for the operations on
640
 
        the data dictionary tables. */
641
 
        trx = innobase_trx_allocate(user_session);
642
 
        trx_start_if_not_started(trx);
643
 
 
644
 
        innodb_table = indexed_table
645
 
                = dict_table_get(prebuilt->table->name, FALSE);
646
 
 
647
 
        /* Check that index keys are sensible */
648
 
 
649
 
        error = innobase_check_index_keys(key_info, num_of_keys);
650
 
 
651
 
        if (UNIV_UNLIKELY(error)) {
652
 
err_exit:
653
 
                mem_heap_free(heap);
654
 
                trx_general_rollback_for_mysql(trx, FALSE, NULL);
655
 
                trx_free_for_mysql(trx);
656
 
                trx_commit_for_mysql(prebuilt->trx);
657
 
                return(error);
658
 
        }
659
 
 
660
 
        /* Create table containing all indexes to be built in this
661
 
        alter table add index so that they are in the correct order
662
 
        in the table. */
663
 
 
664
 
        num_of_idx = num_of_keys;
665
 
 
666
 
        index_defs = innobase_create_key_def(
667
 
                trx, innodb_table, heap, key_info, num_of_idx);
668
 
 
669
 
        new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
670
 
 
671
 
        /* Allocate memory for dictionary index definitions */
672
 
 
673
 
        index = (dict_index_t**) mem_heap_alloc(
674
 
                heap, num_of_idx * sizeof *index);
675
 
 
676
 
        /* Flag this transaction as a dictionary operation, so that
677
 
        the data dictionary will be locked in crash recovery. */
678
 
        trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
679
 
 
680
 
        /* Acquire a lock on the table before creating any indexes. */
681
 
        error = row_merge_lock_table(prebuilt->trx, innodb_table,
682
 
                                     new_primary ? LOCK_X : LOCK_S);
683
 
 
684
 
        if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
685
 
 
686
 
                goto error_handling;
687
 
        }
688
 
 
689
 
        /* Latch the InnoDB data dictionary exclusively so that no deadlocks
690
 
        or lock waits can happen in it during an index create operation. */
691
 
 
692
 
        row_mysql_lock_data_dictionary(trx);
693
 
        dict_locked = TRUE;
694
 
 
695
 
        /* If a new primary key is defined for the table we need
696
 
        to drop the original table and rebuild all indexes. */
697
 
 
698
 
        if (UNIV_UNLIKELY(new_primary)) {
699
 
                /* This transaction should be the only one
700
 
                operating on the table. */
701
 
                ut_a(innodb_table->n_mysql_handles_opened == 1);
702
 
 
703
 
                char*   new_table_name = innobase_create_temporary_tablename(
704
 
                        heap, '1', innodb_table->name);
705
 
 
706
 
                /* Clone the table. */
707
 
                trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
708
 
                indexed_table = row_merge_create_temporary_table(
709
 
                        new_table_name, index_defs, innodb_table, trx);
710
 
 
711
 
                if (!indexed_table) {
712
 
 
713
 
                        switch (trx->error_state) {
714
 
                        case DB_TABLESPACE_ALREADY_EXISTS:
715
 
                        case DB_DUPLICATE_KEY:
716
 
                                innobase_convert_tablename(new_table_name);
717
 
                                my_error(HA_ERR_TABLE_EXIST, MYF(0),
718
 
                                         new_table_name);
719
 
                                error = HA_ERR_TABLE_EXIST;
720
 
                                break;
721
 
                        default:
722
 
                                error = convert_error_code_to_mysql(
723
 
                                        trx->error_state, innodb_table->flags,
724
 
                                        user_session);
725
 
                        }
726
 
 
727
 
                        row_mysql_unlock_data_dictionary(trx);
728
 
                        goto err_exit;
729
 
                }
730
 
 
731
 
                trx->table_id = indexed_table->id;
732
 
        }
733
 
 
734
 
        /* Create the indexes in SYS_INDEXES and load into dictionary. */
735
 
 
736
 
        for (ulint i = 0; i < num_of_idx; i++) {
737
 
 
738
 
                index[i] = row_merge_create_index(trx, indexed_table,
739
 
                                                  &index_defs[i]);
740
 
 
741
 
                if (!index[i]) {
742
 
                        error = trx->error_state;
743
 
                        goto error_handling;
744
 
                }
745
 
 
746
 
                num_created++;
747
 
        }
748
 
 
749
 
        ut_ad(error == DB_SUCCESS);
750
 
 
751
 
        /* Commit the data dictionary transaction in order to release
752
 
        the table locks on the system tables.  Unfortunately, this
753
 
        means that if MySQL crashes while creating a new primary key
754
 
        inside row_merge_build_indexes(), indexed_table will not be
755
 
        dropped on crash recovery.  Thus, it will become orphaned. */
756
 
        trx_commit_for_mysql(trx);
757
 
 
758
 
        row_mysql_unlock_data_dictionary(trx);
759
 
        dict_locked = FALSE;
760
 
 
761
 
        ut_a(trx->n_active_thrs == 0);
762
 
        ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
763
 
 
764
 
        if (UNIV_UNLIKELY(new_primary)) {
765
 
                /* A primary key is to be built.  Acquire an exclusive
766
 
                table lock also on the table that is being created. */
767
 
                ut_ad(indexed_table != innodb_table);
768
 
 
769
 
                error = row_merge_lock_table(prebuilt->trx, indexed_table,
770
 
                                             LOCK_X);
771
 
 
772
 
                if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
773
 
 
774
 
                        goto error_handling;
775
 
                }
776
 
        }
777
 
 
778
 
        /* Read the clustered index of the table and build indexes
779
 
        based on this information using temporary files and merge sort. */
780
 
        error = row_merge_build_indexes(prebuilt->trx,
781
 
                                        innodb_table, indexed_table,
782
 
                                        index, num_of_idx, i_table);
783
 
 
784
 
error_handling:
785
 
#ifdef UNIV_DEBUG
786
 
        /* TODO: At the moment we can't handle the following statement
787
 
        in our debugging code below:
788
 
 
789
 
        alter table t drop index b, add index (b);
790
 
 
791
 
        The fix will have to parse the SQL and note that the index
792
 
        being added has the same name as the the one being dropped and
793
 
        ignore that in the dup index check.*/
794
 
        //dict_table_check_for_dup_indexes(prebuilt->table);
795
 
#endif
796
 
 
797
 
        /* After an error, remove all those index definitions from the
798
 
        dictionary which were defined. */
799
 
 
800
 
        switch (error) {
801
 
                const char*     old_name;
802
 
                char*           tmp_name;
803
 
        case DB_SUCCESS:
804
 
                ut_a(!dict_locked);
805
 
                row_mysql_lock_data_dictionary(trx);
806
 
                dict_locked = TRUE;
807
 
 
808
 
                if (!new_primary) {
809
 
                        error = row_merge_rename_indexes(trx, indexed_table);
810
 
 
811
 
                        if (error != DB_SUCCESS) {
812
 
                                row_merge_drop_indexes(trx, indexed_table,
813
 
                                                       index, num_created);
814
 
                        }
815
 
 
816
 
                        goto convert_error;
817
 
                }
818
 
 
819
 
                /* If a new primary key was defined for the table and
820
 
                there was no error at this point, we can now rename
821
 
                the old table as a temporary table, rename the new
822
 
                temporary table as the old table and drop the old table. */
823
 
                old_name = innodb_table->name;
824
 
                tmp_name = innobase_create_temporary_tablename(heap, '2',
825
 
                                                               old_name);
826
 
 
827
 
                error = row_merge_rename_tables(innodb_table, indexed_table,
828
 
                                                tmp_name, trx);
829
 
 
830
 
                if (error != DB_SUCCESS) {
831
 
 
832
 
                        row_merge_drop_table(trx, indexed_table);
833
 
 
834
 
                        switch (error) {
835
 
                        case DB_TABLESPACE_ALREADY_EXISTS:
836
 
                        case DB_DUPLICATE_KEY:
837
 
                                innobase_convert_tablename(tmp_name);
838
 
                                my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
839
 
                                error = HA_ERR_TABLE_EXIST;
840
 
                                break;
841
 
                        default:
842
 
                                goto convert_error;
843
 
                        }
844
 
                        break;
845
 
                }
846
 
 
847
 
                trx_commit_for_mysql(prebuilt->trx);
848
 
                row_prebuilt_free(prebuilt, TRUE);
849
 
                prebuilt = row_create_prebuilt(indexed_table);
850
 
 
851
 
                indexed_table->n_mysql_handles_opened++;
852
 
 
853
 
                error = row_merge_drop_table(trx, innodb_table);
854
 
                goto convert_error;
855
 
 
856
 
        case DB_TOO_BIG_RECORD:
857
 
                my_error(HA_ERR_TO_BIG_ROW, MYF(0));
858
 
                goto error;
859
 
        case DB_PRIMARY_KEY_IS_NULL:
860
 
                my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
861
 
                /* fall through */
862
 
        case DB_DUPLICATE_KEY:
863
 
error:
864
 
                prebuilt->trx->error_info = NULL;
865
 
                /* fall through */
866
 
        default:
867
 
                if (new_primary) {
868
 
                        row_merge_drop_table(trx, indexed_table);
869
 
                } else {
870
 
                        if (!dict_locked) {
871
 
                                row_mysql_lock_data_dictionary(trx);
872
 
                                dict_locked = TRUE;
873
 
                        }
874
 
 
875
 
                        row_merge_drop_indexes(trx, indexed_table,
876
 
                                               index, num_created);
877
 
                }
878
 
 
879
 
convert_error:
880
 
                error = convert_error_code_to_mysql(error,
881
 
                                                    innodb_table->flags,
882
 
                                                    user_session);
883
 
        }
884
 
 
885
 
        mem_heap_free(heap);
886
 
        trx_commit_for_mysql(trx);
887
 
        if (prebuilt->trx) {
888
 
                trx_commit_for_mysql(prebuilt->trx);
889
 
        }
890
 
 
891
 
        if (dict_locked) {
892
 
                row_mysql_unlock_data_dictionary(trx);
893
 
        }
894
 
 
895
 
        trx_free_for_mysql(trx);
896
 
 
897
 
        /* There might be work for utility threads.*/
898
 
        srv_active_wake_master_thread();
899
 
 
900
 
        return(error);
901
 
}
902
 
 
903
 
/*******************************************************************//**
904
 
Prepare to drop some indexes of a table.
905
 
@return 0 or error number */
906
 
UNIV_INTERN
907
 
int
908
 
ha_innobase::prepare_drop_index(
909
 
/*============================*/
910
 
        Table*  i_table,        /*!< in: Table where indexes are dropped */
911
 
        uint*   key_num,        /*!< in: Key nums to be dropped */
912
 
        uint    num_of_keys)    /*!< in: Number of keys to be dropped */
913
 
{
914
 
        trx_t*          trx;
915
 
        int             err = 0;
916
 
        uint            n_key;
917
 
 
918
 
        ut_ad(i_table);
919
 
        ut_ad(key_num);
920
 
        ut_ad(num_of_keys);
921
 
        if (srv_created_new_raw || srv_force_recovery) {
922
 
                return(HA_ERR_WRONG_COMMAND);
923
 
        }
924
 
 
925
 
        update_session();
926
 
 
927
 
        trx_search_latch_release_if_reserved(prebuilt->trx);
928
 
        trx = prebuilt->trx;
929
 
 
930
 
        /* Test and mark all the indexes to be dropped */
931
 
 
932
 
        row_mysql_lock_data_dictionary(trx);
933
 
 
934
 
        /* Check that none of the indexes have previously been flagged
935
 
        for deletion. */
936
 
        {
937
 
                const dict_index_t*     index
938
 
                        = dict_table_get_first_index(prebuilt->table);
939
 
                do {
940
 
                        ut_a(!index->to_be_dropped);
941
 
                        index = dict_table_get_next_index(index);
942
 
                } while (index);
943
 
        }
944
 
 
945
 
        for (n_key = 0; n_key < num_of_keys; n_key++) {
946
 
                const KEY*      key;
947
 
                dict_index_t*   index;
948
 
 
949
 
                key = i_table->key_info + key_num[n_key];
950
 
                index = dict_table_get_index_on_name_and_min_id(
951
 
                        prebuilt->table, key->name);
952
 
 
953
 
                if (!index) {
954
 
                        errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB could not find key n:o %u "
955
 
                                        "with name %s for table %s",
956
 
                                        key_num[n_key],
957
 
                                        key ? key->name : "NULL",
958
 
                                        prebuilt->table->name);
959
 
 
960
 
                        err = HA_ERR_KEY_NOT_FOUND;
961
 
                        goto func_exit;
962
 
                }
963
 
 
964
 
                /* Refuse to drop the clustered index.  It would be
965
 
                better to automatically generate a clustered index,
966
 
                but drizzled::alter_table() will call this method only
967
 
                after ha_innobase::add_index(). */
968
 
 
969
 
                if (dict_index_is_clust(index)) {
970
 
                        my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
971
 
                        err = -1;
972
 
                        goto func_exit;
973
 
                }
974
 
 
975
 
                index->to_be_dropped = TRUE;
976
 
        }
977
 
 
978
 
        /* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
979
 
        for a foreign key constraint because InnoDB requires that both
980
 
        tables contain indexes for the constraint.  Note that CREATE
981
 
        INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
982
 
        can ignore here foreign keys because a new index for the
983
 
        foreign key has already been created.
984
 
 
985
 
        We check for the foreign key constraints after marking the
986
 
        candidate indexes for deletion, because when we check for an
987
 
        equivalent foreign index we don't want to select an index that
988
 
        is later deleted. */
989
 
 
990
 
        if (trx->check_foreigns
991
 
            && session_sql_command(user_session) != SQLCOM_CREATE_INDEX) {
992
 
                dict_index_t*   index;
993
 
 
994
 
                for (index = dict_table_get_first_index(prebuilt->table);
995
 
                     index;
996
 
                     index = dict_table_get_next_index(index)) {
997
 
                        dict_foreign_t* foreign;
998
 
 
999
 
                        if (!index->to_be_dropped) {
1000
 
 
1001
 
                                continue;
1002
 
                        }
1003
 
 
1004
 
                        /* Check if the index is referenced. */
1005
 
                        foreign = dict_table_get_referenced_constraint(
1006
 
                                prebuilt->table, index);
1007
 
 
1008
 
                        if (foreign) {
1009
 
index_needed:
1010
 
                                trx_set_detailed_error(
1011
 
                                        trx,
1012
 
                                        "Index needed in foreign key "
1013
 
                                        "constraint");
1014
 
 
1015
 
                                trx->error_info = index;
1016
 
 
1017
 
                                err = HA_ERR_DROP_INDEX_FK;
1018
 
                                break;
1019
 
                        } else {
1020
 
                                /* Check if this index references some
1021
 
                                other table */
1022
 
                                foreign = dict_table_get_foreign_constraint(
1023
 
                                        prebuilt->table, index);
1024
 
 
1025
 
                                if (foreign) {
1026
 
                                        ut_a(foreign->foreign_index == index);
1027
 
 
1028
 
                                        /* Search for an equivalent index that
1029
 
                                        the foreign key constraint could use
1030
 
                                        if this index were to be deleted. */
1031
 
                                        if (!dict_foreign_find_equiv_index(
1032
 
                                                foreign)) {
1033
 
 
1034
 
                                                goto index_needed;
1035
 
                                        }
1036
 
                                }
1037
 
                        }
1038
 
                }
1039
 
        } else if (session_sql_command(user_session) == SQLCOM_CREATE_INDEX) {
1040
 
                /* This is a drop of a foreign key constraint index that
1041
 
                was created by MySQL when the constraint was added.  MySQL
1042
 
                does this when the user creates an index explicitly which
1043
 
                can be used in place of the automatically generated index. */
1044
 
 
1045
 
                dict_index_t*   index;
1046
 
 
1047
 
                for (index = dict_table_get_first_index(prebuilt->table);
1048
 
                     index;
1049
 
                     index = dict_table_get_next_index(index)) {
1050
 
                        dict_foreign_t* foreign;
1051
 
 
1052
 
                        if (!index->to_be_dropped) {
1053
 
 
1054
 
                                continue;
1055
 
                        }
1056
 
 
1057
 
                        /* Check if this index references some other table */
1058
 
                        foreign = dict_table_get_foreign_constraint(
1059
 
                                prebuilt->table, index);
1060
 
 
1061
 
                        if (foreign == NULL) {
1062
 
 
1063
 
                                continue;
1064
 
                        }
1065
 
 
1066
 
                        ut_a(foreign->foreign_index == index);
1067
 
 
1068
 
                        /* Search for an equivalent index that the
1069
 
                        foreign key constraint could use if this index
1070
 
                        were to be deleted. */
1071
 
 
1072
 
                        if (!dict_foreign_find_equiv_index(foreign)) {
1073
 
                                trx_set_detailed_error(
1074
 
                                        trx,
1075
 
                                        "Index needed in foreign key "
1076
 
                                        "constraint");
1077
 
 
1078
 
                                trx->error_info = foreign->foreign_index;
1079
 
 
1080
 
                                err = HA_ERR_DROP_INDEX_FK;
1081
 
                                break;
1082
 
                        }
1083
 
                }
1084
 
        }
1085
 
 
1086
 
func_exit:
1087
 
        if (err) {
1088
 
                /* Undo our changes since there was some sort of error. */
1089
 
                dict_index_t*   index
1090
 
                        = dict_table_get_first_index(prebuilt->table);
1091
 
 
1092
 
                do {
1093
 
                        index->to_be_dropped = FALSE;
1094
 
                        index = dict_table_get_next_index(index);
1095
 
                } while (index);
1096
 
        }
1097
 
 
1098
 
        row_mysql_unlock_data_dictionary(trx);
1099
 
 
1100
 
        return(err);
1101
 
}
1102
 
 
1103
 
/*******************************************************************//**
1104
 
Drop the indexes that were passed to a successful prepare_drop_index().
1105
 
@return 0 or error number */
1106
 
UNIV_INTERN
1107
 
int
1108
 
ha_innobase::final_drop_index(
1109
 
/*==========================*/
1110
 
        Table*  )               /*!< in: Table where indexes are dropped */
1111
 
{
1112
 
        dict_index_t*   index;          /*!< Index to be dropped */
1113
 
        trx_t*          trx;            /*!< Transaction */
1114
 
        int             err;
1115
 
 
1116
 
        if (srv_created_new_raw || srv_force_recovery) {
1117
 
                return(HA_ERR_WRONG_COMMAND);
1118
 
        }
1119
 
 
1120
 
        update_session();
1121
 
 
1122
 
        trx_search_latch_release_if_reserved(prebuilt->trx);
1123
 
        trx_start_if_not_started(prebuilt->trx);
1124
 
 
1125
 
        /* Create a background transaction for the operations on
1126
 
        the data dictionary tables. */
1127
 
        trx = innobase_trx_allocate(user_session);
1128
 
        trx_start_if_not_started(trx);
1129
 
 
1130
 
        /* Flag this transaction as a dictionary operation, so that
1131
 
        the data dictionary will be locked in crash recovery. */
1132
 
        trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1133
 
 
1134
 
        /* Lock the table exclusively, to ensure that no active
1135
 
        transaction depends on an index that is being dropped. */
1136
 
        err = convert_error_code_to_mysql(
1137
 
                row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1138
 
                prebuilt->table->flags, user_session);
1139
 
 
1140
 
        row_mysql_lock_data_dictionary(trx);
1141
 
 
1142
 
        if (UNIV_UNLIKELY(err)) {
1143
 
 
1144
 
                /* Unmark the indexes to be dropped. */
1145
 
                for (index = dict_table_get_first_index(prebuilt->table);
1146
 
                     index; index = dict_table_get_next_index(index)) {
1147
 
 
1148
 
                        index->to_be_dropped = FALSE;
1149
 
                }
1150
 
 
1151
 
                goto func_exit;
1152
 
        }
1153
 
 
1154
 
        /* Drop indexes marked to be dropped */
1155
 
 
1156
 
        index = dict_table_get_first_index(prebuilt->table);
1157
 
 
1158
 
        while (index) {
1159
 
                dict_index_t*   next_index;
1160
 
 
1161
 
                next_index = dict_table_get_next_index(index);
1162
 
 
1163
 
                if (index->to_be_dropped) {
1164
 
 
1165
 
                        row_merge_drop_index(index, prebuilt->table, trx);
1166
 
                }
1167
 
 
1168
 
                index = next_index;
1169
 
        }
1170
 
 
1171
 
        /* Check that all flagged indexes were dropped. */
1172
 
        for (index = dict_table_get_first_index(prebuilt->table);
1173
 
             index; index = dict_table_get_next_index(index)) {
1174
 
                ut_a(!index->to_be_dropped);
1175
 
        }
1176
 
 
1177
 
#ifdef UNIV_DEBUG
1178
 
        dict_table_check_for_dup_indexes(prebuilt->table);
1179
 
#endif
1180
 
 
1181
 
func_exit:
1182
 
        trx_commit_for_mysql(trx);
1183
 
        trx_commit_for_mysql(prebuilt->trx);
1184
 
        row_mysql_unlock_data_dictionary(trx);
1185
 
 
1186
 
        /* Flush the log to reduce probability that the .frm files and
1187
 
        the InnoDB data dictionary get out-of-sync if the user runs
1188
 
        with innodb_flush_log_at_trx_commit = 0 */
1189
 
 
1190
 
        log_buffer_flush_to_disk();
1191
 
 
1192
 
        trx_free_for_mysql(trx);
1193
 
 
1194
 
        /* Tell the InnoDB server that there might be work for
1195
 
        utility threads: */
1196
 
 
1197
 
        srv_active_wake_master_thread();
1198
 
 
1199
 
        return(err);
1200
 
}