1 /*****************************************************************************
2 
3 Copyright (c) 2005, 2013, Oracle and/or its affiliates. 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.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************//**
20 @file handler/handler0alter.cc
21 Smart ALTER TABLE
22 *******************************************************/
23 
24 #include <unireg.h>
25 #include <mysqld_error.h>
26 #include <sql_lex.h>                            // SQLCOM_CREATE_INDEX
27 #include <mysql/innodb_priv.h>
28 
29 extern "C" {
30 #include "log0log.h"
31 #include "row0merge.h"
32 #include "srv0srv.h"
33 #include "trx0trx.h"
34 #include "trx0roll.h"
35 #include "ha_prototypes.h"
36 #include "handler0alter.h"
37 }
38 
39 #include "ha_innodb.h"
40 
41 /*************************************************************//**
42 Copies an InnoDB column to a MySQL field.  This function is
43 adapted from row_sel_field_store_in_mysql_format(). */
44 static
45 void
innobase_col_to_mysql(const dict_col_t * col,const uchar * data,ulint len,Field * field)46 innobase_col_to_mysql(
47 /*==================*/
48 	const dict_col_t*	col,	/*!< in: InnoDB column */
49 	const uchar*		data,	/*!< in: InnoDB column data */
50 	ulint			len,	/*!< in: length of data, in bytes */
51 	Field*			field)	/*!< in/out: MySQL field */
52 {
53 	uchar*	ptr;
54 	uchar*	dest	= field->ptr;
55 	ulint	flen	= field->pack_length();
56 
57 	switch (col->mtype) {
58 	case DATA_INT:
59 		ut_ad(len == flen);
60 
61 		/* Convert integer data from Innobase to little-endian
62 		format, sign bit restored to normal */
63 
64 		for (ptr = dest + len; ptr != dest; ) {
65 			*--ptr = *data++;
66 		}
67 
68 		if (!(field->flags & UNSIGNED_FLAG)) {
69 			((byte*) dest)[len - 1] ^= 0x80;
70 		}
71 
72 		break;
73 
74 	case DATA_VARCHAR:
75 	case DATA_VARMYSQL:
76 	case DATA_BINARY:
77 		field->reset();
78 
79 		if (field->type() == MYSQL_TYPE_VARCHAR) {
80 			/* This is a >= 5.0.3 type true VARCHAR. Store the
81 			length of the data to the first byte or the first
82 			two bytes of dest. */
83 
84 			dest = row_mysql_store_true_var_len(
85 				dest, len, flen - field->key_length());
86 		}
87 
88 		/* Copy the actual data */
89 		memcpy(dest, data, len);
90 		break;
91 
92 	case DATA_BLOB:
93 		/* Store a pointer to the BLOB buffer to dest: the BLOB was
94 		already copied to the buffer in row_sel_store_mysql_rec */
95 
96 		row_mysql_store_blob_ref(dest, flen, data, len);
97 		break;
98 
99 #ifdef UNIV_DEBUG
100 	case DATA_MYSQL:
101 		ut_ad(flen >= len);
102 		ut_ad(DATA_MBMAXLEN(col->mbminmaxlen)
103 		      >= DATA_MBMINLEN(col->mbminmaxlen));
104 		memcpy(dest, data, len);
105 		break;
106 
107 	default:
108 	case DATA_SYS_CHILD:
109 	case DATA_SYS:
110 		/* These column types should never be shipped to MySQL. */
111 		ut_ad(0);
112 
113 	case DATA_FLOAT:
114 	case DATA_DOUBLE:
115 	case DATA_DECIMAL:
116 		/* Above are the valid column types for MySQL data. */
117 		ut_ad(flen == len);
118 		/* fall through */
119 	case DATA_FIXBINARY:
120 	case DATA_CHAR:
121 		/* We may have flen > len when there is a shorter
122 		prefix on the CHAR and BINARY column. */
123 		ut_ad(flen >= len);
124 #else /* UNIV_DEBUG */
125 	default:
126 #endif /* UNIV_DEBUG */
127 		memcpy(dest, data, len);
128 	}
129 }
130 
131 /*************************************************************//**
132 Copies an InnoDB record to table->record[0]. */
133 extern "C" UNIV_INTERN
134 void
innobase_rec_to_mysql(TABLE * table,const rec_t * rec,const dict_index_t * index,const ulint * offsets)135 innobase_rec_to_mysql(
136 /*==================*/
137 	TABLE*			table,		/*!< in/out: MySQL table */
138 	const rec_t*		rec,		/*!< in: record */
139 	const dict_index_t*	index,		/*!< in: index */
140 	const ulint*		offsets)	/*!< in: rec_get_offsets(
141 						rec, index, ...) */
142 {
143 	uint	n_fields	= table->s->fields;
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->field[i];
150 		ulint		ipos;
151 		ulint		ilen;
152 		const uchar*	ifield;
153 
154 		field->reset();
155 
156 		ipos = dict_index_get_nth_col_or_prefix_pos(index, i, TRUE);
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 
174 		innobase_col_to_mysql(
175 			dict_field_get_col(
176 				dict_index_get_nth_field(index, ipos)),
177 			ifield, ilen, field);
178 	}
179 }
180 
181 /*************************************************************//**
182 Resets table->record[0]. */
183 extern "C" UNIV_INTERN
184 void
innobase_rec_reset(TABLE * table)185 innobase_rec_reset(
186 /*===============*/
187 	TABLE*			table)		/*!< in/out: MySQL table */
188 {
189 	uint	n_fields	= table->s->fields;
190 	uint	i;
191 
192 	for (i = 0; i < n_fields; i++) {
193 		table->field[i]->set_default();
194 	}
195 }
196 
197 /******************************************************************//**
198 Removes the filename encoding of a database and table name. */
199 static
200 void
innobase_convert_tablename(char * s)201 innobase_convert_tablename(
202 /*=======================*/
203 	char*	s)	/*!< in: identifier; out: decoded identifier */
204 {
205 	uint	errors;
206 
207 	char*	slash = strchr(s, '/');
208 
209 	if (slash) {
210 		char*	t;
211 		/* Temporarily replace the '/' with NUL. */
212 		*slash = 0;
213 		/* Convert the database name. */
214 		strconvert(&my_charset_filename, s, system_charset_info,
215 			   s, slash - s + 1, &errors);
216 
217 		t = s + strlen(s);
218 		ut_ad(slash >= t);
219 		/* Append a  '.' after the database name. */
220 		*t++ = '.';
221 		slash++;
222 		/* Convert the table name. */
223 		strconvert(&my_charset_filename, slash, system_charset_info,
224 			   t, slash - t + strlen(slash), &errors);
225 	} else {
226 		strconvert(&my_charset_filename, s,
227 			   system_charset_info, s, strlen(s), &errors);
228 	}
229 }
230 
231 /*******************************************************************//**
232 This function checks that index keys are sensible.
233 @return	0 or error number */
234 static
235 int
innobase_check_index_keys(const KEY * key_info,ulint num_of_keys,const dict_table_t * table)236 innobase_check_index_keys(
237 /*======================*/
238 	const KEY*		key_info,	/*!< in: Indexes to be
239 						created */
240 	ulint			num_of_keys,	/*!< in: Number of
241 						indexes to be created */
242 	const dict_table_t*	table)		/*!< in: Existing indexes */
243 {
244 	ulint		key_num;
245 
246 	ut_ad(key_info);
247 	ut_ad(num_of_keys);
248 
249 	for (key_num = 0; key_num < num_of_keys; key_num++) {
250 		const KEY&	key = key_info[key_num];
251 
252 		/* Check that the same index name does not appear
253 		twice in indexes to be created. */
254 
255 		for (ulint i = 0; i < key_num; i++) {
256 			const KEY&	key2 = key_info[i];
257 
258 			if (0 == strcmp(key.name, key2.name)) {
259 				my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
260 					 key.name);
261 
262 				return(ER_WRONG_NAME_FOR_INDEX);
263 			}
264 		}
265 
266 		/* Check that the same index name does not already exist. */
267 
268 		for (const dict_index_t* index
269 			     = dict_table_get_first_index(table);
270 		     index; index = dict_table_get_next_index(index)) {
271 
272 			if (0 == strcmp(key.name, index->name)) {
273 				my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),
274 					 key.name);
275 
276 				return(ER_WRONG_NAME_FOR_INDEX);
277 			}
278 		}
279 
280 		/* Check that MySQL does not try to create a column
281 		prefix index field on an inappropriate data type and
282 		that the same column does not appear twice in the index. */
283 
284 		for (ulint i = 0; i < key.key_parts; i++) {
285 			const KEY_PART_INFO&	key_part1
286 				= key.key_part[i];
287 			const Field*		field
288 				= key_part1.field;
289 			ibool			is_unsigned;
290 
291 			switch (get_innobase_type_from_mysql_type(
292 					&is_unsigned, field)) {
293 			default:
294 				break;
295 			case DATA_INT:
296 			case DATA_FLOAT:
297 			case DATA_DOUBLE:
298 			case DATA_DECIMAL:
299 				if (field->type() == MYSQL_TYPE_VARCHAR) {
300 					if (key_part1.length
301 					    >= field->pack_length()
302 					    - ((Field_varstring*) field)
303 					    ->length_bytes) {
304 						break;
305 					}
306 				} else {
307 					if (key_part1.length
308 					    >= field->pack_length()) {
309 						break;
310 					}
311 				}
312 
313 				my_error(ER_WRONG_KEY_COLUMN, MYF(0),
314 					 field->field_name);
315 				return(ER_WRONG_KEY_COLUMN);
316 			}
317 
318 			for (ulint j = 0; j < i; j++) {
319 				const KEY_PART_INFO&	key_part2
320 					= key.key_part[j];
321 
322 				if (strcmp(key_part1.field->field_name,
323 					   key_part2.field->field_name)) {
324 					continue;
325 				}
326 
327 				my_error(ER_WRONG_KEY_COLUMN, MYF(0),
328 					 key_part1.field->field_name);
329 				return(ER_WRONG_KEY_COLUMN);
330 			}
331 		}
332 	}
333 
334 	return(0);
335 }
336 
337 /*******************************************************************//**
338 Create index field definition for key part */
339 static
340 void
innobase_create_index_field_def(KEY_PART_INFO * key_part,mem_heap_t * heap,merge_index_field_t * index_field)341 innobase_create_index_field_def(
342 /*============================*/
343 	KEY_PART_INFO*		key_part,	/*!< in: MySQL key definition */
344 	mem_heap_t*		heap,		/*!< in: memory heap */
345 	merge_index_field_t*	index_field)	/*!< out: index field
346 						definition for key_part */
347 {
348 	Field*		field;
349 	ibool		is_unsigned;
350 	ulint		col_type;
351 
352 	DBUG_ENTER("innobase_create_index_field_def");
353 
354 	ut_ad(key_part);
355 	ut_ad(index_field);
356 
357 	field = key_part->field;
358 	ut_a(field);
359 
360 	col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
361 
362 	if (DATA_BLOB == col_type
363 	    || (key_part->length < field->pack_length()
364 		&& field->type() != MYSQL_TYPE_VARCHAR)
365 	    || (field->type() == MYSQL_TYPE_VARCHAR
366 		&& key_part->length < field->pack_length()
367 			- ((Field_varstring*)field)->length_bytes)) {
368 
369 		index_field->prefix_len = key_part->length;
370 	} else {
371 		index_field->prefix_len = 0;
372 	}
373 
374 	index_field->field_name = mem_heap_strdup(heap, field->field_name);
375 
376 	DBUG_VOID_RETURN;
377 }
378 
379 /*******************************************************************//**
380 Create index definition for key */
381 static
382 void
innobase_create_index_def(KEY * key,bool new_primary,bool key_primary,merge_index_def_t * index,mem_heap_t * heap)383 innobase_create_index_def(
384 /*======================*/
385 	KEY*			key,		/*!< in: key definition */
386 	bool			new_primary,	/*!< in: TRUE=generating
387 						a new primary key
388 						on the table */
389 	bool			key_primary,	/*!< in: TRUE if this key
390 						is a primary key */
391 	merge_index_def_t*	index,		/*!< out: index definition */
392 	mem_heap_t*		heap)		/*!< in: heap where memory
393 						is allocated */
394 {
395 	ulint	i;
396 	ulint	len;
397 	ulint	n_fields = key->key_parts;
398 	char*	index_name;
399 
400 	DBUG_ENTER("innobase_create_index_def");
401 
402 	index->fields = (merge_index_field_t*) mem_heap_alloc(
403 		heap, n_fields * sizeof *index->fields);
404 
405 	index->ind_type = 0;
406 	index->n_fields = n_fields;
407 	len = strlen(key->name) + 1;
408 	index->name = index_name = (char*) mem_heap_alloc(heap,
409 							  len + !new_primary);
410 
411 	if (UNIV_LIKELY(!new_primary)) {
412 		*index_name++ = TEMP_INDEX_PREFIX;
413 	}
414 
415 	memcpy(index_name, key->name, len);
416 
417 	if (key->flags & HA_NOSAME) {
418 		index->ind_type |= DICT_UNIQUE;
419 	}
420 
421 	if (key_primary) {
422 		index->ind_type |= DICT_CLUSTERED;
423 	}
424 
425 	for (i = 0; i < n_fields; i++) {
426 		innobase_create_index_field_def(&key->key_part[i], heap,
427 						&index->fields[i]);
428 	}
429 
430 	DBUG_VOID_RETURN;
431 }
432 
433 /*******************************************************************//**
434 Copy index field definition */
435 static
436 void
innobase_copy_index_field_def(const dict_field_t * field,merge_index_field_t * index_field)437 innobase_copy_index_field_def(
438 /*==========================*/
439 	const dict_field_t*	field,		/*!< in: definition to copy */
440 	merge_index_field_t*	index_field)	/*!< out: copied definition */
441 {
442 	DBUG_ENTER("innobase_copy_index_field_def");
443 	DBUG_ASSERT(field != NULL);
444 	DBUG_ASSERT(index_field != NULL);
445 
446 	index_field->field_name = field->name;
447 	index_field->prefix_len = field->prefix_len;
448 
449 	DBUG_VOID_RETURN;
450 }
451 
452 /*******************************************************************//**
453 Copy index definition for the index */
454 static
455 void
innobase_copy_index_def(const dict_index_t * index,merge_index_def_t * new_index,mem_heap_t * heap)456 innobase_copy_index_def(
457 /*====================*/
458 	const dict_index_t*	index,	/*!< in: index definition to copy */
459 	merge_index_def_t*	new_index,/*!< out: Index definition */
460 	mem_heap_t*		heap)	/*!< in: heap where allocated */
461 {
462 	ulint	n_fields;
463 	ulint	i;
464 
465 	DBUG_ENTER("innobase_copy_index_def");
466 
467 	/* Note that we take only those fields that user defined to be
468 	in the index.  In the internal representation more colums were
469 	added and those colums are not copied .*/
470 
471 	n_fields = index->n_user_defined_cols;
472 
473 	new_index->fields = (merge_index_field_t*) mem_heap_alloc(
474 		heap, n_fields * sizeof *new_index->fields);
475 
476 	/* When adding a PRIMARY KEY, we may convert a previous
477 	clustered index to a secondary index (UNIQUE NOT NULL). */
478 	new_index->ind_type = index->type & ~DICT_CLUSTERED;
479 	new_index->n_fields = n_fields;
480 	new_index->name = index->name;
481 
482 	for (i = 0; i < n_fields; i++) {
483 		innobase_copy_index_field_def(&index->fields[i],
484 					      &new_index->fields[i]);
485 	}
486 
487 	DBUG_VOID_RETURN;
488 }
489 
490 /*******************************************************************//**
491 Create an index table where indexes are ordered as follows:
492 
493 IF a new primary key is defined for the table THEN
494 
495 	1) New primary key
496 	2) Original secondary indexes
497 	3) New secondary indexes
498 
499 ELSE
500 
501 	1) All new indexes in the order they arrive from MySQL
502 
503 ENDIF
504 
505 
506 @return	key definitions or NULL */
507 static
508 merge_index_def_t*
innobase_create_key_def(trx_t * trx,const dict_table_t * table,mem_heap_t * heap,KEY * key_info,ulint & n_keys)509 innobase_create_key_def(
510 /*====================*/
511 	trx_t*		trx,		/*!< in: trx */
512 	const dict_table_t*table,		/*!< in: table definition */
513 	mem_heap_t*	heap,		/*!< in: heap where space for key
514 					definitions are allocated */
515 	KEY*		key_info,	/*!< in: Indexes to be created */
516 	ulint&		n_keys)		/*!< in/out: Number of indexes to
517 					be created */
518 {
519 	ulint			i = 0;
520 	merge_index_def_t*	indexdef;
521 	merge_index_def_t*	indexdefs;
522 	bool			new_primary;
523 
524 	DBUG_ENTER("innobase_create_key_def");
525 
526 	indexdef = indexdefs = (merge_index_def_t*)
527 		mem_heap_alloc(heap, sizeof *indexdef
528 			       * (n_keys + UT_LIST_GET_LEN(table->indexes)));
529 
530 	/* If there is a primary key, it is always the first index
531 	defined for the table. */
532 
533 	new_primary = !my_strcasecmp(system_charset_info,
534 				     key_info->name, "PRIMARY");
535 
536 	/* If there is a UNIQUE INDEX consisting entirely of NOT NULL
537 	columns and if the index does not contain column prefix(es)
538 	(only prefix/part of the column is indexed), MySQL will treat the
539 	index as a PRIMARY KEY unless the table already has one. */
540 
541 	if (!new_primary && (key_info->flags & HA_NOSAME)
542 	    && (!(key_info->flags & HA_KEY_HAS_PART_KEY_SEG))
543 	    && row_table_got_default_clust_index(table)) {
544 		uint	key_part = key_info->key_parts;
545 
546 		new_primary = TRUE;
547 
548 		while (key_part--) {
549 			if (key_info->key_part[key_part].key_type
550 			    & FIELDFLAG_MAYBE_NULL) {
551 				new_primary = FALSE;
552 				break;
553 			}
554 		}
555 	}
556 
557 	if (new_primary) {
558 		const dict_index_t*	index;
559 
560 		/* Create the PRIMARY key index definition */
561 		innobase_create_index_def(&key_info[i++], TRUE, TRUE,
562 					  indexdef++, heap);
563 
564 		row_mysql_lock_data_dictionary(trx);
565 
566 		index = dict_table_get_first_index(table);
567 
568 		/* Copy the index definitions of the old table.  Skip
569 		the old clustered index if it is a generated clustered
570 		index or a PRIMARY KEY.  If the clustered index is a
571 		UNIQUE INDEX, it must be converted to a secondary index. */
572 
573 		if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
574 		    || !my_strcasecmp(system_charset_info,
575 				      index->name, "PRIMARY")) {
576 			index = dict_table_get_next_index(index);
577 		}
578 
579 		while (index) {
580 			innobase_copy_index_def(index, indexdef++, heap);
581 			index = dict_table_get_next_index(index);
582 		}
583 
584 		row_mysql_unlock_data_dictionary(trx);
585 	}
586 
587 	/* Create definitions for added secondary indexes. */
588 
589 	while (i < n_keys) {
590 		innobase_create_index_def(&key_info[i++], new_primary, FALSE,
591 					  indexdef++, heap);
592 	}
593 
594 	n_keys = indexdef - indexdefs;
595 
596 	DBUG_RETURN(indexdefs);
597 }
598 
599 /*******************************************************************//**
600 Check each index column size, make sure they do not exceed the max limit
601 @return	HA_ERR_INDEX_COL_TOO_LONG if index column size exceeds limit */
602 static
603 int
innobase_check_column_length(const dict_table_t * table,const KEY * key_info)604 innobase_check_column_length(
605 /*=========================*/
606 	const dict_table_t*table,	/*!< in: table definition */
607 	const KEY*	key_info)	/*!< in: Indexes to be created */
608 {
609 	ulint	max_col_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
610 
611 	for (ulint key_part = 0; key_part < key_info->key_parts; key_part++) {
612 		if (key_info->key_part[key_part].length > max_col_len) {
613 			my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0), max_col_len);
614 			return(HA_ERR_INDEX_COL_TOO_LONG);
615 		}
616 	}
617 	return(0);
618 }
619 
620 /*******************************************************************//**
621 Create a temporary tablename using query id, thread id, and id
622 @return	temporary tablename */
623 static
624 char*
innobase_create_temporary_tablename(mem_heap_t * heap,char id,const char * table_name)625 innobase_create_temporary_tablename(
626 /*================================*/
627 	mem_heap_t*	heap,		/*!< in: memory heap */
628 	char		id,		/*!< in: identifier [0-9a-zA-Z] */
629 	const char*     table_name)	/*!< in: table name */
630 {
631 	char*			name;
632 	ulint			len;
633 	static const char	suffix[] = "@0023 "; /* "# " */
634 
635 	len = strlen(table_name);
636 
637 	name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
638 	memcpy(name, table_name, len);
639 	memcpy(name + len, suffix, sizeof suffix);
640 	name[len + (sizeof suffix - 2)] = id;
641 
642 	return(name);
643 }
644 
645 class ha_innobase_add_index : public handler_add_index
646 {
647 public:
648 	/** table where the indexes are being created */
649 	dict_table_t* indexed_table;
ha_innobase_add_index(TABLE * table,KEY * key_info,uint num_of_keys,dict_table_t * indexed_table_arg)650 	ha_innobase_add_index(TABLE* table, KEY* key_info, uint num_of_keys,
651 			      dict_table_t* indexed_table_arg) :
652 		handler_add_index(table, key_info, num_of_keys),
653 		indexed_table (indexed_table_arg) {}
~ha_innobase_add_index()654 	~ha_innobase_add_index() {}
655 };
656 
657 /*******************************************************************//**
658 Create indexes.
659 @return	0 or error number */
660 UNIV_INTERN
661 int
add_index(TABLE * table,KEY * key_info,uint num_of_keys,handler_add_index ** add)662 ha_innobase::add_index(
663 /*===================*/
664 	TABLE*			table,		/*!< in: Table where indexes
665 						are created */
666 	KEY*			key_info,	/*!< in: Indexes
667 						to be created */
668 	uint			num_of_keys,	/*!< in: Number of indexes
669 						to be created */
670 	handler_add_index**	add)		/*!< out: context */
671 {
672 	dict_index_t**	index;		/*!< Index to be created */
673 	dict_table_t*	indexed_table;	/*!< Table where indexes are created */
674 	merge_index_def_t* index_defs;	/*!< Index definitions */
675 	mem_heap_t*     heap;		/*!< Heap for index definitions */
676 	trx_t*		trx;		/*!< Transaction */
677 	ulint		num_of_idx;
678 	ulint		num_created	= 0;
679 	ibool		dict_locked	= FALSE;
680 	ulint		new_primary;
681 	int		error;
682 
683 	DBUG_ENTER("ha_innobase::add_index");
684 	ut_a(table);
685 	ut_a(key_info);
686 	ut_a(num_of_keys);
687 
688 	*add = NULL;
689 
690 	if (srv_created_new_raw || srv_force_recovery) {
691 		DBUG_RETURN(HA_ERR_WRONG_COMMAND);
692 	}
693 
694 	update_thd();
695 
696 	/* In case MySQL calls this in the middle of a SELECT query, release
697 	possible adaptive hash latch to avoid deadlocks of threads. */
698 	trx_search_latch_release_if_reserved(prebuilt->trx);
699 
700 	/* Check if the index name is reserved. */
701 	if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) {
702 		DBUG_RETURN(-1);
703 	}
704 
705 	indexed_table = dict_table_get(prebuilt->table->name, FALSE,
706 				       DICT_ERR_IGNORE_NONE);
707 
708 	if (UNIV_UNLIKELY(!indexed_table)) {
709 		DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
710 	}
711 
712 	ut_a(indexed_table == prebuilt->table);
713 
714 	if (indexed_table->tablespace_discarded) {
715 		DBUG_RETURN(-1);
716 	}
717 
718 	/* Check that index keys are sensible */
719 	error = innobase_check_index_keys(key_info, num_of_keys, prebuilt->table);
720 
721 	if (UNIV_UNLIKELY(error)) {
722 		DBUG_RETURN(error);
723 	}
724 
725 	/* Check each index's column length to make sure they do not
726 	exceed limit */
727 	for (ulint i = 0; i < num_of_keys; i++) {
728 		error = innobase_check_column_length(prebuilt->table,
729 						     &key_info[i]);
730 
731 		if (error) {
732 			DBUG_RETURN(error);
733 		}
734 	}
735 
736 	heap = mem_heap_create(1024);
737 	trx_start_if_not_started(prebuilt->trx);
738 
739 	/* Create a background transaction for the operations on
740 	the data dictionary tables. */
741 	trx = innobase_trx_allocate(user_thd);
742 	trx_start_if_not_started(trx);
743 
744 	/* Create table containing all indexes to be built in this
745 	alter table add index so that they are in the correct order
746 	in the table. */
747 
748 	num_of_idx = num_of_keys;
749 
750 	index_defs = innobase_create_key_def(
751 		trx, prebuilt->table, heap, key_info, num_of_idx);
752 
753 	new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
754 
755 	/* Allocate memory for dictionary index definitions */
756 
757 	index = (dict_index_t**) mem_heap_alloc(
758 		heap, num_of_idx * sizeof *index);
759 
760 	/* Flag this transaction as a dictionary operation, so that
761 	the data dictionary will be locked in crash recovery. */
762 	trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
763 
764 	/* Acquire a lock on the table before creating any indexes. */
765 	error = row_merge_lock_table(prebuilt->trx, prebuilt->table,
766 				     new_primary ? LOCK_X : LOCK_S);
767 
768 	if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
769 
770 		goto error_handling;
771 	}
772 
773 	/* Latch the InnoDB data dictionary exclusively so that no deadlocks
774 	or lock waits can happen in it during an index create operation. */
775 
776 	row_mysql_lock_data_dictionary(trx);
777 	dict_locked = TRUE;
778 
779 	ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
780 
781 	/* If a new primary key is defined for the table we need
782 	to drop the original table and rebuild all indexes. */
783 
784 	if (UNIV_UNLIKELY(new_primary)) {
785 		/* This transaction should be the only one
786 		operating on the table. */
787 		ut_a(prebuilt->table->n_mysql_handles_opened == 1);
788 
789 		char*	new_table_name = innobase_create_temporary_tablename(
790 			heap, '1', prebuilt->table->name);
791 
792 		/* Clone the table. */
793 		trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
794 		indexed_table = row_merge_create_temporary_table(
795 			new_table_name, index_defs, prebuilt->table, trx);
796 
797 		if (!indexed_table) {
798 
799 			switch (trx->error_state) {
800 			case DB_TABLESPACE_ALREADY_EXISTS:
801 			case DB_DUPLICATE_KEY:
802 				innobase_convert_tablename(new_table_name);
803 				my_error(HA_ERR_TABLE_EXIST, MYF(0),
804 					 new_table_name);
805 				error = HA_ERR_TABLE_EXIST;
806 				break;
807 			default:
808 				error = convert_error_code_to_mysql(
809 					trx->error_state,
810 					prebuilt->table->flags,
811 					user_thd);
812 			}
813 
814 			ut_d(dict_table_check_for_dup_indexes(prebuilt->table,
815 							      TRUE));
816 			mem_heap_free(heap);
817 			trx_general_rollback_for_mysql(trx, NULL);
818 			row_mysql_unlock_data_dictionary(trx);
819 			trx_free_for_mysql(trx);
820 			trx_commit_for_mysql(prebuilt->trx);
821 			DBUG_RETURN(error);
822 		}
823 
824 		trx->table_id = indexed_table->id;
825 	}
826 
827 	/* Create the indexes in SYS_INDEXES and load into dictionary. */
828 
829 	for (num_created = 0; num_created < num_of_idx; num_created++) {
830 
831 		index[num_created] = row_merge_create_index(
832 			trx, indexed_table, &index_defs[num_created]);
833 
834 		if (!index[num_created]) {
835 			error = trx->error_state;
836 			goto error_handling;
837 		}
838 	}
839 
840 	ut_ad(error == DB_SUCCESS);
841 
842 	/* Commit the data dictionary transaction in order to release
843 	the table locks on the system tables.  This means that if
844 	MySQL crashes while creating a new primary key inside
845 	row_merge_build_indexes(), indexed_table will not be dropped
846 	by trx_rollback_active().  It will have to be recovered or
847 	dropped by the database administrator. */
848 	trx_commit_for_mysql(trx);
849 
850 	row_mysql_unlock_data_dictionary(trx);
851 	dict_locked = FALSE;
852 
853 	ut_a(trx->n_active_thrs == 0);
854 	ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
855 
856 	if (UNIV_UNLIKELY(new_primary)) {
857 		/* A primary key is to be built.  Acquire an exclusive
858 		table lock also on the table that is being created. */
859 		ut_ad(indexed_table != prebuilt->table);
860 
861 		error = row_merge_lock_table(prebuilt->trx, indexed_table,
862 					     LOCK_X);
863 
864 		if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
865 
866 			goto error_handling;
867 		}
868 	}
869 
870 	/* Read the clustered index of the table and build indexes
871 	based on this information using temporary files and merge sort. */
872 	error = row_merge_build_indexes(prebuilt->trx,
873 					prebuilt->table, indexed_table,
874 					index, num_of_idx, table);
875 
876 error_handling:
877 	/* After an error, remove all those index definitions from the
878 	dictionary which were defined. */
879 
880 	switch (error) {
881 	case DB_SUCCESS:
882 		ut_a(!dict_locked);
883 
884 		ut_d(mutex_enter(&dict_sys->mutex));
885 		ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
886 		ut_d(mutex_exit(&dict_sys->mutex));
887                 *add = new ha_innobase_add_index(table, key_info, num_of_keys,
888                                                  indexed_table);
889 		break;
890 
891 	case DB_TOO_BIG_RECORD:
892 		my_error(HA_ERR_TO_BIG_ROW, MYF(0));
893 		goto error;
894 	case DB_PRIMARY_KEY_IS_NULL:
895 		my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
896 		/* fall through */
897 	case DB_DUPLICATE_KEY:
898 error:
899 		prebuilt->trx->error_info = NULL;
900 		/* fall through */
901 	default:
902 		trx->error_state = DB_SUCCESS;
903 
904 		if (new_primary) {
905 			if (indexed_table != prebuilt->table) {
906 				row_merge_drop_table(trx, indexed_table);
907 			}
908 		} else {
909 			if (!dict_locked) {
910 				row_mysql_lock_data_dictionary(trx);
911 				dict_locked = TRUE;
912 			}
913 
914 			row_merge_drop_indexes(trx, indexed_table,
915 					       index, num_created);
916 		}
917 	}
918 
919 	trx_commit_for_mysql(trx);
920 	if (prebuilt->trx) {
921 		trx_commit_for_mysql(prebuilt->trx);
922 	}
923 
924 	if (dict_locked) {
925 		row_mysql_unlock_data_dictionary(trx);
926 	}
927 
928 	trx_free_for_mysql(trx);
929 	mem_heap_free(heap);
930 
931 	/* There might be work for utility threads.*/
932 	srv_active_wake_master_thread();
933 
934 	DBUG_RETURN(convert_error_code_to_mysql(error, prebuilt->table->flags,
935 						user_thd));
936 }
937 
938 /*******************************************************************//**
939 Finalize or undo add_index().
940 @return	0 or error number */
941 UNIV_INTERN
942 int
final_add_index(handler_add_index * add_arg,bool commit)943 ha_innobase::final_add_index(
944 /*=========================*/
945 	handler_add_index*	add_arg,/*!< in: context from add_index() */
946 	bool			commit)	/*!< in: true=commit, false=rollback */
947 {
948 	ha_innobase_add_index*	add;
949 	trx_t*			trx;
950 	int			err	= 0;
951 
952 	DBUG_ENTER("ha_innobase::final_add_index");
953 
954 	ut_ad(add_arg);
955 	add = static_cast<class ha_innobase_add_index*>(add_arg);
956 
957 	/* Create a background transaction for the operations on
958 	the data dictionary tables. */
959 	trx = innobase_trx_allocate(user_thd);
960 	trx_start_if_not_started(trx);
961 
962 	/* Flag this transaction as a dictionary operation, so that
963 	the data dictionary will be locked in crash recovery. */
964 	trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
965 
966 	/* Latch the InnoDB data dictionary exclusively so that no deadlocks
967 	or lock waits can happen in it during an index create operation. */
968 	row_mysql_lock_data_dictionary(trx);
969 
970 	if (add->indexed_table != prebuilt->table) {
971 		ulint	error;
972 
973 		/* We copied the table (new_primary). */
974 		if (commit) {
975 			mem_heap_t*	heap;
976 			char*		tmp_name;
977 
978 			heap = mem_heap_create(1024);
979 
980 			/* A new primary key was defined for the table
981 			and there was no error at this point. We can
982 			now rename the old table as a temporary table,
983 			rename the new temporary table as the old
984 			table and drop the old table. */
985 			tmp_name = innobase_create_temporary_tablename(
986 				heap, '2', prebuilt->table->name);
987 
988 			error = row_merge_rename_tables(
989 				prebuilt->table, add->indexed_table,
990 				tmp_name, trx);
991 
992 			switch (error) {
993 			case DB_TABLESPACE_ALREADY_EXISTS:
994 			case DB_DUPLICATE_KEY:
995 				innobase_convert_tablename(tmp_name);
996 				my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
997 				err = HA_ERR_TABLE_EXIST;
998 				break;
999 			default:
1000 				err = convert_error_code_to_mysql(
1001 					error, prebuilt->table->flags,
1002 					user_thd);
1003 				break;
1004 			}
1005 
1006 			mem_heap_free(heap);
1007 		}
1008 
1009 		if (!commit || err) {
1010 			error = row_merge_drop_table(trx, add->indexed_table);
1011 			trx_commit_for_mysql(prebuilt->trx);
1012 		} else {
1013 			dict_table_t*	old_table = prebuilt->table;
1014 			trx_commit_for_mysql(prebuilt->trx);
1015 			row_prebuilt_free(prebuilt, TRUE);
1016 			error = row_merge_drop_table(trx, old_table);
1017 			add->indexed_table->n_mysql_handles_opened++;
1018 			prebuilt = row_create_prebuilt(add->indexed_table,
1019 				0 /* XXX Do we know the mysql_row_len here?
1020 				Before the addition of this parameter to
1021 				row_create_prebuilt() the mysql_row_len
1022 				member was left 0 (from zalloc) in the
1023 				prebuilt object. */);
1024 		}
1025 
1026 		err = convert_error_code_to_mysql(
1027 			error, prebuilt->table->flags, user_thd);
1028 	} else {
1029 		/* We created secondary indexes (!new_primary). */
1030 
1031 		if (commit) {
1032 			err = convert_error_code_to_mysql(
1033 				row_merge_rename_indexes(trx, prebuilt->table),
1034 				prebuilt->table->flags, user_thd);
1035 		}
1036 
1037 		if (!commit || err) {
1038 			dict_index_t*	index;
1039 			dict_index_t*	next_index;
1040 
1041 			for (index = dict_table_get_first_index(
1042 				     prebuilt->table);
1043 			     index; index = next_index) {
1044 
1045 				next_index = dict_table_get_next_index(index);
1046 
1047 				if (*index->name == TEMP_INDEX_PREFIX) {
1048 					row_merge_drop_index(
1049 						index, prebuilt->table, trx);
1050 				}
1051 			}
1052 		}
1053 	}
1054 
1055 	/* If index is successfully built, we will need to rebuild index
1056 	translation table. Set valid index entry count in the translation
1057 	table to zero. */
1058 	if (err == 0 && commit) {
1059 		share->idx_trans_tbl.index_count = 0;
1060 	}
1061 
1062 	trx_commit_for_mysql(trx);
1063 	if (prebuilt->trx) {
1064 		trx_commit_for_mysql(prebuilt->trx);
1065 	}
1066 
1067 	ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
1068 	row_mysql_unlock_data_dictionary(trx);
1069 
1070 	trx_free_for_mysql(trx);
1071 
1072 	/* There might be work for utility threads.*/
1073 	srv_active_wake_master_thread();
1074 
1075 	delete add;
1076 	DBUG_RETURN(err);
1077 }
1078 
1079 /*******************************************************************//**
1080 Prepare to drop some indexes of a table.
1081 @return	0 or error number */
1082 UNIV_INTERN
1083 int
prepare_drop_index(TABLE * table,uint * key_num,uint num_of_keys)1084 ha_innobase::prepare_drop_index(
1085 /*============================*/
1086 	TABLE*	table,		/*!< in: Table where indexes are dropped */
1087 	uint*	key_num,	/*!< in: Key nums to be dropped */
1088 	uint	num_of_keys)	/*!< in: Number of keys to be dropped */
1089 {
1090 	trx_t*		trx;
1091 	int		err = 0;
1092 	uint 		n_key;
1093 
1094 	DBUG_ENTER("ha_innobase::prepare_drop_index");
1095 	ut_ad(table);
1096 	ut_ad(key_num);
1097 	ut_ad(num_of_keys);
1098 	if (srv_created_new_raw || srv_force_recovery) {
1099 		DBUG_RETURN(HA_ERR_WRONG_COMMAND);
1100 	}
1101 
1102 	update_thd();
1103 
1104 	trx_search_latch_release_if_reserved(prebuilt->trx);
1105 	trx = prebuilt->trx;
1106 
1107 	/* Test and mark all the indexes to be dropped */
1108 
1109 	row_mysql_lock_data_dictionary(trx);
1110 	ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
1111 
1112 	/* Check that none of the indexes have previously been flagged
1113 	for deletion. */
1114 	{
1115 		const dict_index_t*	index
1116 			= dict_table_get_first_index(prebuilt->table);
1117 		do {
1118 			ut_a(!index->to_be_dropped);
1119 			index = dict_table_get_next_index(index);
1120 		} while (index);
1121 	}
1122 
1123 	for (n_key = 0; n_key < num_of_keys; n_key++) {
1124 		const KEY*	key;
1125 		dict_index_t*	index;
1126 
1127 		key = table->key_info + key_num[n_key];
1128 		index = dict_table_get_index_on_name_and_min_id(
1129 			prebuilt->table, key->name);
1130 
1131 		if (!index) {
1132 			sql_print_error("InnoDB could not find key n:o %u "
1133 					"with name %s for table %s",
1134 					key_num[n_key],
1135 					key ? key->name : "NULL",
1136 					prebuilt->table->name);
1137 
1138 			err = HA_ERR_KEY_NOT_FOUND;
1139 			goto func_exit;
1140 		}
1141 
1142 		/* Refuse to drop the clustered index.  It would be
1143 		better to automatically generate a clustered index,
1144 		but mysql_alter_table() will call this method only
1145 		after ha_innobase::add_index(). */
1146 
1147 		if (dict_index_is_clust(index)) {
1148 			my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
1149 			err = -1;
1150 			goto func_exit;
1151 		}
1152 
1153 		rw_lock_x_lock(dict_index_get_lock(index));
1154 		index->to_be_dropped = TRUE;
1155 		rw_lock_x_unlock(dict_index_get_lock(index));
1156 	}
1157 
1158 	/* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined
1159 	for a foreign key constraint because InnoDB requires that both
1160 	tables contain indexes for the constraint. Such index can
1161 	be dropped only if FOREIGN_KEY_CHECKS is set to 0.
1162 	Note that CREATE INDEX id ON table does a CREATE INDEX and
1163 	DROP INDEX, and we can ignore here foreign keys because a
1164 	new index for the foreign key has already been created.
1165 
1166 	We check for the foreign key constraints after marking the
1167 	candidate indexes for deletion, because when we check for an
1168 	equivalent foreign index we don't want to select an index that
1169 	is later deleted. */
1170 
1171 	if (trx->check_foreigns
1172 	    && thd_sql_command(user_thd) != SQLCOM_CREATE_INDEX) {
1173 		dict_index_t*	index;
1174 
1175 		for (index = dict_table_get_first_index(prebuilt->table);
1176 		     index;
1177 		     index = dict_table_get_next_index(index)) {
1178 			dict_foreign_t*	foreign;
1179 
1180 			if (!index->to_be_dropped) {
1181 
1182 				continue;
1183 			}
1184 
1185 			/* Check if the index is referenced. */
1186 			foreign = dict_table_get_referenced_constraint(
1187 				prebuilt->table, index);
1188 
1189 			if (foreign) {
1190 index_needed:
1191 				trx_set_detailed_error(
1192 					trx,
1193 					"Index needed in foreign key "
1194 					"constraint");
1195 
1196 				trx->error_info = index;
1197 
1198 				err = HA_ERR_DROP_INDEX_FK;
1199 				break;
1200 			} else {
1201 				/* Check if this index references some
1202 				other table */
1203 				foreign = dict_table_get_foreign_constraint(
1204 					prebuilt->table, index);
1205 
1206 				if (foreign) {
1207 					ut_a(foreign->foreign_index == index);
1208 
1209 					/* Search for an equivalent index that
1210 					the foreign key constraint could use
1211 					if this index were to be deleted. */
1212 					if (!dict_foreign_find_equiv_index(
1213 						foreign)) {
1214 
1215 						goto index_needed;
1216 					}
1217 				}
1218 			}
1219 		}
1220 	} else if (thd_sql_command(user_thd) == SQLCOM_CREATE_INDEX) {
1221 		/* This is a drop of a foreign key constraint index that
1222 		was created by MySQL when the constraint was added.  MySQL
1223 		does this when the user creates an index explicitly which
1224 		can be used in place of the automatically generated index. */
1225 
1226 		dict_index_t*	index;
1227 
1228 		for (index = dict_table_get_first_index(prebuilt->table);
1229 		     index;
1230 		     index = dict_table_get_next_index(index)) {
1231 			dict_foreign_t*	foreign;
1232 
1233 			if (!index->to_be_dropped) {
1234 
1235 				continue;
1236 			}
1237 
1238 			/* Check if this index references some other table */
1239 			foreign = dict_table_get_foreign_constraint(
1240 				prebuilt->table, index);
1241 
1242 			if (foreign == NULL) {
1243 
1244 				continue;
1245 			}
1246 
1247 			ut_a(foreign->foreign_index == index);
1248 
1249 			/* Search for an equivalent index that the
1250 			foreign key constraint could use if this index
1251 			were to be deleted. */
1252 
1253 			if (!dict_foreign_find_equiv_index(foreign)) {
1254 				trx_set_detailed_error(
1255 					trx,
1256 					"Index needed in foreign key "
1257 					"constraint");
1258 
1259 				trx->error_info = foreign->foreign_index;
1260 
1261 				err = HA_ERR_DROP_INDEX_FK;
1262 				break;
1263 			}
1264 		}
1265 	}
1266 
1267 func_exit:
1268 	if (err) {
1269 		/* Undo our changes since there was some sort of error. */
1270 		dict_index_t*	index
1271 			= dict_table_get_first_index(prebuilt->table);
1272 
1273 		do {
1274 			rw_lock_x_lock(dict_index_get_lock(index));
1275 			index->to_be_dropped = FALSE;
1276 			rw_lock_x_unlock(dict_index_get_lock(index));
1277 			index = dict_table_get_next_index(index);
1278 		} while (index);
1279 	}
1280 
1281 	ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
1282 	row_mysql_unlock_data_dictionary(trx);
1283 
1284 	DBUG_RETURN(err);
1285 }
1286 
1287 /*******************************************************************//**
1288 Drop the indexes that were passed to a successful prepare_drop_index().
1289 @return	0 or error number */
1290 UNIV_INTERN
1291 int
final_drop_index(TABLE * table)1292 ha_innobase::final_drop_index(
1293 /*==========================*/
1294 	TABLE*	table)		/*!< in: Table where indexes are dropped */
1295 {
1296 	dict_index_t*	index;		/*!< Index to be dropped */
1297 	trx_t*		trx;		/*!< Transaction */
1298 	int		err;
1299 
1300 	DBUG_ENTER("ha_innobase::final_drop_index");
1301 	ut_ad(table);
1302 
1303 	if (srv_created_new_raw || srv_force_recovery) {
1304 		DBUG_RETURN(HA_ERR_WRONG_COMMAND);
1305 	}
1306 
1307 	update_thd();
1308 
1309 	trx_search_latch_release_if_reserved(prebuilt->trx);
1310 	trx_start_if_not_started(prebuilt->trx);
1311 
1312 	/* Create a background transaction for the operations on
1313 	the data dictionary tables. */
1314 	trx = innobase_trx_allocate(user_thd);
1315 	trx_start_if_not_started(trx);
1316 
1317 	/* Flag this transaction as a dictionary operation, so that
1318 	the data dictionary will be locked in crash recovery. */
1319 	trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
1320 
1321 	/* Lock the table exclusively, to ensure that no active
1322 	transaction depends on an index that is being dropped. */
1323 	err = convert_error_code_to_mysql(
1324 		row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
1325 		prebuilt->table->flags, user_thd);
1326 
1327 	row_mysql_lock_data_dictionary(trx);
1328 	ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
1329 
1330 	if (UNIV_UNLIKELY(err)) {
1331 
1332 		/* Unmark the indexes to be dropped. */
1333 		for (index = dict_table_get_first_index(prebuilt->table);
1334 		     index; index = dict_table_get_next_index(index)) {
1335 
1336 			rw_lock_x_lock(dict_index_get_lock(index));
1337 			index->to_be_dropped = FALSE;
1338 			rw_lock_x_unlock(dict_index_get_lock(index));
1339 		}
1340 
1341 		goto func_exit;
1342 	}
1343 
1344 	/* Drop indexes marked to be dropped */
1345 
1346 	index = dict_table_get_first_index(prebuilt->table);
1347 
1348 	while (index) {
1349 		dict_index_t*	next_index;
1350 
1351 		next_index = dict_table_get_next_index(index);
1352 
1353 		if (index->to_be_dropped) {
1354 
1355 			row_merge_drop_index(index, prebuilt->table, trx);
1356 		}
1357 
1358 		index = next_index;
1359 	}
1360 
1361 	/* Check that all flagged indexes were dropped. */
1362 	for (index = dict_table_get_first_index(prebuilt->table);
1363 	     index; index = dict_table_get_next_index(index)) {
1364 		ut_a(!index->to_be_dropped);
1365 	}
1366 
1367 	/* We will need to rebuild index translation table. Set
1368 	valid index entry count in the translation table to zero */
1369 	share->idx_trans_tbl.index_count = 0;
1370 
1371 func_exit:
1372 	ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE));
1373 	trx_commit_for_mysql(trx);
1374 	trx_commit_for_mysql(prebuilt->trx);
1375 	row_mysql_unlock_data_dictionary(trx);
1376 
1377 	/* Flush the log to reduce probability that the .frm files and
1378 	the InnoDB data dictionary get out-of-sync if the user runs
1379 	with innodb_flush_log_at_trx_commit = 0 */
1380 
1381 	log_buffer_flush_to_disk();
1382 
1383 	trx_free_for_mysql(trx);
1384 
1385 	/* Tell the InnoDB server that there might be work for
1386 	utility threads: */
1387 
1388 	srv_active_wake_master_thread();
1389 
1390 	DBUG_RETURN(err);
1391 }
1392