1
/******************************************************
4
(c) 2005-2008 Innobase Oy
5
*******************************************************/
7
#include <drizzled/common_includes.h>
8
#include <drizzled/error.h>
9
#include <mystrings/m_ctype.h>
10
#include <drizzled/field.h>
11
#include <drizzled/table.h>
12
#include <drizzled/log.h>
13
#include <drizzled/field/varstring.h>
17
#include "row0merge.h"
21
#include "ha_prototypes.h"
22
#include "handler0alter.h"
25
#include "ha_innodb.h"
27
/*****************************************************************
28
Copies an InnoDB column to a MySQL field. This function is
29
adapted from row_sel_field_store_in_mysql_format(). */
32
innobase_col_to_mysql(
33
/*==================*/
34
const dict_col_t* col, /* in: InnoDB column */
35
const unsigned char* data, /* in: InnoDB column data */
36
ulint len, /* in: length of data, in bytes */
37
Field* field) /* in/out: MySQL field */
40
unsigned char* dest = field->ptr;
41
ulint flen = field->pack_length();
47
/* Convert integer data from Innobase to little-endian
48
format, sign bit restored to normal */
50
for (ptr = dest + len; ptr != dest; ) {
54
if (!(field->flags & UNSIGNED_FLAG)) {
55
((byte*) dest)[len - 1] ^= 0x80;
65
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
66
/* This is a >= 5.0.3 type true VARCHAR. Store the
67
length of the data to the first byte or the first
70
dest = row_mysql_store_true_var_len(
71
dest, len, flen - field->key_length());
74
/* Copy the actual data */
75
memcpy(dest, data, len);
79
/* Store a pointer to the BLOB buffer to dest: the BLOB was
80
already copied to the buffer in row_sel_store_mysql_rec */
82
row_mysql_store_blob_ref(dest, flen, data, len);
88
ut_ad(col->mbmaxlen >= col->mbminlen);
89
ut_ad(col->mbmaxlen > col->mbminlen || flen == len);
90
memcpy(dest, data, len);
96
/* These column types should never be shipped to MySQL. */
104
/* Above are the valid column types for MySQL data. */
106
#else /* UNIV_DEBUG */
108
#endif /* UNIV_DEBUG */
109
memcpy(dest, data, len);
113
/*****************************************************************
114
Copies an InnoDB record to table->record[0]. */
115
extern "C" UNIV_INTERN
117
innobase_rec_to_mysql(
118
/*==================*/
119
Table* table, /* in/out: MySQL table */
120
const rec_t* rec, /* in: record */
121
const dict_index_t* index, /* in: index */
122
const ulint* offsets) /* in: rec_get_offsets(
125
uint n_fields = table->s->fields;
128
ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
130
for (i = 0; i < n_fields; i++) {
131
Field* field = table->field[i];
134
const unsigned char* ifield;
138
ipos = dict_index_get_nth_col_pos(index, i);
140
if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
146
ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
148
/* Assign the NULL flag */
149
if (ilen == UNIV_SQL_NULL) {
150
ut_ad(field->real_maybe_null());
154
field->set_notnull();
156
innobase_col_to_mysql(
158
dict_index_get_nth_field(index, ipos)),
159
ifield, ilen, field);
163
/*****************************************************************
164
Resets table->record[0]. */
165
extern "C" UNIV_INTERN
169
Table* table) /* in/out: MySQL table */
171
uint n_fields = table->s->fields;
174
for (i = 0; i < n_fields; i++) {
175
table->field[i]->set_default();
179
/**********************************************************************
180
Removes the filename encoding of a database and table name. */
183
innobase_convert_tablename(
184
/*=======================*/
185
char* s) /* in: identifier; out: decoded identifier */
189
char* slash = strchr(s, '/');
193
/* Temporarily replace the '/' with NUL. */
195
/* Convert the database name. */
196
strconvert(&my_charset_filename, s, system_charset_info,
197
s, slash - s + 1, &errors);
201
/* Append a '.' after the database name. */
204
/* Convert the table name. */
205
strconvert(&my_charset_filename, slash, system_charset_info,
206
t, slash - t + strlen(slash), &errors);
208
strconvert(&my_charset_filename, s,
209
system_charset_info, s, strlen(s), &errors);
213
/***********************************************************************
214
This function checks that index keys are sensible. */
217
innobase_check_index_keys(
218
/*======================*/
219
/* out: 0 or error number */
220
const KEY* key_info, /* in: Indexes to be created */
221
ulint num_of_keys) /* in: Number of indexes to
229
for (key_num = 0; key_num < num_of_keys; key_num++) {
230
const KEY& key = key_info[key_num];
232
/* Check that the same index name does not appear
233
twice in indexes to be created. */
235
for (ulint i = 0; i < key_num; i++) {
236
const KEY& key2 = key_info[i];
238
if (0 == strcmp(key.name, key2.name)) {
239
sql_print_error("InnoDB: key name `%s` appears"
240
" twice in CREATE INDEX\n",
243
return(ER_WRONG_NAME_FOR_INDEX);
247
/* Check that MySQL does not try to create a column
248
prefix index field on an inappropriate data type and
249
that the same colum does not appear twice in the index. */
251
for (ulint i = 0; i < key.key_parts; i++) {
252
const KEY_PART_INFO& key_part1
258
switch (get_innobase_type_from_mysql_type(
259
&is_unsigned, field)) {
266
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
268
>= field->pack_length()
269
- ((Field_varstring*) field)
275
>= field->pack_length()) {
280
sql_print_error("InnoDB: MySQL is trying to"
281
" create a column prefix"
283
" inappropriate data type."
288
return(ER_WRONG_KEY_COLUMN);
291
for (ulint j = 0; j < i; j++) {
292
const KEY_PART_INFO& key_part2
295
if (strcmp(key_part1.field->field_name,
296
key_part2.field->field_name)) {
300
sql_print_error("InnoDB: column `%s`"
301
" is not allowed to occur"
302
" twice in index `%s`.\n",
303
key_part1.field->field_name,
305
return(ER_WRONG_KEY_COLUMN);
313
/***********************************************************************
314
Create index field definition for key part */
317
innobase_create_index_field_def(
318
/*============================*/
319
KEY_PART_INFO* key_part, /* in: MySQL key definition */
320
mem_heap_t* heap, /* in: memory heap */
321
merge_index_field_t* index_field) /* out: index field
322
definition for key_part */
331
field = key_part->field;
334
col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
336
if (DATA_BLOB == col_type
337
|| (key_part->length < field->pack_length()
338
&& field->type() != DRIZZLE_TYPE_VARCHAR)
339
|| (field->type() == DRIZZLE_TYPE_VARCHAR
340
&& key_part->length < field->pack_length()
341
- ((Field_varstring*)field)->length_bytes)) {
343
index_field->prefix_len = key_part->length;
345
index_field->prefix_len = 0;
348
index_field->field_name = mem_heap_strdup(heap, field->field_name);
353
/***********************************************************************
354
Create index definition for key */
357
innobase_create_index_def(
358
/*======================*/
359
KEY* key, /* in: key definition */
360
bool new_primary, /* in: TRUE=generating
363
bool key_primary, /* in: TRUE if this key
365
merge_index_def_t* index, /* out: index definition */
366
mem_heap_t* heap) /* in: heap where memory
371
ulint n_fields = key->key_parts;
374
index->fields = (merge_index_field_t*) mem_heap_alloc(
375
heap, n_fields * sizeof *index->fields);
378
index->n_fields = n_fields;
379
len = strlen(key->name) + 1;
380
index->name = index_name = (char*) mem_heap_alloc(heap,
383
if (UNIV_LIKELY(!new_primary)) {
384
*index_name++ = TEMP_INDEX_PREFIX;
387
memcpy(index_name, key->name, len);
389
if (key->flags & HA_NOSAME) {
390
index->ind_type |= DICT_UNIQUE;
394
index->ind_type |= DICT_CLUSTERED;
397
for (i = 0; i < n_fields; i++) {
398
innobase_create_index_field_def(&key->key_part[i], heap,
405
/***********************************************************************
406
Copy index field definition */
409
innobase_copy_index_field_def(
410
/*==========================*/
411
const dict_field_t* field, /* in: definition to copy */
412
merge_index_field_t* index_field) /* out: copied definition */
414
assert(field != NULL);
415
assert(index_field != NULL);
417
index_field->field_name = field->name;
418
index_field->prefix_len = field->prefix_len;
423
/***********************************************************************
424
Copy index definition for the index */
427
innobase_copy_index_def(
428
/*====================*/
429
const dict_index_t* index, /* in: index definition to copy */
430
merge_index_def_t* new_index,/* out: Index definition */
431
mem_heap_t* heap) /* in: heap where allocated */
436
/* Note that we take only those fields that user defined to be
437
in the index. In the internal representation more colums were
438
added and those colums are not copied .*/
440
n_fields = index->n_user_defined_cols;
442
new_index->fields = (merge_index_field_t*) mem_heap_alloc(
443
heap, n_fields * sizeof *new_index->fields);
445
/* When adding a PRIMARY KEY, we may convert a previous
446
clustered index to a secondary index (UNIQUE NOT NULL). */
447
new_index->ind_type = index->type & ~DICT_CLUSTERED;
448
new_index->n_fields = n_fields;
449
new_index->name = index->name;
451
for (i = 0; i < n_fields; i++) {
452
innobase_copy_index_field_def(&index->fields[i],
453
&new_index->fields[i]);
459
/***********************************************************************
460
Create an index table where indexes are ordered as follows:
462
IF a new primary key is defined for the table THEN
465
2) Original secondary indexes
466
3) New secondary indexes
470
1) All new indexes in the order they arrive from MySQL
477
innobase_create_key_def(
478
/*====================*/
479
/* out: key definitions or NULL */
480
trx_t* trx, /* in: trx */
481
const dict_table_t*table, /* in: table definition */
482
mem_heap_t* heap, /* in: heap where space for key
483
definitions are allocated */
484
KEY* key_info, /* in: Indexes to be created */
485
ulint& n_keys) /* in/out: Number of indexes to
489
merge_index_def_t* indexdef;
490
merge_index_def_t* indexdefs;
493
indexdef = indexdefs = (merge_index_def_t*)
494
mem_heap_alloc(heap, sizeof *indexdef
495
* (n_keys + UT_LIST_GET_LEN(table->indexes)));
497
/* If there is a primary key, it is always the first index
498
defined for the table. */
500
new_primary = !my_strcasecmp(system_charset_info,
501
key_info->name, "PRIMARY");
503
/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
504
columns, MySQL will treat it as a PRIMARY KEY unless the
505
table already has one. */
507
if (!new_primary && (key_info->flags & HA_NOSAME)
508
&& row_table_got_default_clust_index(table)) {
509
uint key_part = key_info->key_parts;
514
if (key_info->key_part[key_part].key_type
515
& FIELDFLAG_MAYBE_NULL) {
523
const dict_index_t* index;
525
/* Create the PRIMARY key index definition */
526
innobase_create_index_def(&key_info[i++], TRUE, TRUE,
529
row_mysql_lock_data_dictionary(trx);
531
index = dict_table_get_first_index(table);
533
/* Copy the index definitions of the old table. Skip
534
the old clustered index if it is a generated clustered
535
index or a PRIMARY KEY. If the clustered index is a
536
UNIQUE INDEX, it must be converted to a secondary index. */
538
if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
539
|| !my_strcasecmp(system_charset_info,
540
index->name, "PRIMARY")) {
541
index = dict_table_get_next_index(index);
545
innobase_copy_index_def(index, indexdef++, heap);
546
index = dict_table_get_next_index(index);
549
row_mysql_unlock_data_dictionary(trx);
552
/* Create definitions for added secondary indexes. */
555
innobase_create_index_def(&key_info[i++], new_primary, FALSE,
559
n_keys = indexdef - indexdefs;
564
/***********************************************************************
565
Create a temporary tablename using query id, thread id, and id */
568
innobase_create_temporary_tablename(
569
/*================================*/
570
/* out: temporary tablename */
571
mem_heap_t* heap, /* in: memory heap */
572
char id, /* in: identifier [0-9a-zA-Z] */
573
const char* table_name) /* in: table name */
577
static const char suffix[] = "@0023 "; /* "# " */
579
len = strlen(table_name);
581
name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
582
memcpy(name, table_name, len);
583
memcpy(name + len, suffix, sizeof suffix);
584
name[len + (sizeof suffix - 2)] = id;
589
/***********************************************************************
593
ha_innobase::add_index(
594
/*===================*/
595
/* out: 0 or error number */
596
Table* table, /* in: Table where indexes are created */
597
KEY* key_info, /* in: Indexes to be created */
598
uint num_of_keys) /* in: Number of indexes to be created */
600
dict_index_t** index; /* Index to be created */
601
dict_table_t* innodb_table; /* InnoDB table in dictionary */
602
dict_table_t* indexed_table; /* Table where indexes are created */
603
merge_index_def_t* index_defs; /* Index definitions */
604
mem_heap_t* heap; /* Heap for index definitions */
605
trx_t* trx; /* Transaction */
607
ulint num_created = 0;
608
ibool dict_locked = FALSE;
616
if (srv_created_new_raw || srv_force_recovery) {
617
return(HA_ERR_WRONG_COMMAND);
622
heap = mem_heap_create(1024);
624
/* In case MySQL calls this in the middle of a SELECT query, release
625
possible adaptive hash latch to avoid deadlocks of threads. */
626
trx_search_latch_release_if_reserved(prebuilt->trx);
628
/* Create a background transaction for the operations on
629
the data dictionary tables. */
630
trx = trx_allocate_for_mysql();
631
trx_start_if_not_started(trx);
633
trans_register_ha(user_session, FALSE, ht);
634
prebuilt->trx->active_trans = 1;
636
trx->mysql_thd = user_session;
637
trx->mysql_query_str = session_query(user_session);
639
innodb_table = indexed_table
640
= dict_table_get(prebuilt->table->name, FALSE);
642
/* Check that index keys are sensible */
644
error = innobase_check_index_keys(key_info, num_of_keys);
646
if (UNIV_UNLIKELY(error)) {
649
trx_general_rollback_for_mysql(trx, FALSE, NULL);
650
trx_free_for_mysql(trx);
651
trx_commit_for_mysql(prebuilt->trx);
655
/* Create table containing all indexes to be built in this
656
alter table add index so that they are in the correct order
659
num_of_idx = num_of_keys;
661
index_defs = innobase_create_key_def(
662
trx, innodb_table, heap, key_info, num_of_idx);
664
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
666
/* Allocate memory for dictionary index definitions */
668
index = (dict_index_t**) mem_heap_alloc(
669
heap, num_of_idx * sizeof *index);
671
/* Flag this transaction as a dictionary operation, so that
672
the data dictionary will be locked in crash recovery. */
673
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
675
/* Acquire a lock on the table before creating any indexes. */
676
error = row_merge_lock_table(prebuilt->trx, innodb_table,
677
new_primary ? LOCK_X : LOCK_S);
679
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
684
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
685
or lock waits can happen in it during an index create operation. */
687
row_mysql_lock_data_dictionary(trx);
690
/* If a new primary key is defined for the table we need
691
to drop the original table and rebuild all indexes. */
693
if (UNIV_UNLIKELY(new_primary)) {
694
/* This transaction should be the only one
695
operating on the table. */
696
ut_a(innodb_table->n_mysql_handles_opened == 1);
698
char* new_table_name = innobase_create_temporary_tablename(
699
heap, '1', innodb_table->name);
701
/* Clone the table. */
702
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
703
indexed_table = row_merge_create_temporary_table(
704
new_table_name, index_defs, innodb_table, trx);
706
if (!indexed_table) {
708
switch (trx->error_state) {
709
case DB_TABLESPACE_ALREADY_EXISTS:
710
case DB_DUPLICATE_KEY:
711
innobase_convert_tablename(new_table_name);
712
my_error(HA_ERR_TABLE_EXIST, MYF(0),
714
error = HA_ERR_TABLE_EXIST;
717
error = convert_error_code_to_mysql(
718
trx->error_state, innodb_table->flags,
722
row_mysql_unlock_data_dictionary(trx);
726
trx->table_id = indexed_table->id;
729
/* Create the indexes in SYS_INDEXES and load into dictionary. */
731
for (ulint i = 0; i < num_of_idx; i++) {
733
index[i] = row_merge_create_index(trx, indexed_table,
737
error = trx->error_state;
744
ut_ad(error == DB_SUCCESS);
746
/* Commit the data dictionary transaction in order to release
747
the table locks on the system tables. Unfortunately, this
748
means that if MySQL crashes while creating a new primary key
749
inside row_merge_build_indexes(), indexed_table will not be
750
dropped on crash recovery. Thus, it will become orphaned. */
751
trx_commit_for_mysql(trx);
753
row_mysql_unlock_data_dictionary(trx);
756
ut_a(trx->n_active_thrs == 0);
757
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
759
if (UNIV_UNLIKELY(new_primary)) {
760
/* A primary key is to be built. Acquire an exclusive
761
table lock also on the table that is being created. */
762
ut_ad(indexed_table != innodb_table);
764
error = row_merge_lock_table(prebuilt->trx, indexed_table,
767
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
773
/* Read the clustered index of the table and build indexes
774
based on this information using temporary files and merge sort. */
775
error = row_merge_build_indexes(prebuilt->trx,
776
innodb_table, indexed_table,
777
index, num_of_idx, table);
781
/* TODO: At the moment we can't handle the following statement
782
in our debugging code below:
784
alter table t drop index b, add index (b);
786
The fix will have to parse the SQL and note that the index
787
being added has the same name as the the one being dropped and
788
ignore that in the dup index check.*/
789
//dict_table_check_for_dup_indexes(prebuilt->table);
792
/* After an error, remove all those index definitions from the
793
dictionary which were defined. */
796
const char* old_name;
802
error = row_merge_rename_indexes(trx, indexed_table);
804
if (error != DB_SUCCESS) {
805
row_merge_drop_indexes(trx, indexed_table,
812
/* If a new primary key was defined for the table and
813
there was no error at this point, we can now rename
814
the old table as a temporary table, rename the new
815
temporary table as the old table and drop the old table. */
816
old_name = innodb_table->name;
817
tmp_name = innobase_create_temporary_tablename(heap, '2',
820
row_mysql_lock_data_dictionary(trx);
823
error = row_merge_rename_tables(innodb_table, indexed_table,
826
if (error != DB_SUCCESS) {
828
row_merge_drop_table(trx, indexed_table);
831
case DB_TABLESPACE_ALREADY_EXISTS:
832
case DB_DUPLICATE_KEY:
833
innobase_convert_tablename(tmp_name);
834
my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
835
error = HA_ERR_TABLE_EXIST;
843
trx_commit_for_mysql(prebuilt->trx);
844
row_prebuilt_free(prebuilt, TRUE);
845
prebuilt = row_create_prebuilt(indexed_table);
847
indexed_table->n_mysql_handles_opened++;
849
error = row_merge_drop_table(trx, innodb_table);
852
case DB_TOO_BIG_RECORD:
853
my_error(HA_ERR_TO_BIG_ROW, MYF(0));
855
case DB_PRIMARY_KEY_IS_NULL:
856
my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
858
case DB_DUPLICATE_KEY:
860
prebuilt->trx->error_info = NULL;
864
row_merge_drop_table(trx, indexed_table);
866
row_merge_drop_indexes(trx, indexed_table,
871
error = convert_error_code_to_mysql(error,
877
trx_commit_for_mysql(trx);
879
trx_commit_for_mysql(prebuilt->trx);
883
row_mysql_unlock_data_dictionary(trx);
886
trx_free_for_mysql(trx);
888
/* There might be work for utility threads.*/
889
srv_active_wake_master_thread();
894
/***********************************************************************
895
Prepare to drop some indexes of a table. */
898
ha_innobase::prepare_drop_index(
899
/*============================*/
900
/* out: 0 or error number */
901
Table* table, /* in: Table where indexes are dropped */
902
uint* key_num, /* in: Key nums to be dropped */
903
uint num_of_keys) /* in: Number of keys to be dropped */
912
if (srv_created_new_raw || srv_force_recovery) {
913
return(HA_ERR_WRONG_COMMAND);
918
trx_search_latch_release_if_reserved(prebuilt->trx);
921
/* Test and mark all the indexes to be dropped */
923
row_mysql_lock_data_dictionary(trx);
925
/* Check that none of the indexes have previously been flagged
928
const dict_index_t* index
929
= dict_table_get_first_index(prebuilt->table);
931
ut_a(!index->to_be_dropped);
932
index = dict_table_get_next_index(index);
936
for (n_key = 0; n_key < num_of_keys; n_key++) {
940
key = table->key_info + key_num[n_key];
941
index = dict_table_get_index_on_name_and_min_id(
942
prebuilt->table, key->name);
945
sql_print_error("InnoDB could not find key n:o %u "
946
"with name %s for table %s",
948
key ? key->name : "NULL",
949
prebuilt->table->name);
951
err = HA_ERR_KEY_NOT_FOUND;
955
/* Refuse to drop the clustered index. It would be
956
better to automatically generate a clustered index,
957
but mysql_alter_table() will call this method only
958
after ha_innobase::add_index(). */
960
if (dict_index_is_clust(index)) {
961
my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
966
index->to_be_dropped = TRUE;
969
/* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
970
for a foreign key constraint because InnoDB requires that both
971
tables contain indexes for the constraint. Note that CREATE
972
INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
973
can ignore here foreign keys because a new index for the
974
foreign key has already been created.
976
We check for the foreign key constraints after marking the
977
candidate indexes for deletion, because when we check for an
978
equivalent foreign index we don't want to select an index that
981
if (trx->check_foreigns
982
&& session_sql_command(user_session) != SQLCOM_CREATE_INDEX) {
984
= dict_table_get_first_index(prebuilt->table);
987
dict_foreign_t* foreign;
989
if (!index->to_be_dropped) {
994
/* Check if the index is referenced. */
995
foreign = dict_table_get_referenced_constraint(
996
prebuilt->table, index);
1000
trx_set_detailed_error(
1002
"Index needed in foreign key "
1005
trx->error_info = index;
1007
err = HA_ERR_DROP_INDEX_FK;
1010
/* Check if this index references some
1012
foreign = dict_table_get_foreign_constraint(
1013
prebuilt->table, index);
1016
ut_a(foreign->foreign_index == index);
1018
/* Search for an equivalent index that
1019
the foreign key contraint could use
1020
if this index were to be deleted. */
1021
if (!dict_table_find_equivalent_index(
1023
foreign->foreign_index)) {
1031
index = dict_table_get_next_index(index);
1037
/* Undo our changes since there was some sort of error. */
1039
= dict_table_get_first_index(prebuilt->table);
1042
index->to_be_dropped = FALSE;
1043
index = dict_table_get_next_index(index);
1047
row_mysql_unlock_data_dictionary(trx);
1052
/***********************************************************************
1053
Drop the indexes that were passed to a successful prepare_drop_index(). */
1056
ha_innobase::final_drop_index(
1057
/*==========================*/
1058
/* out: 0 or error number */
1059
Table* ) /* in: Table where indexes are dropped */
1061
dict_index_t* index; /* Index to be dropped */
1062
trx_t* trx; /* Transaction */
1067
if (srv_created_new_raw || srv_force_recovery) {
1068
return(HA_ERR_WRONG_COMMAND);
1073
trx_search_latch_release_if_reserved(prebuilt->trx);
1075
/* Create a background transaction for the operations on
1076
the data dictionary tables. */
1077
trx = trx_allocate_for_mysql();
1078
trx_start_if_not_started(trx);
1080
trans_register_ha(user_session, FALSE, ht);
1081
prebuilt->trx->active_trans = 1;
1083
trx->mysql_thd = user_session;
1084
trx->mysql_query_str = session_query(user_session);
1086
/* Flag this transaction as a dictionary operation, so that
1087
the data dictionary will be locked in crash recovery. */
1088
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1090
/* Lock the table exclusively, to ensure that no active
1091
transaction depends on an index that is being dropped. */
1092
err = convert_error_code_to_mysql(
1093
row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1094
prebuilt->table->flags, user_session);
1096
if (UNIV_UNLIKELY(err)) {
1098
/* Unmark the indexes to be dropped. */
1099
row_mysql_lock_data_dictionary(trx);
1101
for (index = dict_table_get_first_index(prebuilt->table);
1102
index; index = dict_table_get_next_index(index)) {
1104
index->to_be_dropped = FALSE;
1107
row_mysql_unlock_data_dictionary(trx);
1111
/* Drop indexes marked to be dropped */
1113
row_mysql_lock_data_dictionary(trx);
1115
index = dict_table_get_first_index(prebuilt->table);
1118
dict_index_t* next_index;
1120
next_index = dict_table_get_next_index(index);
1122
if (index->to_be_dropped) {
1124
row_merge_drop_index(index, prebuilt->table, trx);
1130
/* Check that all flagged indexes were dropped. */
1131
for (index = dict_table_get_first_index(prebuilt->table);
1132
index; index = dict_table_get_next_index(index)) {
1133
ut_a(!index->to_be_dropped);
1137
dict_table_check_for_dup_indexes(prebuilt->table);
1139
row_mysql_unlock_data_dictionary(trx);
1142
trx_commit_for_mysql(trx);
1143
trx_commit_for_mysql(prebuilt->trx);
1145
/* Flush the log to reduce probability that the .frm files and
1146
the InnoDB data dictionary get out-of-sync if the user runs
1147
with innodb_flush_log_at_trx_commit = 0 */
1149
log_buffer_flush_to_disk();
1151
trx_free_for_mysql(trx);
1153
/* Tell the InnoDB server that there might be work for
1156
srv_active_wake_master_thread();