~drizzle-trunk/drizzle/development

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