~ubuntu-branches/ubuntu/saucy/drizzle/saucy-proposed

« back to all changes in this revision

Viewing changes to .pc/debian-changes-2010.12.06-0ubuntu4/plugin/innobase/handler/handler0alter.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2011-01-04 09:31:58 UTC
  • mfrom: (1.2.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20110104093158-smhgvkfdi2y9au3i
Tags: 2011.01.07-0ubuntu1
New upstream release.

Show diffs side-by-side

added added

removed removed

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