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"
34
#include "row0merge.h"
38
#include "ha_prototypes.h"
39
#include "handler0alter.h"
42
#include "ha_innodb.h"
43
#include "handler0vars.h"
45
/*************************************************************//**
46
Copies an InnoDB column to a MySQL field. This function is
47
adapted from row_sel_field_store_in_mysql_format(). */
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 */
58
unsigned char* dest = field->ptr;
59
ulint flen = field->pack_length();
65
/* Convert integer data from Innobase to little-endian
66
format, sign bit restored to normal */
68
for (ptr = dest + len; ptr != dest; ) {
72
if (!(field->flags & UNSIGNED_FLAG)) {
73
((byte*) dest)[len - 1] ^= 0x80;
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
88
dest = row_mysql_store_true_var_len(
89
dest, len, flen - field->key_length());
92
/* Copy the actual data */
93
memcpy(dest, data, len);
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 */
100
row_mysql_store_blob_ref(dest, flen, data, len);
106
ut_ad(col->mbmaxlen >= col->mbminlen);
107
ut_ad(col->mbmaxlen > col->mbminlen || flen == len);
108
memcpy(dest, data, len);
114
/* These column types should never be shipped to MySQL. */
122
/* Above are the valid column types for MySQL data. */
124
#else /* UNIV_DEBUG */
126
#endif /* UNIV_DEBUG */
127
memcpy(dest, data, len);
131
/*************************************************************//**
132
Copies an InnoDB record to table->record[0]. */
133
extern "C" UNIV_INTERN
135
innobase_rec_to_mysql(
136
/*==================*/
137
Table* table, /*!< in/out: MySQL table */
138
const rec_t* rec, /*!< in: record */
139
const dict_index_t* index, /*!< in: index */
140
const ulint* offsets) /*!< in: rec_get_offsets(
143
uint n_fields = table->s->fields;
146
ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
148
for (i = 0; i < n_fields; i++) {
149
Field* field = table->field[i];
152
const unsigned char* ifield;
156
ipos = dict_index_get_nth_col_pos(index, i);
158
if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
164
ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
166
/* Assign the NULL flag */
167
if (ilen == UNIV_SQL_NULL) {
168
ut_ad(field->real_maybe_null());
172
field->set_notnull();
174
innobase_col_to_mysql(
176
dict_index_get_nth_field(index, ipos)),
177
ifield, ilen, field);
181
/*************************************************************//**
182
Resets table->record[0]. */
183
extern "C" UNIV_INTERN
187
Table* table) /*!< in/out: MySQL table */
189
uint n_fields = table->s->fields;
192
for (i = 0; i < n_fields; i++) {
193
table->field[i]->set_default();
197
/******************************************************************//**
198
Removes the filename encoding of a database and table name. */
201
innobase_convert_tablename(
202
/*=======================*/
203
char* s) /*!< in: identifier; out: decoded identifier */
206
char* slash = strchr(s, '/');
210
/* Temporarily replace the '/' with NUL. */
212
strncpy(s, s, slash - s + 1);
216
/* Append a '.' after the database name. */
219
/* Convert the table name. */
220
strncpy(t, slash, slash - t + strlen(slash));
224
/*******************************************************************//**
225
This function checks that index keys are sensible.
226
@return 0 or error number */
229
innobase_check_index_keys(
230
/*======================*/
231
const KEY* key_info, /*!< in: Indexes to be created */
232
ulint num_of_keys) /*!< in: Number of indexes to
240
for (key_num = 0; key_num < num_of_keys; key_num++) {
241
const KEY& key = key_info[key_num];
243
/* Check that the same index name does not appear
244
twice in indexes to be created. */
246
for (ulint i = 0; i < key_num; i++) {
247
const KEY& key2 = key_info[i];
249
if (0 == strcmp(key.name, key2.name)) {
250
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: key name `%s` appears"
251
" twice in CREATE INDEX\n",
254
return(ER_WRONG_NAME_FOR_INDEX);
258
/* Check that MySQL does not try to create a column
259
prefix index field on an inappropriate data type and
260
that the same colum does not appear twice in the index. */
262
for (ulint i = 0; i < key.key_parts; i++) {
263
const KEY_PART_INFO& key_part1
269
switch (get_innobase_type_from_mysql_type(
270
&is_unsigned, field)) {
277
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
279
>= field->pack_length()
280
- ((Field_varstring*) field)
286
>= field->pack_length()) {
291
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: MySQL is trying to"
292
" create a column prefix"
294
" inappropriate data type."
299
return(ER_WRONG_KEY_COLUMN);
302
for (ulint j = 0; j < i; j++) {
303
const KEY_PART_INFO& key_part2
306
if (strcmp(key_part1.field->field_name,
307
key_part2.field->field_name)) {
311
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: column `%s`"
312
" is not allowed to occur"
313
" twice in index `%s`.\n",
314
key_part1.field->field_name,
316
return(ER_WRONG_KEY_COLUMN);
324
/*******************************************************************//**
325
Create index field definition for key part */
328
innobase_create_index_field_def(
329
/*============================*/
330
KEY_PART_INFO* key_part, /*!< in: MySQL key definition */
331
mem_heap_t* heap, /*!< in: memory heap */
332
merge_index_field_t* index_field) /*!< out: index field
333
definition for key_part */
342
field = key_part->field;
345
col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
347
if (DATA_BLOB == col_type
348
|| (key_part->length < field->pack_length()
349
&& field->type() != DRIZZLE_TYPE_VARCHAR)
350
|| (field->type() == DRIZZLE_TYPE_VARCHAR
351
&& key_part->length < field->pack_length()
352
- ((Field_varstring*)field)->length_bytes)) {
354
index_field->prefix_len = key_part->length;
356
index_field->prefix_len = 0;
359
index_field->field_name = mem_heap_strdup(heap, field->field_name);
364
/*******************************************************************//**
365
Create index definition for key */
368
innobase_create_index_def(
369
/*======================*/
370
KEY* key, /*!< in: key definition */
371
bool new_primary, /*!< in: TRUE=generating
374
bool key_primary, /*!< in: TRUE if this key
376
merge_index_def_t* index, /*!< out: index definition */
377
mem_heap_t* heap) /*!< in: heap where memory
382
ulint n_fields = key->key_parts;
385
index->fields = (merge_index_field_t*) mem_heap_alloc(
386
heap, n_fields * sizeof *index->fields);
389
index->n_fields = n_fields;
390
len = strlen(key->name) + 1;
391
index->name = index_name = (char*) mem_heap_alloc(heap,
394
if (UNIV_LIKELY(!new_primary)) {
395
*index_name++ = TEMP_INDEX_PREFIX;
398
memcpy(index_name, key->name, len);
400
if (key->flags & HA_NOSAME) {
401
index->ind_type |= DICT_UNIQUE;
405
index->ind_type |= DICT_CLUSTERED;
408
for (i = 0; i < n_fields; i++) {
409
innobase_create_index_field_def(&key->key_part[i], heap,
416
/*******************************************************************//**
417
Copy index field definition */
420
innobase_copy_index_field_def(
421
/*==========================*/
422
const dict_field_t* field, /*!< in: definition to copy */
423
merge_index_field_t* index_field) /*!< out: copied definition */
425
assert(field != NULL);
426
assert(index_field != NULL);
428
index_field->field_name = field->name;
429
index_field->prefix_len = field->prefix_len;
434
/*******************************************************************//**
435
Copy index definition for the index */
438
innobase_copy_index_def(
439
/*====================*/
440
const dict_index_t* index, /*!< in: index definition to copy */
441
merge_index_def_t* new_index,/*!< out: Index definition */
442
mem_heap_t* heap) /*!< in: heap where allocated */
447
/* Note that we take only those fields that user defined to be
448
in the index. In the internal representation more colums were
449
added and those colums are not copied .*/
451
n_fields = index->n_user_defined_cols;
453
new_index->fields = (merge_index_field_t*) mem_heap_alloc(
454
heap, n_fields * sizeof *new_index->fields);
456
/* When adding a PRIMARY KEY, we may convert a previous
457
clustered index to a secondary index (UNIQUE NOT NULL). */
458
new_index->ind_type = index->type & ~DICT_CLUSTERED;
459
new_index->n_fields = n_fields;
460
new_index->name = index->name;
462
for (i = 0; i < n_fields; i++) {
463
innobase_copy_index_field_def(&index->fields[i],
464
&new_index->fields[i]);
470
/*******************************************************************//**
471
Create an index table where indexes are ordered as follows:
473
IF a new primary key is defined for the table THEN
476
2) Original secondary indexes
477
3) New secondary indexes
481
1) All new indexes in the order they arrive from MySQL
486
@return key definitions or NULL */
489
innobase_create_key_def(
490
/*====================*/
491
trx_t* trx, /*!< in: trx */
492
const dict_table_t*table, /*!< in: table definition */
493
mem_heap_t* heap, /*!< in: heap where space for key
494
definitions are allocated */
495
KEY* key_info, /*!< in: Indexes to be created */
496
ulint& n_keys) /*!< in/out: Number of indexes to
500
merge_index_def_t* indexdef;
501
merge_index_def_t* indexdefs;
504
indexdef = indexdefs = (merge_index_def_t*)
505
mem_heap_alloc(heap, sizeof *indexdef
506
* (n_keys + UT_LIST_GET_LEN(table->indexes)));
508
/* If there is a primary key, it is always the first index
509
defined for the table. */
511
new_primary = !my_strcasecmp(system_charset_info,
512
key_info->name, "PRIMARY");
514
/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
515
columns, MySQL will treat it as a PRIMARY KEY unless the
516
table already has one. */
518
if (!new_primary && (key_info->flags & HA_NOSAME)
519
&& row_table_got_default_clust_index(table)) {
520
uint key_part = key_info->key_parts;
525
if (key_info->key_part[key_part].null_bit == 0) {
533
const dict_index_t* index;
535
/* Create the PRIMARY key index definition */
536
innobase_create_index_def(&key_info[i++], TRUE, TRUE,
539
row_mysql_lock_data_dictionary(trx);
541
index = dict_table_get_first_index(table);
543
/* Copy the index definitions of the old table. Skip
544
the old clustered index if it is a generated clustered
545
index or a PRIMARY KEY. If the clustered index is a
546
UNIQUE INDEX, it must be converted to a secondary index. */
548
if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
549
|| !my_strcasecmp(system_charset_info,
550
index->name, "PRIMARY")) {
551
index = dict_table_get_next_index(index);
555
innobase_copy_index_def(index, indexdef++, heap);
556
index = dict_table_get_next_index(index);
559
row_mysql_unlock_data_dictionary(trx);
562
/* Create definitions for added secondary indexes. */
565
innobase_create_index_def(&key_info[i++], new_primary, FALSE,
569
n_keys = indexdef - indexdefs;
574
/*******************************************************************//**
575
Create a temporary tablename using query id, thread id, and id
576
@return temporary tablename */
579
innobase_create_temporary_tablename(
580
/*================================*/
581
mem_heap_t* heap, /*!< in: memory heap */
582
char id, /*!< in: identifier [0-9a-zA-Z] */
583
const char* table_name) /*!< in: table name */
587
static const char suffix[] = "@0023 "; /* "# " */
589
len = strlen(table_name);
591
name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
592
memcpy(name, table_name, len);
593
memcpy(name + len, suffix, sizeof suffix);
594
name[len + (sizeof suffix - 2)] = id;
599
/*******************************************************************//**
601
@return 0 or error number */
604
ha_innobase::add_index(
605
/*===================*/
606
Table* i_table, /*!< in: Table where indexes are created */
607
KEY* key_info, /*!< in: Indexes to be created */
608
uint num_of_keys) /*!< in: Number of indexes to be created */
610
dict_index_t** index; /*!< Index to be created */
611
dict_table_t* innodb_table; /*!< InnoDB table in dictionary */
612
dict_table_t* indexed_table; /*!< Table where indexes are created */
613
merge_index_def_t* index_defs; /*!< Index definitions */
614
mem_heap_t* heap; /*!< Heap for index definitions */
615
trx_t* trx; /*!< Transaction */
617
ulint num_created = 0;
618
ibool dict_locked = FALSE;
626
if (srv_created_new_raw || srv_force_recovery) {
627
return(HA_ERR_WRONG_COMMAND);
632
heap = mem_heap_create(1024);
634
/* In case MySQL calls this in the middle of a SELECT query, release
635
possible adaptive hash latch to avoid deadlocks of threads. */
636
trx_search_latch_release_if_reserved(prebuilt->trx);
637
trx_start_if_not_started(prebuilt->trx);
639
/* Create a background transaction for the operations on
640
the data dictionary tables. */
641
trx = innobase_trx_allocate(user_session);
642
trx_start_if_not_started(trx);
644
innodb_table = indexed_table
645
= dict_table_get(prebuilt->table->name, FALSE);
647
/* Check that index keys are sensible */
649
error = innobase_check_index_keys(key_info, num_of_keys);
651
if (UNIV_UNLIKELY(error)) {
654
trx_general_rollback_for_mysql(trx, FALSE, NULL);
655
trx_free_for_mysql(trx);
656
trx_commit_for_mysql(prebuilt->trx);
660
/* Create table containing all indexes to be built in this
661
alter table add index so that they are in the correct order
664
num_of_idx = num_of_keys;
666
index_defs = innobase_create_key_def(
667
trx, innodb_table, heap, key_info, num_of_idx);
669
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
671
/* Allocate memory for dictionary index definitions */
673
index = (dict_index_t**) mem_heap_alloc(
674
heap, num_of_idx * sizeof *index);
676
/* Flag this transaction as a dictionary operation, so that
677
the data dictionary will be locked in crash recovery. */
678
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
680
/* Acquire a lock on the table before creating any indexes. */
681
error = row_merge_lock_table(prebuilt->trx, innodb_table,
682
new_primary ? LOCK_X : LOCK_S);
684
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
689
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
690
or lock waits can happen in it during an index create operation. */
692
row_mysql_lock_data_dictionary(trx);
695
/* If a new primary key is defined for the table we need
696
to drop the original table and rebuild all indexes. */
698
if (UNIV_UNLIKELY(new_primary)) {
699
/* This transaction should be the only one
700
operating on the table. */
701
ut_a(innodb_table->n_mysql_handles_opened == 1);
703
char* new_table_name = innobase_create_temporary_tablename(
704
heap, '1', innodb_table->name);
706
/* Clone the table. */
707
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
708
indexed_table = row_merge_create_temporary_table(
709
new_table_name, index_defs, innodb_table, trx);
711
if (!indexed_table) {
713
switch (trx->error_state) {
714
case DB_TABLESPACE_ALREADY_EXISTS:
715
case DB_DUPLICATE_KEY:
716
innobase_convert_tablename(new_table_name);
717
my_error(HA_ERR_TABLE_EXIST, MYF(0),
719
error = HA_ERR_TABLE_EXIST;
722
error = convert_error_code_to_mysql(
723
trx->error_state, innodb_table->flags,
727
row_mysql_unlock_data_dictionary(trx);
731
trx->table_id = indexed_table->id;
734
/* Create the indexes in SYS_INDEXES and load into dictionary. */
736
for (ulint i = 0; i < num_of_idx; i++) {
738
index[i] = row_merge_create_index(trx, indexed_table,
742
error = trx->error_state;
749
ut_ad(error == DB_SUCCESS);
751
/* Commit the data dictionary transaction in order to release
752
the table locks on the system tables. Unfortunately, this
753
means that if MySQL crashes while creating a new primary key
754
inside row_merge_build_indexes(), indexed_table will not be
755
dropped on crash recovery. Thus, it will become orphaned. */
756
trx_commit_for_mysql(trx);
758
row_mysql_unlock_data_dictionary(trx);
761
ut_a(trx->n_active_thrs == 0);
762
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
764
if (UNIV_UNLIKELY(new_primary)) {
765
/* A primary key is to be built. Acquire an exclusive
766
table lock also on the table that is being created. */
767
ut_ad(indexed_table != innodb_table);
769
error = row_merge_lock_table(prebuilt->trx, indexed_table,
772
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
778
/* Read the clustered index of the table and build indexes
779
based on this information using temporary files and merge sort. */
780
error = row_merge_build_indexes(prebuilt->trx,
781
innodb_table, indexed_table,
782
index, num_of_idx, i_table);
786
/* TODO: At the moment we can't handle the following statement
787
in our debugging code below:
789
alter table t drop index b, add index (b);
791
The fix will have to parse the SQL and note that the index
792
being added has the same name as the the one being dropped and
793
ignore that in the dup index check.*/
794
//dict_table_check_for_dup_indexes(prebuilt->table);
797
/* After an error, remove all those index definitions from the
798
dictionary which were defined. */
801
const char* old_name;
805
row_mysql_lock_data_dictionary(trx);
809
error = row_merge_rename_indexes(trx, indexed_table);
811
if (error != DB_SUCCESS) {
812
row_merge_drop_indexes(trx, indexed_table,
819
/* If a new primary key was defined for the table and
820
there was no error at this point, we can now rename
821
the old table as a temporary table, rename the new
822
temporary table as the old table and drop the old table. */
823
old_name = innodb_table->name;
824
tmp_name = innobase_create_temporary_tablename(heap, '2',
827
error = row_merge_rename_tables(innodb_table, indexed_table,
830
if (error != DB_SUCCESS) {
832
row_merge_drop_table(trx, indexed_table);
835
case DB_TABLESPACE_ALREADY_EXISTS:
836
case DB_DUPLICATE_KEY:
837
innobase_convert_tablename(tmp_name);
838
my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
839
error = HA_ERR_TABLE_EXIST;
847
trx_commit_for_mysql(prebuilt->trx);
848
row_prebuilt_free(prebuilt, TRUE);
849
prebuilt = row_create_prebuilt(indexed_table);
851
indexed_table->n_mysql_handles_opened++;
853
error = row_merge_drop_table(trx, innodb_table);
856
case DB_TOO_BIG_RECORD:
857
my_error(HA_ERR_TO_BIG_ROW, MYF(0));
859
case DB_PRIMARY_KEY_IS_NULL:
860
my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
862
case DB_DUPLICATE_KEY:
864
prebuilt->trx->error_info = NULL;
868
row_merge_drop_table(trx, indexed_table);
871
row_mysql_lock_data_dictionary(trx);
875
row_merge_drop_indexes(trx, indexed_table,
880
error = convert_error_code_to_mysql(error,
886
trx_commit_for_mysql(trx);
888
trx_commit_for_mysql(prebuilt->trx);
892
row_mysql_unlock_data_dictionary(trx);
895
trx_free_for_mysql(trx);
897
/* There might be work for utility threads.*/
898
srv_active_wake_master_thread();
903
/*******************************************************************//**
904
Prepare to drop some indexes of a table.
905
@return 0 or error number */
908
ha_innobase::prepare_drop_index(
909
/*============================*/
910
Table* i_table, /*!< in: Table where indexes are dropped */
911
uint* key_num, /*!< in: Key nums to be dropped */
912
uint num_of_keys) /*!< in: Number of keys to be dropped */
921
if (srv_created_new_raw || srv_force_recovery) {
922
return(HA_ERR_WRONG_COMMAND);
927
trx_search_latch_release_if_reserved(prebuilt->trx);
930
/* Test and mark all the indexes to be dropped */
932
row_mysql_lock_data_dictionary(trx);
934
/* Check that none of the indexes have previously been flagged
937
const dict_index_t* index
938
= dict_table_get_first_index(prebuilt->table);
940
ut_a(!index->to_be_dropped);
941
index = dict_table_get_next_index(index);
945
for (n_key = 0; n_key < num_of_keys; n_key++) {
949
key = i_table->key_info + key_num[n_key];
950
index = dict_table_get_index_on_name_and_min_id(
951
prebuilt->table, key->name);
954
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB could not find key n:o %u "
955
"with name %s for table %s",
957
key ? key->name : "NULL",
958
prebuilt->table->name);
960
err = HA_ERR_KEY_NOT_FOUND;
964
/* Refuse to drop the clustered index. It would be
965
better to automatically generate a clustered index,
966
but drizzled::alter_table() will call this method only
967
after ha_innobase::add_index(). */
969
if (dict_index_is_clust(index)) {
970
my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
975
index->to_be_dropped = TRUE;
978
/* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
979
for a foreign key constraint because InnoDB requires that both
980
tables contain indexes for the constraint. Note that CREATE
981
INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
982
can ignore here foreign keys because a new index for the
983
foreign key has already been created.
985
We check for the foreign key constraints after marking the
986
candidate indexes for deletion, because when we check for an
987
equivalent foreign index we don't want to select an index that
990
if (trx->check_foreigns
991
&& session_sql_command(user_session) != SQLCOM_CREATE_INDEX) {
994
for (index = dict_table_get_first_index(prebuilt->table);
996
index = dict_table_get_next_index(index)) {
997
dict_foreign_t* foreign;
999
if (!index->to_be_dropped) {
1004
/* Check if the index is referenced. */
1005
foreign = dict_table_get_referenced_constraint(
1006
prebuilt->table, index);
1010
trx_set_detailed_error(
1012
"Index needed in foreign key "
1015
trx->error_info = index;
1017
err = HA_ERR_DROP_INDEX_FK;
1020
/* Check if this index references some
1022
foreign = dict_table_get_foreign_constraint(
1023
prebuilt->table, index);
1026
ut_a(foreign->foreign_index == index);
1028
/* Search for an equivalent index that
1029
the foreign key constraint could use
1030
if this index were to be deleted. */
1031
if (!dict_foreign_find_equiv_index(
1039
} else if (session_sql_command(user_session) == SQLCOM_CREATE_INDEX) {
1040
/* This is a drop of a foreign key constraint index that
1041
was created by MySQL when the constraint was added. MySQL
1042
does this when the user creates an index explicitly which
1043
can be used in place of the automatically generated index. */
1045
dict_index_t* index;
1047
for (index = dict_table_get_first_index(prebuilt->table);
1049
index = dict_table_get_next_index(index)) {
1050
dict_foreign_t* foreign;
1052
if (!index->to_be_dropped) {
1057
/* Check if this index references some other table */
1058
foreign = dict_table_get_foreign_constraint(
1059
prebuilt->table, index);
1061
if (foreign == NULL) {
1066
ut_a(foreign->foreign_index == index);
1068
/* Search for an equivalent index that the
1069
foreign key constraint could use if this index
1070
were to be deleted. */
1072
if (!dict_foreign_find_equiv_index(foreign)) {
1073
trx_set_detailed_error(
1075
"Index needed in foreign key "
1078
trx->error_info = foreign->foreign_index;
1080
err = HA_ERR_DROP_INDEX_FK;
1088
/* Undo our changes since there was some sort of error. */
1090
= dict_table_get_first_index(prebuilt->table);
1093
index->to_be_dropped = FALSE;
1094
index = dict_table_get_next_index(index);
1098
row_mysql_unlock_data_dictionary(trx);
1103
/*******************************************************************//**
1104
Drop the indexes that were passed to a successful prepare_drop_index().
1105
@return 0 or error number */
1108
ha_innobase::final_drop_index(
1109
/*==========================*/
1110
Table* ) /*!< in: Table where indexes are dropped */
1112
dict_index_t* index; /*!< Index to be dropped */
1113
trx_t* trx; /*!< Transaction */
1116
if (srv_created_new_raw || srv_force_recovery) {
1117
return(HA_ERR_WRONG_COMMAND);
1122
trx_search_latch_release_if_reserved(prebuilt->trx);
1123
trx_start_if_not_started(prebuilt->trx);
1125
/* Create a background transaction for the operations on
1126
the data dictionary tables. */
1127
trx = innobase_trx_allocate(user_session);
1128
trx_start_if_not_started(trx);
1130
/* Flag this transaction as a dictionary operation, so that
1131
the data dictionary will be locked in crash recovery. */
1132
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1134
/* Lock the table exclusively, to ensure that no active
1135
transaction depends on an index that is being dropped. */
1136
err = convert_error_code_to_mysql(
1137
row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1138
prebuilt->table->flags, user_session);
1140
row_mysql_lock_data_dictionary(trx);
1142
if (UNIV_UNLIKELY(err)) {
1144
/* Unmark the indexes to be dropped. */
1145
for (index = dict_table_get_first_index(prebuilt->table);
1146
index; index = dict_table_get_next_index(index)) {
1148
index->to_be_dropped = FALSE;
1154
/* Drop indexes marked to be dropped */
1156
index = dict_table_get_first_index(prebuilt->table);
1159
dict_index_t* next_index;
1161
next_index = dict_table_get_next_index(index);
1163
if (index->to_be_dropped) {
1165
row_merge_drop_index(index, prebuilt->table, trx);
1171
/* Check that all flagged indexes were dropped. */
1172
for (index = dict_table_get_first_index(prebuilt->table);
1173
index; index = dict_table_get_next_index(index)) {
1174
ut_a(!index->to_be_dropped);
1178
dict_table_check_for_dup_indexes(prebuilt->table);
1182
trx_commit_for_mysql(trx);
1183
trx_commit_for_mysql(prebuilt->trx);
1184
row_mysql_unlock_data_dictionary(trx);
1186
/* Flush the log to reduce probability that the .frm files and
1187
the InnoDB data dictionary get out-of-sync if the user runs
1188
with innodb_flush_log_at_trx_commit = 0 */
1190
log_buffer_flush_to_disk();
1192
trx_free_for_mysql(trx);
1194
/* Tell the InnoDB server that there might be work for
1197
srv_active_wake_master_thread();