~drizzle-trunk/drizzle/development

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