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
/******************************************************
21
*******************************************************/
23
#include <drizzled/server_includes.h>
24
#include <drizzled/error.h>
25
#include <mystrings/m_ctype.h>
26
#include <drizzled/field.h>
27
#include <drizzled/table.h>
28
#include <drizzled/field/varstring.h>
32
#include "row0merge.h"
36
#include "ha_prototypes.h"
37
#include "handler0alter.h"
40
#include "ha_innodb.h"
41
#include "handler0vars.h"
43
/*****************************************************************
44
Copies an InnoDB column to a MySQL field. This function is
45
adapted from row_sel_field_store_in_mysql_format(). */
48
innobase_col_to_mysql(
49
/*==================*/
50
const dict_col_t* col, /* in: InnoDB column */
51
const unsigned char* data, /* in: InnoDB column data */
52
ulint len, /* in: length of data, in bytes */
53
Field* field) /* in/out: MySQL field */
56
unsigned char* dest = field->ptr;
57
ulint flen = field->pack_length();
63
/* Convert integer data from Innobase to little-endian
64
format, sign bit restored to normal */
66
for (ptr = dest + len; ptr != dest; ) {
70
if (!(field->flags & UNSIGNED_FLAG)) {
71
((byte*) dest)[len - 1] ^= 0x80;
81
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
82
/* This is a >= 5.0.3 type true VARCHAR. Store the
83
length of the data to the first byte or the first
86
dest = row_mysql_store_true_var_len(
87
dest, len, flen - field->key_length());
90
/* Copy the actual data */
91
memcpy(dest, data, len);
95
/* Store a pointer to the BLOB buffer to dest: the BLOB was
96
already copied to the buffer in row_sel_store_mysql_rec */
98
row_mysql_store_blob_ref(dest, flen, data, len);
104
ut_ad(col->mbmaxlen >= col->mbminlen);
105
ut_ad(col->mbmaxlen > col->mbminlen || flen == len);
106
memcpy(dest, data, len);
112
/* These column types should never be shipped to MySQL. */
120
/* Above are the valid column types for MySQL data. */
122
#else /* UNIV_DEBUG */
124
#endif /* UNIV_DEBUG */
125
memcpy(dest, data, len);
129
/*****************************************************************
130
Copies an InnoDB record to table->record[0]. */
131
extern "C" UNIV_INTERN
133
innobase_rec_to_mysql(
134
/*==================*/
135
Table* table, /* in/out: MySQL table */
136
const rec_t* rec, /* in: record */
137
const dict_index_t* index, /* in: index */
138
const ulint* offsets) /* in: rec_get_offsets(
141
uint n_fields = table->s->fields;
144
ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
146
for (i = 0; i < n_fields; i++) {
147
Field* field = table->field[i];
150
const unsigned char* ifield;
154
ipos = dict_index_get_nth_col_pos(index, i);
156
if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
162
ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
164
/* Assign the NULL flag */
165
if (ilen == UNIV_SQL_NULL) {
166
ut_ad(field->real_maybe_null());
170
field->set_notnull();
172
innobase_col_to_mysql(
174
dict_index_get_nth_field(index, ipos)),
175
ifield, ilen, field);
179
/*****************************************************************
180
Resets table->record[0]. */
181
extern "C" UNIV_INTERN
185
Table* table) /* in/out: MySQL table */
187
uint n_fields = table->s->fields;
190
for (i = 0; i < n_fields; i++) {
191
table->field[i]->set_default();
195
/**********************************************************************
196
Removes the filename encoding of a database and table name. */
199
innobase_convert_tablename(
200
/*=======================*/
201
char* s) /* in: identifier; out: decoded identifier */
204
char* slash = strchr(s, '/');
208
/* Temporarily replace the '/' with NUL. */
210
strncpy(s, s, slash - s + 1);
214
/* Append a '.' after the database name. */
217
/* Convert the table name. */
218
strncpy(t, slash, slash - t + strlen(slash));
222
/***********************************************************************
223
This function checks that index keys are sensible. */
226
innobase_check_index_keys(
227
/*======================*/
228
/* out: 0 or error number */
229
const KEY* key_info, /* in: Indexes to be created */
230
ulint num_of_keys) /* in: Number of indexes to
238
for (key_num = 0; key_num < num_of_keys; key_num++) {
239
const KEY& key = key_info[key_num];
241
/* Check that the same index name does not appear
242
twice in indexes to be created. */
244
for (ulint i = 0; i < key_num; i++) {
245
const KEY& key2 = key_info[i];
247
if (0 == strcmp(key.name, key2.name)) {
248
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: key name `%s` appears"
249
" twice in CREATE INDEX\n",
252
return(ER_WRONG_NAME_FOR_INDEX);
256
/* Check that MySQL does not try to create a column
257
prefix index field on an inappropriate data type and
258
that the same colum does not appear twice in the index. */
260
for (ulint i = 0; i < key.key_parts; i++) {
261
const KEY_PART_INFO& key_part1
267
switch (get_innobase_type_from_mysql_type(
268
&is_unsigned, field)) {
275
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
277
>= field->pack_length()
278
- ((Field_varstring*) field)
284
>= field->pack_length()) {
289
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: MySQL is trying to"
290
" create a column prefix"
292
" inappropriate data type."
297
return(ER_WRONG_KEY_COLUMN);
300
for (ulint j = 0; j < i; j++) {
301
const KEY_PART_INFO& key_part2
304
if (strcmp(key_part1.field->field_name,
305
key_part2.field->field_name)) {
309
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB: column `%s`"
310
" is not allowed to occur"
311
" twice in index `%s`.\n",
312
key_part1.field->field_name,
314
return(ER_WRONG_KEY_COLUMN);
322
/***********************************************************************
323
Create index field definition for key part */
326
innobase_create_index_field_def(
327
/*============================*/
328
KEY_PART_INFO* key_part, /* in: MySQL key definition */
329
mem_heap_t* heap, /* in: memory heap */
330
merge_index_field_t* index_field) /* out: index field
331
definition for key_part */
340
field = key_part->field;
343
col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
345
if (DATA_BLOB == col_type
346
|| (key_part->length < field->pack_length()
347
&& field->type() != DRIZZLE_TYPE_VARCHAR)
348
|| (field->type() == DRIZZLE_TYPE_VARCHAR
349
&& key_part->length < field->pack_length()
350
- ((Field_varstring*)field)->length_bytes)) {
352
index_field->prefix_len = key_part->length;
354
index_field->prefix_len = 0;
357
index_field->field_name = mem_heap_strdup(heap, field->field_name);
362
/***********************************************************************
363
Create index definition for key */
366
innobase_create_index_def(
367
/*======================*/
368
KEY* key, /* in: key definition */
369
bool new_primary, /* in: TRUE=generating
372
bool key_primary, /* in: TRUE if this key
374
merge_index_def_t* index, /* out: index definition */
375
mem_heap_t* heap) /* in: heap where memory
380
ulint n_fields = key->key_parts;
383
index->fields = (merge_index_field_t*) mem_heap_alloc(
384
heap, n_fields * sizeof *index->fields);
387
index->n_fields = n_fields;
388
len = strlen(key->name) + 1;
389
index->name = index_name = (char*) mem_heap_alloc(heap,
392
if (UNIV_LIKELY(!new_primary)) {
393
*index_name++ = TEMP_INDEX_PREFIX;
396
memcpy(index_name, key->name, len);
398
if (key->flags & HA_NOSAME) {
399
index->ind_type |= DICT_UNIQUE;
403
index->ind_type |= DICT_CLUSTERED;
406
for (i = 0; i < n_fields; i++) {
407
innobase_create_index_field_def(&key->key_part[i], heap,
414
/***********************************************************************
415
Copy index field definition */
418
innobase_copy_index_field_def(
419
/*==========================*/
420
const dict_field_t* field, /* in: definition to copy */
421
merge_index_field_t* index_field) /* out: copied definition */
423
assert(field != NULL);
424
assert(index_field != NULL);
426
index_field->field_name = field->name;
427
index_field->prefix_len = field->prefix_len;
432
/***********************************************************************
433
Copy index definition for the index */
436
innobase_copy_index_def(
437
/*====================*/
438
const dict_index_t* index, /* in: index definition to copy */
439
merge_index_def_t* new_index,/* out: Index definition */
440
mem_heap_t* heap) /* in: heap where allocated */
445
/* Note that we take only those fields that user defined to be
446
in the index. In the internal representation more colums were
447
added and those colums are not copied .*/
449
n_fields = index->n_user_defined_cols;
451
new_index->fields = (merge_index_field_t*) mem_heap_alloc(
452
heap, n_fields * sizeof *new_index->fields);
454
/* When adding a PRIMARY KEY, we may convert a previous
455
clustered index to a secondary index (UNIQUE NOT NULL). */
456
new_index->ind_type = index->type & ~DICT_CLUSTERED;
457
new_index->n_fields = n_fields;
458
new_index->name = index->name;
460
for (i = 0; i < n_fields; i++) {
461
innobase_copy_index_field_def(&index->fields[i],
462
&new_index->fields[i]);
468
/***********************************************************************
469
Create an index table where indexes are ordered as follows:
471
IF a new primary key is defined for the table THEN
474
2) Original secondary indexes
475
3) New secondary indexes
479
1) All new indexes in the order they arrive from MySQL
486
innobase_create_key_def(
487
/*====================*/
488
/* out: key definitions or NULL */
489
trx_t* trx, /* in: trx */
490
const dict_table_t*table, /* in: table definition */
491
mem_heap_t* heap, /* in: heap where space for key
492
definitions are allocated */
493
KEY* key_info, /* in: Indexes to be created */
494
ulint& n_keys) /* in/out: Number of indexes to
498
merge_index_def_t* indexdef;
499
merge_index_def_t* indexdefs;
502
indexdef = indexdefs = (merge_index_def_t*)
503
mem_heap_alloc(heap, sizeof *indexdef
504
* (n_keys + UT_LIST_GET_LEN(table->indexes)));
506
/* If there is a primary key, it is always the first index
507
defined for the table. */
509
new_primary = !my_strcasecmp(system_charset_info,
510
key_info->name, "PRIMARY");
512
/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
513
columns, MySQL will treat it as a PRIMARY KEY unless the
514
table already has one. */
516
if (!new_primary && (key_info->flags & HA_NOSAME)
517
&& row_table_got_default_clust_index(table)) {
518
uint key_part = key_info->key_parts;
523
if (key_info->key_part[key_part].key_type
524
& FIELDFLAG_MAYBE_NULL) {
532
const dict_index_t* index;
534
/* Create the PRIMARY key index definition */
535
innobase_create_index_def(&key_info[i++], TRUE, TRUE,
538
row_mysql_lock_data_dictionary(trx);
540
index = dict_table_get_first_index(table);
542
/* Copy the index definitions of the old table. Skip
543
the old clustered index if it is a generated clustered
544
index or a PRIMARY KEY. If the clustered index is a
545
UNIQUE INDEX, it must be converted to a secondary index. */
547
if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
548
|| !my_strcasecmp(system_charset_info,
549
index->name, "PRIMARY")) {
550
index = dict_table_get_next_index(index);
554
innobase_copy_index_def(index, indexdef++, heap);
555
index = dict_table_get_next_index(index);
558
row_mysql_unlock_data_dictionary(trx);
561
/* Create definitions for added secondary indexes. */
564
innobase_create_index_def(&key_info[i++], new_primary, FALSE,
568
n_keys = indexdef - indexdefs;
573
/***********************************************************************
574
Create a temporary tablename using query id, thread id, and id */
577
innobase_create_temporary_tablename(
578
/*================================*/
579
/* out: temporary tablename */
580
mem_heap_t* heap, /* in: memory heap */
581
char id, /* in: identifier [0-9a-zA-Z] */
582
const char* table_name) /* in: table name */
586
static const char suffix[] = "@0023 "; /* "# " */
588
len = strlen(table_name);
590
name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
591
memcpy(name, table_name, len);
592
memcpy(name + len, suffix, sizeof suffix);
593
name[len + (sizeof suffix - 2)] = id;
598
/***********************************************************************
602
ha_innobase::add_index(
603
/*===================*/
604
/* out: 0 or error number */
605
Table* i_table, /* in: Table where indexes are created */
606
KEY* key_info, /* in: Indexes to be created */
607
uint num_of_keys) /* in: Number of indexes to be created */
609
dict_index_t** index; /* Index to be created */
610
dict_table_t* innodb_table; /* InnoDB table in dictionary */
611
dict_table_t* indexed_table; /* Table where indexes are created */
612
merge_index_def_t* index_defs; /* Index definitions */
613
mem_heap_t* heap; /* Heap for index definitions */
614
trx_t* trx; /* Transaction */
616
ulint num_created = 0;
617
ibool dict_locked = FALSE;
625
if (srv_created_new_raw || srv_force_recovery) {
626
return(HA_ERR_WRONG_COMMAND);
631
heap = mem_heap_create(1024);
633
/* In case MySQL calls this in the middle of a SELECT query, release
634
possible adaptive hash latch to avoid deadlocks of threads. */
635
trx_search_latch_release_if_reserved(prebuilt->trx);
637
/* Create a background transaction for the operations on
638
the data dictionary tables. */
639
trx = innobase_trx_allocate(user_session);
640
trx_start_if_not_started(trx);
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, i_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* i_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 */
919
if (srv_created_new_raw || srv_force_recovery) {
920
return(HA_ERR_WRONG_COMMAND);
925
trx_search_latch_release_if_reserved(prebuilt->trx);
928
/* Test and mark all the indexes to be dropped */
930
row_mysql_lock_data_dictionary(trx);
932
/* Check that none of the indexes have previously been flagged
935
const dict_index_t* index
936
= dict_table_get_first_index(prebuilt->table);
938
ut_a(!index->to_be_dropped);
939
index = dict_table_get_next_index(index);
943
for (n_key = 0; n_key < num_of_keys; n_key++) {
947
key = i_table->key_info + key_num[n_key];
948
index = dict_table_get_index_on_name_and_min_id(
949
prebuilt->table, key->name);
952
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB could not find key n:o %u "
953
"with name %s for table %s",
955
key ? key->name : "NULL",
956
prebuilt->table->name);
958
err = HA_ERR_KEY_NOT_FOUND;
962
/* Refuse to drop the clustered index. It would be
963
better to automatically generate a clustered index,
964
but mysql_alter_table() will call this method only
965
after ha_innobase::add_index(). */
967
if (dict_index_is_clust(index)) {
968
my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
973
index->to_be_dropped = TRUE;
976
/* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
977
for a foreign key constraint because InnoDB requires that both
978
tables contain indexes for the constraint. Note that CREATE
979
INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
980
can ignore here foreign keys because a new index for the
981
foreign key has already been created.
983
We check for the foreign key constraints after marking the
984
candidate indexes for deletion, because when we check for an
985
equivalent foreign index we don't want to select an index that
988
if (trx->check_foreigns
989
&& session_sql_command(user_session) != SQLCOM_CREATE_INDEX) {
992
for (index = dict_table_get_first_index(prebuilt->table);
994
index = dict_table_get_next_index(index)) {
995
dict_foreign_t* foreign;
997
if (!index->to_be_dropped) {
1002
/* Check if the index is referenced. */
1003
foreign = dict_table_get_referenced_constraint(
1004
prebuilt->table, index);
1008
trx_set_detailed_error(
1010
"Index needed in foreign key "
1013
trx->error_info = index;
1015
err = HA_ERR_DROP_INDEX_FK;
1018
/* Check if this index references some
1020
foreign = dict_table_get_foreign_constraint(
1021
prebuilt->table, index);
1024
ut_a(foreign->foreign_index == index);
1026
/* Search for an equivalent index that
1027
the foreign key constraint could use
1028
if this index were to be deleted. */
1029
if (!dict_foreign_find_equiv_index(
1037
} else if (session_sql_command(user_session) == SQLCOM_CREATE_INDEX) {
1038
/* This is a drop of a foreign key constraint index that
1039
was created by MySQL when the constraint was added. MySQL
1040
does this when the user creates an index explicitly which
1041
can be used in place of the automatically generated index. */
1043
dict_index_t* index;
1045
for (index = dict_table_get_first_index(prebuilt->table);
1047
index = dict_table_get_next_index(index)) {
1048
dict_foreign_t* foreign;
1050
if (!index->to_be_dropped) {
1055
/* Check if this index references some other table */
1056
foreign = dict_table_get_foreign_constraint(
1057
prebuilt->table, index);
1059
if (foreign == NULL) {
1064
ut_a(foreign->foreign_index == index);
1066
/* Search for an equivalent index that the
1067
foreign key constraint could use if this index
1068
were to be deleted. */
1070
if (!dict_foreign_find_equiv_index(foreign)) {
1071
trx_set_detailed_error(
1073
"Index needed in foreign key "
1076
trx->error_info = foreign->foreign_index;
1078
err = HA_ERR_DROP_INDEX_FK;
1086
/* Undo our changes since there was some sort of error. */
1088
= dict_table_get_first_index(prebuilt->table);
1091
index->to_be_dropped = FALSE;
1092
index = dict_table_get_next_index(index);
1096
row_mysql_unlock_data_dictionary(trx);
1101
/***********************************************************************
1102
Drop the indexes that were passed to a successful prepare_drop_index(). */
1105
ha_innobase::final_drop_index(
1106
/*==========================*/
1107
/* out: 0 or error number */
1108
Table* ) /* in: Table where indexes are dropped */
1110
dict_index_t* index; /* Index to be dropped */
1111
trx_t* trx; /* Transaction */
1114
if (srv_created_new_raw || srv_force_recovery) {
1115
return(HA_ERR_WRONG_COMMAND);
1120
trx_search_latch_release_if_reserved(prebuilt->trx);
1122
/* Create a background transaction for the operations on
1123
the data dictionary tables. */
1124
trx = innobase_trx_allocate(user_session);
1125
trx_start_if_not_started(trx);
1127
/* Flag this transaction as a dictionary operation, so that
1128
the data dictionary will be locked in crash recovery. */
1129
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1131
/* Lock the table exclusively, to ensure that no active
1132
transaction depends on an index that is being dropped. */
1133
err = convert_error_code_to_mysql(
1134
row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1135
prebuilt->table->flags, user_session);
1137
row_mysql_lock_data_dictionary(trx);
1139
if (UNIV_UNLIKELY(err)) {
1141
/* Unmark the indexes to be dropped. */
1142
for (index = dict_table_get_first_index(prebuilt->table);
1143
index; index = dict_table_get_next_index(index)) {
1145
index->to_be_dropped = FALSE;
1151
/* Drop indexes marked to be dropped */
1153
index = dict_table_get_first_index(prebuilt->table);
1156
dict_index_t* next_index;
1158
next_index = dict_table_get_next_index(index);
1160
if (index->to_be_dropped) {
1162
row_merge_drop_index(index, prebuilt->table, trx);
1168
/* Check that all flagged indexes were dropped. */
1169
for (index = dict_table_get_first_index(prebuilt->table);
1170
index; index = dict_table_get_next_index(index)) {
1171
ut_a(!index->to_be_dropped);
1175
dict_table_check_for_dup_indexes(prebuilt->table);
1179
trx_commit_for_mysql(trx);
1180
trx_commit_for_mysql(prebuilt->trx);
1181
row_mysql_unlock_data_dictionary(trx);
1183
/* Flush the log to reduce probability that the .frm files and
1184
the InnoDB data dictionary get out-of-sync if the user runs
1185
with innodb_flush_log_at_trx_commit = 0 */
1187
log_buffer_flush_to_disk();
1189
trx_free_for_mysql(trx);
1191
/* Tell the InnoDB server that there might be work for
1194
srv_active_wake_master_thread();