~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

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