1
/******************************************************
4
(c) 2005-2008 Innobase Oy
5
*******************************************************/
7
#include <mysql_priv.h>
8
#include <mysqld_error.h>
12
#include "row0merge.h"
16
#include "ha_prototypes.h"
17
#include "handler0alter.h"
20
#include "ha_innodb.h"
21
#include "handler0vars.h"
23
/*****************************************************************
24
Copies an InnoDB column to a MySQL field. This function is
25
adapted from row_sel_field_store_in_mysql_format(). */
28
innobase_col_to_mysql(
29
/*==================*/
30
const dict_col_t* col, /* in: InnoDB column */
31
const uchar* data, /* in: InnoDB column data */
32
ulint len, /* in: length of data, in bytes */
33
Field* field) /* in/out: MySQL field */
36
uchar* dest = field->ptr;
37
ulint flen = field->pack_length();
43
/* Convert integer data from Innobase to little-endian
44
format, sign bit restored to normal */
46
for (ptr = dest + len; ptr != dest; ) {
50
if (!(field->flags & UNSIGNED_FLAG)) {
51
((byte*) dest)[len - 1] ^= 0x80;
61
if (field->type() == MYSQL_TYPE_VARCHAR) {
62
/* This is a >= 5.0.3 type true VARCHAR. Store the
63
length of the data to the first byte or the first
66
dest = row_mysql_store_true_var_len(
67
dest, len, flen - field->key_length());
70
/* Copy the actual data */
71
memcpy(dest, data, len);
75
/* Store a pointer to the BLOB buffer to dest: the BLOB was
76
already copied to the buffer in row_sel_store_mysql_rec */
78
row_mysql_store_blob_ref(dest, flen, data, len);
84
ut_ad(col->mbmaxlen >= col->mbminlen);
85
ut_ad(col->mbmaxlen > col->mbminlen || flen == len);
86
memcpy(dest, data, len);
92
/* These column types should never be shipped to MySQL. */
100
/* Above are the valid column types for MySQL data. */
102
#else /* UNIV_DEBUG */
104
#endif /* UNIV_DEBUG */
105
memcpy(dest, data, len);
109
/*****************************************************************
110
Copies an InnoDB record to table->record[0]. */
111
extern "C" UNIV_INTERN
113
innobase_rec_to_mysql(
114
/*==================*/
115
TABLE* table, /* in/out: MySQL table */
116
const rec_t* rec, /* in: record */
117
const dict_index_t* index, /* in: index */
118
const ulint* offsets) /* in: rec_get_offsets(
121
uint n_fields = table->s->fields;
124
ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
126
for (i = 0; i < n_fields; i++) {
127
Field* field = table->field[i];
134
ipos = dict_index_get_nth_col_pos(index, i);
136
if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
142
ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
144
/* Assign the NULL flag */
145
if (ilen == UNIV_SQL_NULL) {
146
ut_ad(field->real_maybe_null());
150
field->set_notnull();
152
innobase_col_to_mysql(
154
dict_index_get_nth_field(index, ipos)),
155
ifield, ilen, field);
159
/*****************************************************************
160
Resets table->record[0]. */
161
extern "C" UNIV_INTERN
165
TABLE* table) /* in/out: MySQL table */
167
uint n_fields = table->s->fields;
170
for (i = 0; i < n_fields; i++) {
171
table->field[i]->set_default();
175
/**********************************************************************
176
Removes the filename encoding of a database and table name. */
179
innobase_convert_tablename(
180
/*=======================*/
181
char* s) /* in: identifier; out: decoded identifier */
185
char* slash = strchr(s, '/');
189
/* Temporarily replace the '/' with NUL. */
191
/* Convert the database name. */
192
strconvert(&my_charset_filename, s, system_charset_info,
193
s, slash - s + 1, &errors);
197
/* Append a '.' after the database name. */
200
/* Convert the table name. */
201
strconvert(&my_charset_filename, slash, system_charset_info,
202
t, slash - t + strlen(slash), &errors);
204
strconvert(&my_charset_filename, s,
205
system_charset_info, s, strlen(s), &errors);
209
/***********************************************************************
210
This function checks that index keys are sensible. */
213
innobase_check_index_keys(
214
/*======================*/
215
/* out: 0 or error number */
216
const KEY* key_info, /* in: Indexes to be created */
217
ulint num_of_keys) /* in: Number of indexes to
225
for (key_num = 0; key_num < num_of_keys; key_num++) {
226
const KEY& key = key_info[key_num];
228
/* Check that the same index name does not appear
229
twice in indexes to be created. */
231
for (ulint i = 0; i < key_num; i++) {
232
const KEY& key2 = key_info[i];
234
if (0 == strcmp(key.name, key2.name)) {
235
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: key name `%s` appears"
236
" twice in CREATE INDEX\n",
239
return(ER_WRONG_NAME_FOR_INDEX);
243
/* Check that MySQL does not try to create a column
244
prefix index field on an inappropriate data type and
245
that the same colum does not appear twice in the index. */
247
for (ulint i = 0; i < key.key_parts; i++) {
248
const KEY_PART_INFO& key_part1
254
switch (get_innobase_type_from_mysql_type(
255
&is_unsigned, field)) {
262
if (field->type() == MYSQL_TYPE_VARCHAR) {
264
>= field->pack_length()
265
- ((Field_varstring*) field)
271
>= field->pack_length()) {
276
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: MySQL is trying to"
277
" create a column prefix"
279
" inappropriate data type."
284
return(ER_WRONG_KEY_COLUMN);
287
for (ulint j = 0; j < i; j++) {
288
const KEY_PART_INFO& key_part2
291
if (strcmp(key_part1.field->field_name,
292
key_part2.field->field_name)) {
296
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: column `%s`"
297
" is not allowed to occur"
298
" twice in index `%s`.\n",
299
key_part1.field->field_name,
301
return(ER_WRONG_KEY_COLUMN);
309
/***********************************************************************
310
Create index field definition for key part */
313
innobase_create_index_field_def(
314
/*============================*/
315
KEY_PART_INFO* key_part, /* in: MySQL key definition */
316
mem_heap_t* heap, /* in: memory heap */
317
merge_index_field_t* index_field) /* out: index field
318
definition for key_part */
324
DBUG_ENTER("innobase_create_index_field_def");
329
field = key_part->field;
332
col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
334
if (DATA_BLOB == col_type
335
|| (key_part->length < field->pack_length()
336
&& field->type() != MYSQL_TYPE_VARCHAR)
337
|| (field->type() == MYSQL_TYPE_VARCHAR
338
&& key_part->length < field->pack_length()
339
- ((Field_varstring*)field)->length_bytes)) {
341
index_field->prefix_len = key_part->length;
343
index_field->prefix_len = 0;
346
index_field->field_name = mem_heap_strdup(heap, field->field_name);
351
/***********************************************************************
352
Create index definition for key */
355
innobase_create_index_def(
356
/*======================*/
357
KEY* key, /* in: key definition */
358
bool new_primary, /* in: TRUE=generating
361
bool key_primary, /* in: TRUE if this key
363
merge_index_def_t* index, /* out: index definition */
364
mem_heap_t* heap) /* in: heap where memory
369
ulint n_fields = key->key_parts;
372
DBUG_ENTER("innobase_create_index_def");
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
DBUG_ENTER("innobase_copy_index_field_def");
415
DBUG_ASSERT(field != NULL);
416
DBUG_ASSERT(index_field != NULL);
418
index_field->field_name = field->name;
419
index_field->prefix_len = field->prefix_len;
424
/***********************************************************************
425
Copy index definition for the index */
428
innobase_copy_index_def(
429
/*====================*/
430
const dict_index_t* index, /* in: index definition to copy */
431
merge_index_def_t* new_index,/* out: Index definition */
432
mem_heap_t* heap) /* in: heap where allocated */
437
DBUG_ENTER("innobase_copy_index_def");
439
/* Note that we take only those fields that user defined to be
440
in the index. In the internal representation more colums were
441
added and those colums are not copied .*/
443
n_fields = index->n_user_defined_cols;
445
new_index->fields = (merge_index_field_t*) mem_heap_alloc(
446
heap, n_fields * sizeof *new_index->fields);
448
/* When adding a PRIMARY KEY, we may convert a previous
449
clustered index to a secondary index (UNIQUE NOT NULL). */
450
new_index->ind_type = index->type & ~DICT_CLUSTERED;
451
new_index->n_fields = n_fields;
452
new_index->name = index->name;
454
for (i = 0; i < n_fields; i++) {
455
innobase_copy_index_field_def(&index->fields[i],
456
&new_index->fields[i]);
462
/***********************************************************************
463
Create an index table where indexes are ordered as follows:
465
IF a new primary key is defined for the table THEN
468
2) Original secondary indexes
469
3) New secondary indexes
473
1) All new indexes in the order they arrive from MySQL
480
innobase_create_key_def(
481
/*====================*/
482
/* out: key definitions or NULL */
483
trx_t* trx, /* in: trx */
484
const dict_table_t*table, /* in: table definition */
485
mem_heap_t* heap, /* in: heap where space for key
486
definitions are allocated */
487
KEY* key_info, /* in: Indexes to be created */
488
ulint& n_keys) /* in/out: Number of indexes to
492
merge_index_def_t* indexdef;
493
merge_index_def_t* indexdefs;
496
DBUG_ENTER("innobase_create_key_def");
498
indexdef = indexdefs = (merge_index_def_t*)
499
mem_heap_alloc(heap, sizeof *indexdef
500
* (n_keys + UT_LIST_GET_LEN(table->indexes)));
502
/* If there is a primary key, it is always the first index
503
defined for the table. */
505
new_primary = !my_strcasecmp(system_charset_info,
506
key_info->name, "PRIMARY");
508
/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
509
columns, MySQL will treat it as a PRIMARY KEY unless the
510
table already has one. */
512
if (!new_primary && (key_info->flags & HA_NOSAME)
513
&& row_table_got_default_clust_index(table)) {
514
uint key_part = key_info->key_parts;
519
if (key_info->key_part[key_part].key_type
520
& FIELDFLAG_MAYBE_NULL) {
528
const dict_index_t* index;
530
/* Create the PRIMARY key index definition */
531
innobase_create_index_def(&key_info[i++], TRUE, TRUE,
534
row_mysql_lock_data_dictionary(trx);
536
index = dict_table_get_first_index(table);
538
/* Copy the index definitions of the old table. Skip
539
the old clustered index if it is a generated clustered
540
index or a PRIMARY KEY. If the clustered index is a
541
UNIQUE INDEX, it must be converted to a secondary index. */
543
if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
544
|| !my_strcasecmp(system_charset_info,
545
index->name, "PRIMARY")) {
546
index = dict_table_get_next_index(index);
550
innobase_copy_index_def(index, indexdef++, heap);
551
index = dict_table_get_next_index(index);
554
row_mysql_unlock_data_dictionary(trx);
557
/* Create definitions for added secondary indexes. */
560
innobase_create_index_def(&key_info[i++], new_primary, FALSE,
564
n_keys = indexdef - indexdefs;
566
DBUG_RETURN(indexdefs);
569
/***********************************************************************
570
Create a temporary tablename using query id, thread id, and id */
573
innobase_create_temporary_tablename(
574
/*================================*/
575
/* out: temporary tablename */
576
mem_heap_t* heap, /* in: memory heap */
577
char id, /* in: identifier [0-9a-zA-Z] */
578
const char* table_name) /* in: table name */
582
static const char suffix[] = "@0023 "; /* "# " */
584
len = strlen(table_name);
586
name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
587
memcpy(name, table_name, len);
588
memcpy(name + len, suffix, sizeof suffix);
589
name[len + (sizeof suffix - 2)] = id;
594
/***********************************************************************
598
ha_innobase::add_index(
599
/*===================*/
600
/* out: 0 or error number */
601
TABLE* table, /* in: Table where indexes are created */
602
KEY* key_info, /* in: Indexes to be created */
603
uint num_of_keys) /* in: Number of indexes to be created */
605
dict_index_t** index; /* Index to be created */
606
dict_table_t* innodb_table; /* InnoDB table in dictionary */
607
dict_table_t* indexed_table; /* Table where indexes are created */
608
merge_index_def_t* index_defs; /* Index definitions */
609
mem_heap_t* heap; /* Heap for index definitions */
610
trx_t* trx; /* Transaction */
612
ulint num_created = 0;
613
ibool dict_locked = FALSE;
617
DBUG_ENTER("ha_innobase::add_index");
622
if (srv_created_new_raw || srv_force_recovery) {
623
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
628
heap = mem_heap_create(1024);
630
/* In case MySQL calls this in the middle of a SELECT query, release
631
possible adaptive hash latch to avoid deadlocks of threads. */
632
trx_search_latch_release_if_reserved(prebuilt->trx);
634
/* Create a background transaction for the operations on
635
the data dictionary tables. */
636
trx = trx_allocate_for_mysql();
637
trx_start_if_not_started(trx);
639
trx->mysql_thd = user_thd;
640
trx->mysql_query_str = thd_query(user_thd);
642
innodb_table = indexed_table
643
= dict_table_get(prebuilt->table->name, FALSE);
645
/* Check that index keys are sensible */
647
error = innobase_check_index_keys(key_info, num_of_keys);
649
if (UNIV_UNLIKELY(error)) {
652
trx_general_rollback_for_mysql(trx, FALSE, NULL);
653
trx_free_for_mysql(trx);
654
trx_commit_for_mysql(prebuilt->trx);
658
/* Create table containing all indexes to be built in this
659
alter table add index so that they are in the correct order
662
num_of_idx = num_of_keys;
664
index_defs = innobase_create_key_def(
665
trx, innodb_table, heap, key_info, num_of_idx);
667
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
669
/* Allocate memory for dictionary index definitions */
671
index = (dict_index_t**) mem_heap_alloc(
672
heap, num_of_idx * sizeof *index);
674
/* Flag this transaction as a dictionary operation, so that
675
the data dictionary will be locked in crash recovery. */
676
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
678
/* Acquire a lock on the table before creating any indexes. */
679
error = row_merge_lock_table(prebuilt->trx, innodb_table,
680
new_primary ? LOCK_X : LOCK_S);
682
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
687
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
688
or lock waits can happen in it during an index create operation. */
690
row_mysql_lock_data_dictionary(trx);
693
/* If a new primary key is defined for the table we need
694
to drop the original table and rebuild all indexes. */
696
if (UNIV_UNLIKELY(new_primary)) {
697
/* This transaction should be the only one
698
operating on the table. */
699
ut_a(innodb_table->n_mysql_handles_opened == 1);
701
char* new_table_name = innobase_create_temporary_tablename(
702
heap, '1', innodb_table->name);
704
/* Clone the table. */
705
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
706
indexed_table = row_merge_create_temporary_table(
707
new_table_name, index_defs, innodb_table, trx);
709
if (!indexed_table) {
711
switch (trx->error_state) {
712
case DB_TABLESPACE_ALREADY_EXISTS:
713
case DB_DUPLICATE_KEY:
714
innobase_convert_tablename(new_table_name);
715
my_error(HA_ERR_TABLE_EXIST, MYF(0),
717
error = HA_ERR_TABLE_EXIST;
720
error = convert_error_code_to_mysql(
721
trx->error_state, innodb_table->flags,
725
row_mysql_unlock_data_dictionary(trx);
729
trx->table_id = indexed_table->id;
732
/* Create the indexes in SYS_INDEXES and load into dictionary. */
734
for (ulint i = 0; i < num_of_idx; i++) {
736
index[i] = row_merge_create_index(trx, indexed_table,
740
error = trx->error_state;
747
ut_ad(error == DB_SUCCESS);
749
/* Commit the data dictionary transaction in order to release
750
the table locks on the system tables. Unfortunately, this
751
means that if MySQL crashes while creating a new primary key
752
inside row_merge_build_indexes(), indexed_table will not be
753
dropped on crash recovery. Thus, it will become orphaned. */
754
trx_commit_for_mysql(trx);
756
row_mysql_unlock_data_dictionary(trx);
759
ut_a(trx->n_active_thrs == 0);
760
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
762
if (UNIV_UNLIKELY(new_primary)) {
763
/* A primary key is to be built. Acquire an exclusive
764
table lock also on the table that is being created. */
765
ut_ad(indexed_table != innodb_table);
767
error = row_merge_lock_table(prebuilt->trx, indexed_table,
770
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
776
/* Read the clustered index of the table and build indexes
777
based on this information using temporary files and merge sort. */
778
error = row_merge_build_indexes(prebuilt->trx,
779
innodb_table, indexed_table,
780
index, num_of_idx, table);
784
/* TODO: At the moment we can't handle the following statement
785
in our debugging code below:
787
alter table t drop index b, add index (b);
789
The fix will have to parse the SQL and note that the index
790
being added has the same name as the the one being dropped and
791
ignore that in the dup index check.*/
792
//dict_table_check_for_dup_indexes(prebuilt->table);
795
/* After an error, remove all those index definitions from the
796
dictionary which were defined. */
799
const char* old_name;
803
row_mysql_lock_data_dictionary(trx);
807
error = row_merge_rename_indexes(trx, indexed_table);
809
if (error != DB_SUCCESS) {
810
row_merge_drop_indexes(trx, indexed_table,
817
/* If a new primary key was defined for the table and
818
there was no error at this point, we can now rename
819
the old table as a temporary table, rename the new
820
temporary table as the old table and drop the old table. */
821
old_name = innodb_table->name;
822
tmp_name = innobase_create_temporary_tablename(heap, '2',
825
error = row_merge_rename_tables(innodb_table, indexed_table,
828
if (error != DB_SUCCESS) {
830
row_merge_drop_table(trx, indexed_table);
833
case DB_TABLESPACE_ALREADY_EXISTS:
834
case DB_DUPLICATE_KEY:
835
innobase_convert_tablename(tmp_name);
836
my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
837
error = HA_ERR_TABLE_EXIST;
845
trx_commit_for_mysql(prebuilt->trx);
846
row_prebuilt_free(prebuilt, TRUE);
847
prebuilt = row_create_prebuilt(indexed_table);
849
indexed_table->n_mysql_handles_opened++;
851
error = row_merge_drop_table(trx, innodb_table);
854
case DB_TOO_BIG_RECORD:
855
my_error(HA_ERR_TO_BIG_ROW, MYF(0));
857
case DB_PRIMARY_KEY_IS_NULL:
858
my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
860
case DB_DUPLICATE_KEY:
862
prebuilt->trx->error_info = NULL;
866
row_merge_drop_table(trx, indexed_table);
869
row_mysql_lock_data_dictionary(trx);
873
row_merge_drop_indexes(trx, indexed_table,
878
error = convert_error_code_to_mysql(error,
884
trx_commit_for_mysql(trx);
886
trx_commit_for_mysql(prebuilt->trx);
890
row_mysql_unlock_data_dictionary(trx);
893
trx_free_for_mysql(trx);
895
/* There might be work for utility threads.*/
896
srv_active_wake_master_thread();
901
/***********************************************************************
902
Prepare to drop some indexes of a table. */
905
ha_innobase::prepare_drop_index(
906
/*============================*/
907
/* out: 0 or error number */
908
TABLE* table, /* in: Table where indexes are dropped */
909
uint* key_num, /* in: Key nums to be dropped */
910
uint num_of_keys) /* in: Number of keys to be dropped */
916
DBUG_ENTER("ha_innobase::prepare_drop_index");
920
if (srv_created_new_raw || srv_force_recovery) {
921
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
926
trx_search_latch_release_if_reserved(prebuilt->trx);
929
/* Test and mark all the indexes to be dropped */
931
row_mysql_lock_data_dictionary(trx);
933
/* Check that none of the indexes have previously been flagged
936
const dict_index_t* index
937
= dict_table_get_first_index(prebuilt->table);
939
ut_a(!index->to_be_dropped);
940
index = dict_table_get_next_index(index);
944
for (n_key = 0; n_key < num_of_keys; n_key++) {
948
key = table->key_info + key_num[n_key];
949
index = dict_table_get_index_on_name_and_min_id(
950
prebuilt->table, key->name);
953
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB could not find key n:o %u "
954
"with name %s for table %s",
956
key ? key->name : "NULL",
957
prebuilt->table->name);
959
err = HA_ERR_KEY_NOT_FOUND;
963
/* Refuse to drop the clustered index. It would be
964
better to automatically generate a clustered index,
965
but mysql_alter_table() will call this method only
966
after ha_innobase::add_index(). */
968
if (dict_index_is_clust(index)) {
969
my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
974
index->to_be_dropped = TRUE;
977
/* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
978
for a foreign key constraint because InnoDB requires that both
979
tables contain indexes for the constraint. Note that CREATE
980
INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
981
can ignore here foreign keys because a new index for the
982
foreign key has already been created.
984
We check for the foreign key constraints after marking the
985
candidate indexes for deletion, because when we check for an
986
equivalent foreign index we don't want to select an index that
989
if (trx->check_foreigns
990
&& thd_sql_command(user_thd) != SQLCOM_CREATE_INDEX) {
993
for (index = dict_table_get_first_index(prebuilt->table);
995
index = dict_table_get_next_index(index)) {
996
dict_foreign_t* foreign;
998
if (!index->to_be_dropped) {
1003
/* Check if the index is referenced. */
1004
foreign = dict_table_get_referenced_constraint(
1005
prebuilt->table, index);
1009
trx_set_detailed_error(
1011
"Index needed in foreign key "
1014
trx->error_info = index;
1016
err = HA_ERR_DROP_INDEX_FK;
1019
/* Check if this index references some
1021
foreign = dict_table_get_foreign_constraint(
1022
prebuilt->table, index);
1025
ut_a(foreign->foreign_index == index);
1027
/* Search for an equivalent index that
1028
the foreign key constraint could use
1029
if this index were to be deleted. */
1030
if (!dict_foreign_find_equiv_index(
1038
} else if (thd_sql_command(user_thd) == SQLCOM_CREATE_INDEX) {
1039
/* This is a drop of a foreign key constraint index that
1040
was created by MySQL when the constraint was added. MySQL
1041
does this when the user creates an index explicitly which
1042
can be used in place of the automatically generated index. */
1044
dict_index_t* index;
1046
for (index = dict_table_get_first_index(prebuilt->table);
1048
index = dict_table_get_next_index(index)) {
1049
dict_foreign_t* foreign;
1051
if (!index->to_be_dropped) {
1056
/* Check if this index references some other table */
1057
foreign = dict_table_get_foreign_constraint(
1058
prebuilt->table, index);
1060
if (foreign == NULL) {
1065
ut_a(foreign->foreign_index == index);
1067
/* Search for an equivalent index that the
1068
foreign key constraint could use if this index
1069
were to be deleted. */
1071
if (!dict_foreign_find_equiv_index(foreign)) {
1072
trx_set_detailed_error(
1074
"Index needed in foreign key "
1077
trx->error_info = foreign->foreign_index;
1079
err = HA_ERR_DROP_INDEX_FK;
1087
/* Undo our changes since there was some sort of error. */
1089
= dict_table_get_first_index(prebuilt->table);
1092
index->to_be_dropped = FALSE;
1093
index = dict_table_get_next_index(index);
1097
row_mysql_unlock_data_dictionary(trx);
1102
/***********************************************************************
1103
Drop the indexes that were passed to a successful prepare_drop_index(). */
1106
ha_innobase::final_drop_index(
1107
/*==========================*/
1108
/* out: 0 or error number */
1109
TABLE* table) /* in: Table where indexes are dropped */
1111
dict_index_t* index; /* Index to be dropped */
1112
trx_t* trx; /* Transaction */
1115
DBUG_ENTER("ha_innobase::final_drop_index");
1118
if (srv_created_new_raw || srv_force_recovery) {
1119
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
1124
trx_search_latch_release_if_reserved(prebuilt->trx);
1126
/* Create a background transaction for the operations on
1127
the data dictionary tables. */
1128
trx = trx_allocate_for_mysql();
1129
trx_start_if_not_started(trx);
1131
trx->mysql_thd = user_thd;
1132
trx->mysql_query_str = thd_query(user_thd);
1134
/* Flag this transaction as a dictionary operation, so that
1135
the data dictionary will be locked in crash recovery. */
1136
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1138
/* Lock the table exclusively, to ensure that no active
1139
transaction depends on an index that is being dropped. */
1140
err = convert_error_code_to_mysql(
1141
row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1142
prebuilt->table->flags, user_thd);
1144
row_mysql_lock_data_dictionary(trx);
1146
if (UNIV_UNLIKELY(err)) {
1148
/* Unmark the indexes to be dropped. */
1149
for (index = dict_table_get_first_index(prebuilt->table);
1150
index; index = dict_table_get_next_index(index)) {
1152
index->to_be_dropped = FALSE;
1158
/* Drop indexes marked to be dropped */
1160
index = dict_table_get_first_index(prebuilt->table);
1163
dict_index_t* next_index;
1165
next_index = dict_table_get_next_index(index);
1167
if (index->to_be_dropped) {
1169
row_merge_drop_index(index, prebuilt->table, trx);
1175
/* Check that all flagged indexes were dropped. */
1176
for (index = dict_table_get_first_index(prebuilt->table);
1177
index; index = dict_table_get_next_index(index)) {
1178
ut_a(!index->to_be_dropped);
1182
dict_table_check_for_dup_indexes(prebuilt->table);
1186
trx_commit_for_mysql(trx);
1187
trx_commit_for_mysql(prebuilt->trx);
1188
row_mysql_unlock_data_dictionary(trx);
1190
/* Flush the log to reduce probability that the .frm files and
1191
the InnoDB data dictionary get out-of-sync if the user runs
1192
with innodb_flush_log_at_trx_commit = 0 */
1194
log_buffer_flush_to_disk();
1196
trx_free_for_mysql(trx);
1198
/* Tell the InnoDB server that there might be work for
1201
srv_active_wake_master_thread();