mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innodb_plugin / handler / handler0alter.cc
blobb3ecd02f5752d84d2e72f17b64a7640056f17d11
1 /*****************************************************************************
3 Copyright (c) 2005, 2012, Oracle and/or its affiliates. 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.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 *****************************************************************************/
19 /**************************************************//**
20 @file handler/handler0alter.cc
21 Smart ALTER TABLE
22 *******************************************************/
24 #include <mysql_priv.h>
25 #include <mysqld_error.h>
27 extern "C" {
28 #include "log0log.h"
29 #include "row0merge.h"
30 #include "srv0srv.h"
31 #include "trx0trx.h"
32 #include "trx0roll.h"
33 #include "ha_prototypes.h"
34 #include "handler0alter.h"
37 #include "ha_innodb.h"
39 /*************************************************************//**
40 Copies an InnoDB column to a MySQL field. This function is
41 adapted from row_sel_field_store_in_mysql_format(). */
42 static
43 void
44 innobase_col_to_mysql(
45 /*==================*/
46 const dict_col_t* col, /*!< in: InnoDB column */
47 const uchar* data, /*!< in: InnoDB column data */
48 ulint len, /*!< in: length of data, in bytes */
49 Field* field) /*!< in/out: MySQL field */
51 uchar* ptr;
52 uchar* dest = field->ptr;
53 ulint flen = field->pack_length();
55 switch (col->mtype) {
56 case DATA_INT:
57 ut_ad(len == flen);
59 /* Convert integer data from Innobase to little-endian
60 format, sign bit restored to normal */
62 for (ptr = dest + len; ptr != dest; ) {
63 *--ptr = *data++;
66 if (!(field->flags & UNSIGNED_FLAG)) {
67 ((byte*) dest)[len - 1] ^= 0x80;
70 break;
72 case DATA_VARCHAR:
73 case DATA_VARMYSQL:
74 case DATA_BINARY:
75 field->reset();
77 if (field->type() == MYSQL_TYPE_VARCHAR) {
78 /* This is a >= 5.0.3 type true VARCHAR. Store the
79 length of the data to the first byte or the first
80 two bytes of dest. */
82 dest = row_mysql_store_true_var_len(
83 dest, len, flen - field->key_length());
86 /* Copy the actual data */
87 memcpy(dest, data, len);
88 break;
90 case DATA_BLOB:
91 /* Store a pointer to the BLOB buffer to dest: the BLOB was
92 already copied to the buffer in row_sel_store_mysql_rec */
94 row_mysql_store_blob_ref(dest, flen, data, len);
95 break;
97 #ifdef UNIV_DEBUG
98 case DATA_MYSQL:
99 ut_ad(flen >= len);
100 ut_ad(col->mbmaxlen >= col->mbminlen);
101 memcpy(dest, data, len);
102 break;
104 default:
105 case DATA_SYS_CHILD:
106 case DATA_SYS:
107 /* These column types should never be shipped to MySQL. */
108 ut_ad(0);
110 case DATA_FIXBINARY:
111 case DATA_FLOAT:
112 case DATA_DOUBLE:
113 case DATA_DECIMAL:
114 /* Above are the valid column types for MySQL data. */
115 ut_ad(flen == len);
116 /* fall through */
117 case DATA_CHAR:
118 /* We may have flen > len when there is a shorter
119 prefix on a CHAR column. */
120 ut_ad(flen >= len);
121 #else /* UNIV_DEBUG */
122 default:
123 #endif /* UNIV_DEBUG */
124 memcpy(dest, data, len);
128 /*************************************************************//**
129 Copies an InnoDB record to table->record[0]. */
130 extern "C" UNIV_INTERN
131 void
132 innobase_rec_to_mysql(
133 /*==================*/
134 TABLE* table, /*!< in/out: MySQL table */
135 const rec_t* rec, /*!< in: record */
136 const dict_index_t* index, /*!< in: index */
137 const ulint* offsets) /*!< in: rec_get_offsets(
138 rec, index, ...) */
140 uint n_fields = table->s->fields;
141 uint i;
143 ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
145 for (i = 0; i < n_fields; i++) {
146 Field* field = table->field[i];
147 ulint ipos;
148 ulint ilen;
149 const uchar* ifield;
151 field->reset();
153 ipos = dict_index_get_nth_col_or_prefix_pos(index, i, TRUE);
155 if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
156 null_field:
157 field->set_null();
158 continue;
161 ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
163 /* Assign the NULL flag */
164 if (ilen == UNIV_SQL_NULL) {
165 ut_ad(field->real_maybe_null());
166 goto null_field;
169 field->set_notnull();
171 innobase_col_to_mysql(
172 dict_field_get_col(
173 dict_index_get_nth_field(index, ipos)),
174 ifield, ilen, field);
178 /*************************************************************//**
179 Resets table->record[0]. */
180 extern "C" UNIV_INTERN
181 void
182 innobase_rec_reset(
183 /*===============*/
184 TABLE* table) /*!< in/out: MySQL table */
186 uint n_fields = table->s->fields;
187 uint i;
189 for (i = 0; i < n_fields; i++) {
190 table->field[i]->set_default();
194 /******************************************************************//**
195 Removes the filename encoding of a database and table name. */
196 static
197 void
198 innobase_convert_tablename(
199 /*=======================*/
200 char* s) /*!< in: identifier; out: decoded identifier */
202 uint errors;
204 char* slash = strchr(s, '/');
206 if (slash) {
207 char* t;
208 /* Temporarily replace the '/' with NUL. */
209 *slash = 0;
210 /* Convert the database name. */
211 strconvert(&my_charset_filename, s, system_charset_info,
212 s, slash - s + 1, &errors);
214 t = s + strlen(s);
215 ut_ad(slash >= t);
216 /* Append a '.' after the database name. */
217 *t++ = '.';
218 slash++;
219 /* Convert the table name. */
220 strconvert(&my_charset_filename, slash, system_charset_info,
221 t, slash - t + strlen(slash), &errors);
222 } else {
223 strconvert(&my_charset_filename, s,
224 system_charset_info, s, strlen(s), &errors);
228 /*******************************************************************//**
229 This function checks that index keys are sensible.
230 @return 0 or error number */
231 static
233 innobase_check_index_keys(
234 /*======================*/
235 const KEY* key_info, /*!< in: Indexes to be
236 created */
237 ulint num_of_keys, /*!< in: Number of
238 indexes to be created */
239 const dict_table_t* table) /*!< in: Existing indexes */
241 ulint key_num;
243 ut_ad(key_info);
244 ut_ad(num_of_keys);
246 for (key_num = 0; key_num < num_of_keys; key_num++) {
247 const KEY& key = key_info[key_num];
249 /* Check that the same index name does not appear
250 twice in indexes to be created. */
252 for (ulint i = 0; i < key_num; i++) {
253 const KEY& key2 = key_info[i];
255 if (0 == strcmp(key.name, key2.name)) {
256 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
257 key.name);
259 return(ER_WRONG_NAME_FOR_INDEX);
263 /* Check that the same index name does not already exist. */
265 for (const dict_index_t* index
266 = dict_table_get_first_index(table);
267 index; index = dict_table_get_next_index(index)) {
269 if (0 == strcmp(key.name, index->name)) {
270 my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
271 key.name);
273 return(ER_WRONG_NAME_FOR_INDEX);
277 /* Check that MySQL does not try to create a column
278 prefix index field on an inappropriate data type and
279 that the same column does not appear twice in the index. */
281 for (ulint i = 0; i < key.key_parts; i++) {
282 const KEY_PART_INFO& key_part1
283 = key.key_part[i];
284 const Field* field
285 = key_part1.field;
286 ibool is_unsigned;
288 switch (get_innobase_type_from_mysql_type(
289 &is_unsigned, field)) {
290 default:
291 break;
292 case DATA_INT:
293 case DATA_FLOAT:
294 case DATA_DOUBLE:
295 case DATA_DECIMAL:
296 if (field->type() == MYSQL_TYPE_VARCHAR) {
297 if (key_part1.length
298 >= field->pack_length()
299 - ((Field_varstring*) field)
300 ->length_bytes) {
301 break;
303 } else {
304 if (key_part1.length
305 >= field->pack_length()) {
306 break;
310 my_error(ER_WRONG_KEY_COLUMN, MYF(0),
311 field->field_name);
312 return(ER_WRONG_KEY_COLUMN);
315 for (ulint j = 0; j < i; j++) {
316 const KEY_PART_INFO& key_part2
317 = key.key_part[j];
319 if (strcmp(key_part1.field->field_name,
320 key_part2.field->field_name)) {
321 continue;
324 my_error(ER_WRONG_KEY_COLUMN, MYF(0),
325 key_part1.field->field_name);
326 return(ER_WRONG_KEY_COLUMN);
331 return(0);
334 /*******************************************************************//**
335 Create index field definition for key part */
336 static
337 void
338 innobase_create_index_field_def(
339 /*============================*/
340 KEY_PART_INFO* key_part, /*!< in: MySQL key definition */
341 mem_heap_t* heap, /*!< in: memory heap */
342 merge_index_field_t* index_field) /*!< out: index field
343 definition for key_part */
345 Field* field;
346 ibool is_unsigned;
347 ulint col_type;
349 DBUG_ENTER("innobase_create_index_field_def");
351 ut_ad(key_part);
352 ut_ad(index_field);
354 field = key_part->field;
355 ut_a(field);
357 col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
359 if (DATA_BLOB == col_type
360 || (key_part->length < field->pack_length()
361 && field->type() != MYSQL_TYPE_VARCHAR)
362 || (field->type() == MYSQL_TYPE_VARCHAR
363 && key_part->length < field->pack_length()
364 - ((Field_varstring*)field)->length_bytes)) {
366 index_field->prefix_len = key_part->length;
367 } else {
368 index_field->prefix_len = 0;
371 index_field->field_name = mem_heap_strdup(heap, field->field_name);
373 DBUG_VOID_RETURN;
376 /*******************************************************************//**
377 Create index definition for key */
378 static
379 void
380 innobase_create_index_def(
381 /*======================*/
382 KEY* key, /*!< in: key definition */
383 bool new_primary, /*!< in: TRUE=generating
384 a new primary key
385 on the table */
386 bool key_primary, /*!< in: TRUE if this key
387 is a primary key */
388 merge_index_def_t* index, /*!< out: index definition */
389 mem_heap_t* heap) /*!< in: heap where memory
390 is allocated */
392 ulint i;
393 ulint len;
394 ulint n_fields = key->key_parts;
395 char* index_name;
397 DBUG_ENTER("innobase_create_index_def");
399 index->fields = (merge_index_field_t*) mem_heap_alloc(
400 heap, n_fields * sizeof *index->fields);
402 index->ind_type = 0;
403 index->n_fields = n_fields;
404 len = strlen(key->name) + 1;
405 index->name = index_name = (char*) mem_heap_alloc(heap,
406 len + !new_primary);
408 if (UNIV_LIKELY(!new_primary)) {
409 *index_name++ = TEMP_INDEX_PREFIX;
412 memcpy(index_name, key->name, len);
414 if (key->flags & HA_NOSAME) {
415 index->ind_type |= DICT_UNIQUE;
418 if (key_primary) {
419 index->ind_type |= DICT_CLUSTERED;
422 for (i = 0; i < n_fields; i++) {
423 innobase_create_index_field_def(&key->key_part[i], heap,
424 &index->fields[i]);
427 DBUG_VOID_RETURN;
430 /*******************************************************************//**
431 Copy index field definition */
432 static
433 void
434 innobase_copy_index_field_def(
435 /*==========================*/
436 const dict_field_t* field, /*!< in: definition to copy */
437 merge_index_field_t* index_field) /*!< out: copied definition */
439 DBUG_ENTER("innobase_copy_index_field_def");
440 DBUG_ASSERT(field != NULL);
441 DBUG_ASSERT(index_field != NULL);
443 index_field->field_name = field->name;
444 index_field->prefix_len = field->prefix_len;
446 DBUG_VOID_RETURN;
449 /*******************************************************************//**
450 Copy index definition for the index */
451 static
452 void
453 innobase_copy_index_def(
454 /*====================*/
455 const dict_index_t* index, /*!< in: index definition to copy */
456 merge_index_def_t* new_index,/*!< out: Index definition */
457 mem_heap_t* heap) /*!< in: heap where allocated */
459 ulint n_fields;
460 ulint i;
462 DBUG_ENTER("innobase_copy_index_def");
464 /* Note that we take only those fields that user defined to be
465 in the index. In the internal representation more colums were
466 added and those colums are not copied .*/
468 n_fields = index->n_user_defined_cols;
470 new_index->fields = (merge_index_field_t*) mem_heap_alloc(
471 heap, n_fields * sizeof *new_index->fields);
473 /* When adding a PRIMARY KEY, we may convert a previous
474 clustered index to a secondary index (UNIQUE NOT NULL). */
475 new_index->ind_type = index->type & ~DICT_CLUSTERED;
476 new_index->n_fields = n_fields;
477 new_index->name = index->name;
479 for (i = 0; i < n_fields; i++) {
480 innobase_copy_index_field_def(&index->fields[i],
481 &new_index->fields[i]);
484 DBUG_VOID_RETURN;
487 /*******************************************************************//**
488 Create an index table where indexes are ordered as follows:
490 IF a new primary key is defined for the table THEN
492 1) New primary key
493 2) Original secondary indexes
494 3) New secondary indexes
496 ELSE
498 1) All new indexes in the order they arrive from MySQL
500 ENDIF
503 @return key definitions or NULL */
504 static
505 merge_index_def_t*
506 innobase_create_key_def(
507 /*====================*/
508 trx_t* trx, /*!< in: trx */
509 const dict_table_t*table, /*!< in: table definition */
510 mem_heap_t* heap, /*!< in: heap where space for key
511 definitions are allocated */
512 KEY* key_info, /*!< in: Indexes to be created */
513 ulint& n_keys) /*!< in/out: Number of indexes to
514 be created */
516 ulint i = 0;
517 merge_index_def_t* indexdef;
518 merge_index_def_t* indexdefs;
519 bool new_primary;
521 DBUG_ENTER("innobase_create_key_def");
523 indexdef = indexdefs = (merge_index_def_t*)
524 mem_heap_alloc(heap, sizeof *indexdef
525 * (n_keys + UT_LIST_GET_LEN(table->indexes)));
527 /* If there is a primary key, it is always the first index
528 defined for the table. */
530 new_primary = !my_strcasecmp(system_charset_info,
531 key_info->name, "PRIMARY");
533 /* If there is a UNIQUE INDEX consisting entirely of NOT NULL
534 columns and if the index does not contain column prefix(es)
535 (only prefix/part of the column is indexed), MySQL will treat the
536 index as a PRIMARY KEY unless the table already has one. */
538 if (!new_primary && (key_info->flags & HA_NOSAME)
539 && (!(key_info->flags & HA_KEY_HAS_PART_KEY_SEG))
540 && row_table_got_default_clust_index(table)) {
541 uint key_part = key_info->key_parts;
543 new_primary = TRUE;
545 while (key_part--) {
546 if (key_info->key_part[key_part].key_type
547 & FIELDFLAG_MAYBE_NULL) {
548 new_primary = FALSE;
549 break;
554 if (new_primary) {
555 const dict_index_t* index;
557 /* Create the PRIMARY key index definition */
558 innobase_create_index_def(&key_info[i++], TRUE, TRUE,
559 indexdef++, heap);
561 row_mysql_lock_data_dictionary(trx);
563 index = dict_table_get_first_index(table);
565 /* Copy the index definitions of the old table. Skip
566 the old clustered index if it is a generated clustered
567 index or a PRIMARY KEY. If the clustered index is a
568 UNIQUE INDEX, it must be converted to a secondary index. */
570 if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
571 || !my_strcasecmp(system_charset_info,
572 index->name, "PRIMARY")) {
573 index = dict_table_get_next_index(index);
576 while (index) {
577 innobase_copy_index_def(index, indexdef++, heap);
578 index = dict_table_get_next_index(index);
581 row_mysql_unlock_data_dictionary(trx);
584 /* Create definitions for added secondary indexes. */
586 while (i < n_keys) {
587 innobase_create_index_def(&key_info[i++], new_primary, FALSE,
588 indexdef++, heap);
591 n_keys = indexdef - indexdefs;
593 DBUG_RETURN(indexdefs);
596 /*******************************************************************//**
597 Create a temporary tablename using query id, thread id, and id
598 @return temporary tablename */
599 static
600 char*
601 innobase_create_temporary_tablename(
602 /*================================*/
603 mem_heap_t* heap, /*!< in: memory heap */
604 char id, /*!< in: identifier [0-9a-zA-Z] */
605 const char* table_name) /*!< in: table name */
607 char* name;
608 ulint len;
609 static const char suffix[] = "@0023 "; /* "# " */
611 len = strlen(table_name);
613 name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
614 memcpy(name, table_name, len);
615 memcpy(name + len, suffix, sizeof suffix);
616 name[len + (sizeof suffix - 2)] = id;
618 return(name);
621 /*******************************************************************//**
622 Create indexes.
623 @return 0 or error number */
624 UNIV_INTERN
626 ha_innobase::add_index(
627 /*===================*/
628 TABLE* table, /*!< in: Table where indexes are created */
629 KEY* key_info, /*!< in: Indexes to be created */
630 uint num_of_keys) /*!< in: Number of indexes to be created */
632 dict_index_t** index; /*!< Index to be created */
633 dict_table_t* innodb_table; /*!< InnoDB table in dictionary */
634 dict_table_t* indexed_table; /*!< Table where indexes are created */
635 merge_index_def_t* index_defs; /*!< Index definitions */
636 mem_heap_t* heap; /*!< Heap for index definitions */
637 trx_t* trx; /*!< Transaction */
638 ulint num_of_idx;
639 ulint num_created = 0;
640 ibool dict_locked = FALSE;
641 ulint new_primary;
642 int error;
644 DBUG_ENTER("ha_innobase::add_index");
645 ut_a(table);
646 ut_a(key_info);
647 ut_a(num_of_keys);
649 if (srv_created_new_raw || srv_force_recovery) {
650 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
653 update_thd();
655 /* In case MySQL calls this in the middle of a SELECT query, release
656 possible adaptive hash latch to avoid deadlocks of threads. */
657 trx_search_latch_release_if_reserved(prebuilt->trx);
659 /* Check if the index name is reserved. */
660 if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) {
661 DBUG_RETURN(-1);
664 innodb_table = indexed_table
665 = dict_table_get(prebuilt->table->name, FALSE);
667 if (UNIV_UNLIKELY(!innodb_table)) {
668 DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
671 if (innodb_table->tablespace_discarded) {
672 DBUG_RETURN(-1);
675 /* Check that index keys are sensible */
676 error = innobase_check_index_keys(key_info, num_of_keys, innodb_table);
678 if (UNIV_UNLIKELY(error)) {
679 DBUG_RETURN(error);
682 heap = mem_heap_create(1024);
683 trx_start_if_not_started(prebuilt->trx);
685 /* Create a background transaction for the operations on
686 the data dictionary tables. */
687 trx = innobase_trx_allocate(user_thd);
688 trx_start_if_not_started(trx);
690 /* Create table containing all indexes to be built in this
691 alter table add index so that they are in the correct order
692 in the table. */
694 num_of_idx = num_of_keys;
696 index_defs = innobase_create_key_def(
697 trx, innodb_table, heap, key_info, num_of_idx);
699 new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
701 /* Allocate memory for dictionary index definitions */
703 index = (dict_index_t**) mem_heap_alloc(
704 heap, num_of_idx * sizeof *index);
706 /* Flag this transaction as a dictionary operation, so that
707 the data dictionary will be locked in crash recovery. */
708 trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
710 /* Acquire a lock on the table before creating any indexes. */
711 error = row_merge_lock_table(prebuilt->trx, innodb_table,
712 new_primary ? LOCK_X : LOCK_S);
714 if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
716 goto error_handling;
719 /* Latch the InnoDB data dictionary exclusively so that no deadlocks
720 or lock waits can happen in it during an index create operation. */
722 row_mysql_lock_data_dictionary(trx);
723 dict_locked = TRUE;
725 ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE));
727 /* If a new primary key is defined for the table we need
728 to drop the original table and rebuild all indexes. */
730 if (UNIV_UNLIKELY(new_primary)) {
731 /* This transaction should be the only one
732 operating on the table. */
733 ut_a(innodb_table->n_mysql_handles_opened == 1);
735 char* new_table_name = innobase_create_temporary_tablename(
736 heap, '1', innodb_table->name);
738 /* Clone the table. */
739 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
740 indexed_table = row_merge_create_temporary_table(
741 new_table_name, index_defs, innodb_table, trx);
743 if (!indexed_table) {
745 switch (trx->error_state) {
746 case DB_TABLESPACE_ALREADY_EXISTS:
747 case DB_DUPLICATE_KEY:
748 innobase_convert_tablename(new_table_name);
749 my_error(HA_ERR_TABLE_EXIST, MYF(0),
750 new_table_name);
751 error = HA_ERR_TABLE_EXIST;
752 break;
753 default:
754 error = convert_error_code_to_mysql(
755 trx->error_state, innodb_table->flags,
756 user_thd);
759 ut_d(dict_table_check_for_dup_indexes(innodb_table,
760 FALSE));
761 mem_heap_free(heap);
762 trx_general_rollback_for_mysql(trx, NULL);
763 row_mysql_unlock_data_dictionary(trx);
764 trx_free_for_mysql(trx);
765 trx_commit_for_mysql(prebuilt->trx);
766 DBUG_RETURN(error);
769 trx->table_id = indexed_table->id;
772 /* Create the indexes in SYS_INDEXES and load into dictionary. */
774 for (ulint i = 0; i < num_of_idx; i++) {
776 index[i] = row_merge_create_index(trx, indexed_table,
777 &index_defs[i]);
779 if (!index[i]) {
780 error = trx->error_state;
781 goto error_handling;
784 num_created++;
787 ut_ad(error == DB_SUCCESS);
789 /* Commit the data dictionary transaction in order to release
790 the table locks on the system tables. This means that if
791 MySQL crashes while creating a new primary key inside
792 row_merge_build_indexes(), indexed_table will not be dropped
793 by trx_rollback_active(). It will have to be recovered or
794 dropped by the database administrator. */
795 trx_commit_for_mysql(trx);
797 row_mysql_unlock_data_dictionary(trx);
798 dict_locked = FALSE;
800 ut_a(trx->n_active_thrs == 0);
801 ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
803 if (UNIV_UNLIKELY(new_primary)) {
804 /* A primary key is to be built. Acquire an exclusive
805 table lock also on the table that is being created. */
806 ut_ad(indexed_table != innodb_table);
808 error = row_merge_lock_table(prebuilt->trx, indexed_table,
809 LOCK_X);
811 if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
813 goto error_handling;
817 /* Read the clustered index of the table and build indexes
818 based on this information using temporary files and merge sort. */
819 error = row_merge_build_indexes(prebuilt->trx,
820 innodb_table, indexed_table,
821 index, num_of_idx, table);
823 error_handling:
824 /* After an error, remove all those index definitions from the
825 dictionary which were defined. */
827 switch (error) {
828 const char* old_name;
829 char* tmp_name;
830 case DB_SUCCESS:
831 ut_a(!dict_locked);
832 row_mysql_lock_data_dictionary(trx);
833 dict_locked = TRUE;
835 ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
837 if (!new_primary) {
838 error = row_merge_rename_indexes(trx, indexed_table);
840 if (error != DB_SUCCESS) {
841 row_merge_drop_indexes(trx, indexed_table,
842 index, num_created);
845 goto convert_error;
848 /* If a new primary key was defined for the table and
849 there was no error at this point, we can now rename
850 the old table as a temporary table, rename the new
851 temporary table as the old table and drop the old table. */
852 old_name = innodb_table->name;
853 tmp_name = innobase_create_temporary_tablename(heap, '2',
854 old_name);
856 error = row_merge_rename_tables(innodb_table, indexed_table,
857 tmp_name, trx);
859 if (error != DB_SUCCESS) {
861 row_merge_drop_table(trx, indexed_table);
863 switch (error) {
864 case DB_TABLESPACE_ALREADY_EXISTS:
865 case DB_DUPLICATE_KEY:
866 innobase_convert_tablename(tmp_name);
867 my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
868 error = HA_ERR_TABLE_EXIST;
869 break;
870 default:
871 goto convert_error;
873 break;
876 trx_commit_for_mysql(prebuilt->trx);
877 row_prebuilt_free(prebuilt, TRUE);
878 prebuilt = row_create_prebuilt(indexed_table);
880 indexed_table->n_mysql_handles_opened++;
882 error = row_merge_drop_table(trx, innodb_table);
883 innodb_table = indexed_table;
884 goto convert_error;
886 case DB_TOO_BIG_RECORD:
887 my_error(HA_ERR_TO_BIG_ROW, MYF(0));
888 goto error;
889 case DB_PRIMARY_KEY_IS_NULL:
890 my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
891 /* fall through */
892 case DB_DUPLICATE_KEY:
893 error:
894 prebuilt->trx->error_info = NULL;
895 /* fall through */
896 default:
897 trx->error_state = DB_SUCCESS;
899 if (new_primary) {
900 if (indexed_table != innodb_table) {
901 row_merge_drop_table(trx, indexed_table);
903 } else {
904 if (!dict_locked) {
905 row_mysql_lock_data_dictionary(trx);
906 dict_locked = TRUE;
909 row_merge_drop_indexes(trx, indexed_table,
910 index, num_created);
913 convert_error:
914 if (error == DB_SUCCESS) {
915 /* Build index is successful. We will need to
916 rebuild index translation table. Reset the
917 index entry count in the translation table
918 to zero, so that translation table will be rebuilt */
919 share->idx_trans_tbl.index_count = 0;
922 error = convert_error_code_to_mysql(error,
923 innodb_table->flags,
924 user_thd);
927 mem_heap_free(heap);
928 trx_commit_for_mysql(trx);
929 if (prebuilt->trx) {
930 trx_commit_for_mysql(prebuilt->trx);
933 if (dict_locked) {
934 ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE));
935 row_mysql_unlock_data_dictionary(trx);
938 trx_free_for_mysql(trx);
940 /* There might be work for utility threads.*/
941 srv_active_wake_master_thread();
943 DBUG_RETURN(error);
946 /*******************************************************************//**
947 Prepare to drop some indexes of a table.
948 @return 0 or error number */
949 UNIV_INTERN
951 ha_innobase::prepare_drop_index(
952 /*============================*/
953 TABLE* table, /*!< in: Table where indexes are dropped */
954 uint* key_num, /*!< in: Key nums to be dropped */
955 uint num_of_keys) /*!< in: Number of keys to be dropped */
957 trx_t* trx;
958 int err = 0;
959 uint n_key;
961 DBUG_ENTER("ha_innobase::prepare_drop_index");
962 ut_ad(table);
963 ut_ad(key_num);
964 ut_ad(num_of_keys);
965 if (srv_created_new_raw || srv_force_recovery) {
966 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
969 update_thd();
971 trx_search_latch_release_if_reserved(prebuilt->trx);
972 trx = prebuilt->trx;
974 /* Test and mark all the indexes to be dropped */
976 row_mysql_lock_data_dictionary(trx);
977 ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
979 /* Check that none of the indexes have previously been flagged
980 for deletion. */
982 const dict_index_t* index
983 = dict_table_get_first_index(prebuilt->table);
984 do {
985 ut_a(!index->to_be_dropped);
986 index = dict_table_get_next_index(index);
987 } while (index);
990 for (n_key = 0; n_key < num_of_keys; n_key++) {
991 const KEY* key;
992 dict_index_t* index;
994 key = table->key_info + key_num[n_key];
995 index = dict_table_get_index_on_name_and_min_id(
996 prebuilt->table, key->name);
998 if (!index) {
999 sql_print_error("InnoDB could not find key n:o %u "
1000 "with name %s for table %s",
1001 key_num[n_key],
1002 key ? key->name : "NULL",
1003 prebuilt->table->name);
1005 err = HA_ERR_KEY_NOT_FOUND;
1006 goto func_exit;
1009 /* Refuse to drop the clustered index. It would be
1010 better to automatically generate a clustered index,
1011 but mysql_alter_table() will call this method only
1012 after ha_innobase::add_index(). */
1014 if (dict_index_is_clust(index)) {
1015 my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
1016 err = -1;
1017 goto func_exit;
1020 rw_lock_x_lock(dict_index_get_lock(index));
1021 index->to_be_dropped = TRUE;
1022 rw_lock_x_unlock(dict_index_get_lock(index));
1025 /* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined
1026 for a foreign key constraint because InnoDB requires that both
1027 tables contain indexes for the constraint. Such index can
1028 be dropped only if FOREIGN_KEY_CHECKS is set to 0.
1029 Note that CREATE INDEX id ON table does a CREATE INDEX and
1030 DROP INDEX, and we can ignore here foreign keys because a
1031 new index for the foreign key has already been created.
1033 We check for the foreign key constraints after marking the
1034 candidate indexes for deletion, because when we check for an
1035 equivalent foreign index we don't want to select an index that
1036 is later deleted. */
1038 if (trx->check_foreigns
1039 && thd_sql_command(user_thd) != SQLCOM_CREATE_INDEX) {
1040 dict_index_t* index;
1042 for (index = dict_table_get_first_index(prebuilt->table);
1043 index;
1044 index = dict_table_get_next_index(index)) {
1045 dict_foreign_t* foreign;
1047 if (!index->to_be_dropped) {
1049 continue;
1052 /* Check if the index is referenced. */
1053 foreign = dict_table_get_referenced_constraint(
1054 prebuilt->table, index);
1056 if (foreign) {
1057 index_needed:
1058 trx_set_detailed_error(
1059 trx,
1060 "Index needed in foreign key "
1061 "constraint");
1063 trx->error_info = index;
1065 err = HA_ERR_DROP_INDEX_FK;
1066 break;
1067 } else {
1068 /* Check if this index references some
1069 other table */
1070 foreign = dict_table_get_foreign_constraint(
1071 prebuilt->table, index);
1073 if (foreign) {
1074 ut_a(foreign->foreign_index == index);
1076 /* Search for an equivalent index that
1077 the foreign key constraint could use
1078 if this index were to be deleted. */
1079 if (!dict_foreign_find_equiv_index(
1080 foreign)) {
1082 goto index_needed;
1087 } else if (thd_sql_command(user_thd) == SQLCOM_CREATE_INDEX) {
1088 /* This is a drop of a foreign key constraint index that
1089 was created by MySQL when the constraint was added. MySQL
1090 does this when the user creates an index explicitly which
1091 can be used in place of the automatically generated index. */
1093 dict_index_t* index;
1095 for (index = dict_table_get_first_index(prebuilt->table);
1096 index;
1097 index = dict_table_get_next_index(index)) {
1098 dict_foreign_t* foreign;
1100 if (!index->to_be_dropped) {
1102 continue;
1105 /* Check if this index references some other table */
1106 foreign = dict_table_get_foreign_constraint(
1107 prebuilt->table, index);
1109 if (foreign == NULL) {
1111 continue;
1114 ut_a(foreign->foreign_index == index);
1116 /* Search for an equivalent index that the
1117 foreign key constraint could use if this index
1118 were to be deleted. */
1120 if (!dict_foreign_find_equiv_index(foreign)) {
1121 trx_set_detailed_error(
1122 trx,
1123 "Index needed in foreign key "
1124 "constraint");
1126 trx->error_info = foreign->foreign_index;
1128 err = HA_ERR_DROP_INDEX_FK;
1129 break;
1134 func_exit:
1135 if (err) {
1136 /* Undo our changes since there was some sort of error. */
1137 dict_index_t* index
1138 = dict_table_get_first_index(prebuilt->table);
1140 do {
1141 rw_lock_x_lock(dict_index_get_lock(index));
1142 index->to_be_dropped = FALSE;
1143 rw_lock_x_unlock(dict_index_get_lock(index));
1144 index = dict_table_get_next_index(index);
1145 } while (index);
1148 ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1149 row_mysql_unlock_data_dictionary(trx);
1151 DBUG_RETURN(err);
1154 /*******************************************************************//**
1155 Drop the indexes that were passed to a successful prepare_drop_index().
1156 @return 0 or error number */
1157 UNIV_INTERN
1159 ha_innobase::final_drop_index(
1160 /*==========================*/
1161 TABLE* table) /*!< in: Table where indexes are dropped */
1163 dict_index_t* index; /*!< Index to be dropped */
1164 trx_t* trx; /*!< Transaction */
1165 int err;
1167 DBUG_ENTER("ha_innobase::final_drop_index");
1168 ut_ad(table);
1170 if (srv_created_new_raw || srv_force_recovery) {
1171 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
1174 update_thd();
1176 trx_search_latch_release_if_reserved(prebuilt->trx);
1177 trx_start_if_not_started(prebuilt->trx);
1179 /* Create a background transaction for the operations on
1180 the data dictionary tables. */
1181 trx = innobase_trx_allocate(user_thd);
1182 trx_start_if_not_started(trx);
1184 /* Flag this transaction as a dictionary operation, so that
1185 the data dictionary will be locked in crash recovery. */
1186 trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1188 /* Lock the table exclusively, to ensure that no active
1189 transaction depends on an index that is being dropped. */
1190 err = convert_error_code_to_mysql(
1191 row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1192 prebuilt->table->flags, user_thd);
1194 row_mysql_lock_data_dictionary(trx);
1195 ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1197 if (UNIV_UNLIKELY(err)) {
1199 /* Unmark the indexes to be dropped. */
1200 for (index = dict_table_get_first_index(prebuilt->table);
1201 index; index = dict_table_get_next_index(index)) {
1203 rw_lock_x_lock(dict_index_get_lock(index));
1204 index->to_be_dropped = FALSE;
1205 rw_lock_x_unlock(dict_index_get_lock(index));
1208 goto func_exit;
1211 /* Drop indexes marked to be dropped */
1213 index = dict_table_get_first_index(prebuilt->table);
1215 while (index) {
1216 dict_index_t* next_index;
1218 next_index = dict_table_get_next_index(index);
1220 if (index->to_be_dropped) {
1222 row_merge_drop_index(index, prebuilt->table, trx);
1225 index = next_index;
1228 /* Check that all flagged indexes were dropped. */
1229 for (index = dict_table_get_first_index(prebuilt->table);
1230 index; index = dict_table_get_next_index(index)) {
1231 ut_a(!index->to_be_dropped);
1234 /* We will need to rebuild index translation table. Set
1235 valid index entry count in the translation table to zero */
1236 share->idx_trans_tbl.index_count = 0;
1238 func_exit:
1239 ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1240 trx_commit_for_mysql(trx);
1241 trx_commit_for_mysql(prebuilt->trx);
1242 row_mysql_unlock_data_dictionary(trx);
1244 /* Flush the log to reduce probability that the .frm files and
1245 the InnoDB data dictionary get out-of-sync if the user runs
1246 with innodb_flush_log_at_trx_commit = 0 */
1248 log_buffer_flush_to_disk();
1250 trx_free_for_mysql(trx);
1252 /* Tell the InnoDB server that there might be work for
1253 utility threads: */
1255 srv_active_wake_master_thread();
1257 DBUG_RETURN(err);