~drizzle-trunk/drizzle/development

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