1
/*****************************************************************************
3
Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved.
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.
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.
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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 USA
17
*****************************************************************************/
19
/**************************************************//**
20
@file handler/handler0alter.cc
22
*******************************************************/
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
#include "drizzled/my_error.h"
35
#include "row0merge.h"
39
#include "ha_prototypes.h"
40
#include "handler0alter.h"
43
#include "ha_innodb.h"
44
#include "handler0vars.h"
46
/*************************************************************//**
47
Copies an InnoDB column to a MySQL field. This function is
48
adapted from row_sel_field_store_in_mysql_format(). */
51
innobase_col_to_mysql(
52
/*==================*/
53
const dict_col_t* col, /*!< in: InnoDB column */
54
const unsigned char* data, /*!< in: InnoDB column data */
55
ulint len, /*!< in: length of data, in bytes */
56
Field* field) /*!< in/out: MySQL field */
59
unsigned char* dest = field->ptr;
60
ulint flen = field->pack_length();
66
/* Convert integer data from Innobase to little-endian
67
format, sign bit restored to normal */
69
for (ptr = dest + len; ptr != dest; ) {
73
if (!(field->flags & UNSIGNED_FLAG)) {
74
((byte*) dest)[len - 1] ^= 0x80;
84
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
85
/* This is a >= 5.0.3 type true VARCHAR. Store the
86
length of the data to the first byte or the first
89
dest = row_mysql_store_true_var_len(
90
dest, len, flen - field->key_length());
93
/* Copy the actual data */
94
memcpy(dest, data, len);
98
/* Store a pointer to the BLOB buffer to dest: the BLOB was
99
already copied to the buffer in row_sel_store_mysql_rec */
101
row_mysql_store_blob_ref(dest, flen, data, len);
107
ut_ad(col->mbmaxlen >= col->mbminlen);
108
ut_ad(col->mbmaxlen > col->mbminlen || flen == len);
109
memcpy(dest, data, len);
115
/* These column types should never be shipped to MySQL. */
123
/* Above are the valid column types for MySQL data. */
125
#else /* UNIV_DEBUG */
127
#endif /* UNIV_DEBUG */
128
memcpy(dest, data, len);
132
/*************************************************************//**
133
Copies an InnoDB record to table->record[0]. */
134
extern "C" UNIV_INTERN
136
innobase_rec_to_mysql(
137
/*==================*/
138
Table* table, /*!< in/out: MySQL table */
139
const rec_t* rec, /*!< in: record */
140
const dict_index_t* index, /*!< in: index */
141
const ulint* offsets) /*!< in: rec_get_offsets(
144
uint n_fields = table->s->fields;
147
ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
149
for (i = 0; i < n_fields; i++) {
150
Field* field = table->field[i];
153
const unsigned char* ifield;
157
ipos = dict_index_get_nth_col_pos(index, i);
159
if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
165
ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
167
/* Assign the NULL flag */
168
if (ilen == UNIV_SQL_NULL) {
169
ut_ad(field->real_maybe_null());
173
field->set_notnull();
175
innobase_col_to_mysql(
177
dict_index_get_nth_field(index, ipos)),
178
ifield, ilen, field);
182
/*************************************************************//**
183
Resets table->record[0]. */
184
extern "C" UNIV_INTERN
188
Table* table) /*!< in/out: MySQL table */
190
uint n_fields = table->s->fields;
193
for (i = 0; i < n_fields; i++) {
194
table->field[i]->set_default();
198
/******************************************************************//**
199
Removes the filename encoding of a database and table name. */
202
innobase_convert_tablename(
203
/*=======================*/
204
char* s) /*!< in: identifier; out: decoded identifier */
207
char* slash = strchr(s, '/');
211
/* Temporarily replace the '/' with NUL. */
213
strncpy(s, s, slash - s + 1);
217
/* Append a '.' after the database name. */
220
/* Convert the table name. */
221
strncpy(t, slash, slash - t + strlen(slash));
225
/*******************************************************************//**
226
This function checks that index keys are sensible.
227
@return 0 or error number */
230
innobase_check_index_keys(
231
/*======================*/
232
const KEY* key_info, /*!< in: Indexes to be created */
233
ulint num_of_keys) /*!< in: Number of indexes to
241
for (key_num = 0; key_num < num_of_keys; key_num++) {
242
const KEY& key = key_info[key_num];
244
/* Check that the same index name does not appear
245
twice in indexes to be created. */
247
for (ulint i = 0; i < key_num; i++) {
248
const KEY& key2 = key_info[i];
250
if (0 == strcmp(key.name, key2.name)) {
251
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: key name `%s` appears"
252
" twice in CREATE INDEX\n",
255
return(ER_WRONG_NAME_FOR_INDEX);
259
/* Check that MySQL does not try to create a column
260
prefix index field on an inappropriate data type and
261
that the same colum does not appear twice in the index. */
263
for (ulint i = 0; i < key.key_parts; i++) {
264
const KEY_PART_INFO& key_part1
270
switch (get_innobase_type_from_mysql_type(
271
&is_unsigned, field)) {
278
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
280
>= field->pack_length()
281
- ((Field_varstring*) field)
287
>= field->pack_length()) {
292
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: MySQL is trying to"
293
" create a column prefix"
295
" inappropriate data type."
300
return(ER_WRONG_KEY_COLUMN);
303
for (ulint j = 0; j < i; j++) {
304
const KEY_PART_INFO& key_part2
307
if (strcmp(key_part1.field->field_name,
308
key_part2.field->field_name)) {
312
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: column `%s`"
313
" is not allowed to occur"
314
" twice in index `%s`.\n",
315
key_part1.field->field_name,
317
return(ER_WRONG_KEY_COLUMN);
325
/*******************************************************************//**
326
Create index field definition for key part */
329
innobase_create_index_field_def(
330
/*============================*/
331
KEY_PART_INFO* key_part, /*!< in: MySQL key definition */
332
mem_heap_t* heap, /*!< in: memory heap */
333
merge_index_field_t* index_field) /*!< out: index field
334
definition for key_part */
343
field = key_part->field;
346
col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
348
if (DATA_BLOB == col_type
349
|| (key_part->length < field->pack_length()
350
&& field->type() != DRIZZLE_TYPE_VARCHAR)
351
|| (field->type() == DRIZZLE_TYPE_VARCHAR
352
&& key_part->length < field->pack_length()
353
- ((Field_varstring*)field)->length_bytes)) {
355
index_field->prefix_len = key_part->length;
357
index_field->prefix_len = 0;
360
index_field->field_name = mem_heap_strdup(heap, field->field_name);
365
/*******************************************************************//**
366
Create index definition for key */
369
innobase_create_index_def(
370
/*======================*/
371
KEY* key, /*!< in: key definition */
372
bool new_primary, /*!< in: TRUE=generating
375
bool key_primary, /*!< in: TRUE if this key
377
merge_index_def_t* index, /*!< out: index definition */
378
mem_heap_t* heap) /*!< in: heap where memory
383
ulint n_fields = key->key_parts;
386
index->fields = (merge_index_field_t*) mem_heap_alloc(
387
heap, n_fields * sizeof *index->fields);
390
index->n_fields = n_fields;
391
len = strlen(key->name) + 1;
392
index->name = index_name = (char*) mem_heap_alloc(heap,
395
if (UNIV_LIKELY(!new_primary)) {
396
*index_name++ = TEMP_INDEX_PREFIX;
399
memcpy(index_name, key->name, len);
401
if (key->flags & HA_NOSAME) {
402
index->ind_type |= DICT_UNIQUE;
406
index->ind_type |= DICT_CLUSTERED;
409
for (i = 0; i < n_fields; i++) {
410
innobase_create_index_field_def(&key->key_part[i], heap,
417
/*******************************************************************//**
418
Copy index field definition */
421
innobase_copy_index_field_def(
422
/*==========================*/
423
const dict_field_t* field, /*!< in: definition to copy */
424
merge_index_field_t* index_field) /*!< out: copied definition */
426
assert(field != NULL);
427
assert(index_field != NULL);
429
index_field->field_name = field->name;
430
index_field->prefix_len = field->prefix_len;
435
/*******************************************************************//**
436
Copy index definition for the index */
439
innobase_copy_index_def(
440
/*====================*/
441
const dict_index_t* index, /*!< in: index definition to copy */
442
merge_index_def_t* new_index,/*!< out: Index definition */
443
mem_heap_t* heap) /*!< in: heap where allocated */
448
/* Note that we take only those fields that user defined to be
449
in the index. In the internal representation more colums were
450
added and those colums are not copied .*/
452
n_fields = index->n_user_defined_cols;
454
new_index->fields = (merge_index_field_t*) mem_heap_alloc(
455
heap, n_fields * sizeof *new_index->fields);
457
/* When adding a PRIMARY KEY, we may convert a previous
458
clustered index to a secondary index (UNIQUE NOT NULL). */
459
new_index->ind_type = index->type & ~DICT_CLUSTERED;
460
new_index->n_fields = n_fields;
461
new_index->name = index->name;
463
for (i = 0; i < n_fields; i++) {
464
innobase_copy_index_field_def(&index->fields[i],
465
&new_index->fields[i]);
471
/*******************************************************************//**
472
Create an index table where indexes are ordered as follows:
474
IF a new primary key is defined for the table THEN
477
2) Original secondary indexes
478
3) New secondary indexes
482
1) All new indexes in the order they arrive from MySQL
487
@return key definitions or NULL */
490
innobase_create_key_def(
491
/*====================*/
492
trx_t* trx, /*!< in: trx */
493
const dict_table_t*table, /*!< in: table definition */
494
mem_heap_t* heap, /*!< in: heap where space for key
495
definitions are allocated */
496
KEY* key_info, /*!< in: Indexes to be created */
497
ulint& n_keys) /*!< in/out: Number of indexes to
501
merge_index_def_t* indexdef;
502
merge_index_def_t* indexdefs;
505
indexdef = indexdefs = (merge_index_def_t*)
506
mem_heap_alloc(heap, sizeof *indexdef
507
* (n_keys + UT_LIST_GET_LEN(table->indexes)));
509
/* If there is a primary key, it is always the first index
510
defined for the table. */
512
new_primary = !my_strcasecmp(system_charset_info,
513
key_info->name, "PRIMARY");
515
/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
516
columns, MySQL will treat it as a PRIMARY KEY unless the
517
table already has one. */
519
if (!new_primary && (key_info->flags & HA_NOSAME)
520
&& row_table_got_default_clust_index(table)) {
521
uint key_part = key_info->key_parts;
526
if (key_info->key_part[key_part].null_bit == 0) {
534
const dict_index_t* index;
536
/* Create the PRIMARY key index definition */
537
innobase_create_index_def(&key_info[i++], TRUE, TRUE,
540
row_mysql_lock_data_dictionary(trx);
542
index = dict_table_get_first_index(table);
544
/* Copy the index definitions of the old table. Skip
545
the old clustered index if it is a generated clustered
546
index or a PRIMARY KEY. If the clustered index is a
547
UNIQUE INDEX, it must be converted to a secondary index. */
549
if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
550
|| !my_strcasecmp(system_charset_info,
551
index->name, "PRIMARY")) {
552
index = dict_table_get_next_index(index);
556
innobase_copy_index_def(index, indexdef++, heap);
557
index = dict_table_get_next_index(index);
560
row_mysql_unlock_data_dictionary(trx);
563
/* Create definitions for added secondary indexes. */
566
innobase_create_index_def(&key_info[i++], new_primary, FALSE,
570
n_keys = indexdef - indexdefs;
575
/*******************************************************************//**
576
Create a temporary tablename using query id, thread id, and id
577
@return temporary tablename */
580
innobase_create_temporary_tablename(
581
/*================================*/
582
mem_heap_t* heap, /*!< in: memory heap */
583
char id, /*!< in: identifier [0-9a-zA-Z] */
584
const char* table_name) /*!< in: table name */
588
static const char suffix[] = "@0023 "; /* "# " */
590
len = strlen(table_name);
592
name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
593
memcpy(name, table_name, len);
594
memcpy(name + len, suffix, sizeof suffix);
595
name[len + (sizeof suffix - 2)] = id;
600
/*******************************************************************//**
602
@return 0 or error number */
605
ha_innobase::add_index(
606
/*===================*/
607
Table* i_table, /*!< in: Table where indexes are created */
608
KEY* key_info, /*!< in: Indexes to be created */
609
uint num_of_keys) /*!< in: Number of indexes to be created */
611
dict_index_t** index; /*!< Index to be created */
612
dict_table_t* innodb_table; /*!< InnoDB table in dictionary */
613
dict_table_t* indexed_table; /*!< Table where indexes are created */
614
merge_index_def_t* index_defs; /*!< Index definitions */
615
mem_heap_t* heap; /*!< Heap for index definitions */
616
trx_t* trx; /*!< Transaction */
618
ulint num_created = 0;
619
ibool dict_locked = FALSE;
627
if (srv_created_new_raw || srv_force_recovery) {
628
return(HA_ERR_WRONG_COMMAND);
633
heap = mem_heap_create(1024);
635
/* In case MySQL calls this in the middle of a SELECT query, release
636
possible adaptive hash latch to avoid deadlocks of threads. */
637
trx_search_latch_release_if_reserved(prebuilt->trx);
638
trx_start_if_not_started(prebuilt->trx);
640
/* Create a background transaction for the operations on
641
the data dictionary tables. */
642
trx = innobase_trx_allocate(user_session);
643
trx_start_if_not_started(trx);
645
innodb_table = indexed_table
646
= dict_table_get(prebuilt->table->name, FALSE);
648
/* Check that index keys are sensible */
650
error = innobase_check_index_keys(key_info, num_of_keys);
652
if (UNIV_UNLIKELY(error)) {
655
trx_general_rollback_for_mysql(trx, FALSE, NULL);
656
trx_free_for_mysql(trx);
657
trx_commit_for_mysql(prebuilt->trx);
661
/* Create table containing all indexes to be built in this
662
alter table add index so that they are in the correct order
665
num_of_idx = num_of_keys;
667
index_defs = innobase_create_key_def(
668
trx, innodb_table, heap, key_info, num_of_idx);
670
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
672
/* Allocate memory for dictionary index definitions */
674
index = (dict_index_t**) mem_heap_alloc(
675
heap, num_of_idx * sizeof *index);
677
/* Flag this transaction as a dictionary operation, so that
678
the data dictionary will be locked in crash recovery. */
679
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
681
/* Acquire a lock on the table before creating any indexes. */
682
error = row_merge_lock_table(prebuilt->trx, innodb_table,
683
new_primary ? LOCK_X : LOCK_S);
685
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
690
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
691
or lock waits can happen in it during an index create operation. */
693
row_mysql_lock_data_dictionary(trx);
696
/* If a new primary key is defined for the table we need
697
to drop the original table and rebuild all indexes. */
699
if (UNIV_UNLIKELY(new_primary)) {
700
/* This transaction should be the only one
701
operating on the table. */
702
ut_a(innodb_table->n_mysql_handles_opened == 1);
704
char* new_table_name = innobase_create_temporary_tablename(
705
heap, '1', innodb_table->name);
707
/* Clone the table. */
708
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
709
indexed_table = row_merge_create_temporary_table(
710
new_table_name, index_defs, innodb_table, trx);
712
if (!indexed_table) {
714
switch (trx->error_state) {
715
case DB_TABLESPACE_ALREADY_EXISTS:
716
case DB_DUPLICATE_KEY:
717
innobase_convert_tablename(new_table_name);
718
my_error(HA_ERR_TABLE_EXIST, MYF(0),
720
error = HA_ERR_TABLE_EXIST;
723
error = convert_error_code_to_mysql(
724
trx->error_state, innodb_table->flags,
728
row_mysql_unlock_data_dictionary(trx);
732
trx->table_id = indexed_table->id;
735
/* Create the indexes in SYS_INDEXES and load into dictionary. */
737
for (ulint i = 0; i < num_of_idx; i++) {
739
index[i] = row_merge_create_index(trx, indexed_table,
743
error = trx->error_state;
750
ut_ad(error == DB_SUCCESS);
752
/* Commit the data dictionary transaction in order to release
753
the table locks on the system tables. Unfortunately, this
754
means that if MySQL crashes while creating a new primary key
755
inside row_merge_build_indexes(), indexed_table will not be
756
dropped on crash recovery. Thus, it will become orphaned. */
757
trx_commit_for_mysql(trx);
759
row_mysql_unlock_data_dictionary(trx);
762
ut_a(trx->n_active_thrs == 0);
763
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
765
if (UNIV_UNLIKELY(new_primary)) {
766
/* A primary key is to be built. Acquire an exclusive
767
table lock also on the table that is being created. */
768
ut_ad(indexed_table != innodb_table);
770
error = row_merge_lock_table(prebuilt->trx, indexed_table,
773
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
779
/* Read the clustered index of the table and build indexes
780
based on this information using temporary files and merge sort. */
781
error = row_merge_build_indexes(prebuilt->trx,
782
innodb_table, indexed_table,
783
index, num_of_idx, i_table);
787
/* TODO: At the moment we can't handle the following statement
788
in our debugging code below:
790
alter table t drop index b, add index (b);
792
The fix will have to parse the SQL and note that the index
793
being added has the same name as the the one being dropped and
794
ignore that in the dup index check.*/
795
//dict_table_check_for_dup_indexes(prebuilt->table);
798
/* After an error, remove all those index definitions from the
799
dictionary which were defined. */
802
const char* old_name;
806
row_mysql_lock_data_dictionary(trx);
810
error = row_merge_rename_indexes(trx, indexed_table);
812
if (error != DB_SUCCESS) {
813
row_merge_drop_indexes(trx, indexed_table,
820
/* If a new primary key was defined for the table and
821
there was no error at this point, we can now rename
822
the old table as a temporary table, rename the new
823
temporary table as the old table and drop the old table. */
824
old_name = innodb_table->name;
825
tmp_name = innobase_create_temporary_tablename(heap, '2',
828
error = row_merge_rename_tables(innodb_table, indexed_table,
831
if (error != DB_SUCCESS) {
833
row_merge_drop_table(trx, indexed_table);
836
case DB_TABLESPACE_ALREADY_EXISTS:
837
case DB_DUPLICATE_KEY:
838
innobase_convert_tablename(tmp_name);
839
my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
840
error = HA_ERR_TABLE_EXIST;
848
trx_commit_for_mysql(prebuilt->trx);
849
row_prebuilt_free(prebuilt, TRUE);
850
prebuilt = row_create_prebuilt(indexed_table);
852
indexed_table->n_mysql_handles_opened++;
854
error = row_merge_drop_table(trx, innodb_table);
857
case DB_TOO_BIG_RECORD:
858
my_error(HA_ERR_TO_BIG_ROW, MYF(0));
860
case DB_PRIMARY_KEY_IS_NULL:
861
my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
863
case DB_DUPLICATE_KEY:
865
prebuilt->trx->error_info = NULL;
869
row_merge_drop_table(trx, indexed_table);
872
row_mysql_lock_data_dictionary(trx);
876
row_merge_drop_indexes(trx, indexed_table,
881
error = convert_error_code_to_mysql(error,
887
trx_commit_for_mysql(trx);
889
trx_commit_for_mysql(prebuilt->trx);
893
row_mysql_unlock_data_dictionary(trx);
896
trx_free_for_mysql(trx);
898
/* There might be work for utility threads.*/
899
srv_active_wake_master_thread();
904
/*******************************************************************//**
905
Prepare to drop some indexes of a table.
906
@return 0 or error number */
909
ha_innobase::prepare_drop_index(
910
/*============================*/
911
Table* i_table, /*!< in: Table where indexes are dropped */
912
uint* key_num, /*!< in: Key nums to be dropped */
913
uint num_of_keys) /*!< in: Number of keys to be dropped */
922
if (srv_created_new_raw || srv_force_recovery) {
923
return(HA_ERR_WRONG_COMMAND);
928
trx_search_latch_release_if_reserved(prebuilt->trx);
931
/* Test and mark all the indexes to be dropped */
933
row_mysql_lock_data_dictionary(trx);
935
/* Check that none of the indexes have previously been flagged
938
const dict_index_t* index
939
= dict_table_get_first_index(prebuilt->table);
941
ut_a(!index->to_be_dropped);
942
index = dict_table_get_next_index(index);
946
for (n_key = 0; n_key < num_of_keys; n_key++) {
950
key = i_table->key_info + key_num[n_key];
951
index = dict_table_get_index_on_name_and_min_id(
952
prebuilt->table, key->name);
955
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB could not find key n:o %u "
956
"with name %s for table %s",
958
key ? key->name : "NULL",
959
prebuilt->table->name);
961
err = HA_ERR_KEY_NOT_FOUND;
965
/* Refuse to drop the clustered index. It would be
966
better to automatically generate a clustered index,
967
but drizzled::alter_table() will call this method only
968
after ha_innobase::add_index(). */
970
if (dict_index_is_clust(index)) {
971
my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
976
index->to_be_dropped = TRUE;
979
/* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
980
for a foreign key constraint because InnoDB requires that both
981
tables contain indexes for the constraint. Note that CREATE
982
INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
983
can ignore here foreign keys because a new index for the
984
foreign key has already been created.
986
We check for the foreign key constraints after marking the
987
candidate indexes for deletion, because when we check for an
988
equivalent foreign index we don't want to select an index that
991
if (trx->check_foreigns
992
&& session_sql_command(user_session) != SQLCOM_CREATE_INDEX) {
995
for (index = dict_table_get_first_index(prebuilt->table);
997
index = dict_table_get_next_index(index)) {
998
dict_foreign_t* foreign;
1000
if (!index->to_be_dropped) {
1005
/* Check if the index is referenced. */
1006
foreign = dict_table_get_referenced_constraint(
1007
prebuilt->table, index);
1011
trx_set_detailed_error(
1013
"Index needed in foreign key "
1016
trx->error_info = index;
1018
err = HA_ERR_DROP_INDEX_FK;
1021
/* Check if this index references some
1023
foreign = dict_table_get_foreign_constraint(
1024
prebuilt->table, index);
1027
ut_a(foreign->foreign_index == index);
1029
/* Search for an equivalent index that
1030
the foreign key constraint could use
1031
if this index were to be deleted. */
1032
if (!dict_foreign_find_equiv_index(
1040
} else if (session_sql_command(user_session) == SQLCOM_CREATE_INDEX) {
1041
/* This is a drop of a foreign key constraint index that
1042
was created by MySQL when the constraint was added. MySQL
1043
does this when the user creates an index explicitly which
1044
can be used in place of the automatically generated index. */
1046
dict_index_t* index;
1048
for (index = dict_table_get_first_index(prebuilt->table);
1050
index = dict_table_get_next_index(index)) {
1051
dict_foreign_t* foreign;
1053
if (!index->to_be_dropped) {
1058
/* Check if this index references some other table */
1059
foreign = dict_table_get_foreign_constraint(
1060
prebuilt->table, index);
1062
if (foreign == NULL) {
1067
ut_a(foreign->foreign_index == index);
1069
/* Search for an equivalent index that the
1070
foreign key constraint could use if this index
1071
were to be deleted. */
1073
if (!dict_foreign_find_equiv_index(foreign)) {
1074
trx_set_detailed_error(
1076
"Index needed in foreign key "
1079
trx->error_info = foreign->foreign_index;
1081
err = HA_ERR_DROP_INDEX_FK;
1089
/* Undo our changes since there was some sort of error. */
1091
= dict_table_get_first_index(prebuilt->table);
1094
index->to_be_dropped = FALSE;
1095
index = dict_table_get_next_index(index);
1099
row_mysql_unlock_data_dictionary(trx);
1104
/*******************************************************************//**
1105
Drop the indexes that were passed to a successful prepare_drop_index().
1106
@return 0 or error number */
1109
ha_innobase::final_drop_index(
1110
/*==========================*/
1111
Table* ) /*!< in: Table where indexes are dropped */
1113
dict_index_t* index; /*!< Index to be dropped */
1114
trx_t* trx; /*!< Transaction */
1117
if (srv_created_new_raw || srv_force_recovery) {
1118
return(HA_ERR_WRONG_COMMAND);
1123
trx_search_latch_release_if_reserved(prebuilt->trx);
1124
trx_start_if_not_started(prebuilt->trx);
1126
/* Create a background transaction for the operations on
1127
the data dictionary tables. */
1128
trx = innobase_trx_allocate(user_session);
1129
trx_start_if_not_started(trx);
1131
/* Flag this transaction as a dictionary operation, so that
1132
the data dictionary will be locked in crash recovery. */
1133
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1135
/* Lock the table exclusively, to ensure that no active
1136
transaction depends on an index that is being dropped. */
1137
err = convert_error_code_to_mysql(
1138
row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1139
prebuilt->table->flags, user_session);
1141
row_mysql_lock_data_dictionary(trx);
1143
if (UNIV_UNLIKELY(err)) {
1145
/* Unmark the indexes to be dropped. */
1146
for (index = dict_table_get_first_index(prebuilt->table);
1147
index; index = dict_table_get_next_index(index)) {
1149
index->to_be_dropped = FALSE;
1155
/* Drop indexes marked to be dropped */
1157
index = dict_table_get_first_index(prebuilt->table);
1160
dict_index_t* next_index;
1162
next_index = dict_table_get_next_index(index);
1164
if (index->to_be_dropped) {
1166
row_merge_drop_index(index, prebuilt->table, trx);
1172
/* Check that all flagged indexes were dropped. */
1173
for (index = dict_table_get_first_index(prebuilt->table);
1174
index; index = dict_table_get_next_index(index)) {
1175
ut_a(!index->to_be_dropped);
1179
dict_table_check_for_dup_indexes(prebuilt->table);
1183
trx_commit_for_mysql(trx);
1184
trx_commit_for_mysql(prebuilt->trx);
1185
row_mysql_unlock_data_dictionary(trx);
1187
/* Flush the log to reduce probability that the .frm files and
1188
the InnoDB data dictionary get out-of-sync if the user runs
1189
with innodb_flush_log_at_trx_commit = 0 */
1191
log_buffer_flush_to_disk();
1193
trx_free_for_mysql(trx);
1195
/* Tell the InnoDB server that there might be work for
1198
srv_active_wake_master_thread();