1
/*****************************************************************************
3
Copyright (c) 2005, 2010, 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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 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(DATA_MBMAXLEN(col->mbminmaxlen)
107
>= DATA_MBMINLEN(col->mbminmaxlen));
108
ut_ad(DATA_MBMAXLEN(col->mbminmaxlen)
109
> DATA_MBMINLEN(col->mbminmaxlen) || flen == len);
110
memcpy(dest, data, len);
116
/* These column types should never be shipped to MySQL. */
124
/* Above are the valid column types for MySQL data. */
126
#else /* UNIV_DEBUG */
128
#endif /* UNIV_DEBUG */
129
memcpy(dest, data, len);
133
/*************************************************************//**
134
Copies an InnoDB record to table->getInsertRecord(). */
135
extern "C" UNIV_INTERN
137
innobase_rec_to_mysql(
138
/*==================*/
139
Table* table, /*!< in/out: MySQL table */
140
const rec_t* rec, /*!< in: record */
141
const dict_index_t* index, /*!< in: index */
142
const ulint* offsets) /*!< in: rec_get_offsets(
145
uint n_fields = table->getShare()->sizeFields();
148
ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
150
for (i = 0; i < n_fields; i++) {
151
Field* field = table->getField(i);
154
const unsigned char* ifield;
158
ipos = dict_index_get_nth_col_pos(index, i);
160
if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
166
ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
168
/* Assign the NULL flag */
169
if (ilen == UNIV_SQL_NULL) {
170
ut_ad(field->real_maybe_null());
174
field->set_notnull();
176
innobase_col_to_mysql(
178
dict_index_get_nth_field(index, ipos)),
179
ifield, ilen, field);
183
/*************************************************************//**
184
Resets table->getInsertRecord(). */
185
extern "C" UNIV_INTERN
189
Table* table) /*!< in/out: MySQL table */
191
uint n_fields = table->getShare()->sizeFields();
194
for (i = 0; i < n_fields; i++) {
195
table->getField(i)->set_default();
199
#if 0 // This is a part of the fast index code.
200
/******************************************************************//**
201
Removes the filename encoding of a database and table name. */
204
innobase_convert_tablename(
205
/*=======================*/
206
char* s) /*!< in: identifier; out: decoded identifier */
209
char* slash = strchr(s, '/');
213
/* Temporarily replace the '/' with NUL. */
215
strncpy(s, s, slash - s + 1);
219
/* Append a '.' after the database name. */
222
/* Convert the table name. */
223
strncpy(t, slash, slash - t + strlen(slash));
228
/*******************************************************************//**
229
This function checks that index keys are sensible.
230
@return 0 or error number */
233
innobase_check_index_keys(
234
/*======================*/
235
const KeyInfo* key_info, /*!< in: Indexes to be created */
236
ulint num_of_keys, /*!< in: Number of indexes to
238
const dict_table_t* table) /*!< in: Existing indexes */
245
for (key_num = 0; key_num < num_of_keys; key_num++) {
246
const KeyInfo& key = key_info[key_num];
248
/* Check that the same index name does not appear
249
twice in indexes to be created. */
251
for (ulint i = 0; i < key_num; i++) {
252
const KeyInfo& key2 = key_info[i];
254
if (0 == strcmp(key.name, key2.name)) {
255
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
258
return(ER_WRONG_NAME_FOR_INDEX);
262
/* Check that the same index name does not already exist. */
264
for (const dict_index_t* index
265
= dict_table_get_first_index(table);
266
index; index = dict_table_get_next_index(index)) {
268
if (0 == strcmp(key.name, index->name)) {
269
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
272
return(ER_WRONG_NAME_FOR_INDEX);
276
/* Check that MySQL does not try to create a column
277
prefix index field on an inappropriate data type and
278
that the same column does not appear twice in the index. */
280
for (ulint i = 0; i < key.key_parts; i++) {
281
const KeyPartInfo& key_part1
287
switch (get_innobase_type_from_mysql_type(
288
&is_unsigned, field)) {
295
if (field->type() == DRIZZLE_TYPE_VARCHAR) {
297
>= field->pack_length()
298
- ((Field_varstring*) field)
304
>= field->pack_length()) {
309
my_error(ER_WRONG_KEY_COLUMN, MYF(0),
311
return(ER_WRONG_KEY_COLUMN);
314
for (ulint j = 0; j < i; j++) {
315
const KeyPartInfo& key_part2
318
if (strcmp(key_part1.field->field_name,
319
key_part2.field->field_name)) {
323
my_error(ER_WRONG_KEY_COLUMN, MYF(0),
324
key_part1.field->field_name);
325
return(ER_WRONG_KEY_COLUMN);
333
/*******************************************************************//**
334
Create index field definition for key part */
337
innobase_create_index_field_def(
338
/*============================*/
339
KeyPartInfo* key_part, /*!< in: MySQL key definition */
340
mem_heap_t* heap, /*!< in: memory heap */
341
merge_index_field_t* index_field) /*!< out: index field
342
definition for key_part */
351
field = key_part->field;
354
col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
356
if (DATA_BLOB == col_type
357
|| (key_part->length < field->pack_length()
358
&& field->type() != DRIZZLE_TYPE_VARCHAR)
359
|| (field->type() == DRIZZLE_TYPE_VARCHAR
360
&& key_part->length < field->pack_length()
361
- ((Field_varstring*)field)->length_bytes)) {
363
index_field->prefix_len = key_part->length;
365
index_field->prefix_len = 0;
368
index_field->field_name = mem_heap_strdup(heap, field->field_name);
373
/*******************************************************************//**
374
Create index definition for key */
377
innobase_create_index_def(
378
/*======================*/
379
KeyInfo* key, /*!< in: key definition */
380
bool new_primary, /*!< in: TRUE=generating
383
bool key_primary, /*!< in: TRUE if this key
385
merge_index_def_t* index, /*!< out: index definition */
386
mem_heap_t* heap) /*!< in: heap where memory
391
ulint n_fields = key->key_parts;
394
index->fields = (merge_index_field_t*) mem_heap_alloc(
395
heap, n_fields * sizeof *index->fields);
398
index->n_fields = n_fields;
399
len = strlen(key->name) + 1;
400
index->name = index_name = (char*) mem_heap_alloc(heap,
403
if (UNIV_LIKELY(!new_primary)) {
404
*index_name++ = TEMP_INDEX_PREFIX;
407
memcpy(index_name, key->name, len);
409
if (key->flags & HA_NOSAME) {
410
index->ind_type |= DICT_UNIQUE;
414
index->ind_type |= DICT_CLUSTERED;
417
for (i = 0; i < n_fields; i++) {
418
innobase_create_index_field_def(&key->key_part[i], heap,
425
/*******************************************************************//**
426
Copy index field definition */
429
innobase_copy_index_field_def(
430
/*==========================*/
431
const dict_field_t* field, /*!< in: definition to copy */
432
merge_index_field_t* index_field) /*!< out: copied definition */
434
assert(field != NULL);
435
assert(index_field != NULL);
437
index_field->field_name = field->name;
438
index_field->prefix_len = field->prefix_len;
443
/*******************************************************************//**
444
Copy index definition for the index */
447
innobase_copy_index_def(
448
/*====================*/
449
const dict_index_t* index, /*!< in: index definition to copy */
450
merge_index_def_t* new_index,/*!< out: Index definition */
451
mem_heap_t* heap) /*!< in: heap where allocated */
456
/* Note that we take only those fields that user defined to be
457
in the index. In the internal representation more colums were
458
added and those colums are not copied .*/
460
n_fields = index->n_user_defined_cols;
462
new_index->fields = (merge_index_field_t*) mem_heap_alloc(
463
heap, n_fields * sizeof *new_index->fields);
465
/* When adding a PRIMARY KEY, we may convert a previous
466
clustered index to a secondary index (UNIQUE NOT NULL). */
467
new_index->ind_type = index->type & ~DICT_CLUSTERED;
468
new_index->n_fields = n_fields;
469
new_index->name = index->name;
471
for (i = 0; i < n_fields; i++) {
472
innobase_copy_index_field_def(&index->fields[i],
473
&new_index->fields[i]);
479
/*******************************************************************//**
480
Create an index table where indexes are ordered as follows:
482
IF a new primary key is defined for the table THEN
485
2) Original secondary indexes
486
3) New secondary indexes
490
1) All new indexes in the order they arrive from MySQL
495
@return key definitions or NULL */
499
innobase_create_key_def(
500
/*====================*/
501
trx_t* trx, /*!< in: trx */
502
const dict_table_t*table, /*!< in: table definition */
503
mem_heap_t* heap, /*!< in: heap where space for key
504
definitions are allocated */
505
KeyInfo* key_info, /*!< in: Indexes to be created */
506
ulint& n_keys) /*!< in/out: Number of indexes to
510
merge_index_def_t* indexdef;
511
merge_index_def_t* indexdefs;
514
indexdef = indexdefs = (merge_index_def_t*)
515
mem_heap_alloc(heap, sizeof *indexdef
516
* (n_keys + UT_LIST_GET_LEN(table->indexes)));
518
/* If there is a primary key, it is always the first index
519
defined for the table. */
521
new_primary = !my_strcasecmp(system_charset_info,
522
key_info->name, "PRIMARY");
524
/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
525
columns and if the index does not contain column prefix(es)
526
(only prefix/part of the column is indexed), MySQL will treat the
527
index as a PRIMARY KEY unless the table already has one. */
529
if (!new_primary && (key_info->flags & HA_NOSAME)
530
&& (!(key_info->flags & HA_KEY_HAS_PART_KEY_SEG))
531
&& row_table_got_default_clust_index(table)) {
532
uint key_part = key_info->key_parts;
537
if (key_info->key_part[key_part].null_bit == 0) {
545
const dict_index_t* index;
547
/* Create the PRIMARY key index definition */
548
innobase_create_index_def(&key_info[i++], TRUE, TRUE,
551
row_mysql_lock_data_dictionary(trx);
553
index = dict_table_get_first_index(table);
555
/* Copy the index definitions of the old table. Skip
556
the old clustered index if it is a generated clustered
557
index or a PRIMARY KEY. If the clustered index is a
558
UNIQUE INDEX, it must be converted to a secondary index. */
560
if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
561
|| !my_strcasecmp(system_charset_info,
562
index->name, "PRIMARY")) {
563
index = dict_table_get_next_index(index);
567
innobase_copy_index_def(index, indexdef++, heap);
568
index = dict_table_get_next_index(index);
571
row_mysql_unlock_data_dictionary(trx);
574
/* Create definitions for added secondary indexes. */
577
innobase_create_index_def(&key_info[i++], new_primary, FALSE,
581
n_keys = indexdef - indexdefs;
586
/*******************************************************************//**
587
Create a temporary tablename using query id, thread id, and id
588
@return temporary tablename */
591
innobase_create_temporary_tablename(
592
/*================================*/
593
mem_heap_t* heap, /*!< in: memory heap */
594
char id, /*!< in: identifier [0-9a-zA-Z] */
595
const char* table_name) /*!< in: table name */
599
static const char suffix[] = "@0023 "; /* "# " */
601
len = strlen(table_name);
603
name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
604
memcpy(name, table_name, len);
605
memcpy(name + len, suffix, sizeof suffix);
606
name[len + (sizeof suffix - 2)] = id;
612
/*******************************************************************//**
614
@return 0 or error number */
617
ha_innobase::add_index(
618
/*===================*/
620
Table* i_table, /*!< in: Table where indexes are created */
621
KeyInfo* key_info, /*!< in: Indexes to be created */
622
uint num_of_keys) /*!< in: Number of indexes to be created */
624
dict_index_t** index; /*!< Index to be created */
625
dict_table_t* innodb_table; /*!< InnoDB table in dictionary */
626
dict_table_t* indexed_table; /*!< Table where indexes are created */
627
merge_index_def_t* index_defs; /*!< Index definitions */
628
mem_heap_t* heap; /*!< Heap for index definitions */
629
trx_t* trx; /*!< Transaction */
631
ulint num_created = 0;
632
ibool dict_locked = FALSE;
640
if (srv_created_new_raw || srv_force_recovery) {
641
return(HA_ERR_WRONG_COMMAND);
644
update_session(session);
646
heap = mem_heap_create(1024);
648
/* In case MySQL calls this in the middle of a SELECT query, release
649
possible adaptive hash latch to avoid deadlocks of threads. */
650
trx_search_latch_release_if_reserved(prebuilt->trx);
651
trx_start_if_not_started(prebuilt->trx);
653
/* Create a background transaction for the operations on
654
the data dictionary tables. */
655
trx = innobase_trx_allocate(user_session);
656
trx_start_if_not_started(trx);
658
innodb_table = indexed_table
659
= dict_table_get(prebuilt->table->name, FALSE);
661
if (UNIV_UNLIKELY(!innodb_table)) {
662
error = HA_ERR_NO_SUCH_TABLE;
666
/* Check if the index name is reserved. */
667
if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) {
670
/* Check that index keys are sensible */
671
error = innobase_check_index_keys(key_info, num_of_keys,
675
if (UNIV_UNLIKELY(error)) {
678
trx_general_rollback_for_mysql(trx, NULL);
679
trx_free_for_mysql(trx);
680
trx_commit_for_mysql(prebuilt->trx);
684
/* Create table containing all indexes to be built in this
685
alter table add index so that they are in the correct order
688
num_of_idx = num_of_keys;
690
index_defs = innobase_create_key_def(
691
trx, innodb_table, heap, key_info, num_of_idx);
693
new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
695
/* Allocate memory for dictionary index definitions */
697
index = (dict_index_t**) mem_heap_alloc(
698
heap, num_of_idx * sizeof *index);
700
/* Flag this transaction as a dictionary operation, so that
701
the data dictionary will be locked in crash recovery. */
702
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
704
/* Acquire a lock on the table before creating any indexes. */
705
error = row_merge_lock_table(prebuilt->trx, innodb_table,
706
new_primary ? LOCK_X : LOCK_S);
708
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
713
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
714
or lock waits can happen in it during an index create operation. */
716
row_mysql_lock_data_dictionary(trx);
719
ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE));
721
/* If a new primary key is defined for the table we need
722
to drop the original table and rebuild all indexes. */
724
if (UNIV_UNLIKELY(new_primary)) {
725
/* This transaction should be the only one
726
operating on the table. */
727
ut_a(innodb_table->n_mysql_handles_opened == 1);
729
char* new_table_name = innobase_create_temporary_tablename(
730
heap, '1', innodb_table->name);
732
/* Clone the table. */
733
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
734
indexed_table = row_merge_create_temporary_table(
735
new_table_name, index_defs, innodb_table, trx);
737
if (!indexed_table) {
739
switch (trx->error_state) {
740
case DB_TABLESPACE_ALREADY_EXISTS:
741
case DB_DUPLICATE_KEY:
742
innobase_convert_tablename(new_table_name);
743
my_error(HA_ERR_TABLE_EXIST, MYF(0),
745
error = HA_ERR_TABLE_EXIST;
748
error = convert_error_code_to_mysql(
749
trx->error_state, innodb_table->flags,
753
ut_d(dict_table_check_for_dup_indexes(innodb_table,
755
row_mysql_unlock_data_dictionary(trx);
759
trx->table_id = indexed_table->id;
762
/* Create the indexes in SYS_INDEXES and load into dictionary. */
764
for (ulint i = 0; i < num_of_idx; i++) {
766
index[i] = row_merge_create_index(trx, indexed_table,
770
error = trx->error_state;
777
ut_ad(error == DB_SUCCESS);
779
/* We will need to rebuild index translation table. Set
780
valid index entry count in the translation table to zero */
781
share->idx_trans_tbl.index_count = 0;
783
/* Commit the data dictionary transaction in order to release
784
the table locks on the system tables. This means that if
785
MySQL crashes while creating a new primary key inside
786
row_merge_build_indexes(), indexed_table will not be dropped
787
by trx_rollback_active(). It will have to be recovered or
788
dropped by the database administrator. */
789
trx_commit_for_mysql(trx);
791
row_mysql_unlock_data_dictionary(trx);
794
ut_a(trx->n_active_thrs == 0);
795
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
797
if (UNIV_UNLIKELY(new_primary)) {
798
/* A primary key is to be built. Acquire an exclusive
799
table lock also on the table that is being created. */
800
ut_ad(indexed_table != innodb_table);
802
error = row_merge_lock_table(prebuilt->trx, indexed_table,
805
if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
811
/* Read the clustered index of the table and build indexes
812
based on this information using temporary files and merge sort. */
813
error = row_merge_build_indexes(prebuilt->trx,
814
innodb_table, indexed_table,
815
index, num_of_idx, i_table);
819
/* After an error, remove all those index definitions from the
820
dictionary which were defined. */
823
const char* old_name;
827
row_mysql_lock_data_dictionary(trx);
830
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
833
error = row_merge_rename_indexes(trx, indexed_table);
835
if (error != DB_SUCCESS) {
836
row_merge_drop_indexes(trx, indexed_table,
843
/* If a new primary key was defined for the table and
844
there was no error at this point, we can now rename
845
the old table as a temporary table, rename the new
846
temporary table as the old table and drop the old table. */
847
old_name = innodb_table->name;
848
tmp_name = innobase_create_temporary_tablename(heap, '2',
851
error = row_merge_rename_tables(innodb_table, indexed_table,
854
if (error != DB_SUCCESS) {
856
row_merge_drop_table(trx, indexed_table);
859
case DB_TABLESPACE_ALREADY_EXISTS:
860
case DB_DUPLICATE_KEY:
861
innobase_convert_tablename(tmp_name);
862
my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
863
error = HA_ERR_TABLE_EXIST;
871
trx_commit_for_mysql(prebuilt->trx);
872
row_prebuilt_free(prebuilt, TRUE);
873
prebuilt = row_create_prebuilt(indexed_table);
875
indexed_table->n_mysql_handles_opened++;
877
error = row_merge_drop_table(trx, innodb_table);
878
innodb_table = indexed_table;
881
case DB_TOO_BIG_RECORD:
882
my_error(HA_ERR_TO_BIG_ROW, MYF(0));
884
case DB_PRIMARY_KEY_IS_NULL:
885
my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
887
case DB_DUPLICATE_KEY:
889
prebuilt->trx->error_info = NULL;
892
trx->error_state = DB_SUCCESS;
895
if (indexed_table != innodb_table) {
896
row_merge_drop_table(trx, indexed_table);
900
row_mysql_lock_data_dictionary(trx);
904
row_merge_drop_indexes(trx, indexed_table,
909
error = convert_error_code_to_mysql(error,
915
trx_commit_for_mysql(trx);
917
trx_commit_for_mysql(prebuilt->trx);
921
ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE));
922
row_mysql_unlock_data_dictionary(trx);
925
trx_free_for_mysql(trx);
927
/* There might be work for utility threads.*/
928
srv_active_wake_master_thread();
933
/*******************************************************************//**
934
Prepare to drop some indexes of a table.
935
@return 0 or error number */
938
ha_innobase::prepare_drop_index(
939
/*============================*/
941
Table* i_table, /*!< in: Table where indexes are dropped */
942
uint* key_num, /*!< in: Key nums to be dropped */
943
uint num_of_keys) /*!< in: Number of keys to be dropped */
952
if (srv_created_new_raw || srv_force_recovery) {
953
return(HA_ERR_WRONG_COMMAND);
956
update_session(session);
958
trx_search_latch_release_if_reserved(prebuilt->trx);
961
/* Test and mark all the indexes to be dropped */
963
row_mysql_lock_data_dictionary(trx);
964
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
966
/* Check that none of the indexes have previously been flagged
969
const dict_index_t* index
970
= dict_table_get_first_index(prebuilt->table);
972
ut_a(!index->to_be_dropped);
973
index = dict_table_get_next_index(index);
977
for (n_key = 0; n_key < num_of_keys; n_key++) {
981
key = i_table->key_info + key_num[n_key];
982
index = dict_table_get_index_on_name_and_min_id(
983
prebuilt->table, key->name);
986
errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB could not find key n:o %u "
987
"with name %s for table %s",
989
key ? key->name : "NULL",
990
prebuilt->table->name);
992
err = HA_ERR_KEY_NOT_FOUND;
996
/* Refuse to drop the clustered index. It would be
997
better to automatically generate a clustered index,
998
but drizzled::alter_table() will call this method only
999
after ha_innobase::add_index(). */
1001
if (dict_index_is_clust(index)) {
1002
my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
1007
index->to_be_dropped = TRUE;
1010
/* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
1011
for a foreign key constraint because InnoDB requires that both
1012
tables contain indexes for the constraint. Note that CREATE
1013
INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
1014
can ignore here foreign keys because a new index for the
1015
foreign key has already been created.
1017
We check for the foreign key constraints after marking the
1018
candidate indexes for deletion, because when we check for an
1019
equivalent foreign index we don't want to select an index that
1020
is later deleted. */
1022
if (trx->check_foreigns
1023
&& session_sql_command(user_session) != SQLCOM_CREATE_INDEX) {
1024
dict_index_t* index;
1026
for (index = dict_table_get_first_index(prebuilt->table);
1028
index = dict_table_get_next_index(index)) {
1029
dict_foreign_t* foreign;
1031
if (!index->to_be_dropped) {
1036
/* Check if the index is referenced. */
1037
foreign = dict_table_get_referenced_constraint(
1038
prebuilt->table, index);
1042
trx_set_detailed_error(
1044
"Index needed in foreign key "
1047
trx->error_info = index;
1049
err = HA_ERR_DROP_INDEX_FK;
1052
/* Check if this index references some
1054
foreign = dict_table_get_foreign_constraint(
1055
prebuilt->table, index);
1058
ut_a(foreign->foreign_index == index);
1060
/* Search for an equivalent index that
1061
the foreign key constraint could use
1062
if this index were to be deleted. */
1063
if (!dict_foreign_find_equiv_index(
1071
} else if (session_sql_command(user_session) == SQLCOM_CREATE_INDEX) {
1072
/* This is a drop of a foreign key constraint index that
1073
was created by MySQL when the constraint was added. MySQL
1074
does this when the user creates an index explicitly which
1075
can be used in place of the automatically generated index. */
1077
dict_index_t* index;
1079
for (index = dict_table_get_first_index(prebuilt->table);
1081
index = dict_table_get_next_index(index)) {
1082
dict_foreign_t* foreign;
1084
if (!index->to_be_dropped) {
1089
/* Check if this index references some other table */
1090
foreign = dict_table_get_foreign_constraint(
1091
prebuilt->table, index);
1093
if (foreign == NULL) {
1098
ut_a(foreign->foreign_index == index);
1100
/* Search for an equivalent index that the
1101
foreign key constraint could use if this index
1102
were to be deleted. */
1104
if (!dict_foreign_find_equiv_index(foreign)) {
1105
trx_set_detailed_error(
1107
"Index needed in foreign key "
1110
trx->error_info = foreign->foreign_index;
1112
err = HA_ERR_DROP_INDEX_FK;
1120
/* Undo our changes since there was some sort of error. */
1122
= dict_table_get_first_index(prebuilt->table);
1125
index->to_be_dropped = FALSE;
1126
index = dict_table_get_next_index(index);
1130
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1131
row_mysql_unlock_data_dictionary(trx);
1136
/*******************************************************************//**
1137
Drop the indexes that were passed to a successful prepare_drop_index().
1138
@return 0 or error number */
1141
ha_innobase::final_drop_index(
1142
/*==========================*/
1144
Table* ) /*!< in: Table where indexes are dropped */
1146
dict_index_t* index; /*!< Index to be dropped */
1147
trx_t* trx; /*!< Transaction */
1150
if (srv_created_new_raw || srv_force_recovery) {
1151
return(HA_ERR_WRONG_COMMAND);
1154
update_session(session);
1156
trx_search_latch_release_if_reserved(prebuilt->trx);
1157
trx_start_if_not_started(prebuilt->trx);
1159
/* Create a background transaction for the operations on
1160
the data dictionary tables. */
1161
trx = innobase_trx_allocate(user_session);
1162
trx_start_if_not_started(trx);
1164
/* Flag this transaction as a dictionary operation, so that
1165
the data dictionary will be locked in crash recovery. */
1166
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1168
/* Lock the table exclusively, to ensure that no active
1169
transaction depends on an index that is being dropped. */
1170
err = convert_error_code_to_mysql(
1171
row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1172
prebuilt->table->flags, user_session);
1174
row_mysql_lock_data_dictionary(trx);
1175
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1177
if (UNIV_UNLIKELY(err)) {
1179
/* Unmark the indexes to be dropped. */
1180
for (index = dict_table_get_first_index(prebuilt->table);
1181
index; index = dict_table_get_next_index(index)) {
1183
index->to_be_dropped = FALSE;
1189
/* Drop indexes marked to be dropped */
1191
index = dict_table_get_first_index(prebuilt->table);
1194
dict_index_t* next_index;
1196
next_index = dict_table_get_next_index(index);
1198
if (index->to_be_dropped) {
1200
row_merge_drop_index(index, prebuilt->table, trx);
1206
/* Check that all flagged indexes were dropped. */
1207
for (index = dict_table_get_first_index(prebuilt->table);
1208
index; index = dict_table_get_next_index(index)) {
1209
ut_a(!index->to_be_dropped);
1212
/* We will need to rebuild index translation table. Set
1213
valid index entry count in the translation table to zero */
1214
share->idx_trans_tbl.index_count = 0;
1217
ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1218
trx_commit_for_mysql(trx);
1219
trx_commit_for_mysql(prebuilt->trx);
1220
row_mysql_unlock_data_dictionary(trx);
1222
/* Flush the log to reduce probability that the .frm files and
1223
the InnoDB data dictionary get out-of-sync if the user runs
1224
with innodb_flush_log_at_trx_commit = 0 */
1226
log_buffer_flush_to_disk();
1228
trx_free_for_mysql(trx);
1230
/* Tell the InnoDB server that there might be work for
1233
srv_active_wake_master_thread();