~drizzle-trunk/drizzle/development

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