Drizzled Public API Documentation

handler0alter.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (C) 2005, 2010, Innobase Oy. All Rights Reserved.
4 
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.
8 
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.
12 
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
16 
17 *****************************************************************************/
18 
19 /**************************************************/
24 #include <config.h>
25 #include <drizzled/error.h>
26 #include <drizzled/charset.h>
27 #include <drizzled/field.h>
28 #include <drizzled/table.h>
29 #include <drizzled/field/varstring.h>
30 #include <drizzled/internal/my_sys.h>
31 
32 #include "log0log.h"
33 #include "row0merge.h"
34 #include "srv0srv.h"
35 #include "trx0trx.h"
36 #include "trx0roll.h"
37 #include "ha_prototypes.h"
38 #include "handler0alter.h"
39 
40 #include "ha_innodb.h"
41 #include "handler0vars.h"
42 
43 /*************************************************************/
46 static
47 void
49 /*==================*/
50  const dict_col_t* col,
51  const unsigned char* data,
52  ulint len,
53  Field* field)
54 {
55  unsigned char* ptr;
56  unsigned char* dest = field->ptr;
57  ulint flen = field->pack_length();
58 
59  switch (col->mtype) {
60  case DATA_INT:
61  ut_ad(len == flen);
62 
63  /* Convert integer data from Innobase to little-endian
64  format, sign bit restored to normal */
65 
66  for (ptr = dest + len; ptr != dest; ) {
67  *--ptr = *data++;
68  }
69 
70  if (!(field->flags & UNSIGNED_FLAG)) {
71  ((byte*) dest)[len - 1] ^= 0x80;
72  }
73 
74  break;
75 
76  case DATA_VARCHAR:
77  case DATA_VARMYSQL:
78  case DATA_BINARY:
79  field->reset();
80 
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
84  two bytes of dest. */
85 
87  dest, len, flen - field->key_length());
88  }
89 
90  /* Copy the actual data */
91  memcpy(dest, data, len);
92  break;
93 
94  case DATA_BLOB:
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 */
97 
98  row_mysql_store_blob_ref(dest, flen, data, len);
99  break;
100 
101 #ifdef UNIV_DEBUG
102  case DATA_MYSQL:
103  ut_ad(flen >= len);
104  ut_ad(DATA_MBMAXLEN(col->mbminmaxlen)
105  >= DATA_MBMINLEN(col->mbminmaxlen));
106  ut_ad(DATA_MBMAXLEN(col->mbminmaxlen)
107  > DATA_MBMINLEN(col->mbminmaxlen) || flen == len);
108  memcpy(dest, data, len);
109  break;
110 
111  default:
112  case DATA_SYS_CHILD:
113  case DATA_SYS:
114  /* These column types should never be shipped to MySQL. */
115  ut_ad(0);
116 
117  case DATA_CHAR:
118  case DATA_FIXBINARY:
119  case DATA_FLOAT:
120  case DATA_DOUBLE:
121  case DATA_DECIMAL:
122  /* Above are the valid column types for MySQL data. */
123  ut_ad(flen == len);
124 #else /* UNIV_DEBUG */
125  default:
126 #endif /* UNIV_DEBUG */
127  memcpy(dest, data, len);
128  }
129 }
130 
131 /*************************************************************/
133 UNIV_INTERN
134 void
136 /*==================*/
137  Table* table,
138  const rec_t* rec,
139  const dict_index_t* index,
140  const ulint* offsets)
142 {
143  uint n_fields = table->getShare()->sizeFields();
144  uint i;
145 
146  ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
147 
148  for (i = 0; i < n_fields; i++) {
149  Field* field = table->getField(i);
150  ulint ipos;
151  ulint ilen;
152  const unsigned char* ifield;
153 
154  field->reset();
155 
156  ipos = dict_index_get_nth_col_pos(index, i);
157 
158  if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
159 null_field:
160  field->set_null();
161  continue;
162  }
163 
164  ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
165 
166  /* Assign the NULL flag */
167  if (ilen == UNIV_SQL_NULL) {
168  ut_ad(field->real_maybe_null());
169  goto null_field;
170  }
171 
172  field->set_notnull();
173 
176  dict_index_get_nth_field(index, ipos)),
177  ifield, ilen, field);
178  }
179 }
180 
181 /*************************************************************/
183 UNIV_INTERN
184 void
186 /*===============*/
187  Table* table)
188 {
189  uint n_fields = table->getShare()->sizeFields();
190  uint i;
191 
192  for (i = 0; i < n_fields; i++) {
193  table->getField(i)->set_default();
194  }
195 }
196 
197 #if 0 // This is a part of the fast index code.
198 /******************************************************************/
200 static
201 void
202 innobase_convert_tablename(
203 /*=======================*/
204  char* s)
205 {
206 
207  char* slash = strchr(s, '/');
208 
209  if (slash) {
210  char* t;
211  /* Temporarily replace the '/' with NUL. */
212  *slash = 0;
213  strncpy(s, s, slash - s + 1);
214 
215  t = s + strlen(s);
216  ut_ad(slash >= t);
217  /* Append a '.' after the database name. */
218  *t++ = '.';
219  slash++;
220  /* Convert the table name. */
221  strncpy(t, slash, slash - t + strlen(slash));
222  }
223 }
224 
225 
226 /*******************************************************************/
229 static
230 int
231 innobase_check_index_keys(
232 /*======================*/
233  const KeyInfo* key_info,
234  ulint num_of_keys,
236  const dict_table_t* table)
237 {
238  ulint key_num;
239 
240  ut_ad(key_info);
241  ut_ad(num_of_keys);
242 
243  for (key_num = 0; key_num < num_of_keys; key_num++) {
244  const KeyInfo& key = key_info[key_num];
245 
246  /* Check that the same index name does not appear
247  twice in indexes to be created. */
248 
249  for (ulint i = 0; i < key_num; i++) {
250  const KeyInfo& key2 = key_info[i];
251 
252  if (0 == strcmp(key.name, key2.name)) {
253  my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
254  key.name);
255 
256  return(ER_WRONG_NAME_FOR_INDEX);
257  }
258  }
259 
260  /* Check that the same index name does not already exist. */
261 
262  for (const dict_index_t* index
263  = dict_table_get_first_index(table);
264  index; index = dict_table_get_next_index(index)) {
265 
266  if (0 == strcmp(key.name, index->name)) {
267  my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
268  key.name);
269 
270  return(ER_WRONG_NAME_FOR_INDEX);
271  }
272  }
273 
274  /* Check that MySQL does not try to create a column
275  prefix index field on an inappropriate data type and
276  that the same column does not appear twice in the index. */
277 
278  for (ulint i = 0; i < key.key_parts; i++) {
279  const KeyPartInfo& key_part1
280  = key.key_part[i];
281  const Field* field
282  = key_part1.field;
283  ibool is_unsigned;
284 
286  &is_unsigned, field)) {
287  default:
288  break;
289  case DATA_INT:
290  case DATA_FLOAT:
291  case DATA_DOUBLE:
292  case DATA_DECIMAL:
293  if (field->type() == DRIZZLE_TYPE_VARCHAR) {
294  if (key_part1.length
295  >= field->pack_length()
296  - ((Field_varstring*) field)
297  ->length_bytes) {
298  break;
299  }
300  } else {
301  if (key_part1.length
302  >= field->pack_length()) {
303  break;
304  }
305  }
306 
307  my_error(ER_WRONG_KEY_COLUMN, MYF(0),
308  field->field_name);
309  return(ER_WRONG_KEY_COLUMN);
310  }
311 
312  for (ulint j = 0; j < i; j++) {
313  const KeyPartInfo& key_part2
314  = key.key_part[j];
315 
316  if (strcmp(key_part1.field->field_name,
317  key_part2.field->field_name)) {
318  continue;
319  }
320 
321  my_error(ER_WRONG_KEY_COLUMN, MYF(0),
322  key_part1.field->field_name);
323  return(ER_WRONG_KEY_COLUMN);
324  }
325  }
326  }
327 
328  return(0);
329 }
330 
331 /*******************************************************************/
333 static
334 void
335 innobase_create_index_field_def(
336 /*============================*/
337  KeyPartInfo* key_part,
338  mem_heap_t* heap,
339  merge_index_field_t* index_field)
341 {
342  Field* field;
343  ibool is_unsigned;
344  ulint col_type;
345 
346  ut_ad(key_part);
347  ut_ad(index_field);
348 
349  field = key_part->field;
350  ut_a(field);
351 
352  col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
353 
354  if (DATA_BLOB == col_type
355  || (key_part->length < field->pack_length()
356  && field->type() != DRIZZLE_TYPE_VARCHAR)
357  || (field->type() == DRIZZLE_TYPE_VARCHAR
358  && key_part->length < field->pack_length()
359  - ((Field_varstring*)field)->length_bytes)) {
360 
361  index_field->prefix_len = key_part->length;
362  } else {
363  index_field->prefix_len = 0;
364  }
365 
366  index_field->field_name = mem_heap_strdup(heap, field->field_name);
367 
368  return;
369 }
370 
371 /*******************************************************************/
373 static
374 void
375 innobase_create_index_def(
376 /*======================*/
377  KeyInfo* key,
378  bool new_primary,
381  bool key_primary,
383  merge_index_def_t* index,
384  mem_heap_t* heap)
386 {
387  ulint i;
388  ulint len;
389  ulint n_fields = key->key_parts;
390  char* index_name;
391 
393  heap, n_fields * sizeof *index->fields);
394 
395  index->ind_type = 0;
396  index->n_fields = n_fields;
397  len = strlen(key->name) + 1;
398  index->name = index_name = (char*) mem_heap_alloc(heap,
399  len + !new_primary);
400 
401  if (UNIV_LIKELY(!new_primary)) {
402  *index_name++ = TEMP_INDEX_PREFIX;
403  }
404 
405  memcpy(index_name, key->name, len);
406 
407  if (key->flags & HA_NOSAME) {
408  index->ind_type |= DICT_UNIQUE;
409  }
410 
411  if (key_primary) {
412  index->ind_type |= DICT_CLUSTERED;
413  }
414 
415  for (i = 0; i < n_fields; i++) {
416  innobase_create_index_field_def(&key->key_part[i], heap,
417  &index->fields[i]);
418  }
419 
420  return;
421 }
422 
423 /*******************************************************************/
425 static
426 void
427 innobase_copy_index_field_def(
428 /*==========================*/
429  const dict_field_t* field,
430  merge_index_field_t* index_field)
431 {
432  assert(field != NULL);
433  assert(index_field != NULL);
434 
435  index_field->field_name = field->name;
436  index_field->prefix_len = field->prefix_len;
437 
438  return;
439 }
440 
441 /*******************************************************************/
443 static
444 void
445 innobase_copy_index_def(
446 /*====================*/
447  const dict_index_t* index,
448  merge_index_def_t* new_index,
449  mem_heap_t* heap)
450 {
451  ulint n_fields;
452  ulint i;
453 
454  /* Note that we take only those fields that user defined to be
455  in the index. In the internal representation more colums were
456  added and those colums are not copied .*/
457 
458  n_fields = index->n_user_defined_cols;
459 
460  new_index->fields = (merge_index_field_t*) mem_heap_alloc(
461  heap, n_fields * sizeof *new_index->fields);
462 
463  /* When adding a PRIMARY KEY, we may convert a previous
464  clustered index to a secondary index (UNIQUE NOT NULL). */
465  new_index->ind_type = index->type & ~DICT_CLUSTERED;
466  new_index->n_fields = n_fields;
467  new_index->name = index->name;
468 
469  for (i = 0; i < n_fields; i++) {
470  innobase_copy_index_field_def(&index->fields[i],
471  &new_index->fields[i]);
472  }
473 
474  return;
475 }
476 
477 /*******************************************************************/
495 static
497 innobase_create_key_def(
498 /*====================*/
499  trx_t* trx,
500  const dict_table_t*table,
501  mem_heap_t* heap,
503  KeyInfo* key_info,
504  ulint& n_keys)
506 {
507  ulint i = 0;
508  merge_index_def_t* indexdef;
509  merge_index_def_t* indexdefs;
510  bool new_primary;
511 
512  indexdef = indexdefs = (merge_index_def_t*)
513  mem_heap_alloc(heap, sizeof *indexdef
514  * (n_keys + UT_LIST_GET_LEN(table->indexes)));
515 
516  /* If there is a primary key, it is always the first index
517  defined for the table. */
518 
519  new_primary = !system_charset_info->strcasecmp(key_info->name, "PRIMARY");
520 
521  /* If there is a UNIQUE INDEX consisting entirely of NOT NULL
522  columns and if the index does not contain column prefix(es)
523  (only prefix/part of the column is indexed), MySQL will treat the
524  index as a PRIMARY KEY unless the table already has one. */
525 
526  if (!new_primary && (key_info->flags & HA_NOSAME)
527  && (!(key_info->flags & HA_KEY_HAS_PART_KEY_SEG))
529  uint key_part = key_info->key_parts;
530 
531  new_primary = TRUE;
532 
533  while (key_part--) {
534  if (key_info->key_part[key_part].null_bit == 0) {
535  new_primary = FALSE;
536  break;
537  }
538  }
539  }
540 
541  if (new_primary) {
542  const dict_index_t* index;
543 
544  /* Create the PRIMARY key index definition */
545  innobase_create_index_def(&key_info[i++], TRUE, TRUE,
546  indexdef++, heap);
547 
548  row_mysql_lock_data_dictionary(trx);
549 
550  index = dict_table_get_first_index(table);
551 
552  /* Copy the index definitions of the old table. Skip
553  the old clustered index if it is a generated clustered
554  index or a PRIMARY KEY. If the clustered index is a
555  UNIQUE INDEX, it must be converted to a secondary index. */
556 
557  if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
558  || !system_charset_info->strcasecmp(index->name, "PRIMARY"))
559  {
560  index = dict_table_get_next_index(index);
561  }
562 
563  while (index) {
564  innobase_copy_index_def(index, indexdef++, heap);
565  index = dict_table_get_next_index(index);
566  }
567 
569  }
570 
571  /* Create definitions for added secondary indexes. */
572 
573  while (i < n_keys) {
574  innobase_create_index_def(&key_info[i++], new_primary, FALSE,
575  indexdef++, heap);
576  }
577 
578  n_keys = indexdef - indexdefs;
579 
580  return(indexdefs);
581 }
582 
583 /*******************************************************************/
586 static
587 char*
588 innobase_create_temporary_tablename(
589 /*================================*/
590  mem_heap_t* heap,
591  char id,
592  const char* table_name)
593 {
594  char* name;
595  ulint len;
596  static const char suffix[] = "@0023 "; /* "# " */
597 
598  len = strlen(table_name);
599 
600  name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
601  memcpy(name, table_name, len);
602  memcpy(name + len, suffix, sizeof suffix);
603  name[len + (sizeof suffix - 2)] = id;
604 
605  return(name);
606 }
607 
608 
609 /*******************************************************************/
612 UNIV_INTERN
613 int
614 ha_innobase::add_index(
615 /*===================*/
616  Session *session,
617  Table* i_table,
618  KeyInfo* key_info,
619  uint num_of_keys)
620 {
621  dict_index_t** index;
622  dict_table_t* innodb_table;
623  dict_table_t* indexed_table;
624  merge_index_def_t* index_defs;
625  mem_heap_t* heap;
626  trx_t* trx;
627  ulint num_of_idx;
628  ulint num_created = 0;
629  ibool dict_locked = FALSE;
630  ulint new_primary;
631  int error;
632 
633  ut_a(i_table);
634  ut_a(key_info);
635  ut_a(num_of_keys);
636 
637  if (srv_created_new_raw || srv_force_recovery) {
638  return(HA_ERR_WRONG_COMMAND);
639  }
640 
641  update_session(session);
642 
643  heap = mem_heap_create(1024);
644 
645  /* In case MySQL calls this in the middle of a SELECT query, release
646  possible adaptive hash latch to avoid deadlocks of threads. */
649 
650  /* Create a background transaction for the operations on
651  the data dictionary tables. */
654 
655  innodb_table = indexed_table
656  = dict_table_get(prebuilt->table->name, FALSE);
657 
658  if (UNIV_UNLIKELY(!innodb_table)) {
659  error = HA_ERR_NO_SUCH_TABLE;
660  goto err_exit;
661  }
662 
663  /* Check if the index name is reserved. */
664  if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) {
665  error = -1;
666  } else {
667  /* Check that index keys are sensible */
668  error = innobase_check_index_keys(key_info, num_of_keys,
669  innodb_table);
670  }
671 
672  if (UNIV_UNLIKELY(error)) {
673 err_exit:
674  mem_heap_free(heap);
676  trx_free_for_mysql(trx);
678  return(error);
679  }
680 
681  /* Create table containing all indexes to be built in this
682  alter table add index so that they are in the correct order
683  in the table. */
684 
685  num_of_idx = num_of_keys;
686 
687  index_defs = innobase_create_key_def(
688  trx, innodb_table, heap, key_info, num_of_idx);
689 
690  new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
691 
692  /* Allocate memory for dictionary index definitions */
693 
694  index = (dict_index_t**) mem_heap_alloc(
695  heap, num_of_idx * sizeof *index);
696 
697  /* Flag this transaction as a dictionary operation, so that
698  the data dictionary will be locked in crash recovery. */
700 
701  /* Acquire a lock on the table before creating any indexes. */
702  error = row_merge_lock_table(prebuilt->trx, innodb_table,
703  new_primary ? LOCK_X : LOCK_S);
704 
705  if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
706 
707  goto error_handling;
708  }
709 
710  /* Latch the InnoDB data dictionary exclusively so that no deadlocks
711  or lock waits can happen in it during an index create operation. */
712 
713  row_mysql_lock_data_dictionary(trx);
714  dict_locked = TRUE;
715 
716  ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE));
717 
718  /* If a new primary key is defined for the table we need
719  to drop the original table and rebuild all indexes. */
720 
721  if (UNIV_UNLIKELY(new_primary)) {
722  /* This transaction should be the only one
723  operating on the table. */
724  ut_a(innodb_table->n_mysql_handles_opened == 1);
725 
726  char* new_table_name = innobase_create_temporary_tablename(
727  heap, '1', innodb_table->name);
728 
729  /* Clone the table. */
731  indexed_table = row_merge_create_temporary_table(
732  new_table_name, index_defs, innodb_table, trx);
733 
734  if (!indexed_table) {
735 
736  switch (trx->error_state) {
737  case DB_TABLESPACE_ALREADY_EXISTS:
738  case DB_DUPLICATE_KEY:
739  innobase_convert_tablename(new_table_name);
740  my_error(HA_ERR_TABLE_EXIST, MYF(0),
741  new_table_name);
742  error = HA_ERR_TABLE_EXIST;
743  break;
744  default:
746  trx->error_state, innodb_table->flags,
747  user_session);
748  }
749 
750  ut_d(dict_table_check_for_dup_indexes(innodb_table,
751  FALSE));
753  goto err_exit;
754  }
755 
756  trx->table_id = indexed_table->id;
757  }
758 
759  /* Create the indexes in SYS_INDEXES and load into dictionary. */
760 
761  for (ulint i = 0; i < num_of_idx; i++) {
762 
763  index[i] = row_merge_create_index(trx, indexed_table,
764  &index_defs[i]);
765 
766  if (!index[i]) {
767  error = trx->error_state;
768  goto error_handling;
769  }
770 
771  num_created++;
772  }
773 
774  ut_ad(error == DB_SUCCESS);
775 
776  /* Commit the data dictionary transaction in order to release
777  the table locks on the system tables. This means that if
778  MySQL crashes while creating a new primary key inside
779  row_merge_build_indexes(), indexed_table will not be dropped
780  by trx_rollback_active(). It will have to be recovered or
781  dropped by the database administrator. */
783 
785  dict_locked = FALSE;
786 
787  ut_a(trx->n_active_thrs == 0);
788  ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
789 
790  if (UNIV_UNLIKELY(new_primary)) {
791  /* A primary key is to be built. Acquire an exclusive
792  table lock also on the table that is being created. */
793  ut_ad(indexed_table != innodb_table);
794 
795  error = row_merge_lock_table(prebuilt->trx, indexed_table,
796  LOCK_X);
797 
798  if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
799 
800  goto error_handling;
801  }
802  }
803 
804  /* Read the clustered index of the table and build indexes
805  based on this information using temporary files and merge sort. */
807  innodb_table, indexed_table,
808  index, num_of_idx, i_table);
809 
810 error_handling:
811 
812  /* After an error, remove all those index definitions from the
813  dictionary which were defined. */
814 
815  switch (error) {
816  const char* old_name;
817  char* tmp_name;
818  case DB_SUCCESS:
819  ut_a(!dict_locked);
820  row_mysql_lock_data_dictionary(trx);
821  dict_locked = TRUE;
822 
823  ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
824 
825  if (!new_primary) {
826  error = row_merge_rename_indexes(trx, indexed_table);
827 
828  if (error != DB_SUCCESS) {
829  row_merge_drop_indexes(trx, indexed_table,
830  index, num_created);
831  }
832 
833  goto convert_error;
834  }
835 
836  /* If a new primary key was defined for the table and
837  there was no error at this point, we can now rename
838  the old table as a temporary table, rename the new
839  temporary table as the old table and drop the old table. */
840  old_name = innodb_table->name;
841  tmp_name = innobase_create_temporary_tablename(heap, '2',
842  old_name);
843 
844  error = row_merge_rename_tables(innodb_table, indexed_table,
845  tmp_name, trx);
846 
847  if (error != DB_SUCCESS) {
848 
849  row_merge_drop_table(trx, indexed_table);
850 
851  switch (error) {
852  case DB_TABLESPACE_ALREADY_EXISTS:
853  case DB_DUPLICATE_KEY:
854  innobase_convert_tablename(tmp_name);
855  my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
856  error = HA_ERR_TABLE_EXIST;
857  break;
858  default:
859  goto convert_error;
860  }
861  break;
862  }
863 
866  prebuilt = row_create_prebuilt(indexed_table);
867 
868  indexed_table->n_mysql_handles_opened++;
869 
870  error = row_merge_drop_table(trx, innodb_table);
871  innodb_table = indexed_table;
872  goto convert_error;
873 
874  case DB_TOO_BIG_RECORD:
875  my_error(HA_ERR_TO_BIG_ROW, MYF(0));
876  goto error;
877  case DB_PRIMARY_KEY_IS_NULL:
878  my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
879  /* fall through */
880  case DB_DUPLICATE_KEY:
881 error:
882  prebuilt->trx->error_info = NULL;
883  /* fall through */
884  default:
885  trx->error_state = DB_SUCCESS;
886 
887  if (new_primary) {
888  if (indexed_table != innodb_table) {
889  row_merge_drop_table(trx, indexed_table);
890  }
891  } else {
892  if (!dict_locked) {
893  row_mysql_lock_data_dictionary(trx);
894  dict_locked = TRUE;
895  }
896 
897  row_merge_drop_indexes(trx, indexed_table,
898  index, num_created);
899  }
900 
901 convert_error:
902  if (error == DB_SUCCESS) {
903  /* Build index is successful. We will need to
904  rebuild index translation table. Reset the
905  index entry count in the translation table
906  to zero, so that translation table will be rebuilt */
908  }
909 
910  error = convert_error_code_to_mysql(error,
911  innodb_table->flags,
912  user_session);
913  }
914 
915  mem_heap_free(heap);
917  if (prebuilt->trx) {
919  }
920 
921  if (dict_locked) {
922  ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE));
924  }
925 
926  trx_free_for_mysql(trx);
927 
928  /* There might be work for utility threads.*/
930 
931  return(error);
932 }
933 
934 /*******************************************************************/
937 UNIV_INTERN
938 int
939 ha_innobase::prepare_drop_index(
940 /*============================*/
941  Session *session,
942  Table* i_table,
943  uint* key_num,
944  uint num_of_keys)
945 {
946  trx_t* trx;
947  int err = 0;
948  uint n_key;
949 
950  ut_ad(i_table);
951  ut_ad(key_num);
952  ut_ad(num_of_keys);
953  if (srv_created_new_raw || srv_force_recovery) {
954  return(HA_ERR_WRONG_COMMAND);
955  }
956 
957  update_session(session);
958 
960  trx = prebuilt->trx;
961 
962  /* Test and mark all the indexes to be dropped */
963 
964  row_mysql_lock_data_dictionary(trx);
965  ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
966 
967  /* Check that none of the indexes have previously been flagged
968  for deletion. */
969  {
970  const dict_index_t* index
971  = dict_table_get_first_index(prebuilt->table);
972  do {
973  ut_a(!index->to_be_dropped);
974  index = dict_table_get_next_index(index);
975  } while (index);
976  }
977 
978  for (n_key = 0; n_key < num_of_keys; n_key++) {
979  const KeyInfo* key;
980  dict_index_t* index;
981 
982  key = i_table->key_info + key_num[n_key];
984  prebuilt->table, key->name);
985 
986  if (!index) {
987  errmsg_printf(ERRMSG_LVL_ERROR, "InnoDB could not find key n:o %u "
988  "with name %s for table %s",
989  key_num[n_key],
990  key ? key->name : "NULL",
991  prebuilt->table->name);
992 
993  err = HA_ERR_KEY_NOT_FOUND;
994  goto func_exit;
995  }
996 
997  /* Refuse to drop the clustered index. It would be
998  better to automatically generate a clustered index,
999  but drizzled::alter_table() will call this method only
1000  after ha_innobase::add_index(). */
1001 
1002  if (dict_index_is_clust(index)) {
1003  my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
1004  err = -1;
1005  goto func_exit;
1006  }
1007 
1008  index->to_be_dropped = TRUE;
1009  }
1010 
1011  /* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined
1012  for a foreign key constraint because InnoDB requires that both
1013  tables contain indexes for the constraint. Such index can
1014  be dropped only if FOREIGN_KEY_CHECKS is set to 0.
1015  Note that CREATE INDEX id ON table does a CREATE INDEX and
1016  DROP INDEX, and we can ignore here foreign keys because a
1017  new index for the foreign key has already been created.
1018 
1019  We check for the foreign key constraints after marking the
1020  candidate indexes for deletion, because when we check for an
1021  equivalent foreign index we don't want to select an index that
1022  is later deleted. */
1023 
1024  if (trx->check_foreigns
1025  && session_sql_command(user_session) != SQLCOM_CREATE_INDEX) {
1026  dict_index_t* index;
1027 
1028  for (index = dict_table_get_first_index(prebuilt->table);
1029  index;
1030  index = dict_table_get_next_index(index)) {
1031  dict_foreign_t* foreign;
1032 
1033  if (!index->to_be_dropped) {
1034 
1035  continue;
1036  }
1037 
1038  /* Check if the index is referenced. */
1040  prebuilt->table, index);
1041 
1042  if (foreign) {
1043 index_needed:
1045  trx,
1046  "Index needed in foreign key "
1047  "constraint");
1048 
1049  trx->error_info = index;
1050 
1051  err = HA_ERR_DROP_INDEX_FK;
1052  break;
1053  } else {
1054  /* Check if this index references some
1055  other table */
1057  prebuilt->table, index);
1058 
1059  if (foreign) {
1060  ut_a(foreign->foreign_index == index);
1061 
1062  /* Search for an equivalent index that
1063  the foreign key constraint could use
1064  if this index were to be deleted. */
1066  foreign)) {
1067 
1068  goto index_needed;
1069  }
1070  }
1071  }
1072  }
1073  } else if (session_sql_command(user_session) == SQLCOM_CREATE_INDEX) {
1074  /* This is a drop of a foreign key constraint index that
1075  was created by MySQL when the constraint was added. MySQL
1076  does this when the user creates an index explicitly which
1077  can be used in place of the automatically generated index. */
1078 
1079  dict_index_t* index;
1080 
1081  for (index = dict_table_get_first_index(prebuilt->table);
1082  index;
1083  index = dict_table_get_next_index(index)) {
1084  dict_foreign_t* foreign;
1085 
1086  if (!index->to_be_dropped) {
1087 
1088  continue;
1089  }
1090 
1091  /* Check if this index references some other table */
1093  prebuilt->table, index);
1094 
1095  if (foreign == NULL) {
1096 
1097  continue;
1098  }
1099 
1100  ut_a(foreign->foreign_index == index);
1101 
1102  /* Search for an equivalent index that the
1103  foreign key constraint could use if this index
1104  were to be deleted. */
1105 
1106  if (!dict_foreign_find_equiv_index(foreign)) {
1108  trx,
1109  "Index needed in foreign key "
1110  "constraint");
1111 
1112  trx->error_info = foreign->foreign_index;
1113 
1114  err = HA_ERR_DROP_INDEX_FK;
1115  break;
1116  }
1117  }
1118  }
1119 
1120 func_exit:
1121  if (err) {
1122  /* Undo our changes since there was some sort of error. */
1123  dict_index_t* index
1124  = dict_table_get_first_index(prebuilt->table);
1125 
1126  do {
1127  index->to_be_dropped = FALSE;
1128  index = dict_table_get_next_index(index);
1129  } while (index);
1130  }
1131 
1132  ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1134 
1135  return(err);
1136 }
1137 
1138 /*******************************************************************/
1141 UNIV_INTERN
1142 int
1143 ha_innobase::final_drop_index(
1144 /*==========================*/
1145  Session *session,
1146  Table* )
1147 {
1148  dict_index_t* index;
1149  trx_t* trx;
1150  int err;
1151 
1152  if (srv_created_new_raw || srv_force_recovery) {
1153  return(HA_ERR_WRONG_COMMAND);
1154  }
1155 
1156  update_session(session);
1157 
1160 
1161  /* Create a background transaction for the operations on
1162  the data dictionary tables. */
1165 
1166  /* Flag this transaction as a dictionary operation, so that
1167  the data dictionary will be locked in crash recovery. */
1169 
1170  /* Lock the table exclusively, to ensure that no active
1171  transaction depends on an index that is being dropped. */
1175 
1176  row_mysql_lock_data_dictionary(trx);
1177  ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1178 
1179  if (UNIV_UNLIKELY(err)) {
1180 
1181  /* Unmark the indexes to be dropped. */
1182  for (index = dict_table_get_first_index(prebuilt->table);
1183  index; index = dict_table_get_next_index(index)) {
1184 
1185  index->to_be_dropped = FALSE;
1186  }
1187 
1188  goto func_exit;
1189  }
1190 
1191  /* Drop indexes marked to be dropped */
1192 
1193  index = dict_table_get_first_index(prebuilt->table);
1194 
1195  while (index) {
1196  dict_index_t* next_index;
1197 
1198  next_index = dict_table_get_next_index(index);
1199 
1200  if (index->to_be_dropped) {
1201 
1202  row_merge_drop_index(index, prebuilt->table, trx);
1203  }
1204 
1205  index = next_index;
1206  }
1207 
1208  /* Check that all flagged indexes were dropped. */
1209  for (index = dict_table_get_first_index(prebuilt->table);
1210  index; index = dict_table_get_next_index(index)) {
1211  ut_a(!index->to_be_dropped);
1212  }
1213 
1214  /* We will need to rebuild index translation table. Set
1215  valid index entry count in the translation table to zero */
1217 
1218 func_exit:
1219  ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE));
1220  trx_commit_for_mysql(trx);
1223 
1224  /* Flush the log to reduce probability that the .frm files and
1225  the InnoDB data dictionary get out-of-sync if the user runs
1226  with innodb_flush_log_at_trx_commit = 0 */
1227 
1229 
1230  trx_free_for_mysql(trx);
1231 
1232  /* Tell the InnoDB server that there might be work for
1233  utility threads: */
1234 
1236 
1237  return(err);
1238 }
1239 #endif
UNIV_INTERN void row_mysql_store_blob_ref(byte *dest, ulint col_len, const void *data, ulint len)
Definition: row0mysql.cc:196
#define UT_LIST_GET_LEN(BASE)
Definition: ut0lst.h:217
virtual uint32_t pack_length() const
Definition: field.cc:707
UNIV_INTERN void trx_free_for_mysql(trx_t *trx)
Definition: trx0trx.cc:342
UNIV_INTERN dict_index_t * dict_table_get_index_on_name_and_min_id(dict_table_t *table, const char *name)
Definition: dict0dict.cc:4909
const char * name
Definition: dict0mem.h:339
UNIV_INLINE void trx_start_if_not_started(trx_t *trx)
dict_table_t * table
Definition: row0mysql.h:592
UNIV_INLINE void trx_set_dict_operation(trx_t *trx, enum trx_dict_op op)
ulint n_active_thrs
Definition: trx0trx.h:619
UNIV_INTERN void innobase_rec_to_mysql(Table *table, const rec_t *rec, const dict_index_t *index, const ulint *offsets)
dict_field_t * fields
Definition: dict0mem.h:371
unsigned type
Definition: dict0mem.h:347
INNOBASE_SHARE * share
Definition: ha_innodb.h:89
table_id_t table_id
Definition: trx0trx.h:556
UNIV_INTERN dict_foreign_t * dict_table_get_referenced_constraint(dict_table_t *table, dict_index_t *index)
Definition: dict0dict.cc:2248
const dict_index_t * error_info
Definition: trx0trx.h:606
Session * user_session
Definition: ha_innodb.h:85
UNIV_INTERN void srv_active_wake_master_thread(void)
Definition: srv0srv.cc:2617
UNIV_INTERN void innobase_rec_reset(Table *table)
UNIV_INTERN int trx_general_rollback_for_mysql(trx_t *trx, trx_savept_t *savept)
Definition: trx0roll.cc:65
UNIV_INTERN ulint dict_index_get_nth_col_pos(const dict_index_t *index, ulint n)
Definition: dict0dict.cc:502
#define ut_d(EXPR)
Definition: ut0dbg.h:129
#define mem_heap_free(heap)
Definition: mem0mem.h:117
UNIV_INTERN ulint trx_commit_for_mysql(trx_t *trx)
Definition: trx0trx.cc:1596
UNIV_INLINE const dict_col_t * dict_index_get_nth_col(const dict_index_t *index, ulint pos)
unsigned n_user_defined_cols
Definition: dict0mem.h:353
static void innobase_col_to_mysql(const dict_col_t *col, const unsigned char *data, ulint len, Field *field)
UNIV_INTERN ulint row_merge_lock_table(trx_t *trx, dict_table_t *table, enum lock_mode mode)
Definition: row0merge.cc:1954
UNIV_INTERN ulint row_merge_drop_table(trx_t *trx, dict_table_t *table)
Definition: row0merge.cc:2614
#define DICT_UNIQUE
Definition: dict0mem.h:52
UNIV_INTERN ulint row_merge_rename_indexes(trx_t *trx, dict_table_t *table)
Definition: row0merge.cc:2364
dict_index_t * foreign_index
Definition: dict0mem.h:448
UNIV_INTERN char * mem_heap_strdup(mem_heap_t *heap, const char *str)
Definition: mem0mem.cc:107
UNIV_INTERN ulint get_innobase_type_from_mysql_type(ulint *unsigned_flag, const void *f)
Definition: ha_innodb.cc:4012
UNIV_INTERN void log_buffer_flush_to_disk(void)
Definition: log0log.cc:1603
UNIV_INTERN dict_table_t * row_merge_create_temporary_table(const char *table_name, const merge_index_def_t *index_def, const dict_table_t *table, trx_t *trx)
Definition: row0merge.cc:2311
UNIV_INTERN void trx_search_latch_release_if_reserved(trx_t *trx)
Definition: trx0trx.cc:244
UNIV_INTERN int convert_error_code_to_mysql(int error, ulint flags, Session *session)
Definition: ha_innodb.cc:1120
#define DICT_CLUSTERED
Definition: dict0mem.h:51
UNIV_INTERN ulint row_merge_build_indexes(trx_t *trx, dict_table_t *old_table, dict_table_t *new_table, dict_index_t **indexes, ulint n_indexes, TABLE *table)
Definition: row0merge.cc:2632
UNIV_INTERN void row_prebuilt_free(row_prebuilt_t *prebuilt, ibool dict_locked)
Definition: row0mysql.cc:712
unsigned to_be_dropped
Definition: dict0mem.h:365
unsigned prefix_len
Definition: dict0mem.h:322
table_id_t id
Definition: dict0mem.h:477
UNIV_INLINE ulint dict_index_is_clust(const dict_index_t *index) __attribute__((pure))
const char * name
Definition: dict0mem.h:321
UNIV_INTERN ulint row_merge_rename_tables(dict_table_t *old_table, dict_table_t *new_table, const char *tmp_name, trx_t *trx)
Definition: row0merge.cc:2415
#define ut_a(EXPR)
Definition: ut0dbg.h:105
UNIV_INLINE const dict_col_t * dict_field_get_col(const dict_field_t *field)
UNIV_INLINE void * mem_heap_alloc(mem_heap_t *heap, ulint n)
#define mem_heap_create(N)
Definition: mem0mem.h:97
dict_table_t * table
Definition: dict0mem.h:341
KeyInfo * key_info
Definition: table.h:141
merge_index_field_t * fields
Definition: row0merge.h:60
ulint n_mysql_handles_opened
Definition: dict0mem.h:527
UNIV_INTERN row_prebuilt_t * row_create_prebuilt(dict_table_t *table)
Definition: row0mysql.cc:650
row_prebuilt_t * prebuilt
Definition: ha_innodb.h:82
const char * field_name
Definition: row0merge.h:47
UNIV_INTERN dict_foreign_t * dict_table_get_foreign_constraint(dict_table_t *table, dict_index_t *index)
Definition: dict0dict.cc:2279
#define ut_ad(EXPR)
Definition: ut0dbg.h:127
UNIV_INTERN dict_index_t * row_merge_create_index(trx_t *trx, dict_table_t *table, const merge_index_def_t *index_def)
Definition: row0merge.cc:2547
UNIV_INLINE ulint dict_table_get_n_user_cols(const dict_table_t *table)
unsigned flags
Definition: dict0mem.h:489
UNIV_INTERN trx_t * innobase_trx_allocate(Session *session)
Definition: ha_innodb.cc:1638
innodb_idx_translate_t idx_trans_tbl
Definition: ha_innodb.h:56
UNIV_INTERN void trx_set_detailed_error(trx_t *trx, const char *msg)
Definition: trx0trx.cc:63
UNIV_INTERN void row_merge_drop_index(dict_index_t *index, dict_table_t *table, trx_t *trx)
Definition: row0merge.cc:2034
const char * name
Definition: row0merge.h:55
UNIV_INTERN dict_table_t * dict_table_get(const char *table_name, ibool inc_mysql_count)
Definition: dict0dict.cc:746
UNIV_INTERN dict_index_t * dict_foreign_find_equiv_index(dict_foreign_t *foreign)
Definition: dict0dict.cc:2472
const char * field_name
Definition: field.h:102
UNIV_INTERN byte * row_mysql_store_true_var_len(byte *dest, ulint len, ulint lenlen)
Definition: row0mysql.cc:143
unsigned mbminmaxlen
Definition: dict0mem.h:292
ulint error_state
Definition: trx0trx.h:601
UNIV_INTERN void update_session(Session *session)
Definition: ha_innodb.cc:1711
UNIV_INTERN void row_mysql_unlock_data_dictionary(trx_t *trx)
Definition: row0mysql.cc:1790
UNIV_INTERN void row_merge_drop_indexes(trx_t *trx, dict_table_t *table, dict_index_t **index, ulint num_created)
Definition: row0merge.cc:2092
#define TEMP_INDEX_PREFIX
Definition: ut0ut.h:51
UNIV_INTERN ibool row_table_got_default_clust_index(const dict_table_t *table)
Definition: row0mysql.cc:1719
unsigned mtype
Definition: dict0mem.h:272
unsigned char * ptr
Definition: field.h:71