~drizzle-trunk/drizzle/development

641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1
/*****************************************************************************
2
1999.6.1 by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file
3
Copyright (C) 2000, 2010, Innobase Oy. All Rights Reserved.
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
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
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
16
17
*****************************************************************************/
18
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
19
/**************************************************//**
20
@file row/row0mysql.c
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
21
Interface between Innobase row operations and MySQL.
22
Contains also create table and other data dictionary operations.
23
24
Created 9/17/2000 Heikki Tuuri
25
*******************************************************/
26
27
#include "row0mysql.h"
28
29
#ifdef UNIV_NONINL
30
#include "row0mysql.ic"
31
#endif
32
33
#include "row0ins.h"
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
34
#include "row0merge.h"
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
35
#include "row0sel.h"
36
#include "row0upd.h"
37
#include "row0row.h"
38
#include "que0que.h"
39
#include "pars0pars.h"
40
#include "dict0dict.h"
41
#include "dict0crea.h"
42
#include "dict0load.h"
43
#include "dict0boot.h"
44
#include "trx0roll.h"
45
#include "trx0purge.h"
46
#include "trx0rec.h"
47
#include "trx0undo.h"
48
#include "lock0lock.h"
49
#include "rem0cmp.h"
50
#include "log0log.h"
51
#include "btr0sea.h"
52
#include "fil0fil.h"
53
#include "ibuf0ibuf.h"
54
1241.9.1 by Monty Taylor
Removed global.h. Fixed all the headers.
55
#include <errno.h>
56
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
57
/** Provide optional 4.x backwards compatibility for 5.0 and above */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
58
UNIV_INTERN ibool	row_rollback_on_timeout	= FALSE;
59
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
60
/** Chain node of the list of tables to drop in the background. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
61
typedef struct row_mysql_drop_struct	row_mysql_drop_t;
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
62
63
/** Chain node of the list of tables to drop in the background. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
64
struct row_mysql_drop_struct{
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
65
	char*				table_name;	/*!< table name */
66
	UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
67
							/*!< list chain node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
68
};
69
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
70
/** @brief List of tables we should drop in background.
71
72
ALTER TABLE in MySQL requires that the table handler can drop the
73
table in background when there are no queries to it any
74
more.  Protected by kernel_mutex. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
75
static UT_LIST_BASE_NODE_T(row_mysql_drop_t)	row_mysql_drop_list;
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
76
/** Flag: has row_mysql_drop_list been initialized? */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
77
static ibool	row_mysql_drop_list_inited	= FALSE;
78
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
79
/** Magic table names for invoking various monitor threads */
80
/* @{ */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
81
static const char S_innodb_monitor[] = "innodb_monitor";
82
static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
83
static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
84
static const char S_innodb_table_monitor[] = "innodb_table_monitor";
85
static const char S_innodb_mem_validate[] = "innodb_mem_validate";
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
86
/* @} */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
87
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
88
/** Evaluates to true if str1 equals str2_onstack, used for comparing
89
the magic table names.
90
@param str1		in: string to compare
91
@param str1_len 	in: length of str1, in bytes, including terminating NUL
92
@param str2_onstack	in: char[] array containing a NUL terminated string
93
@return			TRUE if str1 equals str2_onstack */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
94
#define STR_EQ(str1, str1_len, str2_onstack) \
95
	((str1_len) == sizeof(str2_onstack) \
96
	 && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
97
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
98
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
99
If a table is not yet in the drop list, adds the table to the list of tables
100
which the master thread drops in background. We need this on Unix because in
101
ALTER TABLE MySQL may call drop table even if the table has running queries on
102
it. Also, if there are running foreign key checks on the table, we drop the
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
103
table lazily.
104
@return	TRUE if the table was not yet in the drop list, and was added there */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
105
static
106
ibool
107
row_add_table_to_background_drop_list(
108
/*==================================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
109
	const char*	name);	/*!< in: table name */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
110
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
111
/*******************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
112
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
113
static
114
void
115
row_mysql_delay_if_needed(void)
116
/*===========================*/
117
{
118
	if (srv_dml_needed_delay) {
119
		os_thread_sleep(srv_dml_needed_delay);
120
	}
121
}
122
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
123
/*******************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
124
Frees the blob heap in prebuilt when no longer needed. */
125
UNIV_INTERN
126
void
127
row_mysql_prebuilt_free_blob_heap(
128
/*==============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
129
	row_prebuilt_t*	prebuilt)	/*!< in: prebuilt struct of a
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
130
					ha_innobase:: table handle */
131
{
132
	mem_heap_free(prebuilt->blob_heap);
133
	prebuilt->blob_heap = NULL;
134
}
135
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
136
/*******************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
137
Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
138
format.
139
@return pointer to the data, we skip the 1 or 2 bytes at the start
140
that are used to store the len */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
141
UNIV_INTERN
142
byte*
143
row_mysql_store_true_var_len(
144
/*=========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
145
	byte*	dest,	/*!< in: where to store */
146
	ulint	len,	/*!< in: length, must fit in two bytes */
147
	ulint	lenlen)	/*!< in: storage length of len: either 1 or 2 bytes */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
148
{
149
	if (lenlen == 2) {
150
		ut_a(len < 256 * 256);
151
152
		mach_write_to_2_little_endian(dest, len);
153
154
		return(dest + 2);
155
	}
156
157
	ut_a(lenlen == 1);
158
	ut_a(len < 256);
159
160
	mach_write_to_1(dest, len);
161
162
	return(dest + 1);
163
}
164
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
165
/*******************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
166
Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
167
returns a pointer to the data.
168
@return pointer to the data, we skip the 1 or 2 bytes at the start
169
that are used to store the len */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
170
UNIV_INTERN
171
const byte*
172
row_mysql_read_true_varchar(
173
/*========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
174
	ulint*		len,	/*!< out: variable-length field length */
175
	const byte*	field,	/*!< in: field in the MySQL format */
176
	ulint		lenlen)	/*!< in: storage length of len: either 1
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
177
				or 2 bytes */
178
{
179
	if (lenlen == 2) {
180
		*len = mach_read_from_2_little_endian(field);
181
182
		return(field + 2);
183
	}
184
185
	ut_a(lenlen == 1);
186
187
	*len = mach_read_from_1(field);
188
189
	return(field + 1);
190
}
191
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
192
/*******************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
193
Stores a reference to a BLOB in the MySQL format. */
194
UNIV_INTERN
195
void
196
row_mysql_store_blob_ref(
197
/*=====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
198
	byte*		dest,	/*!< in: where to store */
199
	ulint		col_len,/*!< in: dest buffer size: determines into
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
200
				how many bytes the BLOB length is stored,
201
				the space for the length may vary from 1
202
				to 4 bytes */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
203
	const void*	data,	/*!< in: BLOB data; if the value to store
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
204
				is SQL NULL this should be NULL pointer */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
205
	ulint		len)	/*!< in: BLOB length; if the value to store
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
206
				is SQL NULL this should be 0; remember
207
				also to set the NULL bit in the MySQL record
208
				header! */
209
{
210
	/* MySQL might assume the field is set to zero except the length and
211
	the pointer fields */
212
213
	memset(dest, '\0', col_len);
214
215
	/* In dest there are 1 - 4 bytes reserved for the BLOB length,
216
	and after that 8 bytes reserved for the pointer to the data.
217
	In 32-bit architectures we only use the first 4 bytes of the pointer
218
	slot. */
219
220
	ut_a(col_len - 8 > 1 || len < 256);
221
	ut_a(col_len - 8 > 2 || len < 256 * 256);
222
	ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
223
224
	mach_write_to_n_little_endian(dest, col_len - 8, len);
225
226
	memcpy(dest + col_len - 8, &data, sizeof data);
227
}
228
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
229
/*******************************************************************//**
230
Reads a reference to a BLOB in the MySQL format.
231
@return	pointer to BLOB data */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
232
UNIV_INTERN
233
const byte*
234
row_mysql_read_blob_ref(
235
/*====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
236
	ulint*		len,		/*!< out: BLOB length */
237
	const byte*	ref,		/*!< in: BLOB reference in the
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
238
					MySQL format */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
239
	ulint		col_len)	/*!< in: BLOB reference length
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
240
					(not BLOB length) */
241
{
242
	byte*	data;
243
244
	*len = mach_read_from_n_little_endian(ref, col_len - 8);
245
246
	memcpy(&data, ref + col_len - 8, sizeof data);
247
248
	return(data);
249
}
250
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
251
/**************************************************************//**
1819.9.36 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100629113248-fvl48lnzr44z94gg from MySQL InnoDB
252
Pad a column with spaces. */
253
UNIV_INTERN
254
void
255
row_mysql_pad_col(
256
/*==============*/
257
	ulint	mbminlen,	/*!< in: minimum size of a character,
258
				in bytes */
259
	byte*	pad,		/*!< out: padded buffer */
260
	ulint	len)		/*!< in: number of bytes to pad */
261
{
262
	const byte*	pad_end;
263
264
	switch (UNIV_EXPECT(mbminlen, 1)) {
265
	default:
266
		ut_error;
267
	case 1:
268
		/* space=0x20 */
269
		memset(pad, 0x20, len);
270
		break;
271
	case 2:
272
		/* space=0x0020 */
273
		pad_end = pad + len;
274
		ut_a(!(len % 2));
275
		do {
276
			*pad++ = 0x00;
277
			*pad++ = 0x20;
278
		} while (pad < pad_end);
279
		break;
280
	case 4:
281
		/* space=0x00000020 */
282
		pad_end = pad + len;
283
		ut_a(!(len % 4));
284
		do {
285
			*pad++ = 0x00;
286
			*pad++ = 0x00;
287
			*pad++ = 0x00;
288
			*pad++ = 0x20;
289
		} while (pad < pad_end);
290
		break;
291
	}
292
}
293
294
/**************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
295
Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
296
The counterpart of this function is row_sel_field_store_in_mysql_format() in
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
297
row0sel.c.
298
@return	up to which byte we used buf in the conversion */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
299
UNIV_INTERN
300
byte*
301
row_mysql_store_col_in_innobase_format(
302
/*===================================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
303
	dfield_t*	dfield,		/*!< in/out: dfield where dtype
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
304
					information must be already set when
305
					this function is called! */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
306
	byte*		buf,		/*!< in/out: buffer for a converted
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
307
					integer value; this must be at least
308
					col_len long then! */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
309
	ibool		row_format_col,	/*!< TRUE if the mysql_data is from
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
310
					a MySQL row, FALSE if from a MySQL
311
					key value;
312
					in MySQL, a true VARCHAR storage
313
					format differs in a row and in a
314
					key value: in a key value the length
315
					is always stored in 2 bytes! */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
316
	const byte*	mysql_data,	/*!< in: MySQL column value, not
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
317
					SQL NULL; NOTE that dfield may also
318
					get a pointer to mysql_data,
319
					therefore do not discard this as long
320
					as dfield is used! */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
321
	ulint		col_len,	/*!< in: MySQL column length; NOTE that
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
322
					this is the storage length of the
323
					column in the MySQL format row, not
324
					necessarily the length of the actual
325
					payload data; if the column is a true
326
					VARCHAR then this is irrelevant */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
327
	ulint		comp)		/*!< in: nonzero=compact format */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
328
{
329
	const byte*	ptr	= mysql_data;
330
	const dtype_t*	dtype;
331
	ulint		type;
332
	ulint		lenlen;
333
334
	dtype = dfield_get_type(dfield);
335
336
	type = dtype->mtype;
337
338
	if (type == DATA_INT) {
339
		/* Store integer data in Innobase in a big-endian format,
340
		sign bit negated if the data is a signed integer. In MySQL,
341
		integers are stored in a little-endian format. */
342
343
		byte*	p = buf + col_len;
344
345
		for (;;) {
346
			p--;
347
			*p = *mysql_data;
348
			if (p == buf) {
349
				break;
350
			}
351
			mysql_data++;
352
		}
353
354
		if (!(dtype->prtype & DATA_UNSIGNED)) {
355
356
			*buf ^= 128;
357
		}
358
359
		ptr = buf;
360
		buf += col_len;
361
	} else if ((type == DATA_VARCHAR
362
		    || type == DATA_VARMYSQL
363
		    || type == DATA_BINARY)) {
364
365
		if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
366
			/* The length of the actual data is stored to 1 or 2
367
			bytes at the start of the field */
368
369
			if (row_format_col) {
370
				if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
371
					lenlen = 2;
372
				} else {
373
					lenlen = 1;
374
				}
375
			} else {
376
				/* In a MySQL key value, lenlen is always 2 */
377
				lenlen = 2;
378
			}
379
380
			ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
381
							  lenlen);
382
		} else {
383
			/* Remove trailing spaces from old style VARCHAR
384
			columns. */
385
1819.9.36 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100629113248-fvl48lnzr44z94gg from MySQL InnoDB
386
			/* Handle Unicode strings differently. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
387
			ulint	mbminlen	= dtype_get_mbminlen(dtype);
388
389
			ptr = mysql_data;
390
1819.9.36 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100629113248-fvl48lnzr44z94gg from MySQL InnoDB
391
			switch (mbminlen) {
392
			default:
393
				ut_error;
394
			case 4:
395
				/* space=0x00000020 */
396
				/* Trim "half-chars", just in case. */
397
				col_len &= ~3;
398
399
				while (col_len >= 4
400
				       && ptr[col_len - 4] == 0x00
401
				       && ptr[col_len - 3] == 0x00
402
				       && ptr[col_len - 2] == 0x00
403
				       && ptr[col_len - 1] == 0x20) {
404
					col_len -= 4;
405
				}
406
				break;
407
			case 2:
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
408
				/* space=0x0020 */
409
				/* Trim "half-chars", just in case. */
410
				col_len &= ~1;
411
412
				while (col_len >= 2 && ptr[col_len - 2] == 0x00
413
				       && ptr[col_len - 1] == 0x20) {
414
					col_len -= 2;
415
				}
1819.9.36 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100629113248-fvl48lnzr44z94gg from MySQL InnoDB
416
				break;
417
			case 1:
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
418
				/* space=0x20 */
419
				while (col_len > 0
420
				       && ptr[col_len - 1] == 0x20) {
421
					col_len--;
422
				}
423
			}
424
		}
425
	} else if (comp && type == DATA_MYSQL
426
		   && dtype_get_mbminlen(dtype) == 1
427
		   && dtype_get_mbmaxlen(dtype) > 1) {
428
		/* In some cases we strip trailing spaces from UTF-8 and other
429
		multibyte charsets, from FIXED-length CHAR columns, to save
430
		space. UTF-8 would otherwise normally use 3 * the string length
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
431
		bytes to store an ASCII string! */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
432
433
		/* We assume that this CHAR field is encoded in a
434
		variable-length character set where spaces have
435
		1:1 correspondence to 0x20 bytes, such as UTF-8.
436
437
		Consider a CHAR(n) field, a field of n characters.
438
		It will contain between n * mbminlen and n * mbmaxlen bytes.
439
		We will try to truncate it to n bytes by stripping
440
		space padding.	If the field contains single-byte
441
		characters only, it will be truncated to n characters.
442
		Consider a CHAR(5) field containing the string ".a   "
443
		where "." denotes a 3-byte character represented by
444
		the bytes "$%&".  After our stripping, the string will
445
		be stored as "$%&a " (5 bytes).	 The string ".abc "
446
		will be stored as "$%&abc" (6 bytes).
447
448
		The space padding will be restored in row0sel.c, function
449
		row_sel_field_store_in_mysql_format(). */
450
451
		ulint		n_chars;
452
453
		ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
454
455
		n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
456
457
		/* Strip space padding. */
458
		while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
459
			col_len--;
460
		}
461
	} else if (type == DATA_BLOB && row_format_col) {
462
463
		ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
464
	}
465
466
	dfield_set_data(dfield, ptr, col_len);
467
468
	return(buf);
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
Convert a row in the MySQL format to a row in the Innobase format. Note that
473
the function to convert a MySQL format key value to an InnoDB dtuple is
474
row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
475
static
476
void
477
row_mysql_convert_row_to_innobase(
478
/*==============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
479
	dtuple_t*	row,		/*!< in/out: Innobase row where the
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
480
					field type information is already
481
					copied there! */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
482
	row_prebuilt_t*	prebuilt,	/*!< in: prebuilt struct where template
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
483
					must be of type ROW_MYSQL_WHOLE_ROW */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
484
	byte*		mysql_rec)	/*!< in: row in the MySQL format;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
485
					NOTE: do not discard as long as
486
					row is used, as row may contain
487
					pointers to this record! */
488
{
1819.9.169 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20101019060415-bj3u6ewk022mk4nr from MySQL InnoDB
489
	const mysql_row_templ_t*templ;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
490
	dfield_t*		dfield;
491
	ulint			i;
492
493
	ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
494
	ut_ad(prebuilt->mysql_template);
495
496
	for (i = 0; i < prebuilt->n_template; i++) {
497
498
		templ = prebuilt->mysql_template + i;
499
		dfield = dtuple_get_nth_field(row, i);
500
501
		if (templ->mysql_null_bit_mask != 0) {
502
			/* Column may be SQL NULL */
503
504
			if (mysql_rec[templ->mysql_null_byte_offset]
505
			    & (byte) (templ->mysql_null_bit_mask)) {
506
507
				/* It is SQL NULL */
508
509
				dfield_set_null(dfield);
510
511
				goto next_column;
512
			}
513
		}
514
515
		row_mysql_store_col_in_innobase_format(
516
			dfield,
517
			prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
518
			TRUE, /* MySQL row format data */
519
			mysql_rec + templ->mysql_col_offset,
520
			templ->mysql_col_len,
521
			dict_table_is_comp(prebuilt->table));
522
next_column:
523
		;
524
	}
525
}
526
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
527
/****************************************************************//**
528
Handles user errors and lock waits detected by the database engine.
529
@return TRUE if it was a lock wait and we should continue running the
1819.5.179 by vasil
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6527 from MySQL InnoDB
530
query thread and in that case the thr is ALREADY in the running state. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
531
UNIV_INTERN
532
ibool
533
row_mysql_handle_errors(
534
/*====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
535
	ulint*		new_err,/*!< out: possible new error encountered in
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
536
				lock wait, or if no new error, the value
537
				of trx->error_state at the entry of this
538
				function */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
539
	trx_t*		trx,	/*!< in: transaction */
540
	que_thr_t*	thr,	/*!< in: query thread */
541
	trx_savept_t*	savept)	/*!< in: savepoint or NULL */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
542
{
543
	ulint	err;
544
545
handle_new_error:
546
	err = trx->error_state;
547
548
	ut_a(err != DB_SUCCESS);
549
550
	trx->error_state = DB_SUCCESS;
551
552
	switch (err) {
553
	case DB_LOCK_WAIT_TIMEOUT:
554
		if (row_rollback_on_timeout) {
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
555
			trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
556
			break;
557
		}
558
		/* fall through */
559
	case DB_DUPLICATE_KEY:
560
	case DB_FOREIGN_DUPLICATE_KEY:
561
	case DB_TOO_BIG_RECORD:
562
	case DB_ROW_IS_REFERENCED:
563
	case DB_NO_REFERENCED_ROW:
564
	case DB_CANNOT_ADD_CONSTRAINT:
565
	case DB_TOO_MANY_CONCURRENT_TRXS:
566
	case DB_OUT_OF_FILE_SPACE:
1819.7.118 by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100513074652-0cvlhgkesgbb2bfh from MySQL InnoDB
567
	case DB_INTERRUPTED:
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
568
		if (savept) {
569
			/* Roll back the latest, possibly incomplete
570
			insertion or update */
571
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
572
			trx_general_rollback_for_mysql(trx, savept);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
573
		}
574
		/* MySQL will roll back the latest SQL statement */
575
		break;
576
	case DB_LOCK_WAIT:
577
		srv_suspend_mysql_thread(thr);
578
579
		if (trx->error_state != DB_SUCCESS) {
580
			que_thr_stop_for_mysql(thr);
581
582
			goto handle_new_error;
583
		}
584
585
		*new_err = err;
586
587
		return(TRUE);
588
589
	case DB_DEADLOCK:
590
	case DB_LOCK_TABLE_FULL:
591
		/* Roll back the whole transaction; this resolution was added
592
		to version 3.23.43 */
593
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
594
		trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
595
		break;
596
597
	case DB_MUST_GET_MORE_FILE_SPACE:
598
		fputs("InnoDB: The database cannot continue"
599
		      " operation because of\n"
600
		      "InnoDB: lack of space. You must add"
601
		      " a new data file to\n"
602
		      "InnoDB: my.cnf and restart the database.\n", stderr);
603
604
		exit(1);
605
606
	case DB_CORRUPTION:
607
		fputs("InnoDB: We detected index corruption"
608
		      " in an InnoDB type table.\n"
609
		      "InnoDB: You have to dump + drop + reimport"
610
		      " the table or, in\n"
611
		      "InnoDB: a case of widespread corruption,"
612
		      " dump all InnoDB\n"
613
		      "InnoDB: tables and recreate the"
614
		      " whole InnoDB tablespace.\n"
615
		      "InnoDB: If the mysqld server crashes"
616
		      " after the startup or when\n"
617
		      "InnoDB: you dump the tables, look at\n"
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
618
		      "InnoDB: " REFMAN "forcing-recovery.html"
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
619
		      " for help.\n", stderr);
620
		break;
1819.9.148 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006135534-6m2rb97xpbrkxux5 from MySQL InnoDB
621
	case DB_FOREIGN_EXCEED_MAX_CASCADE:
622
		fprintf(stderr, "InnoDB: Cannot delete/update rows with"
623
			" cascading foreign key constraints that exceed max"
624
			" depth of %lu\n"
625
			"Please drop excessive foreign constraints"
626
			" and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
627
		break;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
628
	default:
629
		fprintf(stderr, "InnoDB: unknown error code %lu\n",
630
			(ulong) err);
631
		ut_error;
632
	}
633
634
	if (trx->error_state != DB_SUCCESS) {
635
		*new_err = trx->error_state;
636
	} else {
637
		*new_err = err;
638
	}
639
640
	trx->error_state = DB_SUCCESS;
641
642
	return(FALSE);
643
}
644
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
645
/********************************************************************//**
646
Create a prebuilt struct for a MySQL table handle.
647
@return	own: a prebuilt struct */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
648
UNIV_INTERN
649
row_prebuilt_t*
650
row_create_prebuilt(
651
/*================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
652
	dict_table_t*	table)	/*!< in: Innobase table handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
653
{
654
	row_prebuilt_t*	prebuilt;
655
	mem_heap_t*	heap;
656
	dict_index_t*	clust_index;
657
	dtuple_t*	ref;
658
	ulint		ref_len;
659
660
	heap = mem_heap_create(sizeof *prebuilt + 128);
661
662
	prebuilt = mem_heap_zalloc(heap, sizeof *prebuilt);
663
664
	prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
665
	prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
666
667
	prebuilt->table = table;
668
669
	prebuilt->sql_stat_start = TRUE;
670
	prebuilt->heap = heap;
671
672
	prebuilt->pcur = btr_pcur_create_for_mysql();
673
	prebuilt->clust_pcur = btr_pcur_create_for_mysql();
674
675
	prebuilt->select_lock_type = LOCK_NONE;
676
	prebuilt->stored_select_lock_type = 99999999;
1819.7.154 by Marko Mäkelä
Merge Revision revid:marko.makela@oracle.com-20100601120933-r8fnhig5m5qnnohz from MySQL InnoDB
677
	UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
678
			 sizeof prebuilt->stored_select_lock_type);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
679
680
	prebuilt->search_tuple = dtuple_create(
681
		heap, 2 * dict_table_get_n_cols(table));
682
683
	clust_index = dict_table_get_first_index(table);
684
685
	/* Make sure that search_tuple is long enough for clustered index */
686
	ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
687
688
	ref_len = dict_index_get_n_unique(clust_index);
689
690
	ref = dtuple_create(heap, ref_len);
691
692
	dict_index_copy_types(ref, clust_index, ref_len);
693
694
	prebuilt->clust_ref = ref;
695
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
696
	prebuilt->autoinc_error = 0;
697
	prebuilt->autoinc_offset = 0;
698
660.1.4 by Eric Herman
un-fixing whitespace changes to storage/innobase
699
	/* Default to 1, we will set the actual value later in 
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
700
	ha_innobase::get_auto_increment(). */
701
	prebuilt->autoinc_increment = 1;
702
703
	prebuilt->autoinc_last_value = 0;
704
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
705
	return(prebuilt);
706
}
707
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
708
/********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
709
Free a prebuilt struct for a MySQL table handle. */
710
UNIV_INTERN
711
void
712
row_prebuilt_free(
713
/*==============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
714
	row_prebuilt_t*	prebuilt,	/*!< in, own: prebuilt struct */
715
	ibool		dict_locked)	/*!< in: TRUE=data dictionary locked */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
716
{
717
	ulint	i;
718
719
	if (UNIV_UNLIKELY
720
	    (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
721
	     || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
722
723
		fprintf(stderr,
724
			"InnoDB: Error: trying to free a corrupt\n"
725
			"InnoDB: table handle. Magic n %lu,"
726
			" magic n2 %lu, table name ",
727
			(ulong) prebuilt->magic_n,
728
			(ulong) prebuilt->magic_n2);
729
		ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
730
		putc('\n', stderr);
731
732
		mem_analyze_corruption(prebuilt);
733
734
		ut_error;
735
	}
736
737
	prebuilt->magic_n = ROW_PREBUILT_FREED;
738
	prebuilt->magic_n2 = ROW_PREBUILT_FREED;
739
740
	btr_pcur_free_for_mysql(prebuilt->pcur);
741
	btr_pcur_free_for_mysql(prebuilt->clust_pcur);
742
743
	if (prebuilt->mysql_template) {
744
		mem_free(prebuilt->mysql_template);
745
	}
746
747
	if (prebuilt->ins_graph) {
748
		que_graph_free_recursive(prebuilt->ins_graph);
749
	}
750
751
	if (prebuilt->sel_graph) {
752
		que_graph_free_recursive(prebuilt->sel_graph);
753
	}
754
755
	if (prebuilt->upd_graph) {
756
		que_graph_free_recursive(prebuilt->upd_graph);
757
	}
758
759
	if (prebuilt->blob_heap) {
760
		mem_heap_free(prebuilt->blob_heap);
761
	}
762
763
	if (prebuilt->old_vers_heap) {
764
		mem_heap_free(prebuilt->old_vers_heap);
765
	}
766
767
	for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
768
		if (prebuilt->fetch_cache[i] != NULL) {
769
770
			if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
771
				     (prebuilt->fetch_cache[i]) - 4))
772
			    || (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
773
					(prebuilt->fetch_cache[i])
774
					+ prebuilt->mysql_row_len))) {
775
				fputs("InnoDB: Error: trying to free"
776
				      " a corrupt fetch buffer.\n", stderr);
777
778
				mem_analyze_corruption(
779
					prebuilt->fetch_cache[i]);
780
781
				ut_error;
782
			}
783
784
			mem_free((prebuilt->fetch_cache[i]) - 4);
785
		}
786
	}
787
788
	dict_table_decrement_handle_count(prebuilt->table, dict_locked);
789
790
	mem_heap_free(prebuilt->heap);
791
}
792
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
793
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
794
Updates the transaction pointers in query graphs stored in the prebuilt
795
struct. */
796
UNIV_INTERN
797
void
798
row_update_prebuilt_trx(
799
/*====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
800
	row_prebuilt_t*	prebuilt,	/*!< in/out: prebuilt struct
801
					in MySQL handle */
802
	trx_t*		trx)		/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
803
{
804
	if (trx->magic_n != TRX_MAGIC_N) {
805
		fprintf(stderr,
806
			"InnoDB: Error: trying to use a corrupt\n"
807
			"InnoDB: trx handle. Magic n %lu\n",
808
			(ulong) trx->magic_n);
809
810
		mem_analyze_corruption(trx);
811
812
		ut_error;
813
	}
814
815
	if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
816
		fprintf(stderr,
817
			"InnoDB: Error: trying to use a corrupt\n"
818
			"InnoDB: table handle. Magic n %lu, table name ",
819
			(ulong) prebuilt->magic_n);
820
		ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
821
		putc('\n', stderr);
822
823
		mem_analyze_corruption(prebuilt);
824
825
		ut_error;
826
	}
827
828
	prebuilt->trx = trx;
829
830
	if (prebuilt->ins_graph) {
831
		prebuilt->ins_graph->trx = trx;
832
	}
833
834
	if (prebuilt->upd_graph) {
835
		prebuilt->upd_graph->trx = trx;
836
	}
837
838
	if (prebuilt->sel_graph) {
839
		prebuilt->sel_graph->trx = trx;
840
	}
841
}
842
1802.18.1 by Stewart Smith
migrate innobase insert_replication_mesasge to instead use the INNOBASE API directly instead of through the InnoDB parser. This means it should be reentrant. We construct our own prebuilt structure, set the row data and write the row as part of the transaction (as before). We currently do *NOT* handle any row lock conflicts. i.e. if you ever write code that can block the insert into the table, this will explode horribly. You also probably want to take note that the create table statement for the innobase parser only creates 4 byte integers, so i've had to just take the low 32bits of txn id.
843
dtuple_t* row_get_prebuilt_insert_row(row_prebuilt_t*	prebuilt);
844
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
845
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
846
Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
847
has not yet been built in the prebuilt struct, then this function first
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
848
builds it.
849
@return	prebuilt dtuple; the column type information is also set in it */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
850
dtuple_t*
851
row_get_prebuilt_insert_row(
852
/*========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
853
	row_prebuilt_t*	prebuilt)	/*!< in: prebuilt struct in MySQL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
854
					handle */
855
{
856
	ins_node_t*	node;
857
	dtuple_t*	row;
858
	dict_table_t*	table	= prebuilt->table;
859
860
	ut_ad(prebuilt && table && prebuilt->trx);
861
862
	if (prebuilt->ins_node == NULL) {
863
864
		/* Not called before for this handle: create an insert node
865
		and query graph to the prebuilt struct */
866
867
		node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
868
869
		prebuilt->ins_node = node;
870
871
		if (prebuilt->ins_upd_rec_buff == NULL) {
872
			prebuilt->ins_upd_rec_buff = mem_heap_alloc(
873
				prebuilt->heap, prebuilt->mysql_row_len);
874
		}
875
876
		row = dtuple_create(prebuilt->heap,
877
				    dict_table_get_n_cols(table));
878
879
		dict_table_copy_types(row, table);
880
881
		ins_node_set_new_row(node, row);
882
883
		prebuilt->ins_graph = que_node_get_parent(
884
			pars_complete_graph_for_exec(node,
885
						     prebuilt->trx,
886
						     prebuilt->heap));
887
		prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
888
	}
889
890
	return(prebuilt->ins_node->row);
891
}
892
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
893
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
894
Updates the table modification counter and calculates new estimates
895
for table and index statistics if necessary. */
896
UNIV_INLINE
897
void
898
row_update_statistics_if_needed(
899
/*============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
900
	dict_table_t*	table)	/*!< in: table */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
901
{
902
	ulint	counter;
903
904
	counter = table->stat_modified_counter;
905
906
	table->stat_modified_counter = counter + 1;
907
908
	/* Calculate new statistics if 1 / 16 of table has been modified
909
	since the last time a statistics batch was run, or if
910
	stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
911
	We calculate statistics at most every 16th round, since we may have
912
	a counter table which is very small and updated very often. */
913
914
	if (counter > 2000000000
915
	    || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
916
1819.9.194 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20101102165720-164z3666y3tut4c2 from MySQL InnoDB
917
		dict_update_statistics(table, FALSE /* update even if stats
918
						    are initialized */);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
919
	}
920
}
921
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
922
/*********************************************************************//**
1819.5.23 by stewart at flamingspork
[patch 023/129] Merge patch for revision 1811 from InnoDB SVN:
923
Unlocks AUTO_INC type locks that were possibly reserved by a trx. This
924
function should be called at the the end of an SQL statement, by the
925
connection thread that owns the transaction (trx->mysql_thd). */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
926
UNIV_INTERN
927
void
928
row_unlock_table_autoinc_for_mysql(
929
/*===============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
930
	trx_t*	trx)	/*!< in/out: transaction */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
931
{
1819.5.23 by stewart at flamingspork
[patch 023/129] Merge patch for revision 1811 from InnoDB SVN:
932
	if (lock_trx_holds_autoinc_locks(trx)) {
933
		mutex_enter(&kernel_mutex);
934
935
		lock_release_autoinc_locks(trx);
936
937
		mutex_exit(&kernel_mutex);
938
	}
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
939
}
940
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
941
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
942
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
943
AUTO_INC lock gives exclusive access to the auto-inc counter of the
944
table. The lock is reserved only for the duration of an SQL statement.
945
It is not compatible with another AUTO_INC or exclusive lock on the
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
946
table.
947
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
948
UNIV_INTERN
949
int
950
row_lock_table_autoinc_for_mysql(
951
/*=============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
952
	row_prebuilt_t*	prebuilt)	/*!< in: prebuilt struct in the MySQL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
953
					table handle */
954
{
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
955
	trx_t*			trx	= prebuilt->trx;
956
	ins_node_t*		node	= prebuilt->ins_node;
957
	const dict_table_t*	table	= prebuilt->table;
958
	que_thr_t*		thr;
959
	ulint			err;
960
	ibool			was_lock_wait;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
961
962
	ut_ad(trx);
963
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
964
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
965
	/* If we already hold an AUTOINC lock on the table then do nothing.
966
        Note: We peek at the value of the current owner without acquiring
967
	the kernel mutex. **/
968
	if (trx == table->autoinc_trx) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
969
970
		return(DB_SUCCESS);
971
	}
972
973
	trx->op_info = "setting auto-inc lock";
974
975
	if (node == NULL) {
976
		row_get_prebuilt_insert_row(prebuilt);
977
		node = prebuilt->ins_node;
978
	}
979
980
	/* We use the insert query graph as the dummy graph needed
981
	in the lock module call */
982
983
	thr = que_fork_get_first_thr(prebuilt->ins_graph);
984
985
	que_thr_move_to_run_state_for_mysql(thr, trx);
986
987
run_again:
988
	thr->run_node = node;
989
	thr->prev_node = node;
990
991
	/* It may be that the current session has not yet started
992
	its transaction, or it has been committed: */
993
994
	trx_start_if_not_started(trx);
995
996
	err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
997
998
	trx->error_state = err;
999
1000
	if (err != DB_SUCCESS) {
1001
		que_thr_stop_for_mysql(thr);
1002
1003
		was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1004
1005
		if (was_lock_wait) {
1006
			goto run_again;
1007
		}
1008
1009
		trx->op_info = "";
1010
1011
		return((int) err);
1012
	}
1013
1014
	que_thr_stop_for_mysql_no_error(thr, trx);
1015
1016
	trx->op_info = "";
1017
1018
	return((int) err);
1019
}
1020
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1021
/*********************************************************************//**
1022
Sets a table lock on the table mentioned in prebuilt.
1023
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1024
UNIV_INTERN
1025
int
1026
row_lock_table_for_mysql(
1027
/*=====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1028
	row_prebuilt_t*	prebuilt,	/*!< in: prebuilt struct in the MySQL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1029
					table handle */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1030
	dict_table_t*	table,		/*!< in: table to lock, or NULL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1031
					if prebuilt->table should be
1032
					locked as
1033
					prebuilt->select_lock_type */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1034
	ulint		mode)		/*!< in: lock mode of table
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1035
					(ignored if table==NULL) */
1036
{
1037
	trx_t*		trx		= prebuilt->trx;
1038
	que_thr_t*	thr;
1039
	ulint		err;
1040
	ibool		was_lock_wait;
1041
1042
	ut_ad(trx);
1043
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1044
1045
	trx->op_info = "setting table lock";
1046
1047
	if (prebuilt->sel_graph == NULL) {
1048
		/* Build a dummy select query graph */
1049
		row_prebuild_sel_graph(prebuilt);
1050
	}
1051
1052
	/* We use the select query graph as the dummy graph needed
1053
	in the lock module call */
1054
1055
	thr = que_fork_get_first_thr(prebuilt->sel_graph);
1056
1057
	que_thr_move_to_run_state_for_mysql(thr, trx);
1058
1059
run_again:
1060
	thr->run_node = thr;
1061
	thr->prev_node = thr->common.parent;
1062
1063
	/* It may be that the current session has not yet started
1064
	its transaction, or it has been committed: */
1065
1066
	trx_start_if_not_started(trx);
1067
1068
	if (table) {
1069
		err = lock_table(0, table, mode, thr);
1070
	} else {
1071
		err = lock_table(0, prebuilt->table,
1072
				 prebuilt->select_lock_type, thr);
1073
	}
1074
1075
	trx->error_state = err;
1076
1077
	if (err != DB_SUCCESS) {
1078
		que_thr_stop_for_mysql(thr);
1079
1080
		was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1081
1082
		if (was_lock_wait) {
1083
			goto run_again;
1084
		}
1085
1086
		trx->op_info = "";
1087
1088
		return((int) err);
1089
	}
1090
1091
	que_thr_stop_for_mysql_no_error(thr, trx);
1092
1093
	trx->op_info = "";
1094
1095
	return((int) err);
1096
}
1097
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1098
/*********************************************************************//**
1099
Does an insert for MySQL.
1100
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1101
UNIV_INTERN
1102
int
1103
row_insert_for_mysql(
1104
/*=================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1105
	byte*		mysql_rec,	/*!< in: row in the MySQL format */
1106
	row_prebuilt_t*	prebuilt)	/*!< in: prebuilt struct in MySQL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1107
					handle */
1108
{
1109
	trx_savept_t	savept;
1110
	que_thr_t*	thr;
1111
	ulint		err;
1112
	ibool		was_lock_wait;
1113
	trx_t*		trx		= prebuilt->trx;
1114
	ins_node_t*	node		= prebuilt->ins_node;
1115
1116
	ut_ad(trx);
1117
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1118
1119
	if (prebuilt->table->ibd_file_missing) {
1120
		ut_print_timestamp(stderr);
1121
		fprintf(stderr, "  InnoDB: Error:\n"
1122
			"InnoDB: MySQL is trying to use a table handle"
1123
			" but the .ibd file for\n"
1124
			"InnoDB: table %s does not exist.\n"
1125
			"InnoDB: Have you deleted the .ibd file"
1126
			" from the database directory under\n"
1127
			"InnoDB: the MySQL datadir, or have you"
1128
			" used DISCARD TABLESPACE?\n"
1129
			"InnoDB: Look from\n"
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1130
			"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1131
			"InnoDB: how you can resolve the problem.\n",
1132
			prebuilt->table->name);
1133
		return(DB_ERROR);
1134
	}
1135
1136
	if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1137
		fprintf(stderr,
1138
			"InnoDB: Error: trying to free a corrupt\n"
1139
			"InnoDB: table handle. Magic n %lu, table name ",
1140
			(ulong) prebuilt->magic_n);
1141
		ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1142
		putc('\n', stderr);
1143
1144
		mem_analyze_corruption(prebuilt);
1145
1146
		ut_error;
1147
	}
1148
1149
	if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1150
		fputs("InnoDB: A new raw disk partition was initialized or\n"
1151
		      "InnoDB: innodb_force_recovery is on: we do not allow\n"
1152
		      "InnoDB: database modifications by the user. Shut down\n"
1153
		      "InnoDB: mysqld and edit my.cnf so that"
1154
		      " newraw is replaced\n"
1155
		      "InnoDB: with raw, and innodb_force_... is removed.\n",
1156
		      stderr);
1157
1158
		return(DB_ERROR);
1159
	}
1160
1161
	trx->op_info = "inserting";
1162
1163
	row_mysql_delay_if_needed();
1164
1165
	trx_start_if_not_started(trx);
1166
1167
	if (node == NULL) {
1168
		row_get_prebuilt_insert_row(prebuilt);
1169
		node = prebuilt->ins_node;
1170
	}
1171
1172
	row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1173
1174
	savept = trx_savept_take(trx);
1175
1176
	thr = que_fork_get_first_thr(prebuilt->ins_graph);
1177
1178
	if (prebuilt->sql_stat_start) {
1179
		node->state = INS_NODE_SET_IX_LOCK;
1180
		prebuilt->sql_stat_start = FALSE;
1181
	} else {
1182
		node->state = INS_NODE_ALLOC_ROW_ID;
1183
	}
1184
1185
	que_thr_move_to_run_state_for_mysql(thr, trx);
1186
1187
run_again:
1188
	thr->run_node = node;
1189
	thr->prev_node = node;
1190
1191
	row_ins_step(thr);
1192
1193
	err = trx->error_state;
1194
1195
	if (err != DB_SUCCESS) {
1196
		que_thr_stop_for_mysql(thr);
1197
1198
		/* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1199
1200
		was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1201
							&savept);
1202
		thr->lock_state= QUE_THR_LOCK_NOLOCK;
1203
1204
		if (was_lock_wait) {
1205
			goto run_again;
1206
		}
1207
1208
		trx->op_info = "";
1209
1210
		return((int) err);
1211
	}
1212
1213
	que_thr_stop_for_mysql_no_error(thr, trx);
1214
1215
	prebuilt->table->stat_n_rows++;
1216
1217
	srv_n_rows_inserted++;
1218
1219
	if (prebuilt->table->stat_n_rows == 0) {
1220
		/* Avoid wrap-over */
1221
		prebuilt->table->stat_n_rows--;
1222
	}
1223
1224
	row_update_statistics_if_needed(prebuilt->table);
1225
	trx->op_info = "";
1226
1227
	return((int) err);
1228
}
1229
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1230
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1231
Builds a dummy query graph used in selects. */
1232
UNIV_INTERN
1233
void
1234
row_prebuild_sel_graph(
1235
/*===================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1236
	row_prebuilt_t*	prebuilt)	/*!< in: prebuilt struct in MySQL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1237
					handle */
1238
{
1239
	sel_node_t*	node;
1240
1241
	ut_ad(prebuilt && prebuilt->trx);
1242
1243
	if (prebuilt->sel_graph == NULL) {
1244
1245
		node = sel_node_create(prebuilt->heap);
1246
1247
		prebuilt->sel_graph = que_node_get_parent(
1248
			pars_complete_graph_for_exec(node,
1249
						     prebuilt->trx,
1250
						     prebuilt->heap));
1251
1252
		prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1253
	}
1254
}
1255
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1256
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1257
Creates an query graph node of 'update' type to be used in the MySQL
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1258
interface.
1259
@return	own: update node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1260
UNIV_INTERN
1261
upd_node_t*
1262
row_create_update_node_for_mysql(
1263
/*=============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1264
	dict_table_t*	table,	/*!< in: table to update */
1265
	mem_heap_t*	heap)	/*!< in: mem heap from which allocated */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1266
{
1267
	upd_node_t*	node;
1268
1269
	node = upd_node_create(heap);
1270
1271
	node->in_mysql_interface = TRUE;
1272
	node->is_delete = FALSE;
1273
	node->searched_update = FALSE;
1274
	node->select = NULL;
1275
	node->pcur = btr_pcur_create_for_mysql();
1276
	node->table = table;
1277
1278
	node->update = upd_create(dict_table_get_n_cols(table), heap);
1279
1280
	node->update_n_fields = dict_table_get_n_cols(table);
1281
1282
	UT_LIST_INIT(node->columns);
1283
	node->has_clust_rec_x_lock = TRUE;
1284
	node->cmpl_info = 0;
1285
1286
	node->table_sym = NULL;
1287
	node->col_assign_list = NULL;
1288
1289
	return(node);
1290
}
1291
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1292
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1293
Gets pointer to a prebuilt update vector used in updates. If the update
1294
graph has not yet been built in the prebuilt struct, then this function
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1295
first builds it.
1296
@return	prebuilt update vector */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1297
UNIV_INTERN
1298
upd_t*
1299
row_get_prebuilt_update_vector(
1300
/*===========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1301
	row_prebuilt_t*	prebuilt)	/*!< in: prebuilt struct in MySQL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1302
					handle */
1303
{
1304
	dict_table_t*	table	= prebuilt->table;
1305
	upd_node_t*	node;
1306
1307
	ut_ad(prebuilt && table && prebuilt->trx);
1308
1309
	if (prebuilt->upd_node == NULL) {
1310
1311
		/* Not called before for this handle: create an update node
1312
		and query graph to the prebuilt struct */
1313
1314
		node = row_create_update_node_for_mysql(table, prebuilt->heap);
1315
1316
		prebuilt->upd_node = node;
1317
1318
		prebuilt->upd_graph = que_node_get_parent(
1319
			pars_complete_graph_for_exec(node,
1320
						     prebuilt->trx,
1321
						     prebuilt->heap));
1322
		prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1323
	}
1324
1325
	return(prebuilt->upd_node->update);
1326
}
1327
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1328
/*********************************************************************//**
1329
Does an update or delete of a row for MySQL.
1330
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1331
UNIV_INTERN
1332
int
1333
row_update_for_mysql(
1334
/*=================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1335
	byte*		mysql_rec,	/*!< in: the row to be updated, in
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1336
					the MySQL format */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1337
	row_prebuilt_t*	prebuilt)	/*!< in: prebuilt struct in MySQL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1338
					handle */
1339
{
1340
	trx_savept_t	savept;
1341
	ulint		err;
1342
	que_thr_t*	thr;
1343
	ibool		was_lock_wait;
1344
	dict_index_t*	clust_index;
1345
	/*	ulint		ref_len; */
1346
	upd_node_t*	node;
1347
	dict_table_t*	table		= prebuilt->table;
1348
	trx_t*		trx		= prebuilt->trx;
1349
1350
	ut_ad(prebuilt && trx);
1351
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1352
	UT_NOT_USED(mysql_rec);
1353
1354
	if (prebuilt->table->ibd_file_missing) {
1355
		ut_print_timestamp(stderr);
1356
		fprintf(stderr, "  InnoDB: Error:\n"
1357
			"InnoDB: MySQL is trying to use a table handle"
1358
			" but the .ibd file for\n"
1359
			"InnoDB: table %s does not exist.\n"
1360
			"InnoDB: Have you deleted the .ibd file"
1361
			" from the database directory under\n"
1362
			"InnoDB: the MySQL datadir, or have you"
1363
			" used DISCARD TABLESPACE?\n"
1364
			"InnoDB: Look from\n"
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1365
			"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1366
			"InnoDB: how you can resolve the problem.\n",
1367
			prebuilt->table->name);
1368
		return(DB_ERROR);
1369
	}
1370
1371
	if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1372
		fprintf(stderr,
1373
			"InnoDB: Error: trying to free a corrupt\n"
1374
			"InnoDB: table handle. Magic n %lu, table name ",
1375
			(ulong) prebuilt->magic_n);
1376
		ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1377
		putc('\n', stderr);
1378
1379
		mem_analyze_corruption(prebuilt);
1380
1381
		ut_error;
1382
	}
1383
1384
	if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1385
		fputs("InnoDB: A new raw disk partition was initialized or\n"
1386
		      "InnoDB: innodb_force_recovery is on: we do not allow\n"
1387
		      "InnoDB: database modifications by the user. Shut down\n"
1388
		      "InnoDB: mysqld and edit my.cnf so that newraw"
1389
		      " is replaced\n"
1390
		      "InnoDB: with raw, and innodb_force_... is removed.\n",
1391
		      stderr);
1392
1393
		return(DB_ERROR);
1394
	}
1395
1396
	trx->op_info = "updating or deleting";
1397
1398
	row_mysql_delay_if_needed();
1399
1400
	trx_start_if_not_started(trx);
1401
1402
	node = prebuilt->upd_node;
1403
1404
	clust_index = dict_table_get_first_index(table);
1405
1406
	if (prebuilt->pcur->btr_cur.index == clust_index) {
1407
		btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1408
	} else {
1409
		btr_pcur_copy_stored_position(node->pcur,
1410
					      prebuilt->clust_pcur);
1411
	}
1412
1413
	ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1414
1415
	/* MySQL seems to call rnd_pos before updating each row it
1416
	has cached: we can get the correct cursor position from
1417
	prebuilt->pcur; NOTE that we cannot build the row reference
1418
	from mysql_rec if the clustered index was automatically
1419
	generated for the table: MySQL does not know anything about
1420
	the row id used as the clustered index key */
1421
1422
	savept = trx_savept_take(trx);
1423
1424
	thr = que_fork_get_first_thr(prebuilt->upd_graph);
1425
1426
	node->state = UPD_NODE_UPDATE_CLUSTERED;
1427
1428
	ut_ad(!prebuilt->sql_stat_start);
1429
1430
	que_thr_move_to_run_state_for_mysql(thr, trx);
1431
1432
run_again:
1433
	thr->run_node = node;
1434
	thr->prev_node = node;
1819.9.148 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006135534-6m2rb97xpbrkxux5 from MySQL InnoDB
1435
	thr->fk_cascade_depth = 0;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1436
1437
	row_upd_step(thr);
1438
1819.9.149 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006104126-0p2gt52pjl98eews from MySQL InnoDB
1439
	/* The recursive call for cascading update/delete happens
1440
	in above row_upd_step(), reset the counter once we come
1441
	out of the recursive call, so it does not accumulate for
1442
	different row deletes */
1443
	thr->fk_cascade_depth = 0;
1444
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1445
	err = trx->error_state;
1446
1819.9.148 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006135534-6m2rb97xpbrkxux5 from MySQL InnoDB
1447
	/* Reset fk_cascade_depth back to 0 */
1448
	thr->fk_cascade_depth = 0;
1449
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1450
	if (err != DB_SUCCESS) {
1451
		que_thr_stop_for_mysql(thr);
1452
1453
		if (err == DB_RECORD_NOT_FOUND) {
1454
			trx->error_state = DB_SUCCESS;
1455
			trx->op_info = "";
1456
1457
			return((int) err);
1458
		}
1459
1460
		thr->lock_state= QUE_THR_LOCK_ROW;
1461
		was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1462
							&savept);
1463
		thr->lock_state= QUE_THR_LOCK_NOLOCK;
1464
1465
		if (was_lock_wait) {
1466
			goto run_again;
1467
		}
1468
1469
		trx->op_info = "";
1470
1471
		return((int) err);
1472
	}
1473
1474
	que_thr_stop_for_mysql_no_error(thr, trx);
1475
1476
	if (node->is_delete) {
1477
		if (prebuilt->table->stat_n_rows > 0) {
1478
			prebuilt->table->stat_n_rows--;
1479
		}
1480
1481
		srv_n_rows_deleted++;
1482
	} else {
1483
		srv_n_rows_updated++;
1484
	}
1485
1819.9.128 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100930124844-yglojy7c3vaji6dx from MySQL InnoDB
1486
	/* We update table statistics only if it is a DELETE or UPDATE
1487
	that changes indexed columns, UPDATEs that change only non-indexed
1488
	columns would not affect statistics. */
1489
	if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1490
		row_update_statistics_if_needed(prebuilt->table);
1491
	}
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1492
1493
	trx->op_info = "";
1494
1495
	return((int) err);
1496
}
1497
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1498
/*********************************************************************//**
1819.7.159 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100602113733-fslfv73nhi0d17t4 from MySQL InnoDB
1499
This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
1500
session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
1501
Before calling this function row_search_for_mysql() must have
1502
initialized prebuilt->new_rec_locks to store the information which new
1503
record locks really were set. This function removes a newly set
1504
clustered index record lock under prebuilt->pcur or
1505
prebuilt->clust_pcur.  Thus, this implements a 'mini-rollback' that
1506
releases the latest clustered index record lock we set.
1507
@return error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1508
UNIV_INTERN
1509
int
1510
row_unlock_for_mysql(
1511
/*=================*/
1819.7.159 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100602113733-fslfv73nhi0d17t4 from MySQL InnoDB
1512
	row_prebuilt_t*	prebuilt,	/*!< in/out: prebuilt struct in MySQL
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1513
					handle */
1819.7.159 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100602113733-fslfv73nhi0d17t4 from MySQL InnoDB
1514
	ibool		has_latches_on_recs)/*!< in: TRUE if called so
1515
					that we have the latches on
1516
					the records under pcur and
1517
					clust_pcur, and we do not need
1518
					to reposition the cursors. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1519
{
1520
	btr_pcur_t*	pcur		= prebuilt->pcur;
1521
	btr_pcur_t*	clust_pcur	= prebuilt->clust_pcur;
1522
	trx_t*		trx		= prebuilt->trx;
1523
1524
	ut_ad(prebuilt && trx);
1525
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1526
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1527
	if (UNIV_UNLIKELY
1528
	    (!srv_locks_unsafe_for_binlog
1819.7.86 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20100504105214-ljj5sy3bk21zl7og from MySQL InnoDB
1529
	     && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1530
1531
		fprintf(stderr,
1532
			"InnoDB: Error: calling row_unlock_for_mysql though\n"
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1533
			"InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1534
			"InnoDB: this session is not using"
1535
			" READ COMMITTED isolation level.\n");
1536
1537
		return(DB_SUCCESS);
1538
	}
1539
1540
	trx->op_info = "unlock_row";
1541
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1542
	if (prebuilt->new_rec_locks >= 1) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1543
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1544
		const rec_t*	rec;
1545
		dict_index_t*	index;
1546
		trx_id_t	rec_trx_id;
1547
		mtr_t		mtr;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1548
1549
		mtr_start(&mtr);
1550
1551
		/* Restore the cursor position and find the record */
1552
1553
		if (!has_latches_on_recs) {
1554
			btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1555
		}
1556
1557
		rec = btr_pcur_get_rec(pcur);
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1558
		index = btr_pcur_get_btr_cur(pcur)->index;
1559
1560
		if (prebuilt->new_rec_locks >= 2) {
1561
			/* Restore the cursor position and find the record
1562
			in the clustered index. */
1563
1564
			if (!has_latches_on_recs) {
1565
				btr_pcur_restore_position(BTR_SEARCH_LEAF,
1566
							  clust_pcur, &mtr);
1567
			}
1568
1569
			rec = btr_pcur_get_rec(clust_pcur);
1570
			index = btr_pcur_get_btr_cur(clust_pcur)->index;
1571
		}
1572
1573
		if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
1574
			/* This is not a clustered index record.  We
1575
			do not know how to unlock the record. */
1576
			goto no_unlock;
1577
		}
1578
1579
		/* If the record has been modified by this
1580
		transaction, do not unlock it. */
1581
1582
		if (index->trx_id_offset) {
1583
			rec_trx_id = trx_read_trx_id(rec
1584
						     + index->trx_id_offset);
1585
		} else {
1586
			mem_heap_t*	heap			= NULL;
1587
			ulint	offsets_[REC_OFFS_NORMAL_SIZE];
1588
			ulint*	offsets				= offsets_;
1589
1590
			rec_offs_init(offsets_);
1591
			offsets = rec_get_offsets(rec, index, offsets,
1592
						  ULINT_UNDEFINED, &heap);
1593
1594
			rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1595
1596
			if (UNIV_LIKELY_NULL(heap)) {
1597
				mem_heap_free(heap);
1598
			}
1599
		}
1600
1819.9.31 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB
1601
		if (rec_trx_id != trx->id) {
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1602
			/* We did not update the record: unlock it */
1603
1604
			rec = btr_pcur_get_rec(pcur);
1605
			index = btr_pcur_get_btr_cur(pcur)->index;
1606
1607
			lock_rec_unlock(trx, btr_pcur_get_block(pcur),
1608
					rec, prebuilt->select_lock_type);
1609
1610
			if (prebuilt->new_rec_locks >= 2) {
1611
				rec = btr_pcur_get_rec(clust_pcur);
1612
				index = btr_pcur_get_btr_cur(clust_pcur)->index;
1613
1614
				lock_rec_unlock(trx,
1615
						btr_pcur_get_block(clust_pcur),
1616
						rec,
1617
						prebuilt->select_lock_type);
1618
			}
1619
		}
1620
no_unlock:
1621
		mtr_commit(&mtr);
1622
	}
1623
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1624
	trx->op_info = "";
1625
1626
	return(DB_SUCCESS);
1627
}
1628
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1629
/**********************************************************************//**
1630
Does a cascaded delete or set null in a foreign key operation.
1631
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1632
UNIV_INTERN
1633
ulint
1634
row_update_cascade_for_mysql(
1635
/*=========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1636
	que_thr_t*	thr,	/*!< in: query thread */
1637
	upd_node_t*	node,	/*!< in: update node used in the cascade
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1638
				or set null operation */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1639
	dict_table_t*	table)	/*!< in: table where we do the operation */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1640
{
1641
	ulint	err;
1642
	trx_t*	trx;
1643
1644
	trx = thr_get_trx(thr);
1819.9.148 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006135534-6m2rb97xpbrkxux5 from MySQL InnoDB
1645
1819.9.149 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006104126-0p2gt52pjl98eews from MySQL InnoDB
1646
	/* Increment fk_cascade_depth to record the recursive call depth on
1647
	a single update/delete that affects multiple tables chained
1648
	together with foreign key relations. */
1819.9.148 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006135534-6m2rb97xpbrkxux5 from MySQL InnoDB
1649
	thr->fk_cascade_depth++;
1650
1651
	if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
1652
		return (DB_FOREIGN_EXCEED_MAX_CASCADE);
1653
	}
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1654
run_again:
1655
	thr->run_node = node;
1656
	thr->prev_node = node;
1657
1658
	row_upd_step(thr);
1659
1819.9.149 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006104126-0p2gt52pjl98eews from MySQL InnoDB
1660
	/* The recursive call for cascading update/delete happens
1661
	in above row_upd_step(), reset the counter once we come
1662
	out of the recursive call, so it does not accumulate for
1663
	different row deletes */
1664
	thr->fk_cascade_depth = 0;
1665
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1666
	err = trx->error_state;
1667
1668
	/* Note that the cascade node is a subnode of another InnoDB
1669
	query graph node. We do a normal lock wait in this node, but
1670
	all errors are handled by the parent node. */
1671
1672
	if (err == DB_LOCK_WAIT) {
1673
		/* Handle lock wait here */
1674
1675
		que_thr_stop_for_mysql(thr);
1676
1677
		srv_suspend_mysql_thread(thr);
1678
1679
		/* Note that a lock wait may also end in a lock wait timeout,
1680
		or this transaction is picked as a victim in selective
1681
		deadlock resolution */
1682
1683
		if (trx->error_state != DB_SUCCESS) {
1684
1685
			return(trx->error_state);
1686
		}
1687
1688
		/* Retry operation after a normal lock wait */
1689
1690
		goto run_again;
1691
	}
1692
1693
	if (err != DB_SUCCESS) {
1694
1695
		return(err);
1696
	}
1697
1698
	if (node->is_delete) {
1699
		if (table->stat_n_rows > 0) {
1700
			table->stat_n_rows--;
1701
		}
1702
1703
		srv_n_rows_deleted++;
1704
	} else {
1705
		srv_n_rows_updated++;
1706
	}
1707
1708
	row_update_statistics_if_needed(table);
1709
1710
	return(err);
1711
}
1712
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1713
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1714
Checks if a table is such that we automatically created a clustered
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1715
index on it (on row id).
1716
@return	TRUE if the clustered index was generated automatically */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1717
UNIV_INTERN
1718
ibool
1719
row_table_got_default_clust_index(
1720
/*==============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1721
	const dict_table_t*	table)	/*!< in: table */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1722
{
1723
	const dict_index_t*	clust_index;
1724
1725
	clust_index = dict_table_get_first_index(table);
1726
1727
	return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1728
}
1729
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1730
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1731
Locks the data dictionary in shared mode from modifications, for performing
1732
foreign key check, rollback, or other operation invisible to MySQL. */
1733
UNIV_INTERN
1734
void
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1735
row_mysql_freeze_data_dictionary_func(
1736
/*==================================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1737
	trx_t*		trx,	/*!< in/out: transaction */
1738
	const char*	file,	/*!< in: file name */
1739
	ulint		line)	/*!< in: line number */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1740
{
1741
	ut_a(trx->dict_operation_lock_mode == 0);
1742
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1743
	rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1744
1745
	trx->dict_operation_lock_mode = RW_S_LATCH;
1746
}
1747
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1748
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1749
Unlocks the data dictionary shared lock. */
1750
UNIV_INTERN
1751
void
1752
row_mysql_unfreeze_data_dictionary(
1753
/*===============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1754
	trx_t*	trx)	/*!< in/out: transaction */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1755
{
1756
	ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
1757
1758
	rw_lock_s_unlock(&dict_operation_lock);
1759
1760
	trx->dict_operation_lock_mode = 0;
1761
}
1762
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1763
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1764
Locks the data dictionary exclusively for performing a table create or other
1765
data dictionary modification operation. */
1766
UNIV_INTERN
1767
void
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1768
row_mysql_lock_data_dictionary_func(
1769
/*================================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1770
	trx_t*		trx,	/*!< in/out: transaction */
1771
	const char*	file,	/*!< in: file name */
1772
	ulint		line)	/*!< in: line number */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1773
{
1774
	ut_a(trx->dict_operation_lock_mode == 0
1775
	     || trx->dict_operation_lock_mode == RW_X_LATCH);
1776
1777
	/* Serialize data dictionary operations with dictionary mutex:
1778
	no deadlocks or lock waits can occur then in these operations */
1779
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
1780
	rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1781
	trx->dict_operation_lock_mode = RW_X_LATCH;
1782
1783
	mutex_enter(&(dict_sys->mutex));
1784
}
1785
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1786
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1787
Unlocks the data dictionary exclusive lock. */
1788
UNIV_INTERN
1789
void
1790
row_mysql_unlock_data_dictionary(
1791
/*=============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1792
	trx_t*	trx)	/*!< in/out: transaction */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1793
{
1794
	ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1795
1796
	/* Serialize data dictionary operations with dictionary mutex:
1797
	no deadlocks can occur then in these operations */
1798
1799
	mutex_exit(&(dict_sys->mutex));
1800
	rw_lock_x_unlock(&dict_operation_lock);
1801
1802
	trx->dict_operation_lock_mode = 0;
1803
}
1804
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1805
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1806
Creates a table for MySQL. If the name of the table ends in
1807
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
1808
"innodb_table_monitor", then this will also start the printing of monitor
1809
output by the master thread. If the table name ends in "innodb_mem_validate",
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1810
InnoDB will try to invoke mem_validate().
1811
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1812
UNIV_INTERN
1813
int
1814
row_create_table_for_mysql(
1815
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1816
	dict_table_t*	table,	/*!< in, own: table definition
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
1817
				(will be freed) */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1818
	trx_t*		trx)	/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1819
{
1820
	tab_node_t*	node;
1821
	mem_heap_t*	heap;
1822
	que_thr_t*	thr;
1823
	const char*	table_name;
1824
	ulint		table_name_len;
1825
	ulint		err;
1826
1827
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1828
#ifdef UNIV_SYNC_DEBUG
1829
	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1830
#endif /* UNIV_SYNC_DEBUG */
1831
	ut_ad(mutex_own(&(dict_sys->mutex)));
1832
	ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1833
1834
	if (srv_created_new_raw) {
1835
		fputs("InnoDB: A new raw disk partition was initialized:\n"
1836
		      "InnoDB: we do not allow database modifications"
1837
		      " by the user.\n"
1838
		      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1839
		      " is replaced with raw.\n", stderr);
1840
		dict_mem_table_free(table);
1841
		trx_commit_for_mysql(trx);
1842
1843
		return(DB_ERROR);
1844
	}
1845
1846
	trx->op_info = "creating table";
1847
1848
	trx_start_if_not_started(trx);
1849
1850
	/* The table name is prefixed with the database name and a '/'.
1851
	Certain table names starting with 'innodb_' have their special
1852
	meaning regardless of the database name.  Thus, we need to
1853
	ignore the database name prefix in the comparisons. */
1854
	table_name = strchr(table->name, '/');
1855
	ut_a(table_name);
1856
	table_name++;
1857
	table_name_len = strlen(table_name) + 1;
1858
1859
	if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
1860
1861
		/* Table equals "innodb_monitor":
1862
		start monitor prints */
1863
1864
		srv_print_innodb_monitor = TRUE;
1865
1866
		/* The lock timeout monitor thread also takes care
1867
		of InnoDB monitor prints */
1868
1869
		os_event_set(srv_lock_timeout_thread_event);
1870
	} else if (STR_EQ(table_name, table_name_len,
1871
			  S_innodb_lock_monitor)) {
1872
1873
		srv_print_innodb_monitor = TRUE;
1874
		srv_print_innodb_lock_monitor = TRUE;
1875
		os_event_set(srv_lock_timeout_thread_event);
1876
	} else if (STR_EQ(table_name, table_name_len,
1877
			  S_innodb_tablespace_monitor)) {
1878
1879
		srv_print_innodb_tablespace_monitor = TRUE;
1880
		os_event_set(srv_lock_timeout_thread_event);
1881
	} else if (STR_EQ(table_name, table_name_len,
1882
			  S_innodb_table_monitor)) {
1883
1884
		srv_print_innodb_table_monitor = TRUE;
1885
		os_event_set(srv_lock_timeout_thread_event);
1886
	} else if (STR_EQ(table_name, table_name_len,
1887
			  S_innodb_mem_validate)) {
1888
		/* We define here a debugging feature intended for
1889
		developers */
1890
1891
		fputs("Validating InnoDB memory:\n"
1892
		      "to use this feature you must compile InnoDB with\n"
1893
		      "UNIV_MEM_DEBUG defined in univ.i and"
1894
		      " the server must be\n"
1895
		      "quiet because allocation from a mem heap"
1896
		      " is not protected\n"
1897
		      "by any semaphore.\n", stderr);
1898
#ifdef UNIV_MEM_DEBUG
1899
		ut_a(mem_validate());
1900
		fputs("Memory validated\n", stderr);
1901
#else /* UNIV_MEM_DEBUG */
1902
		fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1903
		      stderr);
1904
#endif /* UNIV_MEM_DEBUG */
1905
	}
1906
1907
	heap = mem_heap_create(512);
1908
1909
	trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1910
1911
	node = tab_create_graph_create(table, heap);
1912
1913
	thr = pars_complete_graph_for_exec(node, trx, heap);
1914
1915
	ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1916
	que_run_threads(thr);
1917
1918
	err = trx->error_state;
1919
1819.9.177 by Marko Mäkelä
Merge Revision revid:marko.makela@oracle.com-20101011085943-50pskvsbbsujbukg from MySQL InnoDB
1920
	switch (err) {
1921
	case DB_SUCCESS:
1922
		break;
1923
	case DB_OUT_OF_FILE_SPACE:
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1924
		trx->error_state = DB_SUCCESS;
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
1925
		trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1926
1927
		ut_print_timestamp(stderr);
1928
		fputs("  InnoDB: Warning: cannot create table ",
1929
		      stderr);
1930
		ut_print_name(stderr, trx, TRUE, table->name);
1931
		fputs(" because tablespace full\n", stderr);
1932
1933
		if (dict_table_get_low(table->name)) {
1934
1935
			row_drop_table_for_mysql(table->name, trx, FALSE);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
1936
			trx_commit_for_mysql(trx);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1937
		}
1938
		break;
1939
1940
	case DB_DUPLICATE_KEY:
1819.9.177 by Marko Mäkelä
Merge Revision revid:marko.makela@oracle.com-20101011085943-50pskvsbbsujbukg from MySQL InnoDB
1941
	default:
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1942
		/* We may also get err == DB_ERROR if the .ibd file for the
1943
		table already exists */
1944
1819.9.177 by Marko Mäkelä
Merge Revision revid:marko.makela@oracle.com-20101011085943-50pskvsbbsujbukg from MySQL InnoDB
1945
		trx->error_state = DB_SUCCESS;
1946
		trx_general_rollback_for_mysql(trx, NULL);
1947
		dict_mem_table_free(table);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1948
		break;
1949
	}
1950
1951
	que_graph_free((que_t*) que_node_get_parent(thr));
1952
1953
	trx->op_info = "";
1954
1955
	return((int) err);
1956
}
1957
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1958
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1959
Does an index creation operation for MySQL. TODO: currently failure
1960
to create an index results in dropping the whole table! This is no problem
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1961
currently as all indexes must be created at the same time as the table.
1962
@return	error number or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1963
UNIV_INTERN
1964
int
1965
row_create_index_for_mysql(
1966
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1967
	dict_index_t*	index,		/*!< in, own: index definition
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
1968
					(will be freed) */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1969
	trx_t*		trx,		/*!< in: transaction handle */
1970
	const ulint*	field_lengths)	/*!< in: if not NULL, must contain
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1971
					dict_index_get_n_fields(index)
1972
					actual field lengths for the
1973
					index columns, which are
1974
					then checked for not being too
1975
					large. */
1976
{
1977
	ind_node_t*	node;
1978
	mem_heap_t*	heap;
1979
	que_thr_t*	thr;
1980
	ulint		err;
1981
	ulint		i;
1982
	ulint		len;
1983
	char*		table_name;
1984
1985
#ifdef UNIV_SYNC_DEBUG
1986
	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1987
#endif /* UNIV_SYNC_DEBUG */
1988
	ut_ad(mutex_own(&(dict_sys->mutex)));
1989
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1990
1991
	trx->op_info = "creating index";
1992
1993
	/* Copy the table name because we may want to drop the
1994
	table later, after the index object is freed (inside
1995
	que_run_threads()) and thus index->table_name is not available. */
1996
	table_name = mem_strdup(index->table_name);
1997
1998
	trx_start_if_not_started(trx);
1999
2000
	/* Check that the same column does not appear twice in the index.
2001
	Starting from 4.0.14, InnoDB should be able to cope with that, but
2002
	safer not to allow them. */
2003
2004
	for (i = 0; i < dict_index_get_n_fields(index); i++) {
2005
		ulint		j;
2006
2007
		for (j = 0; j < i; j++) {
2008
			if (0 == ut_strcmp(
2009
				    dict_index_get_nth_field(index, j)->name,
2010
				    dict_index_get_nth_field(index, i)->name)) {
2011
				ut_print_timestamp(stderr);
2012
2013
				fputs("  InnoDB: Error: column ", stderr);
2014
				ut_print_name(stderr, trx, FALSE,
2015
					      dict_index_get_nth_field(
2016
						      index, i)->name);
2017
				fputs(" appears twice in ", stderr);
2018
				dict_index_name_print(stderr, trx, index);
2019
				fputs("\n"
2020
				      "InnoDB: This is not allowed"
2021
				      " in InnoDB.\n", stderr);
2022
2023
				err = DB_COL_APPEARS_TWICE_IN_INDEX;
2024
2025
				goto error_handling;
2026
			}
2027
		}
2028
2029
		/* Check also that prefix_len and actual length
2030
		< DICT_MAX_INDEX_COL_LEN */
2031
2032
		len = dict_index_get_nth_field(index, i)->prefix_len;
2033
2034
		if (field_lengths) {
2035
			len = ut_max(len, field_lengths[i]);
2036
		}
2037
2038
		if (len >= DICT_MAX_INDEX_COL_LEN) {
2039
			err = DB_TOO_BIG_RECORD;
2040
2041
			goto error_handling;
2042
		}
2043
	}
2044
2045
	heap = mem_heap_create(512);
2046
2047
	trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2048
2049
	/* Note that the space id where we store the index is inherited from
2050
	the table in dict_build_index_def_step() in dict0crea.c. */
2051
2052
	node = ind_create_graph_create(index, heap);
2053
2054
	thr = pars_complete_graph_for_exec(node, trx, heap);
2055
2056
	ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2057
	que_run_threads(thr);
2058
2059
	err = trx->error_state;
2060
2061
	que_graph_free((que_t*) que_node_get_parent(thr));
2062
2063
error_handling:
2064
	if (err != DB_SUCCESS) {
2065
		/* We have special error handling here */
2066
2067
		trx->error_state = DB_SUCCESS;
2068
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
2069
		trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2070
2071
		row_drop_table_for_mysql(table_name, trx, FALSE);
2072
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
2073
		trx_commit_for_mysql(trx);
2074
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2075
		trx->error_state = DB_SUCCESS;
2076
	}
2077
2078
	trx->op_info = "";
2079
2080
	mem_free(table_name);
2081
2082
	return((int) err);
2083
}
2084
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2085
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2086
Scans a table create SQL string and adds to the data dictionary
2087
the foreign key constraints declared in the string. This function
2088
should be called after the indexes for a table have been created.
2089
Each foreign key constraint must be accompanied with indexes in
1819.5.103 by stewart at flamingspork
[patch 103/129] Merge patch for revision 1910 from InnoDB SVN:
2090
both participating tables. The indexes are allowed to contain more
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2091
fields than mentioned in the constraint. Check also that foreign key
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2092
constraints which reference this table are ok.
2093
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2094
UNIV_INTERN
2095
int
2096
row_table_add_foreign_constraints(
2097
/*==============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2098
	trx_t*		trx,		/*!< in: transaction */
2099
	const char*	sql_string,	/*!< in: table create statement where
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2100
					foreign keys are declared like:
2101
				FOREIGN KEY (a, b) REFERENCES table2(c, d),
2102
					table2 can be written also with the
2103
					database name before it: test.table2 */
1819.7.121 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100514133144-fe0l0b89tea4x4uu from MySQL InnoDB
2104
	size_t		sql_length,	/*!< in: length of sql_string */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2105
	const char*	name,		/*!< in: table full name in the
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2106
					normalized form
2107
					database_name/table_name */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2108
	ibool		reject_fks)	/*!< in: if TRUE, fail with error
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2109
					code DB_CANNOT_ADD_CONSTRAINT if
2110
					any foreign keys are found. */
2111
{
2112
	ulint	err;
2113
2114
	ut_ad(mutex_own(&(dict_sys->mutex)));
2115
#ifdef UNIV_SYNC_DEBUG
2116
	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2117
#endif /* UNIV_SYNC_DEBUG */
2118
	ut_a(sql_string);
2119
2120
	trx->op_info = "adding foreign keys";
2121
2122
	trx_start_if_not_started(trx);
2123
2124
	trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2125
1819.7.121 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100514133144-fe0l0b89tea4x4uu from MySQL InnoDB
2126
	err = dict_create_foreign_constraints(trx, sql_string, sql_length,
2127
					      name, reject_fks);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2128
	if (err == DB_SUCCESS) {
2129
		/* Check that also referencing constraints are ok */
1819.9.148 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006135534-6m2rb97xpbrkxux5 from MySQL InnoDB
2130
		err = dict_load_foreigns(name, FALSE, TRUE);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2131
	}
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2132
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2133
	if (err != DB_SUCCESS) {
2134
		/* We have special error handling here */
2135
2136
		trx->error_state = DB_SUCCESS;
2137
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
2138
		trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2139
2140
		row_drop_table_for_mysql(name, trx, FALSE);
2141
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
2142
		trx_commit_for_mysql(trx);
2143
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2144
		trx->error_state = DB_SUCCESS;
2145
	}
2146
2147
	return((int) err);
2148
}
2149
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2150
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2151
Drops a table for MySQL as a background operation. MySQL relies on Unix
2152
in ALTER TABLE to the fact that the table handler does not remove the
2153
table before all handles to it has been removed. Furhermore, the MySQL's
2154
call to drop table must be non-blocking. Therefore we do the drop table
2155
as a background operation, which is taken care of by the master thread
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2156
in srv0srv.c.
2157
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2158
static
2159
int
2160
row_drop_table_for_mysql_in_background(
2161
/*===================================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2162
	const char*	name)	/*!< in: table name */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2163
{
2164
	ulint	error;
2165
	trx_t*	trx;
2166
2167
	trx = trx_allocate_for_background();
2168
2169
	/* If the original transaction was dropping a table referenced by
2170
	foreign keys, we must set the following to be able to drop the
2171
	table: */
2172
2173
	trx->check_foreigns = FALSE;
2174
2175
	/*	fputs("InnoDB: Error: Dropping table ", stderr);
2176
	ut_print_name(stderr, trx, TRUE, name);
2177
	fputs(" in background drop list\n", stderr); */
2178
2179
	/* Try to drop the table in InnoDB */
2180
2181
	error = row_drop_table_for_mysql(name, trx, FALSE);
2182
2183
	/* Flush the log to reduce probability that the .frm files and
2184
	the InnoDB data dictionary get out-of-sync if the user runs
2185
	with innodb_flush_log_at_trx_commit = 0 */
2186
2187
	log_buffer_flush_to_disk();
2188
2189
	trx_commit_for_mysql(trx);
2190
2191
	trx_free_for_background(trx);
2192
2193
	return((int) error);
2194
}
2195
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2196
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2197
The master thread in srv0srv.c calls this regularly to drop tables which
2198
we must drop in background after queries to them have ended. Such lazy
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2199
dropping of tables is needed in ALTER TABLE on Unix.
2200
@return	how many tables dropped + remaining tables in list */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2201
UNIV_INTERN
2202
ulint
2203
row_drop_tables_for_mysql_in_background(void)
2204
/*=========================================*/
2205
{
2206
	row_mysql_drop_t*	drop;
2207
	dict_table_t*		table;
2208
	ulint			n_tables;
2209
	ulint			n_tables_dropped = 0;
2210
loop:
2211
	mutex_enter(&kernel_mutex);
2212
2213
	if (!row_mysql_drop_list_inited) {
2214
2215
		UT_LIST_INIT(row_mysql_drop_list);
2216
		row_mysql_drop_list_inited = TRUE;
2217
	}
2218
2219
	drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2220
2221
	n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2222
2223
	mutex_exit(&kernel_mutex);
2224
2225
	if (drop == NULL) {
2226
		/* All tables dropped */
2227
2228
		return(n_tables + n_tables_dropped);
2229
	}
2230
2231
	mutex_enter(&(dict_sys->mutex));
2232
	table = dict_table_get_low(drop->table_name);
2233
	mutex_exit(&(dict_sys->mutex));
2234
2235
	if (table == NULL) {
2236
		/* If for some reason the table has already been dropped
2237
		through some other mechanism, do not try to drop it */
2238
2239
		goto already_dropped;
2240
	}
2241
2242
	if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2243
		    drop->table_name)) {
2244
		/* If the DROP fails for some table, we return, and let the
2245
		main thread retry later */
2246
2247
		return(n_tables + n_tables_dropped);
2248
	}
2249
2250
	n_tables_dropped++;
2251
2252
already_dropped:
2253
	mutex_enter(&kernel_mutex);
2254
2255
	UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2256
2257
	ut_print_timestamp(stderr);
2258
	fputs("  InnoDB: Dropped table ", stderr);
2259
	ut_print_name(stderr, NULL, TRUE, drop->table_name);
2260
	fputs(" in background drop queue.\n", stderr);
2261
2262
	mem_free(drop->table_name);
2263
2264
	mem_free(drop);
2265
2266
	mutex_exit(&kernel_mutex);
2267
2268
	goto loop;
2269
}
2270
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2271
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2272
Get the background drop list length. NOTE: the caller must own the kernel
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2273
mutex!
2274
@return	how many tables in list */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2275
UNIV_INTERN
2276
ulint
2277
row_get_background_drop_list_len_low(void)
2278
/*======================================*/
2279
{
2280
	ut_ad(mutex_own(&kernel_mutex));
2281
2282
	if (!row_mysql_drop_list_inited) {
2283
2284
		UT_LIST_INIT(row_mysql_drop_list);
2285
		row_mysql_drop_list_inited = TRUE;
2286
	}
2287
2288
	return(UT_LIST_GET_LEN(row_mysql_drop_list));
2289
}
2290
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2291
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2292
If a table is not yet in the drop list, adds the table to the list of tables
2293
which the master thread drops in background. We need this on Unix because in
2294
ALTER TABLE MySQL may call drop table even if the table has running queries on
2295
it. Also, if there are running foreign key checks on the table, we drop the
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2296
table lazily.
2297
@return	TRUE if the table was not yet in the drop list, and was added there */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2298
static
2299
ibool
2300
row_add_table_to_background_drop_list(
2301
/*==================================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2302
	const char*	name)	/*!< in: table name */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2303
{
2304
	row_mysql_drop_t*	drop;
2305
2306
	mutex_enter(&kernel_mutex);
2307
2308
	if (!row_mysql_drop_list_inited) {
2309
2310
		UT_LIST_INIT(row_mysql_drop_list);
2311
		row_mysql_drop_list_inited = TRUE;
2312
	}
2313
2314
	/* Look if the table already is in the drop list */
2315
	drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2316
2317
	while (drop != NULL) {
2318
		if (strcmp(drop->table_name, name) == 0) {
2319
			/* Already in the list */
2320
2321
			mutex_exit(&kernel_mutex);
2322
2323
			return(FALSE);
2324
		}
2325
2326
		drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2327
	}
2328
2329
	drop = mem_alloc(sizeof(row_mysql_drop_t));
2330
2331
	drop->table_name = mem_strdup(name);
2332
2333
	UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2334
2335
	/*	fputs("InnoDB: Adding table ", stderr);
2336
	ut_print_name(stderr, trx, TRUE, drop->table_name);
2337
	fputs(" to background drop list\n", stderr); */
2338
2339
	mutex_exit(&kernel_mutex);
2340
2341
	return(TRUE);
2342
}
2343
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2344
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2345
Discards the tablespace of a table which stored in an .ibd file. Discarding
2346
means that this function deletes the .ibd file and assigns a new table id for
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2347
the table. Also the flag table->ibd_file_missing is set TRUE.
2348
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2349
UNIV_INTERN
2350
int
2351
row_discard_tablespace_for_mysql(
2352
/*=============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2353
	const char*	name,	/*!< in: table name */
2354
	trx_t*		trx)	/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2355
{
2356
	dict_foreign_t*	foreign;
1819.9.31 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB
2357
	table_id_t	new_id;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2358
	dict_table_t*	table;
2359
	ibool		success;
2360
	ulint		err;
2361
	pars_info_t*	info = NULL;
2362
2363
	/* How do we prevent crashes caused by ongoing operations on
2364
	the table? Old operations could try to access non-existent
2365
	pages.
2366
2367
	1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2368
	MySQL table lock on the table before we can do DISCARD
2369
	TABLESPACE. Then there are no running queries on the table.
2370
2371
	2) Purge and rollback: we assign a new table id for the
2372
	table. Since purge and rollback look for the table based on
2373
	the table id, they see the table as 'dropped' and discard
2374
	their operations.
2375
2376
	3) Insert buffer: we remove all entries for the tablespace in
2377
	the insert buffer tree; as long as the tablespace mem object
2378
	does not exist, ongoing insert buffer page merges are
2379
	discarded in buf0rea.c. If we recreate the tablespace mem
2380
	object with IMPORT TABLESPACE later, then the tablespace will
2381
	have the same id, but the tablespace_version field in the mem
2382
	object is different, and ongoing old insert buffer page merges
2383
	get discarded.
2384
2385
	4) Linear readahead and random readahead: we use the same
2386
	method as in 3) to discard ongoing operations.
2387
2388
	5) FOREIGN KEY operations: if
2389
	table->n_foreign_key_checks_running > 0, we do not allow the
2390
	discard. We also reserve the data dictionary latch. */
2391
2392
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2393
2394
	trx->op_info = "discarding tablespace";
2395
	trx_start_if_not_started(trx);
2396
2397
	/* Serialize data dictionary operations with dictionary mutex:
2398
	no deadlocks can occur then in these operations */
2399
2400
	row_mysql_lock_data_dictionary(trx);
2401
2402
	table = dict_table_get_low(name);
2403
2404
	if (!table) {
2405
		err = DB_TABLE_NOT_FOUND;
2406
2407
		goto funct_exit;
2408
	}
2409
2410
	if (table->space == 0) {
2411
		ut_print_timestamp(stderr);
2412
		fputs("  InnoDB: Error: table ", stderr);
2413
		ut_print_name(stderr, trx, TRUE, name);
2414
		fputs("\n"
2415
		      "InnoDB: is in the system tablespace 0"
2416
		      " which cannot be discarded\n", stderr);
2417
		err = DB_ERROR;
2418
2419
		goto funct_exit;
2420
	}
2421
2422
	if (table->n_foreign_key_checks_running > 0) {
2423
2424
		ut_print_timestamp(stderr);
2425
		fputs("  InnoDB: You are trying to DISCARD table ", stderr);
2426
		ut_print_name(stderr, trx, TRUE, table->name);
2427
		fputs("\n"
2428
		      "InnoDB: though there is a foreign key check"
2429
		      " running on it.\n"
2430
		      "InnoDB: Cannot discard the table.\n",
2431
		      stderr);
2432
2433
		err = DB_ERROR;
2434
2435
		goto funct_exit;
2436
	}
2437
2438
	/* Check if the table is referenced by foreign key constraints from
2439
	some other table (not the table itself) */
2440
2441
	foreign = UT_LIST_GET_FIRST(table->referenced_list);
2442
2443
	while (foreign && foreign->foreign_table == table) {
2444
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2445
	}
2446
2447
	if (foreign && trx->check_foreigns) {
2448
2449
		FILE*	ef	= dict_foreign_err_file;
2450
2451
		/* We only allow discarding a referenced table if
2452
		FOREIGN_KEY_CHECKS is set to 0 */
2453
2454
		err = DB_CANNOT_DROP_CONSTRAINT;
2455
2456
		mutex_enter(&dict_foreign_err_mutex);
2457
		rewind(ef);
2458
		ut_print_timestamp(ef);
2459
2460
		fputs("  Cannot DISCARD table ", ef);
2461
		ut_print_name(stderr, trx, TRUE, name);
2462
		fputs("\n"
2463
		      "because it is referenced by ", ef);
2464
		ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
2465
		putc('\n', ef);
2466
		mutex_exit(&dict_foreign_err_mutex);
2467
2468
		goto funct_exit;
2469
	}
2470
1819.7.140 by Marko Mäkelä
Merge Revision revid:marko.makela@oracle.com-20100524114524-gih3txff2p9rz4rs from MySQL InnoDB
2471
	dict_hdr_get_new_id(&new_id, NULL, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2472
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
2473
	/* Remove all locks except the table-level S and X locks. */
2474
	lock_remove_all_on_table(table, FALSE);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2475
2476
	info = pars_info_create();
2477
2478
	pars_info_add_str_literal(info, "table_name", name);
1819.9.31 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB
2479
	pars_info_add_ull_literal(info, "new_id", new_id);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2480
2481
	err = que_eval_sql(info,
2482
			   "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2483
			   "old_id CHAR;\n"
2484
			   "BEGIN\n"
2485
			   "SELECT ID INTO old_id\n"
2486
			   "FROM SYS_TABLES\n"
2487
			   "WHERE NAME = :table_name\n"
2488
			   "LOCK IN SHARE MODE;\n"
2489
			   "IF (SQL % NOTFOUND) THEN\n"
2490
			   "       COMMIT WORK;\n"
2491
			   "       RETURN;\n"
2492
			   "END IF;\n"
2493
			   "UPDATE SYS_TABLES SET ID = :new_id\n"
2494
			   " WHERE ID = old_id;\n"
2495
			   "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2496
			   " WHERE TABLE_ID = old_id;\n"
2497
			   "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2498
			   " WHERE TABLE_ID = old_id;\n"
2499
			   "COMMIT WORK;\n"
2500
			   "END;\n"
2501
			   , FALSE, trx);
2502
2503
	if (err != DB_SUCCESS) {
2504
		trx->error_state = DB_SUCCESS;
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
2505
		trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2506
		trx->error_state = DB_SUCCESS;
2507
	} else {
2508
		dict_table_change_id_in_cache(table, new_id);
2509
2510
		success = fil_discard_tablespace(table->space);
2511
2512
		if (!success) {
2513
			trx->error_state = DB_SUCCESS;
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
2514
			trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2515
			trx->error_state = DB_SUCCESS;
2516
2517
			err = DB_ERROR;
2518
		} else {
2519
			/* Set the flag which tells that now it is legal to
2520
			IMPORT a tablespace for this table */
2521
			table->tablespace_discarded = TRUE;
2522
			table->ibd_file_missing = TRUE;
2523
		}
2524
	}
2525
2526
funct_exit:
2527
	trx_commit_for_mysql(trx);
2528
2529
	row_mysql_unlock_data_dictionary(trx);
2530
2531
	trx->op_info = "";
2532
2533
	return((int) err);
2534
}
2535
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2536
/*****************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2537
Imports a tablespace. The space id in the .ibd file must match the space id
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2538
of the table in the data dictionary.
2539
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2540
UNIV_INTERN
2541
int
2542
row_import_tablespace_for_mysql(
2543
/*============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2544
	const char*	name,	/*!< in: table name */
2545
	trx_t*		trx)	/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2546
{
2547
	dict_table_t*	table;
2548
	ibool		success;
2549
	ib_uint64_t	current_lsn;
2550
	ulint		err		= DB_SUCCESS;
2551
2552
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2553
2554
	trx_start_if_not_started(trx);
2555
2556
	trx->op_info = "importing tablespace";
2557
2558
	current_lsn = log_get_lsn();
2559
2560
	/* It is possible, though very improbable, that the lsn's in the
2561
	tablespace to be imported have risen above the current system lsn, if
2562
	a lengthy purge, ibuf merge, or rollback was performed on a backup
2563
	taken with ibbackup. If that is the case, reset page lsn's in the
2564
	file. We assume that mysqld was shut down after it performed these
2565
	cleanup operations on the .ibd file, so that it stamped the latest lsn
2566
	to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2567
2568
	TODO: reset also the trx id's in clustered index records and write
2569
	a new space id to each data page. That would allow us to import clean
2570
	.ibd files from another MySQL installation. */
2571
2572
	success = fil_reset_too_high_lsns(name, current_lsn);
2573
2574
	if (!success) {
2575
		ut_print_timestamp(stderr);
2576
		fputs("  InnoDB: Error: cannot reset lsn's in table ", stderr);
2577
		ut_print_name(stderr, trx, TRUE, name);
2578
		fputs("\n"
2579
		      "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2580
		      stderr);
2581
2582
		err = DB_ERROR;
2583
2584
		row_mysql_lock_data_dictionary(trx);
2585
2586
		goto funct_exit;
2587
	}
2588
2589
	/* Serialize data dictionary operations with dictionary mutex:
2590
	no deadlocks can occur then in these operations */
2591
2592
	row_mysql_lock_data_dictionary(trx);
2593
2594
	table = dict_table_get_low(name);
2595
2596
	if (!table) {
2597
		ut_print_timestamp(stderr);
2598
		fputs("  InnoDB: table ", stderr);
2599
		ut_print_name(stderr, trx, TRUE, name);
2600
		fputs("\n"
2601
		      "InnoDB: does not exist in the InnoDB data dictionary\n"
2602
		      "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2603
		      stderr);
2604
2605
		err = DB_TABLE_NOT_FOUND;
2606
2607
		goto funct_exit;
2608
	}
2609
2610
	if (table->space == 0) {
2611
		ut_print_timestamp(stderr);
2612
		fputs("  InnoDB: Error: table ", stderr);
2613
		ut_print_name(stderr, trx, TRUE, name);
2614
		fputs("\n"
2615
		      "InnoDB: is in the system tablespace 0"
2616
		      " which cannot be imported\n", stderr);
2617
		err = DB_ERROR;
2618
2619
		goto funct_exit;
2620
	}
2621
2622
	if (!table->tablespace_discarded) {
2623
		ut_print_timestamp(stderr);
2624
		fputs("  InnoDB: Error: you are trying to"
2625
		      " IMPORT a tablespace\n"
2626
		      "InnoDB: ", stderr);
2627
		ut_print_name(stderr, trx, TRUE, name);
2628
		fputs(", though you have not called DISCARD on it yet\n"
2629
		      "InnoDB: during the lifetime of the mysqld process!\n",
2630
		      stderr);
2631
2632
		err = DB_ERROR;
2633
2634
		goto funct_exit;
2635
	}
2636
2637
	/* Play safe and remove all insert buffer entries, though we should
2638
	have removed them already when DISCARD TABLESPACE was called */
2639
2640
	ibuf_delete_for_discarded_space(table->space);
2641
2642
	success = fil_open_single_table_tablespace(
2643
		TRUE, table->space,
2644
		table->flags == DICT_TF_COMPACT ? 0 : table->flags,
2645
		table->name);
2646
	if (success) {
2647
		table->ibd_file_missing = FALSE;
2648
		table->tablespace_discarded = FALSE;
2649
	} else {
2650
		if (table->ibd_file_missing) {
2651
			ut_print_timestamp(stderr);
2652
			fputs("  InnoDB: cannot find or open in the"
2653
			      " database directory the .ibd file of\n"
2654
			      "InnoDB: table ", stderr);
2655
			ut_print_name(stderr, trx, TRUE, name);
2656
			fputs("\n"
2657
			      "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2658
			      stderr);
2659
		}
2660
2661
		err = DB_ERROR;
2662
	}
2663
2664
funct_exit:
2665
	trx_commit_for_mysql(trx);
2666
2667
	row_mysql_unlock_data_dictionary(trx);
2668
2669
	trx->op_info = "";
2670
2671
	return((int) err);
2672
}
2673
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2674
/*********************************************************************//**
2675
Truncates a table for MySQL.
2676
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2677
UNIV_INTERN
2678
int
2679
row_truncate_table_for_mysql(
2680
/*=========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
2681
	dict_table_t*	table,	/*!< in: table handle */
2682
	trx_t*		trx)	/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2683
{
2684
	dict_foreign_t*	foreign;
2685
	ulint		err;
2686
	mem_heap_t*	heap;
2687
	byte*		buf;
2688
	dtuple_t*	tuple;
2689
	dfield_t*	dfield;
2690
	dict_index_t*	sys_index;
2691
	btr_pcur_t	pcur;
2692
	mtr_t		mtr;
1819.9.31 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB
2693
	table_id_t	new_id;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2694
	ulint		recreate_space = 0;
2695
	pars_info_t*	info = NULL;
2696
2697
	/* How do we prevent crashes caused by ongoing operations on
2698
	the table? Old operations could try to access non-existent
2699
	pages.
2700
2701
	1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2702
	MySQL table lock on the table before we can do TRUNCATE
2703
	TABLE. Then there are no running queries on the table. This is
2704
	guaranteed, because in ha_innobase::store_lock(), we do not
2705
	weaken the TL_WRITE lock requested by MySQL when executing
2706
	SQLCOM_TRUNCATE.
2707
2708
	2) Purge and rollback: we assign a new table id for the
2709
	table. Since purge and rollback look for the table based on
2710
	the table id, they see the table as 'dropped' and discard
2711
	their operations.
2712
2713
	3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2714
	so we do not have to remove insert buffer records, as the
2715
	insert buffer works at a low level. If a freed page is later
2716
	reallocated, the allocator will remove the ibuf entries for
2717
	it.
2718
2719
	When we truncate *.ibd files by recreating them (analogous to
2720
	DISCARD TABLESPACE), we remove all entries for the table in the
2721
	insert buffer tree.  This is not strictly necessary, because
2722
	in 6) we will assign a new tablespace identifier, but we can
2723
	free up some space in the system tablespace.
2724
2725
	4) Linear readahead and random readahead: we use the same
2726
	method as in 3) to discard ongoing operations. (This is only
2727
	relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2728
2729
	5) FOREIGN KEY operations: if
2730
	table->n_foreign_key_checks_running > 0, we do not allow the
2731
	TRUNCATE. We also reserve the data dictionary latch.
2732
2733
	6) Crash recovery: To prevent the application of pre-truncation
2734
	redo log records on the truncated tablespace, we will assign
2735
	a new tablespace identifier to the truncated tablespace. */
2736
2737
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2738
	ut_ad(table);
2739
2740
	if (srv_created_new_raw) {
2741
		fputs("InnoDB: A new raw disk partition was initialized:\n"
2742
		      "InnoDB: we do not allow database modifications"
2743
		      " by the user.\n"
2744
		      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2745
		      " is replaced with raw.\n", stderr);
2746
2747
		return(DB_ERROR);
2748
	}
2749
2750
	trx->op_info = "truncating table";
2751
2752
	trx_start_if_not_started(trx);
2753
2754
	/* Serialize data dictionary operations with dictionary mutex:
2755
	no deadlocks can occur then in these operations */
2756
2757
	ut_a(trx->dict_operation_lock_mode == 0);
2758
	/* Prevent foreign key checks etc. while we are truncating the
2759
	table */
2760
2761
	row_mysql_lock_data_dictionary(trx);
2762
2763
	ut_ad(mutex_own(&(dict_sys->mutex)));
2764
#ifdef UNIV_SYNC_DEBUG
2765
	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2766
#endif /* UNIV_SYNC_DEBUG */
2767
2768
	/* Check if the table is referenced by foreign key constraints from
2769
	some other table (not the table itself) */
2770
2771
	foreign = UT_LIST_GET_FIRST(table->referenced_list);
2772
2773
	while (foreign && foreign->foreign_table == table) {
2774
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2775
	}
2776
2777
	if (foreign && trx->check_foreigns) {
2778
		FILE*	ef	= dict_foreign_err_file;
2779
2780
		/* We only allow truncating a referenced table if
2781
		FOREIGN_KEY_CHECKS is set to 0 */
2782
2783
		mutex_enter(&dict_foreign_err_mutex);
2784
		rewind(ef);
2785
		ut_print_timestamp(ef);
2786
2787
		fputs("  Cannot truncate table ", ef);
2788
		ut_print_name(ef, trx, TRUE, table->name);
2789
		fputs(" by DROP+CREATE\n"
2790
		      "InnoDB: because it is referenced by ", ef);
2791
		ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2792
		putc('\n', ef);
2793
		mutex_exit(&dict_foreign_err_mutex);
2794
2795
		err = DB_ERROR;
2796
		goto funct_exit;
2797
	}
2798
2799
	/* TODO: could we replace the counter n_foreign_key_checks_running
2800
	with lock checks on the table? Acquire here an exclusive lock on the
2801
	table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2802
	they can cope with the table having been truncated here? Foreign key
2803
	checks take an IS or IX lock on the table. */
2804
2805
	if (table->n_foreign_key_checks_running > 0) {
2806
		ut_print_timestamp(stderr);
2807
		fputs("  InnoDB: Cannot truncate table ", stderr);
2808
		ut_print_name(stderr, trx, TRUE, table->name);
2809
		fputs(" by DROP+CREATE\n"
2810
		      "InnoDB: because there is a foreign key check"
2811
		      " running on it.\n",
2812
		      stderr);
2813
		err = DB_ERROR;
2814
2815
		goto funct_exit;
2816
	}
2817
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
2818
	/* Remove all locks except the table-level S and X locks. */
2819
	lock_remove_all_on_table(table, FALSE);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2820
2821
	trx->table_id = table->id;
2822
2823
	if (table->space && !table->dir_path_of_temp_table) {
2824
		/* Discard and create the single-table tablespace. */
2825
		ulint	space	= table->space;
2826
		ulint	flags	= fil_space_get_flags(space);
2827
2828
		if (flags != ULINT_UNDEFINED
2829
		    && fil_discard_tablespace(space)) {
2830
2831
			dict_index_t*	index;
2832
1819.7.140 by Marko Mäkelä
Merge Revision revid:marko.makela@oracle.com-20100524114524-gih3txff2p9rz4rs from MySQL InnoDB
2833
			dict_hdr_get_new_id(NULL, NULL, &space);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2834
1819.9.178 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101025033151-m3n4moml1868uobt from MySQL InnoDB
2835
			/* Lock all index trees for this table. We must
2836
			do so after dict_hdr_get_new_id() to preserve
2837
			the latch order */
2838
			dict_table_x_lock_indexes(table);
2839
1819.7.140 by Marko Mäkelä
Merge Revision revid:marko.makela@oracle.com-20100524114524-gih3txff2p9rz4rs from MySQL InnoDB
2840
			if (space == ULINT_UNDEFINED
2841
			    || fil_create_new_single_table_tablespace(
2842
				    space, table->name, FALSE, flags,
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2843
				    FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
1819.9.88 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20100804103744-vbpeghipkz6pyc9z from MySQL InnoDB
2844
				dict_table_x_unlock_indexes(table);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2845
				ut_print_timestamp(stderr);
2846
				fprintf(stderr,
2847
					"  InnoDB: TRUNCATE TABLE %s failed to"
2848
					" create a new tablespace\n",
2849
					table->name);
2850
				table->ibd_file_missing = 1;
2851
				err = DB_ERROR;
2852
				goto funct_exit;
2853
			}
2854
2855
			recreate_space = space;
2856
2857
			/* Replace the space_id in the data dictionary cache.
2858
			The persisent data dictionary (SYS_TABLES.SPACE
2859
			and SYS_INDEXES.SPACE) are updated later in this
2860
			function. */
2861
			table->space = space;
2862
			index = dict_table_get_first_index(table);
2863
			do {
2864
				index->space = space;
2865
				index = dict_table_get_next_index(index);
2866
			} while (index);
2867
2868
			mtr_start(&mtr);
2869
			fsp_header_init(space,
2870
					FIL_IBD_FILE_INITIAL_SIZE, &mtr);
2871
			mtr_commit(&mtr);
2872
		}
1819.9.178 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101025033151-m3n4moml1868uobt from MySQL InnoDB
2873
	} else {
2874
		/* Lock all index trees for this table, as we will
2875
		truncate the table/index and possibly change their metadata.
2876
		All DML/DDL are blocked by table level lock, with
2877
		a few exceptions such as queries into information schema
2878
		about the table, MySQL could try to access index stats
2879
		for this kind of query, we need to use index locks to
2880
		sync up */
2881
		dict_table_x_lock_indexes(table);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2882
	}
2883
2884
	/* scan SYS_INDEXES for all indexes of the table */
2885
	heap = mem_heap_create(800);
2886
2887
	tuple = dtuple_create(heap, 1);
2888
	dfield = dtuple_get_nth_field(tuple, 0);
2889
2890
	buf = mem_heap_alloc(heap, 8);
2891
	mach_write_to_8(buf, table->id);
2892
2893
	dfield_set_data(dfield, buf, 8);
2894
	sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2895
	dict_index_copy_types(tuple, sys_index, 1);
2896
2897
	mtr_start(&mtr);
2898
	btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2899
				  BTR_MODIFY_LEAF, &pcur, &mtr);
2900
	for (;;) {
2901
		rec_t*		rec;
2902
		const byte*	field;
2903
		ulint		len;
2904
		ulint		root_page_no;
2905
2906
		if (!btr_pcur_is_on_user_rec(&pcur)) {
2907
			/* The end of SYS_INDEXES has been reached. */
2908
			break;
2909
		}
2910
2911
		rec = btr_pcur_get_rec(&pcur);
2912
2913
		field = rec_get_nth_field_old(rec, 0, &len);
2914
		ut_ad(len == 8);
2915
2916
		if (memcmp(buf, field, len) != 0) {
2917
			/* End of indexes for the table (TABLE_ID mismatch). */
2918
			break;
2919
		}
2920
2921
		if (rec_get_deleted_flag(rec, FALSE)) {
2922
			/* The index has been dropped. */
2923
			goto next_rec;
2924
		}
2925
2926
		/* This call may commit and restart mtr
2927
		and reposition pcur. */
2928
		root_page_no = dict_truncate_index_tree(table, recreate_space,
2929
							&pcur, &mtr);
2930
2931
		rec = btr_pcur_get_rec(&pcur);
2932
2933
		if (root_page_no != FIL_NULL) {
2934
			page_rec_write_index_page_no(
2935
				rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2936
				root_page_no, &mtr);
2937
			/* We will need to commit and restart the
2938
			mini-transaction in order to avoid deadlocks.
2939
			The dict_truncate_index_tree() call has allocated
2940
			a page in this mini-transaction, and the rest of
2941
			this loop could latch another index page. */
2942
			mtr_commit(&mtr);
2943
			mtr_start(&mtr);
2944
			btr_pcur_restore_position(BTR_MODIFY_LEAF,
2945
						  &pcur, &mtr);
2946
		}
2947
2948
next_rec:
2949
		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2950
	}
2951
2952
	btr_pcur_close(&pcur);
2953
	mtr_commit(&mtr);
2954
2955
	mem_heap_free(heap);
2956
1819.9.88 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20100804103744-vbpeghipkz6pyc9z from MySQL InnoDB
2957
	/* Done with index truncation, release index tree locks,
2958
	subsequent work relates to table level metadata change */
2959
	dict_table_x_unlock_indexes(table);
2960
1819.7.140 by Marko Mäkelä
Merge Revision revid:marko.makela@oracle.com-20100524114524-gih3txff2p9rz4rs from MySQL InnoDB
2961
	dict_hdr_get_new_id(&new_id, NULL, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2962
2963
	info = pars_info_create();
2964
2965
	pars_info_add_int4_literal(info, "space", (lint) table->space);
1819.9.31 by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB
2966
	pars_info_add_ull_literal(info, "old_id", table->id);
2967
	pars_info_add_ull_literal(info, "new_id", new_id);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2968
2969
	err = que_eval_sql(info,
2970
			   "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2971
			   "BEGIN\n"
2972
			   "UPDATE SYS_TABLES"
2973
			   " SET ID = :new_id, SPACE = :space\n"
2974
			   " WHERE ID = :old_id;\n"
2975
			   "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2976
			   " WHERE TABLE_ID = :old_id;\n"
2977
			   "UPDATE SYS_INDEXES"
2978
			   " SET TABLE_ID = :new_id, SPACE = :space\n"
2979
			   " WHERE TABLE_ID = :old_id;\n"
2980
			   "COMMIT WORK;\n"
2981
			   "END;\n"
2982
			   , FALSE, trx);
2983
2984
	if (err != DB_SUCCESS) {
2985
		trx->error_state = DB_SUCCESS;
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
2986
		trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
2987
		trx->error_state = DB_SUCCESS;
2988
		ut_print_timestamp(stderr);
2989
		fputs("  InnoDB: Unable to assign a new identifier to table ",
2990
		      stderr);
2991
		ut_print_name(stderr, trx, TRUE, table->name);
2992
		fputs("\n"
2993
		      "InnoDB: after truncating it.  Background processes"
2994
		      " may corrupt the table!\n", stderr);
2995
		err = DB_ERROR;
2996
	} else {
2997
		dict_table_change_id_in_cache(table, new_id);
2998
	}
2999
1210 by Brian Aker
Merge new Truncate
3000
	/* 
3001
          MySQL calls ha_innobase::reset_auto_increment() which does
3002
          the same thing. 
3003
        */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3004
	dict_table_autoinc_lock(table);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
3005
	dict_table_autoinc_initialize(table, 1);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3006
	dict_table_autoinc_unlock(table);
1819.9.194 by Vasil Dimov, Stewart Smith
Merge Revision revid:vasil.dimov@oracle.com-20101102165720-164z3666y3tut4c2 from MySQL InnoDB
3007
	dict_update_statistics(table, FALSE /* update even if stats are
3008
					    initialized */);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3009
3010
	trx_commit_for_mysql(trx);
3011
3012
funct_exit:
3013
3014
	row_mysql_unlock_data_dictionary(trx);
3015
3016
	trx->op_info = "";
3017
3018
	srv_wake_master_thread();
3019
3020
	return((int) err);
3021
}
3022
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3023
/*********************************************************************//**
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
3024
Drops a table for MySQL.  If the name of the dropped table ends in
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3025
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
3026
"innodb_table_monitor", then this will also stop the printing of monitor
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
3027
output by the master thread.  If the data dictionary was not already locked
3028
by the transaction, the transaction will be committed.  Otherwise, the
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3029
data dictionary will remain locked.
3030
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3031
UNIV_INTERN
3032
int
3033
row_drop_table_for_mysql(
3034
/*=====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3035
	const char*	name,	/*!< in: table name */
3036
	trx_t*		trx,	/*!< in: transaction handle */
3037
	ibool		drop_db)/*!< in: TRUE=dropping whole database */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3038
{
3039
	dict_foreign_t*	foreign;
3040
	dict_table_t*	table;
3041
	ulint		space_id;
3042
	ulint		err;
3043
	const char*	table_name;
3044
	ulint		namelen;
3045
	ibool		locked_dictionary	= FALSE;
3046
	pars_info_t*    info			= NULL;
3047
3048
	ut_a(name != NULL);
3049
3050
	if (srv_created_new_raw) {
3051
		fputs("InnoDB: A new raw disk partition was initialized:\n"
3052
		      "InnoDB: we do not allow database modifications"
3053
		      " by the user.\n"
3054
		      "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
3055
		      " is replaced with raw.\n", stderr);
3056
3057
		return(DB_ERROR);
3058
	}
3059
3060
	trx->op_info = "dropping table";
3061
3062
	trx_start_if_not_started(trx);
3063
3064
	/* The table name is prefixed with the database name and a '/'.
3065
	Certain table names starting with 'innodb_' have their special
3066
	meaning regardless of the database name.  Thus, we need to
3067
	ignore the database name prefix in the comparisons. */
3068
	table_name = strchr(name, '/');
3069
	ut_a(table_name);
3070
	table_name++;
3071
	namelen = strlen(table_name) + 1;
3072
3073
	if (namelen == sizeof S_innodb_monitor
3074
	    && !memcmp(table_name, S_innodb_monitor,
3075
		       sizeof S_innodb_monitor)) {
3076
3077
		/* Table name equals "innodb_monitor":
3078
		stop monitor prints */
3079
3080
		srv_print_innodb_monitor = FALSE;
3081
		srv_print_innodb_lock_monitor = FALSE;
3082
	} else if (namelen == sizeof S_innodb_lock_monitor
3083
		   && !memcmp(table_name, S_innodb_lock_monitor,
3084
			      sizeof S_innodb_lock_monitor)) {
3085
		srv_print_innodb_monitor = FALSE;
3086
		srv_print_innodb_lock_monitor = FALSE;
3087
	} else if (namelen == sizeof S_innodb_tablespace_monitor
3088
		   && !memcmp(table_name, S_innodb_tablespace_monitor,
3089
			      sizeof S_innodb_tablespace_monitor)) {
3090
3091
		srv_print_innodb_tablespace_monitor = FALSE;
3092
	} else if (namelen == sizeof S_innodb_table_monitor
3093
		   && !memcmp(table_name, S_innodb_table_monitor,
3094
			      sizeof S_innodb_table_monitor)) {
3095
3096
		srv_print_innodb_table_monitor = FALSE;
3097
	}
3098
3099
	/* Serialize data dictionary operations with dictionary mutex:
3100
	no deadlocks can occur then in these operations */
3101
3102
	if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3103
		/* Prevent foreign key checks etc. while we are dropping the
3104
		table */
3105
3106
		row_mysql_lock_data_dictionary(trx);
3107
3108
		locked_dictionary = TRUE;
3109
	}
3110
3111
	ut_ad(mutex_own(&(dict_sys->mutex)));
3112
#ifdef UNIV_SYNC_DEBUG
3113
	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3114
#endif /* UNIV_SYNC_DEBUG */
3115
3116
	table = dict_table_get_low(name);
3117
3118
	if (!table) {
1114.1.1 by Monty Taylor
Merged InnoDB Plugin 1.0.4
3119
#if defined(BUILD_DRIZZLE)
641.1.4 by Monty Taylor
Merged in InnoDB changes.
3120
		err = ENOENT;
1114.1.1 by Monty Taylor
Merged InnoDB Plugin 1.0.4
3121
#else
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3122
		err = DB_TABLE_NOT_FOUND;
3123
		ut_print_timestamp(stderr);
3124
3125
		fputs("  InnoDB: Error: table ", stderr);
3126
		ut_print_name(stderr, trx, TRUE, name);
3127
		fputs(" does not exist in the InnoDB internal\n"
3128
		      "InnoDB: data dictionary though MySQL is"
3129
		      " trying to drop it.\n"
3130
		      "InnoDB: Have you copied the .frm file"
3131
		      " of the table to the\n"
3132
		      "InnoDB: MySQL database directory"
3133
		      " from another database?\n"
3134
		      "InnoDB: You can look for further help from\n"
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3135
		      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3136
		      stderr);
1114.1.1 by Monty Taylor
Merged InnoDB Plugin 1.0.4
3137
#endif /* BUILD_DRIZZLE */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3138
		goto funct_exit;
3139
	}
3140
3141
	/* Check if the table is referenced by foreign key constraints from
3142
	some other table (not the table itself) */
3143
3144
	foreign = UT_LIST_GET_FIRST(table->referenced_list);
3145
3146
	while (foreign && foreign->foreign_table == table) {
3147
check_next_foreign:
3148
		foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3149
	}
3150
3151
	if (foreign && trx->check_foreigns
3152
	    && !(drop_db && dict_tables_have_same_db(
3153
			 name, foreign->foreign_table_name))) {
3154
		FILE*	ef	= dict_foreign_err_file;
3155
3156
		/* We only allow dropping a referenced table if
3157
		FOREIGN_KEY_CHECKS is set to 0 */
3158
3159
		err = DB_CANNOT_DROP_CONSTRAINT;
3160
3161
		mutex_enter(&dict_foreign_err_mutex);
3162
		rewind(ef);
3163
		ut_print_timestamp(ef);
3164
3165
		fputs("  Cannot drop table ", ef);
3166
		ut_print_name(ef, trx, TRUE, name);
3167
		fputs("\n"
3168
		      "because it is referenced by ", ef);
3169
		ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3170
		putc('\n', ef);
3171
		mutex_exit(&dict_foreign_err_mutex);
3172
3173
		goto funct_exit;
3174
	}
3175
3176
	if (foreign && trx->check_foreigns) {
3177
		goto check_next_foreign;
3178
	}
3179
3180
	if (table->n_mysql_handles_opened > 0) {
3181
		ibool	added;
3182
3183
		added = row_add_table_to_background_drop_list(table->name);
3184
3185
		if (added) {
3186
			ut_print_timestamp(stderr);
3187
			fputs("  InnoDB: Warning: MySQL is"
3188
			      " trying to drop table ", stderr);
3189
			ut_print_name(stderr, trx, TRUE, table->name);
3190
			fputs("\n"
3191
			      "InnoDB: though there are still"
3192
			      " open handles to it.\n"
3193
			      "InnoDB: Adding the table to the"
3194
			      " background drop queue.\n",
3195
			      stderr);
3196
3197
			/* We return DB_SUCCESS to MySQL though the drop will
3198
			happen lazily later */
3199
			err = DB_SUCCESS;
3200
		} else {
3201
			/* The table is already in the background drop list */
3202
			err = DB_ERROR;
3203
		}
3204
3205
		goto funct_exit;
3206
	}
3207
3208
	/* TODO: could we replace the counter n_foreign_key_checks_running
3209
	with lock checks on the table? Acquire here an exclusive lock on the
3210
	table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3211
	they can cope with the table having been dropped here? Foreign key
3212
	checks take an IS or IX lock on the table. */
3213
3214
	if (table->n_foreign_key_checks_running > 0) {
3215
3216
		const char*	table_name = table->name;
3217
		ibool		added;
3218
3219
		added = row_add_table_to_background_drop_list(table_name);
3220
3221
		if (added) {
3222
			ut_print_timestamp(stderr);
3223
			fputs("  InnoDB: You are trying to drop table ",
3224
			      stderr);
3225
			ut_print_name(stderr, trx, TRUE, table_name);
3226
			fputs("\n"
3227
			      "InnoDB: though there is a"
3228
			      " foreign key check running on it.\n"
3229
			      "InnoDB: Adding the table to"
3230
			      " the background drop queue.\n",
3231
			      stderr);
3232
3233
			/* We return DB_SUCCESS to MySQL though the drop will
3234
			happen lazily later */
3235
3236
			err = DB_SUCCESS;
3237
		} else {
3238
			/* The table is already in the background drop list */
3239
			err = DB_ERROR;
3240
		}
3241
3242
		goto funct_exit;
3243
	}
3244
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
3245
	/* Remove all locks there are on the table or its records */
3246
	lock_remove_all_on_table(table, TRUE);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3247
3248
	trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
3249
	trx->table_id = table->id;
3250
3251
	/* We use the private SQL parser of Innobase to generate the
3252
	query graphs needed in deleting the dictionary data from system
3253
	tables in Innobase. Deleting a row from SYS_INDEXES table also
3254
	frees the file segments of the B-tree associated with the index. */
3255
3256
	info = pars_info_create();
3257
3258
	pars_info_add_str_literal(info, "table_name", name);
3259
3260
	err = que_eval_sql(info,
3261
			   "PROCEDURE DROP_TABLE_PROC () IS\n"
3262
			   "sys_foreign_id CHAR;\n"
3263
			   "table_id CHAR;\n"
3264
			   "index_id CHAR;\n"
3265
			   "foreign_id CHAR;\n"
3266
			   "found INT;\n"
3267
			   "BEGIN\n"
3268
			   "SELECT ID INTO table_id\n"
3269
			   "FROM SYS_TABLES\n"
3270
			   "WHERE NAME = :table_name\n"
3271
			   "LOCK IN SHARE MODE;\n"
3272
			   "IF (SQL % NOTFOUND) THEN\n"
3273
			   "       RETURN;\n"
3274
			   "END IF;\n"
3275
			   "found := 1;\n"
3276
			   "SELECT ID INTO sys_foreign_id\n"
3277
			   "FROM SYS_TABLES\n"
3278
			   "WHERE NAME = 'SYS_FOREIGN'\n"
3279
			   "LOCK IN SHARE MODE;\n"
3280
			   "IF (SQL % NOTFOUND) THEN\n"
3281
			   "       found := 0;\n"
3282
			   "END IF;\n"
3283
			   "IF (:table_name = 'SYS_FOREIGN') THEN\n"
3284
			   "       found := 0;\n"
3285
			   "END IF;\n"
3286
			   "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3287
			   "       found := 0;\n"
3288
			   "END IF;\n"
3289
			   "WHILE found = 1 LOOP\n"
3290
			   "       SELECT ID INTO foreign_id\n"
3291
			   "       FROM SYS_FOREIGN\n"
3292
			   "       WHERE FOR_NAME = :table_name\n"
3293
			   "               AND TO_BINARY(FOR_NAME)\n"
3294
			   "                 = TO_BINARY(:table_name)\n"
3295
			   "               LOCK IN SHARE MODE;\n"
3296
			   "       IF (SQL % NOTFOUND) THEN\n"
3297
			   "               found := 0;\n"
3298
			   "       ELSE\n"
3299
			   "               DELETE FROM SYS_FOREIGN_COLS\n"
3300
			   "               WHERE ID = foreign_id;\n"
3301
			   "               DELETE FROM SYS_FOREIGN\n"
3302
			   "               WHERE ID = foreign_id;\n"
3303
			   "       END IF;\n"
3304
			   "END LOOP;\n"
3305
			   "found := 1;\n"
3306
			   "WHILE found = 1 LOOP\n"
3307
			   "       SELECT ID INTO index_id\n"
3308
			   "       FROM SYS_INDEXES\n"
3309
			   "       WHERE TABLE_ID = table_id\n"
3310
			   "       LOCK IN SHARE MODE;\n"
3311
			   "       IF (SQL % NOTFOUND) THEN\n"
3312
			   "               found := 0;\n"
3313
			   "       ELSE\n"
3314
			   "               DELETE FROM SYS_FIELDS\n"
3315
			   "               WHERE INDEX_ID = index_id;\n"
3316
			   "               DELETE FROM SYS_INDEXES\n"
3317
			   "               WHERE ID = index_id\n"
3318
			   "               AND TABLE_ID = table_id;\n"
3319
			   "       END IF;\n"
3320
			   "END LOOP;\n"
3321
			   "DELETE FROM SYS_COLUMNS\n"
3322
			   "WHERE TABLE_ID = table_id;\n"
3323
			   "DELETE FROM SYS_TABLES\n"
3324
			   "WHERE ID = table_id;\n"
3325
			   "END;\n"
3326
			   , FALSE, trx);
3327
1819.5.164 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6425 from MySQL InnoDB
3328
	switch (err) {
1819.5.129 by stewart at flamingspork
[patch 129/129] Merge patch for revision 1947 from InnoDB SVN:
3329
		ibool		is_temp;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3330
		const char*	name_or_path;
3331
		mem_heap_t*	heap;
3332
1819.5.164 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6425 from MySQL InnoDB
3333
	case DB_SUCCESS:
3334
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3335
		heap = mem_heap_create(200);
3336
3337
		/* Clone the name, in case it has been allocated
3338
		from table->heap, which will be freed by
3339
		dict_table_remove_from_cache(table) below. */
3340
		name = mem_heap_strdup(heap, name);
3341
		space_id = table->space;
3342
3343
		if (table->dir_path_of_temp_table != NULL) {
3344
			name_or_path = mem_heap_strdup(
3345
				heap, table->dir_path_of_temp_table);
1819.5.129 by stewart at flamingspork
[patch 129/129] Merge patch for revision 1947 from InnoDB SVN:
3346
			is_temp = TRUE;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3347
		} else {
3348
			name_or_path = name;
1819.5.129 by stewart at flamingspork
[patch 129/129] Merge patch for revision 1947 from InnoDB SVN:
3349
			is_temp = (table->flags >> DICT_TF2_SHIFT)
3350
				& DICT_TF2_TEMPORARY;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3351
		}
3352
3353
		dict_table_remove_from_cache(table);
3354
1819.7.143 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20100526014433-bx0t9794mnvkiaft from MySQL InnoDB
3355
		if (dict_load_table(name, TRUE) != NULL) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3356
			ut_print_timestamp(stderr);
3357
			fputs("  InnoDB: Error: not able to remove table ",
3358
			      stderr);
3359
			ut_print_name(stderr, trx, TRUE, name);
3360
			fputs(" from the dictionary cache!\n", stderr);
3361
			err = DB_ERROR;
3362
		}
3363
3364
		/* Do not drop possible .ibd tablespace if something went
3365
		wrong: we do not want to delete valuable data of the user */
3366
3367
		if (err == DB_SUCCESS && space_id > 0) {
3368
			if (!fil_space_for_table_exists_in_mem(space_id,
3369
							       name_or_path,
1819.5.129 by stewart at flamingspork
[patch 129/129] Merge patch for revision 1947 from InnoDB SVN:
3370
							       is_temp, FALSE,
3371
							       !is_temp)) {
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3372
				err = DB_SUCCESS;
3373
3374
				fprintf(stderr,
3375
					"InnoDB: We removed now the InnoDB"
3376
					" internal data dictionary entry\n"
3377
					"InnoDB: of table ");
3378
				ut_print_name(stderr, trx, TRUE, name);
3379
				fprintf(stderr, ".\n");
3380
			} else if (!fil_delete_tablespace(space_id)) {
3381
				fprintf(stderr,
3382
					"InnoDB: We removed now the InnoDB"
3383
					" internal data dictionary entry\n"
3384
					"InnoDB: of table ");
3385
				ut_print_name(stderr, trx, TRUE, name);
3386
				fprintf(stderr, ".\n");
3387
3388
				ut_print_timestamp(stderr);
3389
				fprintf(stderr,
3390
					"  InnoDB: Error: not able to"
3391
					" delete tablespace %lu of table ",
3392
					(ulong) space_id);
3393
				ut_print_name(stderr, trx, TRUE, name);
3394
				fputs("!\n", stderr);
3395
				err = DB_ERROR;
3396
			}
3397
		}
3398
3399
		mem_heap_free(heap);
1819.5.164 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6425 from MySQL InnoDB
3400
		break;
3401
3402
	case DB_TOO_MANY_CONCURRENT_TRXS:
3403
		/* Cannot even find a free slot for the
3404
		the undo log. We can directly exit here
3405
		and return the DB_TOO_MANY_CONCURRENT_TRXS
3406
		error. */
3407
		break;
3408
3409
	case DB_OUT_OF_FILE_SPACE:
3410
		err = DB_MUST_GET_MORE_FILE_SPACE;
3411
3412
		row_mysql_handle_errors(&err, trx, NULL, NULL);
3413
3414
		/* Fall through to raise error */
3415
3416
	default:
3417
		/* No other possible error returns */
3418
		ut_error;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3419
	}
1819.5.164 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6425 from MySQL InnoDB
3420
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3421
funct_exit:
3422
3423
	if (locked_dictionary) {
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
3424
		trx_commit_for_mysql(trx);
3425
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3426
		row_mysql_unlock_data_dictionary(trx);
3427
	}
3428
3429
	trx->op_info = "";
3430
3431
	srv_wake_master_thread();
3432
3433
	return((int) err);
3434
}
3435
1819.5.176 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6521 from MySQL InnoDB
3436
/*********************************************************************//**
3437
Drop all temporary tables during crash recovery. */
3438
UNIV_INTERN
3439
void
3440
row_mysql_drop_temp_tables(void)
3441
/*============================*/
3442
{
1819.5.195 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6610 from MySQL InnoDB
3443
	trx_t*		trx;
3444
	btr_pcur_t	pcur;
3445
	mtr_t		mtr;
3446
	mem_heap_t*	heap;
1819.5.176 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6521 from MySQL InnoDB
3447
3448
	trx = trx_allocate_for_background();
3449
	trx->op_info = "dropping temporary tables";
3450
	row_mysql_lock_data_dictionary(trx);
3451
1819.5.195 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6610 from MySQL InnoDB
3452
	heap = mem_heap_create(200);
3453
3454
	mtr_start(&mtr);
3455
3456
	btr_pcur_open_at_index_side(
3457
		TRUE,
3458
		dict_table_get_first_index(dict_sys->sys_tables),
3459
		BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3460
3461
	for (;;) {
3462
		const rec_t*	rec;
3463
		const byte*	field;
3464
		ulint		len;
3465
		const char*	table_name;
3466
		dict_table_t*	table;
3467
3468
		btr_pcur_move_to_next_user_rec(&pcur, &mtr);
3469
3470
		if (!btr_pcur_is_on_user_rec(&pcur)) {
3471
			break;
3472
		}
3473
3474
		rec = btr_pcur_get_rec(&pcur);
3475
		field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
3476
		if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) {
3477
			continue;
3478
		}
3479
3480
		/* Because this is not a ROW_FORMAT=REDUNDANT table,
3481
		the is_temp flag is valid.  Examine it. */
3482
3483
		field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len);
3484
		if (len != 4
3485
		    || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
3486
			continue;
3487
		}
3488
3489
		/* This is a temporary table. */
3490
		field = rec_get_nth_field_old(rec, 0/*NAME*/, &len);
3491
		if (len == UNIV_SQL_NULL || len == 0) {
3492
			/* Corrupted SYS_TABLES.NAME */
3493
			continue;
3494
		}
3495
3496
		table_name = mem_heap_strdupl(heap, (const char*) field, len);
3497
3498
		btr_pcur_store_position(&pcur, &mtr);
3499
		btr_pcur_commit_specify_mtr(&pcur, &mtr);
3500
1819.7.143 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20100526014433-bx0t9794mnvkiaft from MySQL InnoDB
3501
		table = dict_load_table(table_name, TRUE);
1819.5.195 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6610 from MySQL InnoDB
3502
3503
		if (table) {
3504
			row_drop_table_for_mysql(table_name, trx, FALSE);
3505
			trx_commit_for_mysql(trx);
3506
		}
3507
3508
		mtr_start(&mtr);
3509
		btr_pcur_restore_position(BTR_SEARCH_LEAF,
3510
					  &pcur, &mtr);
1819.5.176 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6521 from MySQL InnoDB
3511
	}
3512
1819.5.195 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6610 from MySQL InnoDB
3513
	btr_pcur_close(&pcur);
3514
	mtr_commit(&mtr);
3515
	mem_heap_free(heap);
1819.5.176 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6521 from MySQL InnoDB
3516
	row_mysql_unlock_data_dictionary(trx);
3517
	trx_free_for_background(trx);
3518
}
3519
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3520
/*******************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3521
Drop all foreign keys in a database, see Bug#18942.
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3522
Called at the end of row_drop_database_for_mysql().
3523
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3524
static
3525
ulint
3526
drop_all_foreign_keys_in_db(
3527
/*========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3528
	const char*	name,	/*!< in: database name which ends to '/' */
3529
	trx_t*		trx)	/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3530
{
3531
	pars_info_t*	pinfo;
3532
	ulint		err;
3533
3534
	ut_a(name[strlen(name) - 1] == '/');
3535
3536
	pinfo = pars_info_create();
3537
3538
	pars_info_add_str_literal(pinfo, "dbname", name);
3539
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3540
/** true if for_name is not prefixed with dbname */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3541
#define TABLE_NOT_IN_THIS_DB \
3542
"SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
3543
3544
	err = que_eval_sql(pinfo,
3545
			   "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
3546
			   "foreign_id CHAR;\n"
3547
			   "for_name CHAR;\n"
3548
			   "found INT;\n"
3549
			   "DECLARE CURSOR cur IS\n"
3550
			   "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
3551
			   "WHERE FOR_NAME >= :dbname\n"
3552
			   "LOCK IN SHARE MODE\n"
3553
			   "ORDER BY FOR_NAME;\n"
3554
			   "BEGIN\n"
3555
			   "found := 1;\n"
3556
			   "OPEN cur;\n"
3557
			   "WHILE found = 1 LOOP\n"
3558
			   "        FETCH cur INTO foreign_id, for_name;\n"
3559
			   "        IF (SQL % NOTFOUND) THEN\n"
3560
			   "                found := 0;\n"
3561
			   "        ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
3562
			   "                found := 0;\n"
3563
			   "        ELSIF (1=1) THEN\n"
3564
			   "                DELETE FROM SYS_FOREIGN_COLS\n"
3565
			   "                WHERE ID = foreign_id;\n"
3566
			   "                DELETE FROM SYS_FOREIGN\n"
3567
			   "                WHERE ID = foreign_id;\n"
3568
			   "        END IF;\n"
3569
			   "END LOOP;\n"
3570
			   "CLOSE cur;\n"
3571
			   "COMMIT WORK;\n"
3572
			   "END;\n",
3573
			   FALSE, /* do not reserve dict mutex,
3574
				  we are already holding it */
3575
			   trx);
3576
3577
	return(err);
3578
}
3579
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3580
/*********************************************************************//**
3581
Drops a database for MySQL.
3582
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3583
UNIV_INTERN
3584
int
3585
row_drop_database_for_mysql(
3586
/*========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3587
	const char*	name,	/*!< in: database name which ends to '/' */
3588
	trx_t*		trx)	/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3589
{
3590
	dict_table_t* table;
3591
	char*	table_name;
3592
	int	err	= DB_SUCCESS;
3593
	ulint	namelen	= strlen(name);
3594
3595
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3596
	ut_a(name != NULL);
3597
	ut_a(name[namelen - 1] == '/');
3598
3599
	trx->op_info = "dropping database";
3600
3601
	trx_start_if_not_started(trx);
3602
loop:
3603
	row_mysql_lock_data_dictionary(trx);
3604
3605
	while ((table_name = dict_get_first_table_name_in_db(name))) {
3606
		ut_a(memcmp(table_name, name, namelen) == 0);
3607
1556.1.2 by Brian Aker
Creates a "cleanup" of Innodb's temp files in case of a crash of the DB.
3608
                // For the time being I would like to see how often we see
3609
                // lost temporary tables. --Brian
3610
                fprintf(stderr, "Dropping lost temporary table %s\n", table_name);
3611
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3612
		table = dict_table_get_low(table_name);
3613
3614
		ut_a(table);
3615
3616
		/* Wait until MySQL does not have any queries running on
3617
		the table */
3618
3619
		if (table->n_mysql_handles_opened > 0) {
3620
			row_mysql_unlock_data_dictionary(trx);
3621
3622
			ut_print_timestamp(stderr);
3623
			fputs("  InnoDB: Warning: MySQL is trying to"
3624
			      " drop database ", stderr);
3625
			ut_print_name(stderr, trx, TRUE, name);
3626
			fputs("\n"
3627
			      "InnoDB: though there are still"
3628
			      " open handles to table ", stderr);
3629
			ut_print_name(stderr, trx, TRUE, table_name);
3630
			fputs(".\n", stderr);
3631
3632
			os_thread_sleep(1000000);
3633
3634
			mem_free(table_name);
3635
3636
			goto loop;
3637
		}
3638
3639
		err = row_drop_table_for_mysql(table_name, trx, TRUE);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
3640
		trx_commit_for_mysql(trx);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3641
3642
		if (err != DB_SUCCESS) {
3643
			fputs("InnoDB: DROP DATABASE ", stderr);
3644
			ut_print_name(stderr, trx, TRUE, name);
3645
			fprintf(stderr, " failed with error %lu for table ",
3646
				(ulint) err);
3647
			ut_print_name(stderr, trx, TRUE, table_name);
3648
			putc('\n', stderr);
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
3649
			mem_free(table_name);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3650
			break;
3651
		}
641.2.1 by Monty Taylor
InnoDB Plugin 1.0.2
3652
3653
		mem_free(table_name);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3654
	}
3655
3656
	if (err == DB_SUCCESS) {
3657
		/* after dropping all tables try to drop all leftover
3658
		foreign keys in case orphaned ones exist */
3659
		err = (int) drop_all_foreign_keys_in_db(name, trx);
3660
3661
		if (err != DB_SUCCESS) {
3662
			fputs("InnoDB: DROP DATABASE ", stderr);
3663
			ut_print_name(stderr, trx, TRUE, name);
3664
			fprintf(stderr, " failed with error %d while "
3665
				"dropping all foreign keys", err);
3666
		}
3667
	}
3668
3669
	trx_commit_for_mysql(trx);
3670
3671
	row_mysql_unlock_data_dictionary(trx);
3672
3673
	trx->op_info = "";
3674
3675
	return(err);
3676
}
3677
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3678
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3679
Checks if a table name contains the string "/#sql" which denotes temporary
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3680
tables in MySQL.
3681
@return	TRUE if temporary table */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3682
static
3683
ibool
3684
row_is_mysql_tmp_table_name(
3685
/*========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3686
	const char*	name)	/*!< in: table name in the form
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3687
				'database/tablename' */
3688
{
3689
	return(strstr(name, "/#sql") != NULL);
3690
	/* return(strstr(name, "/@0023sql") != NULL); */
3691
}
3692
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3693
/****************************************************************//**
3694
Delete a single constraint.
3695
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3696
static
3697
int
3698
row_delete_constraint_low(
3699
/*======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3700
	const char*	id,		/*!< in: constraint id */
3701
	trx_t*		trx)		/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3702
{
3703
	pars_info_t*	info = pars_info_create();
3704
3705
	pars_info_add_str_literal(info, "id", id);
3706
3707
	return((int) que_eval_sql(info,
3708
			    "PROCEDURE DELETE_CONSTRAINT () IS\n"
3709
			    "BEGIN\n"
3710
			    "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3711
			    "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3712
			    "END;\n"
3713
			    , FALSE, trx));
3714
}
3715
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3716
/****************************************************************//**
3717
Delete a single constraint.
3718
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3719
static
3720
int
3721
row_delete_constraint(
3722
/*==================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3723
	const char*	id,		/*!< in: constraint id */
3724
	const char*	database_name,	/*!< in: database name, with the
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3725
					trailing '/' */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3726
	mem_heap_t*	heap,		/*!< in: memory heap */
3727
	trx_t*		trx)		/*!< in: transaction handle */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3728
{
3729
	ulint		err;
3730
3731
	/* New format constraints have ids <databasename>/<constraintname>. */
3732
	err = row_delete_constraint_low(
3733
		mem_heap_strcat(heap, database_name, id), trx);
3734
3735
	if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3736
		/* Old format < 4.0.18 constraints have constraint ids
3737
		<number>_<number>. We only try deleting them if the
3738
		constraint name does not contain a '/' character, otherwise
3739
		deleting a new format constraint named 'foo/bar' from
3740
		database 'baz' would remove constraint 'bar' from database
3741
		'foo', if it existed. */
3742
3743
		err = row_delete_constraint_low(id, trx);
3744
	}
3745
3746
	return((int) err);
3747
}
3748
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3749
/*********************************************************************//**
3750
Renames a table for MySQL.
3751
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3752
UNIV_INTERN
3753
ulint
3754
row_rename_table_for_mysql(
3755
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3756
	const char*	old_name,	/*!< in: old table name */
3757
	const char*	new_name,	/*!< in: new table name */
3758
	trx_t*		trx,		/*!< in: transaction handle */
3759
	ibool		commit)		/*!< in: if TRUE then commit trx */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3760
{
3761
	dict_table_t*	table;
3762
	ulint		err			= DB_ERROR;
3763
	mem_heap_t*	heap			= NULL;
3764
	const char**	constraints_to_drop	= NULL;
3765
	ulint		n_constraints_to_drop	= 0;
3766
	ibool		old_is_tmp, new_is_tmp;
3767
	pars_info_t*	info			= NULL;
3768
3769
	ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3770
	ut_a(old_name != NULL);
3771
	ut_a(new_name != NULL);
3772
3773
	if (srv_created_new_raw || srv_force_recovery) {
3774
		fputs("InnoDB: A new raw disk partition was initialized or\n"
3775
		      "InnoDB: innodb_force_recovery is on: we do not allow\n"
3776
		      "InnoDB: database modifications by the user. Shut down\n"
3777
		      "InnoDB: mysqld and edit my.cnf so that newraw"
3778
		      " is replaced\n"
3779
		      "InnoDB: with raw, and innodb_force_... is removed.\n",
3780
		      stderr);
3781
3782
		goto funct_exit;
3783
	}
3784
3785
	trx->op_info = "renaming table";
3786
	trx_start_if_not_started(trx);
3787
3788
	old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3789
	new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3790
3791
	table = dict_table_get_low(old_name);
3792
3793
	if (!table) {
1114.1.1 by Monty Taylor
Merged InnoDB Plugin 1.0.4
3794
#if defined(BUILD_DRIZZLE)
3795
		err = ENOENT;
3796
#else
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3797
		err = DB_TABLE_NOT_FOUND;
3798
		ut_print_timestamp(stderr);
3799
3800
		fputs("  InnoDB: Error: table ", stderr);
3801
		ut_print_name(stderr, trx, TRUE, old_name);
3802
		fputs(" does not exist in the InnoDB internal\n"
3803
		      "InnoDB: data dictionary though MySQL is"
3804
		      " trying to rename the table.\n"
3805
		      "InnoDB: Have you copied the .frm file"
3806
		      " of the table to the\n"
3807
		      "InnoDB: MySQL database directory"
3808
		      " from another database?\n"
3809
		      "InnoDB: You can look for further help from\n"
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3810
		      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3811
		      stderr);
1114.1.1 by Monty Taylor
Merged InnoDB Plugin 1.0.4
3812
#endif /* BUILD_DRIZZLE */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3813
		goto funct_exit;
3814
	} else if (table->ibd_file_missing) {
3815
		err = DB_TABLE_NOT_FOUND;
3816
		ut_print_timestamp(stderr);
3817
3818
		fputs("  InnoDB: Error: table ", stderr);
3819
		ut_print_name(stderr, trx, TRUE, old_name);
3820
		fputs(" does not have an .ibd file"
3821
		      " in the database directory.\n"
3822
		      "InnoDB: You can look for further help from\n"
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3823
		      "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3824
		      stderr);
3825
		goto funct_exit;
3826
	} else if (new_is_tmp) {
3827
		/* MySQL is doing an ALTER TABLE command and it renames the
3828
		original table to a temporary table name. We want to preserve
3829
		the original foreign key constraint definitions despite the
3830
		name change. An exception is those constraints for which
3831
		the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3832
3833
		heap = mem_heap_create(100);
3834
3835
		err = dict_foreign_parse_drop_constraints(
3836
			heap, trx, table, &n_constraints_to_drop,
3837
			&constraints_to_drop);
3838
3839
		if (err != DB_SUCCESS) {
3840
3841
			goto funct_exit;
3842
		}
3843
	}
3844
3845
	/* We use the private SQL parser of Innobase to generate the query
3846
	graphs needed in updating the dictionary data from system tables. */
3847
3848
	info = pars_info_create();
3849
3850
	pars_info_add_str_literal(info, "new_table_name", new_name);
3851
	pars_info_add_str_literal(info, "old_table_name", old_name);
3852
3853
	err = que_eval_sql(info,
3854
			   "PROCEDURE RENAME_TABLE () IS\n"
3855
			   "BEGIN\n"
3856
			   "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3857
			   " WHERE NAME = :old_table_name;\n"
3858
			   "END;\n"
3859
			   , FALSE, trx);
3860
3861
	if (err != DB_SUCCESS) {
3862
3863
		goto end;
3864
	} else if (!new_is_tmp) {
3865
		/* Rename all constraints. */
3866
3867
		info = pars_info_create();
3868
3869
		pars_info_add_str_literal(info, "new_table_name", new_name);
3870
		pars_info_add_str_literal(info, "old_table_name", old_name);
3871
3872
		err = que_eval_sql(
3873
			info,
3874
			"PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3875
			"gen_constr_prefix CHAR;\n"
3876
			"new_db_name CHAR;\n"
3877
			"foreign_id CHAR;\n"
3878
			"new_foreign_id CHAR;\n"
3879
			"old_db_name_len INT;\n"
3880
			"old_t_name_len INT;\n"
3881
			"new_db_name_len INT;\n"
3882
			"id_len INT;\n"
3883
			"found INT;\n"
3884
			"BEGIN\n"
3885
			"found := 1;\n"
3886
			"old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3887
			"new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3888
			"new_db_name := SUBSTR(:new_table_name, 0,\n"
3889
			"                      new_db_name_len);\n"
3890
			"old_t_name_len := LENGTH(:old_table_name);\n"
3891
			"gen_constr_prefix := CONCAT(:old_table_name,\n"
3892
			"                            '_ibfk_');\n"
3893
			"WHILE found = 1 LOOP\n"
3894
			"       SELECT ID INTO foreign_id\n"
3895
			"        FROM SYS_FOREIGN\n"
3896
			"        WHERE FOR_NAME = :old_table_name\n"
3897
			"         AND TO_BINARY(FOR_NAME)\n"
3898
			"           = TO_BINARY(:old_table_name)\n"
3899
			"         LOCK IN SHARE MODE;\n"
3900
			"       IF (SQL % NOTFOUND) THEN\n"
3901
			"        found := 0;\n"
3902
			"       ELSE\n"
3903
			"        UPDATE SYS_FOREIGN\n"
3904
			"        SET FOR_NAME = :new_table_name\n"
3905
			"         WHERE ID = foreign_id;\n"
3906
			"        id_len := LENGTH(foreign_id);\n"
3907
			"        IF (INSTR(foreign_id, '/') > 0) THEN\n"
3908
			"               IF (INSTR(foreign_id,\n"
3909
			"                         gen_constr_prefix) > 0)\n"
3910
			"               THEN\n"
3911
			"                new_foreign_id :=\n"
3912
			"                CONCAT(:new_table_name,\n"
3913
			"                SUBSTR(foreign_id, old_t_name_len,\n"
3914
			"                       id_len - old_t_name_len));\n"
3915
			"               ELSE\n"
3916
			"                new_foreign_id :=\n"
3917
			"                CONCAT(new_db_name,\n"
3918
			"                SUBSTR(foreign_id,\n"
3919
			"                       old_db_name_len,\n"
3920
			"                       id_len - old_db_name_len));\n"
3921
			"               END IF;\n"
3922
			"               UPDATE SYS_FOREIGN\n"
3923
			"                SET ID = new_foreign_id\n"
3924
			"                WHERE ID = foreign_id;\n"
3925
			"               UPDATE SYS_FOREIGN_COLS\n"
3926
			"                SET ID = new_foreign_id\n"
3927
			"                WHERE ID = foreign_id;\n"
3928
			"        END IF;\n"
3929
			"       END IF;\n"
3930
			"END LOOP;\n"
3931
			"UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
3932
			"WHERE REF_NAME = :old_table_name\n"
3933
			"  AND TO_BINARY(REF_NAME)\n"
3934
			"    = TO_BINARY(:old_table_name);\n"
3935
			"END;\n"
3936
			, FALSE, trx);
3937
3938
	} else if (n_constraints_to_drop > 0) {
3939
		/* Drop some constraints of tmp tables. */
3940
3941
		ulint	db_name_len = dict_get_db_name_len(old_name) + 1;
3942
		char*	db_name = mem_heap_strdupl(heap, old_name,
3943
						   db_name_len);
3944
		ulint	i;
3945
3946
		for (i = 0; i < n_constraints_to_drop; i++) {
3947
			err = row_delete_constraint(constraints_to_drop[i],
3948
						    db_name, heap, trx);
3949
3950
			if (err != DB_SUCCESS) {
3951
				break;
3952
			}
3953
		}
3954
	}
3955
3956
end:
3957
	if (err != DB_SUCCESS) {
3958
		if (err == DB_DUPLICATE_KEY) {
3959
			ut_print_timestamp(stderr);
3960
			fputs("  InnoDB: Error; possible reasons:\n"
3961
			      "InnoDB: 1) Table rename would cause"
3962
			      " two FOREIGN KEY constraints\n"
3963
			      "InnoDB: to have the same internal name"
3964
			      " in case-insensitive comparison.\n"
3965
			      "InnoDB: 2) table ", stderr);
3966
			ut_print_name(stderr, trx, TRUE, new_name);
3967
			fputs(" exists in the InnoDB internal data\n"
3968
			      "InnoDB: dictionary though MySQL is"
3969
			      " trying to rename table ", stderr);
3970
			ut_print_name(stderr, trx, TRUE, old_name);
3971
			fputs(" to it.\n"
3972
			      "InnoDB: Have you deleted the .frm file"
3973
			      " and not used DROP TABLE?\n"
3974
			      "InnoDB: You can look for further help from\n"
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
3975
			      "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3976
			      "InnoDB: If table ", stderr);
3977
			ut_print_name(stderr, trx, TRUE, new_name);
3978
			fputs(" is a temporary table #sql..., then"
3979
			      " it can be that\n"
3980
			      "InnoDB: there are still queries running"
3981
			      " on the table, and it will be\n"
3982
			      "InnoDB: dropped automatically when"
3983
			      " the queries end.\n"
3984
			      "InnoDB: You can drop the orphaned table"
3985
			      " inside InnoDB by\n"
3986
			      "InnoDB: creating an InnoDB table with"
3987
			      " the same name in another\n"
3988
			      "InnoDB: database and copying the .frm file"
3989
			      " to the current database.\n"
3990
			      "InnoDB: Then MySQL thinks the table exists,"
3991
			      " and DROP TABLE will\n"
3992
			      "InnoDB: succeed.\n", stderr);
3993
		}
3994
		trx->error_state = DB_SUCCESS;
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
3995
		trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
3996
		trx->error_state = DB_SUCCESS;
3997
	} else {
3998
		/* The following call will also rename the .ibd data file if
3999
		the table is stored in a single-table tablespace */
4000
4001
		if (!dict_table_rename_in_cache(table, new_name,
4002
						!new_is_tmp)) {
4003
			trx->error_state = DB_SUCCESS;
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
4004
			trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4005
			trx->error_state = DB_SUCCESS;
4006
			goto funct_exit;
4007
		}
4008
4009
		/* We only want to switch off some of the type checking in
4010
		an ALTER, not in a RENAME. */
4011
4012
		err = dict_load_foreigns(
1819.9.148 by Jimmy Yang, Stewart Smith
Merge Revision revid:jimmy.yang@oracle.com-20101006135534-6m2rb97xpbrkxux5 from MySQL InnoDB
4013
			new_name, FALSE, !old_is_tmp || trx->check_foreigns);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4014
4015
		if (err != DB_SUCCESS) {
4016
			ut_print_timestamp(stderr);
4017
4018
			if (old_is_tmp) {
4019
				fputs("  InnoDB: Error: in ALTER TABLE ",
4020
				      stderr);
4021
				ut_print_name(stderr, trx, TRUE, new_name);
4022
				fputs("\n"
4023
				      "InnoDB: has or is referenced"
4024
				      " in foreign key constraints\n"
4025
				      "InnoDB: which are not compatible"
4026
				      " with the new table definition.\n",
4027
				      stderr);
4028
			} else {
4029
				fputs("  InnoDB: Error: in RENAME TABLE"
4030
				      " table ",
4031
				      stderr);
4032
				ut_print_name(stderr, trx, TRUE, new_name);
4033
				fputs("\n"
4034
				      "InnoDB: is referenced in"
4035
				      " foreign key constraints\n"
4036
				      "InnoDB: which are not compatible"
4037
				      " with the new table definition.\n",
4038
				      stderr);
4039
			}
4040
4041
			ut_a(dict_table_rename_in_cache(table,
4042
							old_name, FALSE));
4043
			trx->error_state = DB_SUCCESS;
1819.5.2 by stewart at flamingspork
[patch 002/129] Merge patch for revision 1787 from InnoDB SVN:
4044
			trx_general_rollback_for_mysql(trx, NULL);
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4045
			trx->error_state = DB_SUCCESS;
4046
		}
4047
	}
4048
4049
funct_exit:
4050
4051
	if (commit) {
4052
		trx_commit_for_mysql(trx);
4053
	}
4054
4055
	if (UNIV_LIKELY_NULL(heap)) {
4056
		mem_heap_free(heap);
4057
	}
4058
4059
	trx->op_info = "";
4060
4061
	return(err);
4062
}
4063
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
4064
/*********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4065
Checks that the index contains entries in an ascending order, unique
4066
constraint is not broken, and calculates the number of index entries
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
4067
in the read view of the current transaction.
4068
@return	TRUE if ok */
1819.5.185 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6547 from MySQL InnoDB
4069
UNIV_INTERN
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4070
ibool
1819.5.185 by marko
Merge Revision revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6547 from MySQL InnoDB
4071
row_check_index_for_mysql(
4072
/*======================*/
4073
	row_prebuilt_t*		prebuilt,	/*!< in: prebuilt struct
4074
						in MySQL handle */
4075
	const dict_index_t*	index,		/*!< in: index */
4076
	ulint*			n_rows)		/*!< out: number of entries
4077
						seen in the consistent read */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4078
{
4079
	dtuple_t*	prev_entry	= NULL;
4080
	ulint		matched_fields;
4081
	ulint		matched_bytes;
4082
	byte*		buf;
4083
	ulint		ret;
4084
	rec_t*		rec;
4085
	ibool		is_ok		= TRUE;
4086
	int		cmp;
4087
	ibool		contains_null;
4088
	ulint		i;
4089
	ulint		cnt;
4090
	mem_heap_t*	heap		= NULL;
4091
	ulint		n_ext;
4092
	ulint		offsets_[REC_OFFS_NORMAL_SIZE];
4093
	ulint*		offsets;
4094
	rec_offs_init(offsets_);
4095
4096
	*n_rows = 0;
4097
4098
	buf = mem_alloc(UNIV_PAGE_SIZE);
4099
	heap = mem_heap_create(100);
4100
4101
	cnt = 1000;
4102
4103
	ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
4104
loop:
4105
	/* Check thd->killed every 1,000 scanned rows */
4106
	if (--cnt == 0) {
4107
		if (trx_is_interrupted(prebuilt->trx)) {
4108
			goto func_exit;
4109
		}
4110
		cnt = 1000;
4111
	}
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
4112
4113
	switch (ret) {
4114
	case DB_SUCCESS:
4115
		break;
4116
	default:
4117
		ut_print_timestamp(stderr);
4118
		fputs("  InnoDB: Warning: CHECK TABLE on ", stderr);
4119
		dict_index_name_print(stderr, prebuilt->trx, index);
4120
		fprintf(stderr, " returned %lu\n", ret);
4121
		/* fall through (this error is ignored by CHECK TABLE) */
4122
	case DB_END_OF_INDEX:
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4123
func_exit:
4124
		mem_free(buf);
4125
		mem_heap_free(heap);
4126
4127
		return(is_ok);
4128
	}
4129
4130
	*n_rows = *n_rows + 1;
4131
4132
	/* row_search... returns the index record in buf, record origin offset
4133
	within buf stored in the first 4 bytes, because we have built a dummy
4134
	template */
4135
4136
	rec = buf + mach_read_from_4(buf);
4137
4138
	offsets = rec_get_offsets(rec, index, offsets_,
4139
				  ULINT_UNDEFINED, &heap);
4140
4141
	if (prev_entry != NULL) {
4142
		matched_fields = 0;
4143
		matched_bytes = 0;
4144
4145
		cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
4146
						&matched_fields,
4147
						&matched_bytes);
4148
		contains_null = FALSE;
4149
4150
		/* In a unique secondary index we allow equal key values if
4151
		they contain SQL NULLs */
4152
4153
		for (i = 0;
4154
		     i < dict_index_get_n_ordering_defined_by_user(index);
4155
		     i++) {
4156
			if (UNIV_SQL_NULL == dfield_get_len(
4157
				    dtuple_get_nth_field(prev_entry, i))) {
4158
4159
				contains_null = TRUE;
4160
			}
4161
		}
4162
4163
		if (cmp > 0) {
4164
			fputs("InnoDB: index records in a wrong order in ",
4165
			      stderr);
4166
not_ok:
4167
			dict_index_name_print(stderr,
4168
					      prebuilt->trx, index);
4169
			fputs("\n"
4170
			      "InnoDB: prev record ", stderr);
4171
			dtuple_print(stderr, prev_entry);
4172
			fputs("\n"
4173
			      "InnoDB: record ", stderr);
4174
			rec_print_new(stderr, rec, offsets);
4175
			putc('\n', stderr);
4176
			is_ok = FALSE;
4177
		} else if (dict_index_is_unique(index)
4178
			   && !contains_null
4179
			   && matched_fields
4180
			   >= dict_index_get_n_ordering_defined_by_user(
4181
				   index)) {
4182
4183
			fputs("InnoDB: duplicate key in ", stderr);
4184
			goto not_ok;
4185
		}
4186
	}
4187
4188
	{
4189
		mem_heap_t*	tmp_heap = NULL;
4190
4191
		/* Empty the heap on each round.  But preserve offsets[]
4192
		for the row_rec_to_index_entry() call, by copying them
4193
		into a separate memory heap when needed. */
4194
		if (UNIV_UNLIKELY(offsets != offsets_)) {
4195
			ulint	size = rec_offs_get_n_alloc(offsets)
4196
				* sizeof *offsets;
4197
4198
			tmp_heap = mem_heap_create(size);
4199
			offsets = mem_heap_dup(tmp_heap, offsets, size);
4200
		}
4201
4202
		mem_heap_empty(heap);
4203
4204
		prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
4205
						    index, offsets,
4206
						    &n_ext, heap);
4207
4208
		if (UNIV_LIKELY_NULL(tmp_heap)) {
4209
			mem_heap_free(tmp_heap);
4210
		}
4211
	}
4212
4213
	ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
4214
4215
	goto loop;
4216
}
4217
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
4218
/*********************************************************************//**
4219
Determines if a table is a magic monitor table.
4220
@return	TRUE if monitor table */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4221
UNIV_INTERN
4222
ibool
4223
row_is_magic_monitor_table(
4224
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
4225
	const char*	table_name)	/*!< in: name of the table, in the
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
4226
					form database/table_name */
4227
{
4228
	const char*	name; /* table_name without database/ */
4229
	ulint		len;
4230
4231
	name = strchr(table_name, '/');
4232
	ut_a(name != NULL);
4233
	name++;
4234
	len = strlen(name) + 1;
4235
4236
	if (STR_EQ(name, len, S_innodb_monitor)
4237
	    || STR_EQ(name, len, S_innodb_lock_monitor)
4238
	    || STR_EQ(name, len, S_innodb_tablespace_monitor)
4239
	    || STR_EQ(name, len, S_innodb_table_monitor)
4240
	    || STR_EQ(name, len, S_innodb_mem_validate)) {
4241
4242
		return(TRUE);
4243
	}
4244
4245
	return(FALSE);
4246
}