~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2009-04-14 19:16:51 UTC
  • mto: (997.2.5 mordred)
  • mto: This revision was merged to the branch mainline in revision 994.
  • Revision ID: mordred@inaugust.com-20090414191651-ltbww6hpqks8k7qk
Clarified instructions in README.

Show diffs side-by-side

added added

removed removed

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