~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-01-22 00:53:13 UTC
  • Revision ID: brian@gaz-20100122005313-jmizcbcdi1lt4tcx
Revert db patch.

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