mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innobase / row / row0mysql.c
blob037fb576a4841952e54a9576e2b7787c0c3f5e03
1 /******************************************************
2 Interface between Innobase row operations and MySQL.
3 Contains also create table and other data dictionary operations.
5 (c) 2000 Innobase Oy
7 Created 9/17/2000 Heikki Tuuri
8 *******************************************************/
10 #include "row0mysql.h"
12 #ifdef UNIV_NONINL
13 #include "row0mysql.ic"
14 #endif
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 #include "m_string.h"
35 #include "my_sys.h"
36 #include "ha_prototypes.h"
38 /* A dummy variable used to fool the compiler */
39 ibool row_mysql_identically_false = FALSE;
41 /* Provide optional 4.x backwards compatibility for 5.0 and above */
42 ibool row_rollback_on_timeout = FALSE;
44 /* List of tables we should drop in background. ALTER TABLE in MySQL requires
45 that the table handler can drop the table in background when there are no
46 queries to it any more. Protected by the kernel mutex. */
47 typedef struct row_mysql_drop_struct row_mysql_drop_t;
48 struct row_mysql_drop_struct{
49 char* table_name;
50 UT_LIST_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
53 UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
54 ibool row_mysql_drop_list_inited = FALSE;
56 /* Magic table names for invoking various monitor threads */
57 static const char S_innodb_monitor[] = "innodb_monitor";
58 static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
59 static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
60 static const char S_innodb_table_monitor[] = "innodb_table_monitor";
61 static const char S_innodb_mem_validate[] = "innodb_mem_validate";
63 /* Evaluates to true if str1 equals str2_onstack, used for comparing
64 the above strings. */
65 #define STR_EQ(str1, str1_len, str2_onstack) \
66 ((str1_len) == sizeof(str2_onstack) \
67 && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
69 /***********************************************************************
70 Determine if the given name is a name reserved for MySQL system tables. */
71 static
72 ibool
73 row_mysql_is_system_table(
74 /*======================*/
75 /* out: TRUE if name is a MySQL
76 system table name */
77 const char* name)
79 if (strncmp(name, "mysql/", 6) != 0) {
81 return(FALSE);
84 return(0 == strcmp(name + 6, "host")
85 || 0 == strcmp(name + 6, "user")
86 || 0 == strcmp(name + 6, "db"));
89 /***********************************************************************
90 Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
91 static
92 void
93 row_mysql_delay_if_needed(void)
94 /*===========================*/
96 if (srv_dml_needed_delay) {
97 os_thread_sleep(srv_dml_needed_delay);
101 /***********************************************************************
102 Frees the blob heap in prebuilt when no longer needed. */
104 void
105 row_mysql_prebuilt_free_blob_heap(
106 /*==============================*/
107 row_prebuilt_t* prebuilt) /* in: prebuilt struct of a
108 ha_innobase:: table handle */
110 mem_heap_free(prebuilt->blob_heap);
111 prebuilt->blob_heap = NULL;
114 /***********************************************************************
115 Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
116 format. */
118 byte*
119 row_mysql_store_true_var_len(
120 /*=========================*/
121 /* out: pointer to the data, we skip the 1 or 2 bytes
122 at the start that are used to store the len */
123 byte* dest, /* in: where to store */
124 ulint len, /* in: length, must fit in two bytes */
125 ulint lenlen) /* in: storage length of len: either 1 or 2 bytes */
127 if (lenlen == 2) {
128 ut_a(len < 256 * 256);
130 mach_write_to_2_little_endian(dest, len);
132 return(dest + 2);
135 ut_a(lenlen == 1);
136 ut_a(len < 256);
138 mach_write_to_1(dest, len);
140 return(dest + 1);
143 /***********************************************************************
144 Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
145 returns a pointer to the data. */
147 byte*
148 row_mysql_read_true_varchar(
149 /*========================*/
150 /* out: pointer to the data, we skip the 1 or 2 bytes
151 at the start that are used to store the len */
152 ulint* len, /* out: variable-length field length */
153 byte* field, /* in: field in the MySQL format */
154 ulint lenlen) /* in: storage length of len: either 1 or 2 bytes */
156 if (lenlen == 2) {
157 *len = mach_read_from_2_little_endian(field);
159 return(field + 2);
162 ut_a(lenlen == 1);
164 *len = mach_read_from_1(field);
166 return(field + 1);
169 /***********************************************************************
170 Stores a reference to a BLOB in the MySQL format. */
172 void
173 row_mysql_store_blob_ref(
174 /*=====================*/
175 byte* dest, /* in: where to store */
176 ulint col_len, /* in: dest buffer size: determines into
177 how many bytes the BLOB length is stored,
178 the space for the length may vary from 1
179 to 4 bytes */
180 byte* data, /* in: BLOB data; if the value to store
181 is SQL NULL this should be NULL pointer */
182 ulint len) /* in: BLOB length; if the value to store
183 is SQL NULL this should be 0; remember
184 also to set the NULL bit in the MySQL record
185 header! */
187 /* MySQL might assume the field is set to zero except the length and
188 the pointer fields */
190 memset(dest, '\0', col_len);
192 /* In dest there are 1 - 4 bytes reserved for the BLOB length,
193 and after that 8 bytes reserved for the pointer to the data.
194 In 32-bit architectures we only use the first 4 bytes of the pointer
195 slot. */
197 ut_a(col_len - 8 > 1 || len < 256);
198 ut_a(col_len - 8 > 2 || len < 256 * 256);
199 ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
201 mach_write_to_n_little_endian(dest, col_len - 8, len);
203 ut_memcpy(dest + col_len - 8, &data, sizeof(byte*));
206 /***********************************************************************
207 Reads a reference to a BLOB in the MySQL format. */
209 byte*
210 row_mysql_read_blob_ref(
211 /*====================*/
212 /* out: pointer to BLOB data */
213 ulint* len, /* out: BLOB length */
214 byte* ref, /* in: BLOB reference in the MySQL format */
215 ulint col_len) /* in: BLOB reference length (not BLOB
216 length) */
218 byte* data;
220 *len = mach_read_from_n_little_endian(ref, col_len - 8);
222 ut_memcpy(&data, ref + col_len - 8, sizeof(byte*));
224 return(data);
227 /******************************************************************
228 Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
229 The counterpart of this function is row_sel_field_store_in_mysql_format() in
230 row0sel.c. */
232 byte*
233 row_mysql_store_col_in_innobase_format(
234 /*===================================*/
235 /* out: up to which byte we used
236 buf in the conversion */
237 dfield_t* dfield, /* in/out: dfield where dtype
238 information must be already set when
239 this function is called! */
240 byte* buf, /* in/out: buffer for a converted
241 integer value; this must be at least
242 col_len long then! */
243 ibool row_format_col, /* TRUE if the mysql_data is from
244 a MySQL row, FALSE if from a MySQL
245 key value;
246 in MySQL, a true VARCHAR storage
247 format differs in a row and in a
248 key value: in a key value the length
249 is always stored in 2 bytes! */
250 byte* mysql_data, /* in: MySQL column value, not
251 SQL NULL; NOTE that dfield may also
252 get a pointer to mysql_data,
253 therefore do not discard this as long
254 as dfield is used! */
255 ulint col_len, /* in: MySQL column length; NOTE that
256 this is the storage length of the
257 column in the MySQL format row, not
258 necessarily the length of the actual
259 payload data; if the column is a true
260 VARCHAR then this is irrelevant */
261 ulint comp) /* in: nonzero=compact format */
263 byte* ptr = mysql_data;
264 dtype_t* dtype;
265 ulint type;
266 ulint lenlen;
268 dtype = dfield_get_type(dfield);
270 type = dtype->mtype;
272 if (type == DATA_INT) {
273 /* Store integer data in Innobase in a big-endian format,
274 sign bit negated if the data is a signed integer. In MySQL,
275 integers are stored in a little-endian format. */
277 ptr = buf + col_len;
279 for (;;) {
280 ptr--;
281 *ptr = *mysql_data;
282 if (ptr == buf) {
283 break;
285 mysql_data++;
288 if (!(dtype->prtype & DATA_UNSIGNED)) {
290 *ptr = (byte) (*ptr ^ 128);
293 buf += col_len;
294 } else if ((type == DATA_VARCHAR
295 || type == DATA_VARMYSQL
296 || type == DATA_BINARY)) {
298 if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
299 /* The length of the actual data is stored to 1 or 2
300 bytes at the start of the field */
302 if (row_format_col) {
303 if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
304 lenlen = 2;
305 } else {
306 lenlen = 1;
308 } else {
309 /* In a MySQL key value, lenlen is always 2 */
310 lenlen = 2;
313 ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
314 lenlen);
315 } else {
316 /* Remove trailing spaces from old style VARCHAR
317 columns. */
319 /* Handle UCS2 strings differently. */
320 ulint mbminlen = dtype_get_mbminlen(dtype);
322 ptr = mysql_data;
324 if (mbminlen == 2) {
325 /* space=0x0020 */
326 /* Trim "half-chars", just in case. */
327 col_len &= ~1;
329 while (col_len >= 2 && ptr[col_len - 2] == 0x00
330 && ptr[col_len - 1] == 0x20) {
331 col_len -= 2;
333 } else {
334 ut_a(mbminlen == 1);
335 /* space=0x20 */
336 while (col_len > 0
337 && ptr[col_len - 1] == 0x20) {
338 col_len--;
342 } else if (comp && type == DATA_MYSQL
343 && dtype_get_mbminlen(dtype) == 1
344 && dtype_get_mbmaxlen(dtype) > 1) {
345 /* In some cases we strip trailing spaces from UTF-8 and other
346 multibyte charsets, from FIXED-length CHAR columns, to save
347 space. UTF-8 would otherwise normally use 3 * the string length
348 bytes to store an ASCII string! */
350 /* We assume that this CHAR field is encoded in a
351 variable-length character set where spaces have
352 1:1 correspondence to 0x20 bytes, such as UTF-8.
354 Consider a CHAR(n) field, a field of n characters.
355 It will contain between n * mbminlen and n * mbmaxlen bytes.
356 We will try to truncate it to n bytes by stripping
357 space padding. If the field contains single-byte
358 characters only, it will be truncated to n characters.
359 Consider a CHAR(5) field containing the string ".a "
360 where "." denotes a 3-byte character represented by
361 the bytes "$%&". After our stripping, the string will
362 be stored as "$%&a " (5 bytes). The string ".abc "
363 will be stored as "$%&abc" (6 bytes).
365 The space padding will be restored in row0sel.c, function
366 row_sel_field_store_in_mysql_format(). */
368 ulint n_chars;
370 ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
372 n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
374 /* Strip space padding. */
375 while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
376 col_len--;
378 } else if (type == DATA_BLOB && row_format_col) {
380 ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
383 dfield_set_data(dfield, ptr, col_len);
385 return(buf);
388 /******************************************************************
389 Convert a row in the MySQL format to a row in the Innobase format. Note that
390 the function to convert a MySQL format key value to an InnoDB dtuple is
391 row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
392 static
393 void
394 row_mysql_convert_row_to_innobase(
395 /*==============================*/
396 dtuple_t* row, /* in/out: Innobase row where the
397 field type information is already
398 copied there! */
399 row_prebuilt_t* prebuilt, /* in: prebuilt struct where template
400 must be of type ROW_MYSQL_WHOLE_ROW */
401 byte* mysql_rec) /* in: row in the MySQL format;
402 NOTE: do not discard as long as
403 row is used, as row may contain
404 pointers to this record! */
406 const mysql_row_templ_t*templ;
407 dfield_t* dfield;
408 ulint i;
410 ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
411 ut_ad(prebuilt->mysql_template);
413 for (i = 0; i < prebuilt->n_template; i++) {
415 templ = prebuilt->mysql_template + i;
416 dfield = dtuple_get_nth_field(row, i);
418 if (templ->mysql_null_bit_mask != 0) {
419 /* Column may be SQL NULL */
421 if (mysql_rec[templ->mysql_null_byte_offset]
422 & (byte) (templ->mysql_null_bit_mask)) {
424 /* It is SQL NULL */
426 dfield_set_data(dfield, NULL, UNIV_SQL_NULL);
428 goto next_column;
432 row_mysql_store_col_in_innobase_format(
433 dfield,
434 prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
435 TRUE, /* MySQL row format data */
436 mysql_rec + templ->mysql_col_offset,
437 templ->mysql_col_len,
438 dict_table_is_comp(prebuilt->table));
439 next_column:
444 /********************************************************************
445 Handles user errors and lock waits detected by the database engine. */
447 ibool
448 row_mysql_handle_errors(
449 /*====================*/
450 /* out: TRUE if it was a lock wait and
451 we should continue running the query thread */
452 ulint* new_err,/* out: possible new error encountered in
453 lock wait, or if no new error, the value
454 of trx->error_state at the entry of this
455 function */
456 trx_t* trx, /* in: transaction */
457 que_thr_t* thr, /* in: query thread */
458 trx_savept_t* savept) /* in: savepoint or NULL */
460 #ifndef UNIV_HOTBACKUP
461 ulint err;
463 handle_new_error:
464 err = trx->error_state;
466 ut_a(err != DB_SUCCESS);
468 trx->error_state = DB_SUCCESS;
470 if ((err == DB_DUPLICATE_KEY)
471 || (err == DB_FOREIGN_DUPLICATE_KEY)) {
472 if (savept) {
473 /* Roll back the latest, possibly incomplete
474 insertion or update */
476 trx_general_rollback_for_mysql(trx, TRUE, savept);
478 } else if (err == DB_TOO_BIG_RECORD) {
479 if (savept) {
480 /* Roll back the latest, possibly incomplete
481 insertion or update */
483 trx_general_rollback_for_mysql(trx, TRUE, savept);
485 /* MySQL will roll back the latest SQL statement */
486 } else if (err == DB_ROW_IS_REFERENCED
487 || err == DB_NO_REFERENCED_ROW
488 || err == DB_CANNOT_ADD_CONSTRAINT
489 || err == DB_INTERRUPTED
490 || err == DB_TOO_MANY_CONCURRENT_TRXS) {
491 if (savept) {
492 /* Roll back the latest, possibly incomplete
493 insertion or update */
495 trx_general_rollback_for_mysql(trx, TRUE, savept);
497 /* MySQL will roll back the latest SQL statement */
498 } else if (err == DB_LOCK_WAIT) {
500 srv_suspend_mysql_thread(thr);
502 if (trx->error_state != DB_SUCCESS) {
503 que_thr_stop_for_mysql(thr);
505 goto handle_new_error;
508 *new_err = err;
510 return(TRUE);
512 } else if (err == DB_DEADLOCK
513 || err == DB_LOCK_TABLE_FULL
514 || (err == DB_LOCK_WAIT_TIMEOUT
515 && row_rollback_on_timeout)) {
516 /* Roll back the whole transaction; this resolution was added
517 to version 3.23.43 */
519 trx_general_rollback_for_mysql(trx, FALSE, NULL);
521 } else if (err == DB_OUT_OF_FILE_SPACE
522 || err == DB_LOCK_WAIT_TIMEOUT) {
524 ut_ad(!(err == DB_LOCK_WAIT_TIMEOUT
525 && row_rollback_on_timeout));
527 if (savept) {
528 /* Roll back the latest, possibly incomplete
529 insertion or update */
531 trx_general_rollback_for_mysql(trx, TRUE, savept);
533 /* MySQL will roll back the latest SQL statement */
535 } else if (err == DB_MUST_GET_MORE_FILE_SPACE) {
537 fputs("InnoDB: The database cannot continue"
538 " operation because of\n"
539 "InnoDB: lack of space. You must add"
540 " a new data file to\n"
541 "InnoDB: my.cnf and restart the database.\n", stderr);
543 exit(1);
544 } else if (err == DB_CORRUPTION) {
546 fputs("InnoDB: We detected index corruption"
547 " in an InnoDB type table.\n"
548 "InnoDB: You have to dump + drop + reimport"
549 " the table or, in\n"
550 "InnoDB: a case of widespread corruption,"
551 " dump all InnoDB\n"
552 "InnoDB: tables and recreate the"
553 " whole InnoDB tablespace.\n"
554 "InnoDB: If the mysqld server crashes"
555 " after the startup or when\n"
556 "InnoDB: you dump the tables, look at\n"
557 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
558 "forcing-innodb-recovery.html"
559 " for help.\n", stderr);
561 } else if (err == DB_FOREIGN_EXCEED_MAX_CASCADE) {
562 fprintf(stderr, "InnoDB: Cannot delete/update rows with"
563 " cascading foreign key constraints that exceed max"
564 " depth of %lu\n"
565 "Please drop excessive foreign constraints"
566 " and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
567 } else {
568 fprintf(stderr, "InnoDB: unknown error code %lu\n",
569 (ulong) err);
570 ut_error;
573 if (trx->error_state != DB_SUCCESS) {
574 *new_err = trx->error_state;
575 } else {
576 *new_err = err;
579 trx->error_state = DB_SUCCESS;
581 return(FALSE);
582 #else /* UNIV_HOTBACKUP */
583 /* This function depends on MySQL code that is not included in
584 InnoDB Hot Backup builds. Besides, this function should never
585 be called in InnoDB Hot Backup. */
586 ut_error;
587 return(FALSE);
588 #endif /* UNIV_HOTBACKUP */
591 /************************************************************************
592 Create a prebuilt struct for a MySQL table handle. */
594 row_prebuilt_t*
595 row_create_prebuilt(
596 /*================*/
597 /* out, own: a prebuilt struct */
598 dict_table_t* table) /* in: Innobase table handle */
600 row_prebuilt_t* prebuilt;
601 mem_heap_t* heap;
602 dict_index_t* clust_index;
603 dtuple_t* ref;
604 ulint ref_len;
605 ulint i;
607 heap = mem_heap_create(128);
609 prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t));
611 prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
612 prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
614 prebuilt->table = table;
616 prebuilt->trx = NULL;
618 prebuilt->sql_stat_start = TRUE;
620 prebuilt->mysql_has_locked = FALSE;
622 prebuilt->index = NULL;
624 prebuilt->used_in_HANDLER = FALSE;
626 prebuilt->n_template = 0;
627 prebuilt->mysql_template = NULL;
629 prebuilt->heap = heap;
630 prebuilt->ins_node = NULL;
632 prebuilt->ins_upd_rec_buff = NULL;
633 prebuilt->default_rec = NULL;
635 prebuilt->upd_node = NULL;
636 prebuilt->ins_graph = NULL;
637 prebuilt->upd_graph = NULL;
639 prebuilt->pcur = btr_pcur_create_for_mysql();
640 prebuilt->clust_pcur = btr_pcur_create_for_mysql();
642 prebuilt->select_lock_type = LOCK_NONE;
643 prebuilt->stored_select_lock_type = 99999999;
645 prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
647 prebuilt->sel_graph = NULL;
649 prebuilt->search_tuple = dtuple_create(
650 heap, 2 * dict_table_get_n_cols(table));
652 clust_index = dict_table_get_first_index(table);
654 /* Make sure that search_tuple is long enough for clustered index */
655 ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
657 ref_len = dict_index_get_n_unique(clust_index);
659 ref = dtuple_create(heap, ref_len);
661 dict_index_copy_types(ref, clust_index, ref_len);
663 prebuilt->clust_ref = ref;
665 for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
666 prebuilt->fetch_cache[i] = NULL;
669 prebuilt->n_fetch_cached = 0;
671 prebuilt->blob_heap = NULL;
673 prebuilt->old_vers_heap = NULL;
675 prebuilt->autoinc_error = 0;
676 prebuilt->autoinc_offset = 0;
678 /* Default to 1, we will set the actual value later in
679 ha_innobase::get_auto_increment(). */
680 prebuilt->autoinc_increment = 1;
682 prebuilt->autoinc_last_value = 0;
684 return(prebuilt);
687 /************************************************************************
688 Free a prebuilt struct for a MySQL table handle. */
690 void
691 row_prebuilt_free(
692 /*==============*/
693 row_prebuilt_t* prebuilt) /* in, own: prebuilt struct */
695 ulint i;
697 if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
698 || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED) {
699 fprintf(stderr,
700 "InnoDB: Error: trying to free a corrupt\n"
701 "InnoDB: table handle. Magic n %lu,"
702 " magic n2 %lu, table name",
703 (ulong) prebuilt->magic_n,
704 (ulong) prebuilt->magic_n2);
705 ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
706 putc('\n', stderr);
708 mem_analyze_corruption(prebuilt);
710 ut_error;
713 prebuilt->magic_n = ROW_PREBUILT_FREED;
714 prebuilt->magic_n2 = ROW_PREBUILT_FREED;
716 btr_pcur_free_for_mysql(prebuilt->pcur);
717 btr_pcur_free_for_mysql(prebuilt->clust_pcur);
719 if (prebuilt->mysql_template) {
720 mem_free(prebuilt->mysql_template);
723 if (prebuilt->ins_graph) {
724 que_graph_free_recursive(prebuilt->ins_graph);
727 if (prebuilt->sel_graph) {
728 que_graph_free_recursive(prebuilt->sel_graph);
731 if (prebuilt->upd_graph) {
732 que_graph_free_recursive(prebuilt->upd_graph);
735 if (prebuilt->blob_heap) {
736 mem_heap_free(prebuilt->blob_heap);
739 if (prebuilt->old_vers_heap) {
740 mem_heap_free(prebuilt->old_vers_heap);
743 for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
744 if (prebuilt->fetch_cache[i] != NULL) {
746 if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
747 (prebuilt->fetch_cache[i]) - 4))
748 || (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
749 (prebuilt->fetch_cache[i])
750 + prebuilt->mysql_row_len))) {
751 fputs("InnoDB: Error: trying to free"
752 " a corrupt fetch buffer.\n", stderr);
754 mem_analyze_corruption(
755 prebuilt->fetch_cache[i]);
757 ut_error;
760 mem_free((prebuilt->fetch_cache[i]) - 4);
764 dict_table_decrement_handle_count(prebuilt->table);
766 mem_heap_free(prebuilt->heap);
769 /*************************************************************************
770 Updates the transaction pointers in query graphs stored in the prebuilt
771 struct. */
773 void
774 row_update_prebuilt_trx(
775 /*====================*/
776 /* out: prebuilt dtuple */
777 row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
778 handle */
779 trx_t* trx) /* in: transaction handle */
781 if (trx->magic_n != TRX_MAGIC_N) {
782 fprintf(stderr,
783 "InnoDB: Error: trying to use a corrupt\n"
784 "InnoDB: trx handle. Magic n %lu\n",
785 (ulong) trx->magic_n);
787 mem_analyze_corruption(trx);
789 ut_error;
792 if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
793 fprintf(stderr,
794 "InnoDB: Error: trying to use a corrupt\n"
795 "InnoDB: table handle. Magic n %lu, table name",
796 (ulong) prebuilt->magic_n);
797 ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
798 putc('\n', stderr);
800 mem_analyze_corruption(prebuilt);
802 ut_error;
805 prebuilt->trx = trx;
807 if (prebuilt->ins_graph) {
808 prebuilt->ins_graph->trx = trx;
811 if (prebuilt->upd_graph) {
812 prebuilt->upd_graph->trx = trx;
815 if (prebuilt->sel_graph) {
816 prebuilt->sel_graph->trx = trx;
820 /*************************************************************************
821 Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
822 has not yet been built in the prebuilt struct, then this function first
823 builds it. */
824 static
825 dtuple_t*
826 row_get_prebuilt_insert_row(
827 /*========================*/
828 /* out: prebuilt dtuple; the column
829 type information is also set in it */
830 row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
831 handle */
833 ins_node_t* node;
834 dtuple_t* row;
835 dict_table_t* table = prebuilt->table;
836 ulint i;
838 ut_ad(prebuilt && table && prebuilt->trx);
840 if (prebuilt->ins_node == NULL) {
842 /* Not called before for this handle: create an insert node
843 and query graph to the prebuilt struct */
845 node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
847 prebuilt->ins_node = node;
849 if (prebuilt->ins_upd_rec_buff == NULL) {
850 prebuilt->ins_upd_rec_buff = mem_heap_alloc(
851 prebuilt->heap, prebuilt->mysql_row_len);
854 row = dtuple_create(prebuilt->heap,
855 dict_table_get_n_cols(table));
857 dict_table_copy_types(row, table);
859 /* We init the value of every field to the SQL NULL to avoid
860 a debug assertion from failing */
862 for (i = 0; i < dtuple_get_n_fields(row); i++) {
864 dtuple_get_nth_field(row, i)->len = UNIV_SQL_NULL;
867 ins_node_set_new_row(node, row);
869 prebuilt->ins_graph = que_node_get_parent(
870 pars_complete_graph_for_exec(node,
871 prebuilt->trx,
872 prebuilt->heap));
873 prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
876 return(prebuilt->ins_node->row);
879 /*************************************************************************
880 Updates the table modification counter and calculates new estimates
881 for table and index statistics if necessary. */
882 UNIV_INLINE
883 void
884 row_update_statistics_if_needed(
885 /*============================*/
886 dict_table_t* table) /* in: table */
888 ulint counter;
890 counter = table->stat_modified_counter;
892 table->stat_modified_counter = counter + 1;
894 /* Calculate new statistics if 1 / 16 of table has been modified
895 since the last time a statistics batch was run, or if
896 stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
897 We calculate statistics at most every 16th round, since we may have
898 a counter table which is very small and updated very often. */
900 if (counter > 2000000000
901 || ((ib_longlong)counter > 16 + table->stat_n_rows / 16)) {
903 dict_update_statistics(table);
907 /*************************************************************************
908 Unlocks an AUTO_INC type lock possibly reserved by trx. */
910 void
911 row_unlock_table_autoinc_for_mysql(
912 /*===============================*/
913 trx_t* trx) /* in: transaction */
915 if (!trx->auto_inc_lock) {
917 return;
920 lock_table_unlock_auto_inc(trx);
923 /*************************************************************************
924 Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
925 AUTO_INC lock gives exclusive access to the auto-inc counter of the
926 table. The lock is reserved only for the duration of an SQL statement.
927 It is not compatible with another AUTO_INC or exclusive lock on the
928 table. */
931 row_lock_table_autoinc_for_mysql(
932 /*=============================*/
933 /* out: error code or DB_SUCCESS */
934 row_prebuilt_t* prebuilt) /* in: prebuilt struct in the MySQL
935 table handle */
937 trx_t* trx = prebuilt->trx;
938 ins_node_t* node = prebuilt->ins_node;
939 que_thr_t* thr;
940 ulint err;
941 ibool was_lock_wait;
943 ut_ad(trx);
944 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
946 if (trx->auto_inc_lock) {
948 return(DB_SUCCESS);
951 trx->op_info = "setting auto-inc lock";
953 if (node == NULL) {
954 row_get_prebuilt_insert_row(prebuilt);
955 node = prebuilt->ins_node;
958 /* We use the insert query graph as the dummy graph needed
959 in the lock module call */
961 thr = que_fork_get_first_thr(prebuilt->ins_graph);
963 que_thr_move_to_run_state_for_mysql(thr, trx);
965 run_again:
966 thr->run_node = node;
967 thr->prev_node = node;
969 /* It may be that the current session has not yet started
970 its transaction, or it has been committed: */
972 trx_start_if_not_started(trx);
974 err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
976 trx->error_state = err;
978 if (err != DB_SUCCESS) {
979 que_thr_stop_for_mysql(thr);
981 was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
983 if (was_lock_wait) {
984 goto run_again;
987 trx->op_info = "";
989 return((int) err);
992 que_thr_stop_for_mysql_no_error(thr, trx);
994 trx->op_info = "";
996 return((int) err);
999 /*************************************************************************
1000 Sets a table lock on the table mentioned in prebuilt. */
1003 row_lock_table_for_mysql(
1004 /*=====================*/
1005 /* out: error code or DB_SUCCESS */
1006 row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL
1007 table handle */
1008 dict_table_t* table, /* in: table to lock, or NULL
1009 if prebuilt->table should be
1010 locked as
1011 prebuilt->select_lock_type */
1012 ulint mode) /* in: lock mode of table
1013 (ignored if table==NULL) */
1015 trx_t* trx = prebuilt->trx;
1016 que_thr_t* thr;
1017 ulint err;
1018 ibool was_lock_wait;
1020 ut_ad(trx);
1021 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1023 trx->op_info = "setting table lock";
1025 if (prebuilt->sel_graph == NULL) {
1026 /* Build a dummy select query graph */
1027 row_prebuild_sel_graph(prebuilt);
1030 /* We use the select query graph as the dummy graph needed
1031 in the lock module call */
1033 thr = que_fork_get_first_thr(prebuilt->sel_graph);
1035 que_thr_move_to_run_state_for_mysql(thr, trx);
1037 run_again:
1038 thr->run_node = thr;
1039 thr->prev_node = thr->common.parent;
1041 /* It may be that the current session has not yet started
1042 its transaction, or it has been committed: */
1044 trx_start_if_not_started(trx);
1046 if (table) {
1047 err = lock_table(0, table, mode, thr);
1048 } else {
1049 err = lock_table(0, prebuilt->table,
1050 prebuilt->select_lock_type, thr);
1053 trx->error_state = err;
1055 if (err != DB_SUCCESS) {
1056 que_thr_stop_for_mysql(thr);
1058 was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1060 if (was_lock_wait) {
1061 goto run_again;
1064 trx->op_info = "";
1066 return((int) err);
1069 que_thr_stop_for_mysql_no_error(thr, trx);
1071 trx->op_info = "";
1073 return((int) err);
1076 /*************************************************************************
1077 Does an insert for MySQL. */
1080 row_insert_for_mysql(
1081 /*=================*/
1082 /* out: error code or DB_SUCCESS */
1083 byte* mysql_rec, /* in: row in the MySQL format */
1084 row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1085 handle */
1087 trx_savept_t savept;
1088 que_thr_t* thr;
1089 ulint err;
1090 ibool was_lock_wait;
1091 trx_t* trx = prebuilt->trx;
1092 ins_node_t* node = prebuilt->ins_node;
1094 ut_ad(trx);
1095 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1097 if (prebuilt->table->ibd_file_missing) {
1098 ut_print_timestamp(stderr);
1099 fprintf(stderr, " InnoDB: Error:\n"
1100 "InnoDB: MySQL is trying to use a table handle"
1101 " but the .ibd file for\n"
1102 "InnoDB: table %s does not exist.\n"
1103 "InnoDB: Have you deleted the .ibd file"
1104 " from the database directory under\n"
1105 "InnoDB: the MySQL datadir, or have you"
1106 " used DISCARD TABLESPACE?\n"
1107 "InnoDB: Look from\n"
1108 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
1109 "innodb-troubleshooting.html\n"
1110 "InnoDB: how you can resolve the problem.\n",
1111 prebuilt->table->name);
1112 return(DB_ERROR);
1115 if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
1116 fprintf(stderr,
1117 "InnoDB: Error: trying to free a corrupt\n"
1118 "InnoDB: table handle. Magic n %lu, table name",
1119 (ulong) prebuilt->magic_n);
1120 ut_print_name(stderr, prebuilt->trx, TRUE,
1121 prebuilt->table->name);
1122 putc('\n', stderr);
1124 mem_analyze_corruption(prebuilt);
1126 ut_error;
1129 if (srv_created_new_raw || srv_force_recovery) {
1130 fputs("InnoDB: A new raw disk partition was initialized or\n"
1131 "InnoDB: innodb_force_recovery is on: we do not allow\n"
1132 "InnoDB: database modifications by the user. Shut down\n"
1133 "InnoDB: mysqld and edit my.cnf so that"
1134 " newraw is replaced\n"
1135 "InnoDB: with raw, and innodb_force_... is removed.\n",
1136 stderr);
1138 return(DB_ERROR);
1141 trx->op_info = "inserting";
1143 row_mysql_delay_if_needed();
1145 trx_start_if_not_started(trx);
1147 if (node == NULL) {
1148 row_get_prebuilt_insert_row(prebuilt);
1149 node = prebuilt->ins_node;
1152 row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1154 savept = trx_savept_take(trx);
1156 thr = que_fork_get_first_thr(prebuilt->ins_graph);
1158 if (prebuilt->sql_stat_start) {
1159 node->state = INS_NODE_SET_IX_LOCK;
1160 prebuilt->sql_stat_start = FALSE;
1161 } else {
1162 node->state = INS_NODE_ALLOC_ROW_ID;
1165 que_thr_move_to_run_state_for_mysql(thr, trx);
1167 run_again:
1168 thr->run_node = node;
1169 thr->prev_node = node;
1171 row_ins_step(thr);
1173 err = trx->error_state;
1175 if (err != DB_SUCCESS) {
1176 que_thr_stop_for_mysql(thr);
1178 /* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1180 was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1181 &savept);
1182 thr->lock_state= QUE_THR_LOCK_NOLOCK;
1184 if (was_lock_wait) {
1185 goto run_again;
1188 trx->op_info = "";
1190 return((int) err);
1193 que_thr_stop_for_mysql_no_error(thr, trx);
1195 prebuilt->table->stat_n_rows++;
1197 srv_n_rows_inserted++;
1199 if (prebuilt->table->stat_n_rows == 0) {
1200 /* Avoid wrap-over */
1201 prebuilt->table->stat_n_rows--;
1204 row_update_statistics_if_needed(prebuilt->table);
1205 trx->op_info = "";
1207 return((int) err);
1210 /*************************************************************************
1211 Builds a dummy query graph used in selects. */
1213 void
1214 row_prebuild_sel_graph(
1215 /*===================*/
1216 row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1217 handle */
1219 sel_node_t* node;
1221 ut_ad(prebuilt && prebuilt->trx);
1223 if (prebuilt->sel_graph == NULL) {
1225 node = sel_node_create(prebuilt->heap);
1227 prebuilt->sel_graph = que_node_get_parent(
1228 pars_complete_graph_for_exec(node,
1229 prebuilt->trx,
1230 prebuilt->heap));
1232 prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1236 /*************************************************************************
1237 Creates an query graph node of 'update' type to be used in the MySQL
1238 interface. */
1240 upd_node_t*
1241 row_create_update_node_for_mysql(
1242 /*=============================*/
1243 /* out, own: update node */
1244 dict_table_t* table, /* in: table to update */
1245 mem_heap_t* heap) /* in: mem heap from which allocated */
1247 upd_node_t* node;
1249 node = upd_node_create(heap);
1251 node->in_mysql_interface = TRUE;
1252 node->is_delete = FALSE;
1253 node->searched_update = FALSE;
1254 node->select_will_do_update = FALSE;
1255 node->select = NULL;
1256 node->pcur = btr_pcur_create_for_mysql();
1257 node->table = table;
1259 node->update = upd_create(dict_table_get_n_cols(table), heap);
1261 node->update_n_fields = dict_table_get_n_cols(table);
1263 UT_LIST_INIT(node->columns);
1264 node->has_clust_rec_x_lock = TRUE;
1265 node->cmpl_info = 0;
1267 node->table_sym = NULL;
1268 node->col_assign_list = NULL;
1270 return(node);
1273 /*************************************************************************
1274 Gets pointer to a prebuilt update vector used in updates. If the update
1275 graph has not yet been built in the prebuilt struct, then this function
1276 first builds it. */
1278 upd_t*
1279 row_get_prebuilt_update_vector(
1280 /*===========================*/
1281 /* out: prebuilt update vector */
1282 row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1283 handle */
1285 dict_table_t* table = prebuilt->table;
1286 upd_node_t* node;
1288 ut_ad(prebuilt && table && prebuilt->trx);
1290 if (prebuilt->upd_node == NULL) {
1292 /* Not called before for this handle: create an update node
1293 and query graph to the prebuilt struct */
1295 node = row_create_update_node_for_mysql(table, prebuilt->heap);
1297 prebuilt->upd_node = node;
1299 prebuilt->upd_graph = que_node_get_parent(
1300 pars_complete_graph_for_exec(node,
1301 prebuilt->trx,
1302 prebuilt->heap));
1303 prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1306 return(prebuilt->upd_node->update);
1309 /*************************************************************************
1310 Does an update or delete of a row for MySQL. */
1313 row_update_for_mysql(
1314 /*=================*/
1315 /* out: error code or DB_SUCCESS */
1316 byte* mysql_rec, /* in: the row to be updated, in
1317 the MySQL format */
1318 row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1319 handle */
1321 trx_savept_t savept;
1322 ulint err;
1323 que_thr_t* thr;
1324 ibool was_lock_wait;
1325 dict_index_t* clust_index;
1326 /* ulint ref_len; */
1327 upd_node_t* node;
1328 dict_table_t* table = prebuilt->table;
1329 trx_t* trx = prebuilt->trx;
1331 ut_ad(prebuilt && trx);
1332 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1333 UT_NOT_USED(mysql_rec);
1335 if (prebuilt->table->ibd_file_missing) {
1336 ut_print_timestamp(stderr);
1337 fprintf(stderr, " InnoDB: Error:\n"
1338 "InnoDB: MySQL is trying to use a table handle"
1339 " but the .ibd file for\n"
1340 "InnoDB: table %s does not exist.\n"
1341 "InnoDB: Have you deleted the .ibd file"
1342 " from the database directory under\n"
1343 "InnoDB: the MySQL datadir, or have you"
1344 " used DISCARD TABLESPACE?\n"
1345 "InnoDB: Look from\n"
1346 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
1347 "innodb-troubleshooting.html\n"
1348 "InnoDB: how you can resolve the problem.\n",
1349 prebuilt->table->name);
1350 return(DB_ERROR);
1353 if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
1354 fprintf(stderr,
1355 "InnoDB: Error: trying to free a corrupt\n"
1356 "InnoDB: table handle. Magic n %lu, table name",
1357 (ulong) prebuilt->magic_n);
1358 ut_print_name(stderr, prebuilt->trx, TRUE,
1359 prebuilt->table->name);
1360 putc('\n', stderr);
1362 mem_analyze_corruption(prebuilt);
1364 ut_error;
1367 if (srv_created_new_raw || srv_force_recovery) {
1368 fputs("InnoDB: A new raw disk partition was initialized or\n"
1369 "InnoDB: innodb_force_recovery is on: we do not allow\n"
1370 "InnoDB: database modifications by the user. Shut down\n"
1371 "InnoDB: mysqld and edit my.cnf so that newraw"
1372 " is replaced\n"
1373 "InnoDB: with raw, and innodb_force_... is removed.\n",
1374 stderr);
1376 return(DB_ERROR);
1379 DEBUG_SYNC_C("innodb_row_update_for_mysql_begin");
1381 trx->op_info = "updating or deleting";
1383 row_mysql_delay_if_needed();
1385 trx_start_if_not_started(trx);
1387 node = prebuilt->upd_node;
1389 clust_index = dict_table_get_first_index(table);
1391 if (prebuilt->pcur->btr_cur.index == clust_index) {
1392 btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1393 } else {
1394 btr_pcur_copy_stored_position(node->pcur,
1395 prebuilt->clust_pcur);
1398 ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1400 /* MySQL seems to call rnd_pos before updating each row it
1401 has cached: we can get the correct cursor position from
1402 prebuilt->pcur; NOTE that we cannot build the row reference
1403 from mysql_rec if the clustered index was automatically
1404 generated for the table: MySQL does not know anything about
1405 the row id used as the clustered index key */
1407 savept = trx_savept_take(trx);
1409 thr = que_fork_get_first_thr(prebuilt->upd_graph);
1411 node->state = UPD_NODE_UPDATE_CLUSTERED;
1413 ut_ad(!prebuilt->sql_stat_start);
1415 que_thr_move_to_run_state_for_mysql(thr, trx);
1417 run_again:
1418 thr->run_node = node;
1419 thr->prev_node = node;
1420 thr->fk_cascade_depth = 0;
1422 row_upd_step(thr);
1424 err = trx->error_state;
1426 /* Reset fk_cascade_depth back to 0 */
1427 thr->fk_cascade_depth = 0;
1429 if (err != DB_SUCCESS) {
1430 que_thr_stop_for_mysql(thr);
1432 if (err == DB_RECORD_NOT_FOUND) {
1433 trx->error_state = DB_SUCCESS;
1434 trx->op_info = "";
1436 return((int) err);
1439 thr->lock_state= QUE_THR_LOCK_ROW;
1440 was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1441 &savept);
1442 thr->lock_state= QUE_THR_LOCK_NOLOCK;
1444 if (was_lock_wait) {
1445 goto run_again;
1448 trx->op_info = "";
1450 return((int) err);
1453 que_thr_stop_for_mysql_no_error(thr, trx);
1455 if (node->is_delete) {
1456 if (prebuilt->table->stat_n_rows > 0) {
1457 prebuilt->table->stat_n_rows--;
1460 srv_n_rows_deleted++;
1461 } else {
1462 srv_n_rows_updated++;
1465 /* We update table statistics only if it is a DELETE or UPDATE
1466 that changes indexed columns, UPDATEs that change only non-indexed
1467 columns would not affect statistics. */
1468 if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1469 row_update_statistics_if_needed(prebuilt->table);
1472 trx->op_info = "";
1474 return((int) err);
1477 /*************************************************************************
1478 This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
1479 session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
1480 Before calling this function row_search_for_mysql() must have
1481 initialized prebuilt->new_rec_locks to store the information which new
1482 record locks really were set. This function removes a newly set
1483 clustered index record lock under prebuilt->pcur or
1484 prebuilt->clust_pcur. Thus, this implements a 'mini-rollback' that
1485 releases the latest clustered index record lock we set. */
1488 row_unlock_for_mysql(
1489 /*=================*/
1490 /* out: error code or DB_SUCCESS */
1491 row_prebuilt_t* prebuilt, /* in/out: prebuilt struct in MySQL
1492 handle */
1493 ibool has_latches_on_recs)/* TRUE if called so that we have
1494 the latches on the records under pcur
1495 and clust_pcur, and we do not need to
1496 reposition the cursors. */
1498 btr_pcur_t* pcur = prebuilt->pcur;
1499 btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
1500 trx_t* trx = prebuilt->trx;
1502 ut_ad(prebuilt && trx);
1503 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1505 if (UNIV_UNLIKELY
1506 (!srv_locks_unsafe_for_binlog
1507 && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
1509 fprintf(stderr,
1510 "InnoDB: Error: calling row_unlock_for_mysql though\n"
1511 "InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
1512 "InnoDB: this session is not using"
1513 " READ COMMITTED isolation level.\n");
1515 return(DB_SUCCESS);
1518 trx->op_info = "unlock_row";
1520 if (prebuilt->new_rec_locks >= 1) {
1522 rec_t* rec;
1523 dict_index_t* index;
1524 dulint rec_trx_id;
1525 mtr_t mtr;
1527 mtr_start(&mtr);
1529 /* Restore the cursor position and find the record */
1531 if (!has_latches_on_recs) {
1532 btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1535 rec = btr_pcur_get_rec(pcur);
1536 index = btr_pcur_get_btr_cur(pcur)->index;
1538 if (prebuilt->new_rec_locks >= 2) {
1539 /* Restore the cursor position and find the record
1540 in the clustered index. */
1542 if (!has_latches_on_recs) {
1543 btr_pcur_restore_position(BTR_SEARCH_LEAF,
1544 clust_pcur, &mtr);
1547 rec = btr_pcur_get_rec(clust_pcur);
1548 index = btr_pcur_get_btr_cur(clust_pcur)->index;
1551 if (UNIV_UNLIKELY(!(index->type & DICT_CLUSTERED))) {
1552 /* This is not a clustered index record. We
1553 do not know how to unlock the record. */
1554 goto no_unlock;
1557 /* If the record has been modified by this
1558 transaction, do not unlock it. */
1560 if (index->trx_id_offset) {
1561 rec_trx_id = trx_read_trx_id(rec
1562 + index->trx_id_offset);
1563 } else {
1564 mem_heap_t* heap = NULL;
1565 ulint offsets_[REC_OFFS_NORMAL_SIZE];
1566 ulint* offsets = offsets_;
1568 *offsets_ = (sizeof offsets_) / sizeof *offsets_;
1569 offsets = rec_get_offsets(rec, index, offsets,
1570 ULINT_UNDEFINED, &heap);
1572 rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1574 if (UNIV_LIKELY_NULL(heap)) {
1575 mem_heap_free(heap);
1579 if (ut_dulint_cmp(rec_trx_id, trx->id) != 0) {
1580 /* We did not update the record: unlock it */
1582 rec = btr_pcur_get_rec(pcur);
1583 index = btr_pcur_get_btr_cur(pcur)->index;
1585 lock_rec_unlock(trx, rec, prebuilt->select_lock_type);
1587 if (prebuilt->new_rec_locks >= 2) {
1588 rec = btr_pcur_get_rec(clust_pcur);
1589 index = btr_pcur_get_btr_cur(clust_pcur)->index;
1591 lock_rec_unlock(trx, rec,
1592 prebuilt->select_lock_type);
1595 no_unlock:
1596 mtr_commit(&mtr);
1599 trx->op_info = "";
1601 return(DB_SUCCESS);
1604 /**************************************************************************
1605 Does a cascaded delete or set null in a foreign key operation. */
1607 ulint
1608 row_update_cascade_for_mysql(
1609 /*=========================*/
1610 /* out: error code or DB_SUCCESS */
1611 que_thr_t* thr, /* in: query thread */
1612 upd_node_t* node, /* in: update node used in the cascade
1613 or set null operation */
1614 dict_table_t* table) /* in: table where we do the operation */
1616 ulint err;
1617 trx_t* trx;
1619 trx = thr_get_trx(thr);
1621 /* Increment fk_cascade_depth to record the recursive call depth on
1622 a single update/delete that affects multiple tables chained
1623 together with foreign key relations. */
1624 thr->fk_cascade_depth++;
1626 if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
1627 return (DB_FOREIGN_EXCEED_MAX_CASCADE);
1629 run_again:
1630 thr->run_node = node;
1631 thr->prev_node = node;
1633 row_upd_step(thr);
1635 /* The recursive call for cascading update/delete happens
1636 in above row_upd_step(), reset the counter once we come
1637 out of the recursive call, so it does not accumulate for
1638 different row deletes */
1639 thr->fk_cascade_depth = 0;
1641 err = trx->error_state;
1643 /* Note that the cascade node is a subnode of another InnoDB
1644 query graph node. We do a normal lock wait in this node, but
1645 all errors are handled by the parent node. */
1647 if (err == DB_LOCK_WAIT) {
1648 /* Handle lock wait here */
1650 que_thr_stop_for_mysql(thr);
1652 srv_suspend_mysql_thread(thr);
1654 /* Note that a lock wait may also end in a lock wait timeout,
1655 or this transaction is picked as a victim in selective
1656 deadlock resolution */
1658 if (trx->error_state != DB_SUCCESS) {
1660 return(trx->error_state);
1663 /* Retry operation after a normal lock wait */
1665 goto run_again;
1668 if (err != DB_SUCCESS) {
1670 return(err);
1673 if (node->is_delete) {
1674 if (table->stat_n_rows > 0) {
1675 table->stat_n_rows--;
1678 srv_n_rows_deleted++;
1679 } else {
1680 srv_n_rows_updated++;
1683 row_update_statistics_if_needed(table);
1685 return(err);
1688 /*************************************************************************
1689 Checks if a table is such that we automatically created a clustered
1690 index on it (on row id). */
1692 ibool
1693 row_table_got_default_clust_index(
1694 /*==============================*/
1695 dict_table_t* table)
1697 const dict_index_t* clust_index;
1699 clust_index = dict_table_get_first_index(table);
1701 return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1704 /*************************************************************************
1705 Calculates the key number used inside MySQL for an Innobase index. We have
1706 to take into account if we generated a default clustered index for the table */
1708 ulint
1709 row_get_mysql_key_number_for_index(
1710 /*===============================*/
1711 dict_index_t* index)
1713 dict_index_t* ind;
1714 ulint i;
1716 ut_a(index);
1718 i = 0;
1719 ind = dict_table_get_first_index(index->table);
1721 while (index != ind) {
1722 ind = dict_table_get_next_index(ind);
1723 i++;
1726 if (row_table_got_default_clust_index(index->table)) {
1727 ut_a(i > 0);
1728 i--;
1731 return(i);
1734 /*************************************************************************
1735 Locks the data dictionary in shared mode from modifications, for performing
1736 foreign key check, rollback, or other operation invisible to MySQL. */
1738 void
1739 row_mysql_freeze_data_dictionary(
1740 /*=============================*/
1741 trx_t* trx) /* in: transaction */
1743 ut_a(trx->dict_operation_lock_mode == 0);
1745 rw_lock_s_lock(&dict_operation_lock);
1747 trx->dict_operation_lock_mode = RW_S_LATCH;
1750 /*************************************************************************
1751 Unlocks the data dictionary shared lock. */
1753 void
1754 row_mysql_unfreeze_data_dictionary(
1755 /*===============================*/
1756 trx_t* trx) /* in: transaction */
1758 ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
1760 rw_lock_s_unlock(&dict_operation_lock);
1762 trx->dict_operation_lock_mode = 0;
1765 /*************************************************************************
1766 Locks the data dictionary exclusively for performing a table create or other
1767 data dictionary modification operation. */
1769 void
1770 row_mysql_lock_data_dictionary(
1771 /*===========================*/
1772 trx_t* trx) /* in: transaction */
1774 ut_a(trx->dict_operation_lock_mode == 0
1775 || trx->dict_operation_lock_mode == RW_X_LATCH);
1777 /* Serialize data dictionary operations with dictionary mutex:
1778 no deadlocks or lock waits can occur then in these operations */
1780 rw_lock_x_lock(&dict_operation_lock);
1781 trx->dict_operation_lock_mode = RW_X_LATCH;
1783 mutex_enter(&(dict_sys->mutex));
1786 /*************************************************************************
1787 Unlocks the data dictionary exclusive lock. */
1789 void
1790 row_mysql_unlock_data_dictionary(
1791 /*=============================*/
1792 trx_t* trx) /* in: transaction */
1794 ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1796 /* Serialize data dictionary operations with dictionary mutex:
1797 no deadlocks can occur then in these operations */
1799 mutex_exit(&(dict_sys->mutex));
1800 rw_lock_x_unlock(&dict_operation_lock);
1802 trx->dict_operation_lock_mode = 0;
1805 /*************************************************************************
1806 Creates a table for MySQL. If the name of the table ends in
1807 one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
1808 "innodb_table_monitor", then this will also start the printing of monitor
1809 output by the master thread. If the table name ends in "innodb_mem_validate",
1810 InnoDB will try to invoke mem_validate(). */
1813 row_create_table_for_mysql(
1814 /*=======================*/
1815 /* out: error code or DB_SUCCESS */
1816 dict_table_t* table, /* in: table definition */
1817 trx_t* trx) /* in: transaction handle */
1819 tab_node_t* node;
1820 mem_heap_t* heap;
1821 que_thr_t* thr;
1822 const char* table_name;
1823 ulint table_name_len;
1824 ulint err;
1826 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1827 #ifdef UNIV_SYNC_DEBUG
1828 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1829 #endif /* UNIV_SYNC_DEBUG */
1830 ut_ad(mutex_own(&(dict_sys->mutex)));
1831 ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1833 if (srv_created_new_raw) {
1834 fputs("InnoDB: A new raw disk partition was initialized:\n"
1835 "InnoDB: we do not allow database modifications"
1836 " by the user.\n"
1837 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1838 " is replaced with raw.\n", stderr);
1840 dict_mem_table_free(table);
1841 trx_commit_for_mysql(trx);
1843 return(DB_ERROR);
1846 trx->op_info = "creating table";
1848 if (row_mysql_is_system_table(table->name)) {
1850 fprintf(stderr,
1851 "InnoDB: Error: trying to create a MySQL system"
1852 " table %s of type InnoDB.\n"
1853 "InnoDB: MySQL system tables must be"
1854 " of the MyISAM type!\n",
1855 table->name);
1857 dict_mem_table_free(table);
1858 trx_commit_for_mysql(trx);
1860 return(DB_ERROR);
1863 trx_start_if_not_started(trx);
1865 /* The table name is prefixed with the database name and a '/'.
1866 Certain table names starting with 'innodb_' have their special
1867 meaning regardless of the database name. Thus, we need to
1868 ignore the database name prefix in the comparisons. */
1869 table_name = strchr(table->name, '/');
1870 ut_a(table_name);
1871 table_name++;
1872 table_name_len = strlen(table_name) + 1;
1874 if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
1876 /* Table equals "innodb_monitor":
1877 start monitor prints */
1879 srv_print_innodb_monitor = TRUE;
1881 /* The lock timeout monitor thread also takes care
1882 of InnoDB monitor prints */
1884 os_event_set(srv_lock_timeout_thread_event);
1885 } else if (STR_EQ(table_name, table_name_len,
1886 S_innodb_lock_monitor)) {
1888 srv_print_innodb_monitor = TRUE;
1889 srv_print_innodb_lock_monitor = TRUE;
1890 os_event_set(srv_lock_timeout_thread_event);
1891 } else if (STR_EQ(table_name, table_name_len,
1892 S_innodb_tablespace_monitor)) {
1894 srv_print_innodb_tablespace_monitor = TRUE;
1895 os_event_set(srv_lock_timeout_thread_event);
1896 } else if (STR_EQ(table_name, table_name_len,
1897 S_innodb_table_monitor)) {
1899 srv_print_innodb_table_monitor = TRUE;
1900 os_event_set(srv_lock_timeout_thread_event);
1901 } else if (STR_EQ(table_name, table_name_len,
1902 S_innodb_mem_validate)) {
1903 /* We define here a debugging feature intended for
1904 developers */
1906 fputs("Validating InnoDB memory:\n"
1907 "to use this feature you must compile InnoDB with\n"
1908 "UNIV_MEM_DEBUG defined in univ.i and"
1909 " the server must be\n"
1910 "quiet because allocation from a mem heap"
1911 " is not protected\n"
1912 "by any semaphore.\n", stderr);
1913 #ifdef UNIV_MEM_DEBUG
1914 ut_a(mem_validate());
1915 fputs("Memory validated\n", stderr);
1916 #else /* UNIV_MEM_DEBUG */
1917 fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1918 stderr);
1919 #endif /* UNIV_MEM_DEBUG */
1922 heap = mem_heap_create(512);
1924 trx->dict_operation = TRUE;
1926 node = tab_create_graph_create(table, heap);
1928 thr = pars_complete_graph_for_exec(node, trx, heap);
1930 ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1931 que_run_threads(thr);
1933 err = trx->error_state;
1935 if (err != DB_SUCCESS) {
1936 /* We have special error handling here */
1938 trx->error_state = DB_SUCCESS;
1940 trx_general_rollback_for_mysql(trx, FALSE, NULL);
1942 if (err == DB_OUT_OF_FILE_SPACE) {
1943 ut_print_timestamp(stderr);
1945 fputs(" InnoDB: Warning: cannot create table ",
1946 stderr);
1947 ut_print_name(stderr, trx, TRUE, table->name);
1948 fputs(" because tablespace full\n", stderr);
1950 if (dict_table_get_low(table->name)) {
1952 row_drop_table_for_mysql(table->name, trx,
1953 FALSE);
1956 } else if (err == DB_TOO_MANY_CONCURRENT_TRXS) {
1957 /* We already have .ibd file here. it should be deleted. */
1958 if (table->space
1959 && !fil_delete_tablespace(table->space)) {
1960 ut_print_timestamp(stderr);
1961 fprintf(stderr,
1962 " InnoDB: Error: not able to"
1963 " delete tablespace %lu of table ",
1964 (ulong) table->space);
1965 ut_print_name(stderr, trx, TRUE, table->name);
1966 fputs("!\n", stderr);
1968 } else if (err == DB_DUPLICATE_KEY) {
1969 ut_print_timestamp(stderr);
1971 fputs(" InnoDB: Error: table ", stderr);
1972 ut_print_name(stderr, trx, TRUE, table->name);
1973 fputs(" already exists in InnoDB internal\n"
1974 "InnoDB: data dictionary. Have you deleted"
1975 " the .frm file\n"
1976 "InnoDB: and not used DROP TABLE?"
1977 " Have you used DROP DATABASE\n"
1978 "InnoDB: for InnoDB tables in"
1979 " MySQL version <= 3.23.43?\n"
1980 "InnoDB: See the Restrictions section"
1981 " of the InnoDB manual.\n"
1982 "InnoDB: You can drop the orphaned table"
1983 " inside InnoDB by\n"
1984 "InnoDB: creating an InnoDB table with"
1985 " the same name in another\n"
1986 "InnoDB: database and copying the .frm file"
1987 " to the current database.\n"
1988 "InnoDB: Then MySQL thinks the table exists,"
1989 " and DROP TABLE will\n"
1990 "InnoDB: succeed.\n"
1991 "InnoDB: You can look for further help from\n"
1992 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
1993 "innodb-troubleshooting.html\n",
1994 stderr);
1997 /* We may also get err == DB_ERROR if the .ibd file for the
1998 table already exists */
2000 trx->error_state = DB_SUCCESS;
2001 dict_mem_table_free(table);
2004 que_graph_free((que_t*) que_node_get_parent(thr));
2006 trx->op_info = "";
2008 return((int) err);
2011 /*************************************************************************
2012 Does an index creation operation for MySQL. TODO: currently failure
2013 to create an index results in dropping the whole table! This is no problem
2014 currently as all indexes must be created at the same time as the table. */
2017 row_create_index_for_mysql(
2018 /*=======================*/
2019 /* out: error number or DB_SUCCESS */
2020 dict_index_t* index, /* in: index definition */
2021 trx_t* trx, /* in: transaction handle */
2022 const ulint* field_lengths) /* in: if not NULL, must contain
2023 dict_index_get_n_fields(index)
2024 actual field lengths for the
2025 index columns, which are
2026 then checked for not being too
2027 large. */
2029 ind_node_t* node;
2030 mem_heap_t* heap;
2031 que_thr_t* thr;
2032 ulint err;
2033 ulint i, j;
2034 ulint len;
2035 char* table_name;
2037 #ifdef UNIV_SYNC_DEBUG
2038 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2039 #endif /* UNIV_SYNC_DEBUG */
2040 ut_ad(mutex_own(&(dict_sys->mutex)));
2041 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2043 trx->op_info = "creating index";
2045 /* Copy the table name because we may want to drop the
2046 table later, after the index object is freed (inside
2047 que_run_threads()) and thus index->table_name is not available. */
2048 table_name = mem_strdup(index->table_name);
2050 trx_start_if_not_started(trx);
2052 /* Check that the same column does not appear twice in the index.
2053 Starting from 4.0.14, InnoDB should be able to cope with that, but
2054 safer not to allow them. */
2056 for (i = 0; i < dict_index_get_n_fields(index); i++) {
2057 for (j = 0; j < i; j++) {
2058 if (0 == ut_strcmp(
2059 dict_index_get_nth_field(index, j)->name,
2060 dict_index_get_nth_field(index, i)->name)) {
2062 ut_print_timestamp(stderr);
2064 fputs(" InnoDB: Error: column ", stderr);
2065 ut_print_name(stderr, trx, FALSE,
2066 dict_index_get_nth_field(
2067 index, i)->name);
2068 fputs(" appears twice in ", stderr);
2069 dict_index_name_print(stderr, trx, index);
2070 fputs("\n"
2071 "InnoDB: This is not allowed"
2072 " in InnoDB.\n", stderr);
2074 err = DB_COL_APPEARS_TWICE_IN_INDEX;
2076 goto error_handling;
2080 /* Check also that prefix_len and actual length
2081 < DICT_MAX_INDEX_COL_LEN */
2083 len = dict_index_get_nth_field(index, i)->prefix_len;
2085 if (field_lengths) {
2086 len = ut_max(len, field_lengths[i]);
2089 if (len >= DICT_MAX_INDEX_COL_LEN) {
2090 err = DB_TOO_BIG_RECORD;
2092 goto error_handling;
2096 heap = mem_heap_create(512);
2098 trx->dict_operation = TRUE;
2100 /* Note that the space id where we store the index is inherited from
2101 the table in dict_build_index_def_step() in dict0crea.c. */
2103 node = ind_create_graph_create(index, heap);
2105 thr = pars_complete_graph_for_exec(node, trx, heap);
2107 ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2108 que_run_threads(thr);
2110 err = trx->error_state;
2112 que_graph_free((que_t*) que_node_get_parent(thr));
2114 error_handling:
2115 if (err != DB_SUCCESS) {
2116 /* We have special error handling here */
2118 trx->error_state = DB_SUCCESS;
2120 trx_general_rollback_for_mysql(trx, FALSE, NULL);
2122 row_drop_table_for_mysql(table_name, trx, FALSE);
2124 trx->error_state = DB_SUCCESS;
2127 trx->op_info = "";
2129 mem_free(table_name);
2131 return((int) err);
2134 /*************************************************************************
2135 Scans a table create SQL string and adds to the data dictionary
2136 the foreign key constraints declared in the string. This function
2137 should be called after the indexes for a table have been created.
2138 Each foreign key constraint must be accompanied with indexes in
2139 both participating tables. The indexes are allowed to contain more
2140 fields than mentioned in the constraint. Check also that foreign key
2141 constraints which reference this table are ok. */
2144 row_table_add_foreign_constraints(
2145 /*==============================*/
2146 /* out: error code or DB_SUCCESS */
2147 trx_t* trx, /* in: transaction */
2148 const char* sql_string, /* in: table create statement where
2149 foreign keys are declared like:
2150 FOREIGN KEY (a, b) REFERENCES table2(c, d),
2151 table2 can be written also with the
2152 database name before it: test.table2 */
2153 size_t sql_length, /* in: length of sql_string */
2154 const char* name, /* in: table full name in the
2155 normalized form
2156 database_name/table_name */
2157 ibool reject_fks) /* in: if TRUE, fail with error
2158 code DB_CANNOT_ADD_CONSTRAINT if
2159 any foreign keys are found. */
2161 ulint err;
2163 ut_ad(mutex_own(&(dict_sys->mutex)));
2164 #ifdef UNIV_SYNC_DEBUG
2165 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2166 #endif /* UNIV_SYNC_DEBUG */
2167 ut_a(sql_string);
2169 trx->op_info = "adding foreign keys";
2171 trx_start_if_not_started(trx);
2173 trx->dict_operation = TRUE;
2175 err = dict_create_foreign_constraints(trx, sql_string, sql_length,
2176 name, reject_fks);
2178 if (err == DB_SUCCESS) {
2179 /* Check that also referencing constraints are ok */
2180 err = dict_load_foreigns(name, FALSE, TRUE);
2183 if (err != DB_SUCCESS) {
2184 /* We have special error handling here */
2186 trx->error_state = DB_SUCCESS;
2188 trx_general_rollback_for_mysql(trx, FALSE, NULL);
2190 row_drop_table_for_mysql(name, trx, FALSE);
2192 trx->error_state = DB_SUCCESS;
2195 return((int) err);
2198 /*************************************************************************
2199 Drops a table for MySQL as a background operation. MySQL relies on Unix
2200 in ALTER TABLE to the fact that the table handler does not remove the
2201 table before all handles to it has been removed. Furhermore, the MySQL's
2202 call to drop table must be non-blocking. Therefore we do the drop table
2203 as a background operation, which is taken care of by the master thread
2204 in srv0srv.c. */
2205 static
2207 row_drop_table_for_mysql_in_background(
2208 /*===================================*/
2209 /* out: error code or DB_SUCCESS */
2210 const char* name) /* in: table name */
2212 ulint error;
2213 trx_t* trx;
2215 trx = trx_allocate_for_background();
2217 /* If the original transaction was dropping a table referenced by
2218 foreign keys, we must set the following to be able to drop the
2219 table: */
2221 trx->check_foreigns = FALSE;
2223 /* fputs("InnoDB: Error: Dropping table ", stderr);
2224 ut_print_name(stderr, trx, TRUE, name);
2225 fputs(" in background drop list\n", stderr); */
2227 /* Try to drop the table in InnoDB */
2229 error = row_drop_table_for_mysql(name, trx, FALSE);
2231 /* Flush the log to reduce probability that the .frm files and
2232 the InnoDB data dictionary get out-of-sync if the user runs
2233 with innodb_flush_log_at_trx_commit = 0 */
2235 log_buffer_flush_to_disk();
2237 trx_commit_for_mysql(trx);
2239 trx_free_for_background(trx);
2241 return((int) error);
2244 /*************************************************************************
2245 The master thread in srv0srv.c calls this regularly to drop tables which
2246 we must drop in background after queries to them have ended. Such lazy
2247 dropping of tables is needed in ALTER TABLE on Unix. */
2249 ulint
2250 row_drop_tables_for_mysql_in_background(void)
2251 /*=========================================*/
2252 /* out: how many tables dropped
2253 + remaining tables in list */
2255 row_mysql_drop_t* drop;
2256 dict_table_t* table;
2257 ulint n_tables;
2258 ulint n_tables_dropped = 0;
2259 loop:
2260 mutex_enter(&kernel_mutex);
2262 if (!row_mysql_drop_list_inited) {
2264 UT_LIST_INIT(row_mysql_drop_list);
2265 row_mysql_drop_list_inited = TRUE;
2268 drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2270 n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2272 mutex_exit(&kernel_mutex);
2274 if (drop == NULL) {
2275 /* All tables dropped */
2277 return(n_tables + n_tables_dropped);
2280 mutex_enter(&(dict_sys->mutex));
2281 table = dict_table_get_low(drop->table_name);
2282 mutex_exit(&(dict_sys->mutex));
2284 if (table == NULL) {
2285 /* If for some reason the table has already been dropped
2286 through some other mechanism, do not try to drop it */
2288 goto already_dropped;
2291 if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2292 drop->table_name)) {
2293 /* If the DROP fails for some table, we return, and let the
2294 main thread retry later */
2296 return(n_tables + n_tables_dropped);
2299 n_tables_dropped++;
2301 already_dropped:
2302 mutex_enter(&kernel_mutex);
2304 UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2306 ut_print_timestamp(stderr);
2307 fprintf(stderr,
2308 " InnoDB: Dropped table %s in background drop queue.\n",
2309 drop->table_name);
2311 mem_free(drop->table_name);
2313 mem_free(drop);
2315 mutex_exit(&kernel_mutex);
2317 goto loop;
2320 /*************************************************************************
2321 Get the background drop list length. NOTE: the caller must own the kernel
2322 mutex! */
2324 ulint
2325 row_get_background_drop_list_len_low(void)
2326 /*======================================*/
2327 /* out: how many tables in list */
2329 ut_ad(mutex_own(&kernel_mutex));
2331 if (!row_mysql_drop_list_inited) {
2333 UT_LIST_INIT(row_mysql_drop_list);
2334 row_mysql_drop_list_inited = TRUE;
2337 return(UT_LIST_GET_LEN(row_mysql_drop_list));
2340 /*************************************************************************
2341 If a table is not yet in the drop list, adds the table to the list of tables
2342 which the master thread drops in background. We need this on Unix because in
2343 ALTER TABLE MySQL may call drop table even if the table has running queries on
2344 it. Also, if there are running foreign key checks on the table, we drop the
2345 table lazily. */
2346 static
2347 ibool
2348 row_add_table_to_background_drop_list(
2349 /*==================================*/
2350 /* out: TRUE if the table was not yet in the
2351 drop list, and was added there */
2352 dict_table_t* table) /* in: table */
2354 row_mysql_drop_t* drop;
2356 mutex_enter(&kernel_mutex);
2358 if (!row_mysql_drop_list_inited) {
2360 UT_LIST_INIT(row_mysql_drop_list);
2361 row_mysql_drop_list_inited = TRUE;
2364 /* Look if the table already is in the drop list */
2365 drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2367 while (drop != NULL) {
2368 if (strcmp(drop->table_name, table->name) == 0) {
2369 /* Already in the list */
2371 mutex_exit(&kernel_mutex);
2373 return(FALSE);
2376 drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2379 drop = mem_alloc(sizeof(row_mysql_drop_t));
2381 drop->table_name = mem_strdup(table->name);
2383 UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2385 /* fputs("InnoDB: Adding table ", stderr);
2386 ut_print_name(stderr, trx, TRUE, drop->table_name);
2387 fputs(" to background drop list\n", stderr); */
2389 mutex_exit(&kernel_mutex);
2391 return(TRUE);
2394 #ifndef UNIV_HOTBACKUP
2395 /*************************************************************************
2396 Discards the tablespace of a table which stored in an .ibd file. Discarding
2397 means that this function deletes the .ibd file and assigns a new table id for
2398 the table. Also the flag table->ibd_file_missing is set TRUE. */
2401 row_discard_tablespace_for_mysql(
2402 /*=============================*/
2403 /* out: error code or DB_SUCCESS */
2404 const char* name, /* in: table name */
2405 trx_t* trx) /* in: transaction handle */
2407 dict_foreign_t* foreign;
2408 dulint new_id;
2409 dict_table_t* table;
2410 ibool success;
2411 ulint err;
2412 pars_info_t* info = NULL;
2414 /* How do we prevent crashes caused by ongoing operations on
2415 the table? Old operations could try to access non-existent
2416 pages.
2418 1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2419 MySQL table lock on the table before we can do DISCARD
2420 TABLESPACE. Then there are no running queries on the table.
2422 2) Purge and rollback: we assign a new table id for the
2423 table. Since purge and rollback look for the table based on
2424 the table id, they see the table as 'dropped' and discard
2425 their operations.
2427 3) Insert buffer: we remove all entries for the tablespace in
2428 the insert buffer tree; as long as the tablespace mem object
2429 does not exist, ongoing insert buffer page merges are
2430 discarded in buf0rea.c. If we recreate the tablespace mem
2431 object with IMPORT TABLESPACE later, then the tablespace will
2432 have the same id, but the tablespace_version field in the mem
2433 object is different, and ongoing old insert buffer page merges
2434 get discarded.
2436 4) Linear readahead and random readahead: we use the same
2437 method as in 3) to discard ongoing operations.
2439 5) FOREIGN KEY operations: if
2440 table->n_foreign_key_checks_running > 0, we do not allow the
2441 discard. We also reserve the data dictionary latch. */
2443 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2445 trx->op_info = "discarding tablespace";
2446 trx_start_if_not_started(trx);
2448 /* Serialize data dictionary operations with dictionary mutex:
2449 no deadlocks can occur then in these operations */
2451 row_mysql_lock_data_dictionary(trx);
2453 table = dict_table_get_low(name);
2455 if (!table) {
2456 err = DB_TABLE_NOT_FOUND;
2458 goto funct_exit;
2461 if (table->space == 0) {
2462 ut_print_timestamp(stderr);
2463 fputs(" InnoDB: Error: table ", stderr);
2464 ut_print_name(stderr, trx, TRUE, name);
2465 fputs("\n"
2466 "InnoDB: is in the system tablespace 0"
2467 " which cannot be discarded\n", stderr);
2468 err = DB_ERROR;
2470 goto funct_exit;
2473 if (table->n_foreign_key_checks_running > 0) {
2475 ut_print_timestamp(stderr);
2476 fputs(" InnoDB: You are trying to DISCARD table ", stderr);
2477 ut_print_name(stderr, trx, TRUE, table->name);
2478 fputs("\n"
2479 "InnoDB: though there is a foreign key check"
2480 " running on it.\n"
2481 "InnoDB: Cannot discard the table.\n",
2482 stderr);
2484 err = DB_ERROR;
2486 goto funct_exit;
2489 /* Check if the table is referenced by foreign key constraints from
2490 some other table (not the table itself) */
2492 foreign = UT_LIST_GET_FIRST(table->referenced_list);
2494 while (foreign && foreign->foreign_table == table) {
2495 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2498 if (foreign && trx->check_foreigns) {
2500 FILE* ef = dict_foreign_err_file;
2502 /* We only allow discarding a referenced table if
2503 FOREIGN_KEY_CHECKS is set to 0 */
2505 err = DB_CANNOT_DROP_CONSTRAINT;
2507 mutex_enter(&dict_foreign_err_mutex);
2508 rewind(ef);
2509 ut_print_timestamp(ef);
2511 fputs(" Cannot DISCARD table ", ef);
2512 ut_print_name(ef, trx, TRUE, name);
2513 fputs("\n"
2514 "because it is referenced by ", ef);
2515 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2516 putc('\n', ef);
2517 mutex_exit(&dict_foreign_err_mutex);
2519 goto funct_exit;
2522 new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2524 /* Remove all locks except the table-level S and X locks. */
2525 lock_remove_all_on_table(table, FALSE);
2527 info = pars_info_create();
2529 pars_info_add_str_literal(info, "table_name", name);
2530 pars_info_add_dulint_literal(info, "new_id", new_id);
2532 err = que_eval_sql(info,
2533 "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2534 "old_id CHAR;\n"
2535 "BEGIN\n"
2536 "SELECT ID INTO old_id\n"
2537 "FROM SYS_TABLES\n"
2538 "WHERE NAME = :table_name\n"
2539 "LOCK IN SHARE MODE;\n"
2540 "IF (SQL % NOTFOUND) THEN\n"
2541 " COMMIT WORK;\n"
2542 " RETURN;\n"
2543 "END IF;\n"
2544 "UPDATE SYS_TABLES SET ID = :new_id\n"
2545 " WHERE ID = old_id;\n"
2546 "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2547 " WHERE TABLE_ID = old_id;\n"
2548 "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2549 " WHERE TABLE_ID = old_id;\n"
2550 "COMMIT WORK;\n"
2551 "END;\n"
2552 , FALSE, trx);
2554 if (err != DB_SUCCESS) {
2555 trx->error_state = DB_SUCCESS;
2556 trx_general_rollback_for_mysql(trx, FALSE, NULL);
2557 trx->error_state = DB_SUCCESS;
2558 } else {
2559 dict_table_change_id_in_cache(table, new_id);
2561 success = fil_discard_tablespace(table->space);
2563 if (!success) {
2564 trx->error_state = DB_SUCCESS;
2565 trx_general_rollback_for_mysql(trx, FALSE, NULL);
2566 trx->error_state = DB_SUCCESS;
2568 err = DB_ERROR;
2569 } else {
2570 /* Set the flag which tells that now it is legal to
2571 IMPORT a tablespace for this table */
2572 table->tablespace_discarded = TRUE;
2573 table->ibd_file_missing = TRUE;
2577 funct_exit:
2578 trx_commit_for_mysql(trx);
2580 row_mysql_unlock_data_dictionary(trx);
2582 trx->op_info = "";
2584 return((int) err);
2587 /*********************************************************************
2588 Imports a tablespace. The space id in the .ibd file must match the space id
2589 of the table in the data dictionary. */
2592 row_import_tablespace_for_mysql(
2593 /*============================*/
2594 /* out: error code or DB_SUCCESS */
2595 const char* name, /* in: table name */
2596 trx_t* trx) /* in: transaction handle */
2598 dict_table_t* table;
2599 ibool success;
2600 dulint current_lsn;
2601 ulint err = DB_SUCCESS;
2603 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2605 trx_start_if_not_started(trx);
2607 trx->op_info = "importing tablespace";
2609 current_lsn = log_get_lsn();
2611 /* It is possible, though very improbable, that the lsn's in the
2612 tablespace to be imported have risen above the current system lsn, if
2613 a lengthy purge, ibuf merge, or rollback was performed on a backup
2614 taken with ibbackup. If that is the case, reset page lsn's in the
2615 file. We assume that mysqld was shut down after it performed these
2616 cleanup operations on the .ibd file, so that it stamped the latest lsn
2617 to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2619 TODO: reset also the trx id's in clustered index records and write
2620 a new space id to each data page. That would allow us to import clean
2621 .ibd files from another MySQL installation. */
2623 success = fil_reset_too_high_lsns(name, current_lsn);
2625 if (!success) {
2626 ut_print_timestamp(stderr);
2627 fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
2628 ut_print_name(stderr, trx, TRUE, name);
2629 fputs("\n"
2630 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2631 stderr);
2633 err = DB_ERROR;
2635 row_mysql_lock_data_dictionary(trx);
2637 goto funct_exit;
2640 /* Serialize data dictionary operations with dictionary mutex:
2641 no deadlocks can occur then in these operations */
2643 row_mysql_lock_data_dictionary(trx);
2645 table = dict_table_get_low(name);
2647 if (!table) {
2648 ut_print_timestamp(stderr);
2649 fputs(" InnoDB: table ", stderr);
2650 ut_print_name(stderr, trx, TRUE, name);
2651 fputs("\n"
2652 "InnoDB: does not exist in the InnoDB data dictionary\n"
2653 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2654 stderr);
2656 err = DB_TABLE_NOT_FOUND;
2658 goto funct_exit;
2661 if (table->space == 0) {
2662 ut_print_timestamp(stderr);
2663 fputs(" InnoDB: Error: table ", stderr);
2664 ut_print_name(stderr, trx, TRUE, name);
2665 fputs("\n"
2666 "InnoDB: is in the system tablespace 0"
2667 " which cannot be imported\n", stderr);
2668 err = DB_ERROR;
2670 goto funct_exit;
2673 if (!table->tablespace_discarded) {
2674 ut_print_timestamp(stderr);
2675 fputs(" InnoDB: Error: you are trying to"
2676 " IMPORT a tablespace\n"
2677 "InnoDB: ", stderr);
2678 ut_print_name(stderr, trx, TRUE, name);
2679 fputs(", though you have not called DISCARD on it yet\n"
2680 "InnoDB: during the lifetime of the mysqld process!\n",
2681 stderr);
2683 err = DB_ERROR;
2685 goto funct_exit;
2688 /* Play safe and remove all insert buffer entries, though we should
2689 have removed them already when DISCARD TABLESPACE was called */
2691 ibuf_delete_for_discarded_space(table->space);
2693 success = fil_open_single_table_tablespace(TRUE, table->space,
2694 table->name);
2695 if (success) {
2696 table->ibd_file_missing = FALSE;
2697 table->tablespace_discarded = FALSE;
2698 } else {
2699 if (table->ibd_file_missing) {
2700 ut_print_timestamp(stderr);
2701 fputs(" InnoDB: cannot find or open in the"
2702 " database directory the .ibd file of\n"
2703 "InnoDB: table ", stderr);
2704 ut_print_name(stderr, trx, TRUE, name);
2705 fputs("\n"
2706 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2707 stderr);
2710 err = DB_ERROR;
2713 funct_exit:
2714 trx_commit_for_mysql(trx);
2716 row_mysql_unlock_data_dictionary(trx);
2718 trx->op_info = "";
2720 return((int) err);
2723 /*************************************************************************
2724 Truncates a table for MySQL. */
2727 row_truncate_table_for_mysql(
2728 /*=========================*/
2729 /* out: error code or DB_SUCCESS */
2730 dict_table_t* table, /* in: table handle */
2731 trx_t* trx) /* in: transaction handle */
2733 dict_foreign_t* foreign;
2734 ulint err;
2735 mem_heap_t* heap;
2736 byte* buf;
2737 dtuple_t* tuple;
2738 dfield_t* dfield;
2739 dict_index_t* sys_index;
2740 btr_pcur_t pcur;
2741 mtr_t mtr;
2742 dulint new_id;
2743 pars_info_t* info = NULL;
2745 /* How do we prevent crashes caused by ongoing operations on
2746 the table? Old operations could try to access non-existent
2747 pages.
2749 1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2750 MySQL table lock on the table before we can do TRUNCATE
2751 TABLE. Then there are no running queries on the table. This is
2752 guaranteed, because in ha_innobase::store_lock(), we do not
2753 weaken the TL_WRITE lock requested by MySQL when executing
2754 SQLCOM_TRUNCATE.
2756 2) Purge and rollback: we assign a new table id for the
2757 table. Since purge and rollback look for the table based on
2758 the table id, they see the table as 'dropped' and discard
2759 their operations.
2761 3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2762 so we do not have to remove insert buffer records, as the
2763 insert buffer works at a low level. If a freed page is later
2764 reallocated, the allocator will remove the ibuf entries for
2767 TODO: when we truncate *.ibd files (analogous to DISCARD
2768 TABLESPACE), we will have to remove we remove all entries for
2769 the table in the insert buffer tree!
2771 4) Linear readahead and random readahead: we use the same
2772 method as in 3) to discard ongoing operations. (This will only
2773 be relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2775 5) FOREIGN KEY operations: if
2776 table->n_foreign_key_checks_running > 0, we do not allow the
2777 TRUNCATE. We also reserve the data dictionary latch. */
2779 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2780 ut_ad(table);
2782 if (srv_created_new_raw) {
2783 fputs("InnoDB: A new raw disk partition was initialized:\n"
2784 "InnoDB: we do not allow database modifications"
2785 " by the user.\n"
2786 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2787 " is replaced with raw.\n", stderr);
2789 return(DB_ERROR);
2792 trx->op_info = "truncating table";
2794 trx_start_if_not_started(trx);
2796 /* Serialize data dictionary operations with dictionary mutex:
2797 no deadlocks can occur then in these operations */
2799 ut_a(trx->dict_operation_lock_mode == 0);
2800 /* Prevent foreign key checks etc. while we are truncating the
2801 table */
2803 row_mysql_lock_data_dictionary(trx);
2805 ut_ad(mutex_own(&(dict_sys->mutex)));
2806 #ifdef UNIV_SYNC_DEBUG
2807 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2808 #endif /* UNIV_SYNC_DEBUG */
2810 /* Check if the table is referenced by foreign key constraints from
2811 some other table (not the table itself) */
2813 foreign = UT_LIST_GET_FIRST(table->referenced_list);
2815 while (foreign && foreign->foreign_table == table) {
2816 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2819 if (foreign && trx->check_foreigns) {
2820 FILE* ef = dict_foreign_err_file;
2822 /* We only allow truncating a referenced table if
2823 FOREIGN_KEY_CHECKS is set to 0 */
2825 mutex_enter(&dict_foreign_err_mutex);
2826 rewind(ef);
2827 ut_print_timestamp(ef);
2829 fputs(" Cannot truncate table ", ef);
2830 ut_print_name(ef, trx, TRUE, table->name);
2831 fputs(" by DROP+CREATE\n"
2832 "InnoDB: because it is referenced by ", ef);
2833 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2834 putc('\n', ef);
2835 mutex_exit(&dict_foreign_err_mutex);
2837 err = DB_ERROR;
2838 goto funct_exit;
2841 /* TODO: could we replace the counter n_foreign_key_checks_running
2842 with lock checks on the table? Acquire here an exclusive lock on the
2843 table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2844 they can cope with the table having been truncated here? Foreign key
2845 checks take an IS or IX lock on the table. */
2847 if (table->n_foreign_key_checks_running > 0) {
2848 ut_print_timestamp(stderr);
2849 fputs(" InnoDB: Cannot truncate table ", stderr);
2850 ut_print_name(stderr, trx, TRUE, table->name);
2851 fputs(" by DROP+CREATE\n"
2852 "InnoDB: because there is a foreign key check"
2853 " running on it.\n",
2854 stderr);
2855 err = DB_ERROR;
2857 goto funct_exit;
2860 /* Remove all locks except the table-level S and X locks. */
2861 lock_remove_all_on_table(table, FALSE);
2863 trx->table_id = table->id;
2865 /* Lock all index trees for this table, as we will
2866 truncate the table/index and possibly change their metadata.
2867 All DML/DDL are blocked by table level lock, with
2868 a few exceptions such as queries into information schema
2869 about the table, MySQL could try to access index stats
2870 for this kind of query, we need to use index locks to
2871 sync up */
2872 dict_table_x_lock_indexes(table);
2874 /* scan SYS_INDEXES for all indexes of the table */
2875 heap = mem_heap_create(800);
2877 tuple = dtuple_create(heap, 1);
2878 dfield = dtuple_get_nth_field(tuple, 0);
2880 buf = mem_heap_alloc(heap, 8);
2881 mach_write_to_8(buf, table->id);
2883 dfield_set_data(dfield, buf, 8);
2884 sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2885 dict_index_copy_types(tuple, sys_index, 1);
2887 mtr_start(&mtr);
2888 btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2889 BTR_MODIFY_LEAF, &pcur, &mtr);
2890 for (;;) {
2891 rec_t* rec;
2892 const byte* field;
2893 ulint len;
2894 ulint root_page_no;
2896 if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
2897 /* The end of SYS_INDEXES has been reached. */
2898 break;
2901 rec = btr_pcur_get_rec(&pcur);
2903 field = rec_get_nth_field_old(rec, 0, &len);
2904 ut_ad(len == 8);
2906 if (memcmp(buf, field, len) != 0) {
2907 /* End of indexes for the table (TABLE_ID mismatch). */
2908 break;
2911 if (rec_get_deleted_flag(rec, FALSE)) {
2912 /* The index has been dropped. */
2913 goto next_rec;
2916 /* This call may commit and restart mtr
2917 and reposition pcur. */
2918 root_page_no = dict_truncate_index_tree(table, &pcur, &mtr);
2920 rec = btr_pcur_get_rec(&pcur);
2922 if (root_page_no != FIL_NULL) {
2923 page_rec_write_index_page_no(
2924 rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2925 root_page_no, &mtr);
2926 /* We will need to commit and restart the
2927 mini-transaction in order to avoid deadlocks.
2928 The dict_truncate_index_tree() call has allocated
2929 a page in this mini-transaction, and the rest of
2930 this loop could latch another index page. */
2931 mtr_commit(&mtr);
2932 mtr_start(&mtr);
2933 btr_pcur_restore_position(BTR_MODIFY_LEAF,
2934 &pcur, &mtr);
2937 next_rec:
2938 btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2941 btr_pcur_close(&pcur);
2942 mtr_commit(&mtr);
2944 mem_heap_free(heap);
2946 /* Done with index truncation, release index tree locks,
2947 subsequent work relates to table level metadata change */
2948 dict_table_x_unlock_indexes(table);
2950 new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2952 info = pars_info_create();
2954 pars_info_add_dulint_literal(info, "old_id", table->id);
2955 pars_info_add_dulint_literal(info, "new_id", new_id);
2957 err = que_eval_sql(info,
2958 "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2959 "BEGIN\n"
2960 "UPDATE SYS_TABLES SET ID = :new_id\n"
2961 " WHERE ID = :old_id;\n"
2962 "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2963 " WHERE TABLE_ID = :old_id;\n"
2964 "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2965 " WHERE TABLE_ID = :old_id;\n"
2966 "COMMIT WORK;\n"
2967 "END;\n"
2968 , FALSE, trx);
2970 if (err != DB_SUCCESS) {
2971 trx->error_state = DB_SUCCESS;
2972 trx_general_rollback_for_mysql(trx, FALSE, NULL);
2973 trx->error_state = DB_SUCCESS;
2974 ut_print_timestamp(stderr);
2975 fputs(" InnoDB: Unable to assign a new identifier to table ",
2976 stderr);
2977 ut_print_name(stderr, trx, TRUE, table->name);
2978 fputs("\n"
2979 "InnoDB: after truncating it. Background processes"
2980 " may corrupt the table!\n", stderr);
2981 err = DB_ERROR;
2982 } else {
2983 dict_table_change_id_in_cache(table, new_id);
2986 /* MySQL calls ha_innobase::reset_auto_increment() which does
2987 the same thing. */
2988 dict_table_autoinc_lock(table);
2989 dict_table_autoinc_initialize(table, 1);
2990 dict_table_autoinc_unlock(table);
2991 dict_update_statistics(table);
2993 trx_commit_for_mysql(trx);
2995 funct_exit:
2997 row_mysql_unlock_data_dictionary(trx);
2999 trx->op_info = "";
3001 srv_wake_master_thread();
3003 return((int) err);
3005 #endif /* !UNIV_HOTBACKUP */
3007 /*************************************************************************
3008 Drops a table for MySQL. If the name of the dropped table ends in
3009 one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
3010 "innodb_table_monitor", then this will also stop the printing of monitor
3011 output by the master thread. */
3014 row_drop_table_for_mysql(
3015 /*=====================*/
3016 /* out: error code or DB_SUCCESS */
3017 const char* name, /* in: table name */
3018 trx_t* trx, /* in: transaction handle */
3019 ibool drop_db)/* in: TRUE=dropping whole database */
3021 dict_foreign_t* foreign;
3022 dict_table_t* table;
3023 ulint space_id;
3024 ulint err;
3025 const char* table_name;
3026 ulint namelen;
3027 ibool locked_dictionary = FALSE;
3028 pars_info_t* info = NULL;
3030 ut_a(name != NULL);
3032 if (srv_created_new_raw) {
3033 fputs("InnoDB: A new raw disk partition was initialized:\n"
3034 "InnoDB: we do not allow database modifications"
3035 " by the user.\n"
3036 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
3037 " is replaced with raw.\n", stderr);
3039 return(DB_ERROR);
3042 trx->op_info = "dropping table";
3044 trx_start_if_not_started(trx);
3046 /* The table name is prefixed with the database name and a '/'.
3047 Certain table names starting with 'innodb_' have their special
3048 meaning regardless of the database name. Thus, we need to
3049 ignore the database name prefix in the comparisons. */
3050 table_name = strchr(name, '/');
3051 ut_a(table_name);
3052 table_name++;
3053 namelen = strlen(table_name) + 1;
3055 if (namelen == sizeof S_innodb_monitor
3056 && !memcmp(table_name, S_innodb_monitor,
3057 sizeof S_innodb_monitor)) {
3059 /* Table name equals "innodb_monitor":
3060 stop monitor prints */
3062 srv_print_innodb_monitor = FALSE;
3063 srv_print_innodb_lock_monitor = FALSE;
3064 } else if (namelen == sizeof S_innodb_lock_monitor
3065 && !memcmp(table_name, S_innodb_lock_monitor,
3066 sizeof S_innodb_lock_monitor)) {
3067 srv_print_innodb_monitor = FALSE;
3068 srv_print_innodb_lock_monitor = FALSE;
3069 } else if (namelen == sizeof S_innodb_tablespace_monitor
3070 && !memcmp(table_name, S_innodb_tablespace_monitor,
3071 sizeof S_innodb_tablespace_monitor)) {
3073 srv_print_innodb_tablespace_monitor = FALSE;
3074 } else if (namelen == sizeof S_innodb_table_monitor
3075 && !memcmp(table_name, S_innodb_table_monitor,
3076 sizeof S_innodb_table_monitor)) {
3078 srv_print_innodb_table_monitor = FALSE;
3081 /* Serialize data dictionary operations with dictionary mutex:
3082 no deadlocks can occur then in these operations */
3084 if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3085 /* Prevent foreign key checks etc. while we are dropping the
3086 table */
3088 row_mysql_lock_data_dictionary(trx);
3090 locked_dictionary = TRUE;
3093 ut_ad(mutex_own(&(dict_sys->mutex)));
3094 #ifdef UNIV_SYNC_DEBUG
3095 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3096 #endif /* UNIV_SYNC_DEBUG */
3098 table = dict_table_get_low(name);
3100 if (!table) {
3101 err = DB_TABLE_NOT_FOUND;
3102 ut_print_timestamp(stderr);
3104 fputs(" InnoDB: Error: table ", stderr);
3105 ut_print_name(stderr, trx, TRUE, name);
3106 fputs(" does not exist in the InnoDB internal\n"
3107 "InnoDB: data dictionary though MySQL is"
3108 " trying to drop it.\n"
3109 "InnoDB: Have you copied the .frm file"
3110 " of the table to the\n"
3111 "InnoDB: MySQL database directory"
3112 " from another database?\n"
3113 "InnoDB: You can look for further help from\n"
3114 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3115 "innodb-troubleshooting.html\n",
3116 stderr);
3117 goto funct_exit;
3120 /* Check if the table is referenced by foreign key constraints from
3121 some other table (not the table itself) */
3123 foreign = UT_LIST_GET_FIRST(table->referenced_list);
3125 while (foreign && foreign->foreign_table == table) {
3126 check_next_foreign:
3127 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3130 if (foreign && trx->check_foreigns
3131 && !(drop_db && dict_tables_have_same_db(
3132 name, foreign->foreign_table_name))) {
3133 FILE* ef = dict_foreign_err_file;
3135 /* We only allow dropping a referenced table if
3136 FOREIGN_KEY_CHECKS is set to 0 */
3138 err = DB_CANNOT_DROP_CONSTRAINT;
3140 mutex_enter(&dict_foreign_err_mutex);
3141 rewind(ef);
3142 ut_print_timestamp(ef);
3144 fputs(" Cannot drop table ", ef);
3145 ut_print_name(ef, trx, TRUE, name);
3146 fputs("\n"
3147 "because it is referenced by ", ef);
3148 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3149 putc('\n', ef);
3150 mutex_exit(&dict_foreign_err_mutex);
3152 goto funct_exit;
3155 if (foreign && trx->check_foreigns) {
3156 goto check_next_foreign;
3159 if (table->n_mysql_handles_opened > 0) {
3160 ibool added;
3162 added = row_add_table_to_background_drop_list(table);
3164 if (added) {
3165 ut_print_timestamp(stderr);
3166 fputs(" InnoDB: Warning: MySQL is"
3167 " trying to drop table ", stderr);
3168 ut_print_name(stderr, trx, TRUE, table->name);
3169 fputs("\n"
3170 "InnoDB: though there are still"
3171 " open handles to it.\n"
3172 "InnoDB: Adding the table to the"
3173 " background drop queue.\n",
3174 stderr);
3176 /* We return DB_SUCCESS to MySQL though the drop will
3177 happen lazily later */
3179 err = DB_SUCCESS;
3180 } else {
3181 /* The table is already in the background drop list */
3182 err = DB_ERROR;
3185 goto funct_exit;
3188 /* TODO: could we replace the counter n_foreign_key_checks_running
3189 with lock checks on the table? Acquire here an exclusive lock on the
3190 table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3191 they can cope with the table having been dropped here? Foreign key
3192 checks take an IS or IX lock on the table. */
3194 if (table->n_foreign_key_checks_running > 0) {
3196 ibool added;
3198 added = row_add_table_to_background_drop_list(table);
3200 if (added) {
3201 ut_print_timestamp(stderr);
3202 fputs(" InnoDB: You are trying to drop table ",
3203 stderr);
3204 ut_print_name(stderr, trx, TRUE, table->name);
3205 fputs("\n"
3206 "InnoDB: though there is a"
3207 " foreign key check running on it.\n"
3208 "InnoDB: Adding the table to"
3209 " the background drop queue.\n",
3210 stderr);
3212 /* We return DB_SUCCESS to MySQL though the drop will
3213 happen lazily later */
3215 err = DB_SUCCESS;
3216 } else {
3217 /* The table is already in the background drop list */
3218 err = DB_ERROR;
3221 goto funct_exit;
3224 /* Remove all locks there are on the table or its records */
3225 lock_remove_all_on_table(table, TRUE);
3227 trx->dict_operation = TRUE;
3228 trx->table_id = table->id;
3230 /* We use the private SQL parser of Innobase to generate the
3231 query graphs needed in deleting the dictionary data from system
3232 tables in Innobase. Deleting a row from SYS_INDEXES table also
3233 frees the file segments of the B-tree associated with the index. */
3235 info = pars_info_create();
3237 pars_info_add_str_literal(info, "table_name", name);
3239 err = que_eval_sql(info,
3240 "PROCEDURE DROP_TABLE_PROC () IS\n"
3241 "sys_foreign_id CHAR;\n"
3242 "table_id CHAR;\n"
3243 "index_id CHAR;\n"
3244 "foreign_id CHAR;\n"
3245 "found INT;\n"
3246 "BEGIN\n"
3247 "SELECT ID INTO table_id\n"
3248 "FROM SYS_TABLES\n"
3249 "WHERE NAME = :table_name\n"
3250 "LOCK IN SHARE MODE;\n"
3251 "IF (SQL % NOTFOUND) THEN\n"
3252 " COMMIT WORK;\n"
3253 " RETURN;\n"
3254 "END IF;\n"
3255 "found := 1;\n"
3256 "SELECT ID INTO sys_foreign_id\n"
3257 "FROM SYS_TABLES\n"
3258 "WHERE NAME = 'SYS_FOREIGN'\n"
3259 "LOCK IN SHARE MODE;\n"
3260 "IF (SQL % NOTFOUND) THEN\n"
3261 " found := 0;\n"
3262 "END IF;\n"
3263 "IF (:table_name = 'SYS_FOREIGN') THEN\n"
3264 " found := 0;\n"
3265 "END IF;\n"
3266 "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3267 " found := 0;\n"
3268 "END IF;\n"
3269 "WHILE found = 1 LOOP\n"
3270 " SELECT ID INTO foreign_id\n"
3271 " FROM SYS_FOREIGN\n"
3272 " WHERE FOR_NAME = :table_name\n"
3273 " AND TO_BINARY(FOR_NAME)\n"
3274 " = TO_BINARY(:table_name)\n"
3275 " LOCK IN SHARE MODE;\n"
3276 " IF (SQL % NOTFOUND) THEN\n"
3277 " found := 0;\n"
3278 " ELSE\n"
3279 " DELETE FROM SYS_FOREIGN_COLS\n"
3280 " WHERE ID = foreign_id;\n"
3281 " DELETE FROM SYS_FOREIGN\n"
3282 " WHERE ID = foreign_id;\n"
3283 " END IF;\n"
3284 "END LOOP;\n"
3285 "found := 1;\n"
3286 "WHILE found = 1 LOOP\n"
3287 " SELECT ID INTO index_id\n"
3288 " FROM SYS_INDEXES\n"
3289 " WHERE TABLE_ID = table_id\n"
3290 " LOCK IN SHARE MODE;\n"
3291 " IF (SQL % NOTFOUND) THEN\n"
3292 " found := 0;\n"
3293 " ELSE\n"
3294 " DELETE FROM SYS_FIELDS\n"
3295 " WHERE INDEX_ID = index_id;\n"
3296 " DELETE FROM SYS_INDEXES\n"
3297 " WHERE ID = index_id\n"
3298 " AND TABLE_ID = table_id;\n"
3299 " END IF;\n"
3300 "END LOOP;\n"
3301 "DELETE FROM SYS_COLUMNS\n"
3302 "WHERE TABLE_ID = table_id;\n"
3303 "DELETE FROM SYS_TABLES\n"
3304 "WHERE ID = table_id;\n"
3305 "COMMIT WORK;\n"
3306 "END;\n"
3307 , FALSE, trx);
3309 switch (err) {
3310 ibool is_path;
3311 const char* name_or_path;
3312 mem_heap_t* heap;
3314 case DB_SUCCESS:
3316 heap = mem_heap_create(200);
3318 /* Clone the name, in case it has been allocated
3319 from table->heap, which will be freed by
3320 dict_table_remove_from_cache(table) below. */
3321 name = mem_heap_strdup(heap, name);
3322 space_id = table->space;
3324 if (table->dir_path_of_temp_table != NULL) {
3325 is_path = TRUE;
3326 name_or_path = mem_heap_strdup(
3327 heap, table->dir_path_of_temp_table);
3328 } else {
3329 is_path = FALSE;
3330 name_or_path = name;
3333 dict_table_remove_from_cache(table);
3335 if (dict_load_table(name) != NULL) {
3336 ut_print_timestamp(stderr);
3337 fputs(" InnoDB: Error: not able to remove table ",
3338 stderr);
3339 ut_print_name(stderr, trx, TRUE, name);
3340 fputs(" from the dictionary cache!\n", stderr);
3341 err = DB_ERROR;
3344 /* Do not drop possible .ibd tablespace if something went
3345 wrong: we do not want to delete valuable data of the user */
3347 if (err == DB_SUCCESS && space_id > 0) {
3348 if (!fil_space_for_table_exists_in_mem(space_id,
3349 name_or_path,
3350 is_path,
3351 FALSE, TRUE)) {
3352 err = DB_SUCCESS;
3354 fprintf(stderr,
3355 "InnoDB: We removed now the InnoDB"
3356 " internal data dictionary entry\n"
3357 "InnoDB: of table ");
3358 ut_print_name(stderr, trx, TRUE, name);
3359 fprintf(stderr, ".\n");
3360 } else if (!fil_delete_tablespace(space_id)) {
3361 fprintf(stderr,
3362 "InnoDB: We removed now the InnoDB"
3363 " internal data dictionary entry\n"
3364 "InnoDB: of table ");
3365 ut_print_name(stderr, trx, TRUE, name);
3366 fprintf(stderr, ".\n");
3368 ut_print_timestamp(stderr);
3369 fprintf(stderr,
3370 " InnoDB: Error: not able to"
3371 " delete tablespace %lu of table ",
3372 (ulong) space_id);
3373 ut_print_name(stderr, trx, TRUE, name);
3374 fputs("!\n", stderr);
3375 err = DB_ERROR;
3379 mem_heap_free(heap);
3380 break;
3382 case DB_TOO_MANY_CONCURRENT_TRXS:
3383 /* Cannot even find a free slot for the
3384 the undo log. We can directly exit here
3385 and return the DB_TOO_MANY_CONCURRENT_TRXS
3386 error. */
3387 break;
3389 case DB_OUT_OF_FILE_SPACE:
3390 err = DB_MUST_GET_MORE_FILE_SPACE;
3392 row_mysql_handle_errors(&err, trx, NULL, NULL);
3394 /* Fall through to raise error */
3396 default:
3397 /* No other possible error returns */
3398 ut_error;
3401 funct_exit:
3403 trx_commit_for_mysql(trx);
3405 if (locked_dictionary) {
3406 row_mysql_unlock_data_dictionary(trx);
3409 trx->op_info = "";
3411 #ifndef UNIV_HOTBACKUP
3412 srv_wake_master_thread();
3413 #endif /* !UNIV_HOTBACKUP */
3415 return((int) err);
3418 /***********************************************************************
3419 Drop all foreign keys in a database, see Bug#18942.
3420 Called at the end of row_drop_database_for_mysql(). */
3421 static
3422 ulint
3423 drop_all_foreign_keys_in_db(
3424 /*========================*/
3425 /* out: error code or DB_SUCCESS */
3426 const char* name, /* in: database name which ends to '/' */
3427 trx_t* trx) /* in: transaction handle */
3429 pars_info_t* pinfo;
3430 ulint err;
3432 ut_a(name[strlen(name) - 1] == '/');
3434 pinfo = pars_info_create();
3436 pars_info_add_str_literal(pinfo, "dbname", name);
3438 /* true if for_name is not prefixed with dbname */
3439 #define TABLE_NOT_IN_THIS_DB \
3440 "SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
3442 err = que_eval_sql(pinfo,
3443 "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
3444 "foreign_id CHAR;\n"
3445 "for_name CHAR;\n"
3446 "found INT;\n"
3447 "DECLARE CURSOR cur IS\n"
3448 "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
3449 "WHERE FOR_NAME >= :dbname\n"
3450 "LOCK IN SHARE MODE\n"
3451 "ORDER BY FOR_NAME;\n"
3452 "BEGIN\n"
3453 "found := 1;\n"
3454 "OPEN cur;\n"
3455 "WHILE found = 1 LOOP\n"
3456 " FETCH cur INTO foreign_id, for_name;\n"
3457 " IF (SQL % NOTFOUND) THEN\n"
3458 " found := 0;\n"
3459 " ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
3460 " found := 0;\n"
3461 " ELSIF (1=1) THEN\n"
3462 " DELETE FROM SYS_FOREIGN_COLS\n"
3463 " WHERE ID = foreign_id;\n"
3464 " DELETE FROM SYS_FOREIGN\n"
3465 " WHERE ID = foreign_id;\n"
3466 " END IF;\n"
3467 "END LOOP;\n"
3468 "CLOSE cur;\n"
3469 "COMMIT WORK;\n"
3470 "END;\n",
3471 FALSE, /* do not reserve dict mutex,
3472 we are already holding it */
3473 trx);
3475 return(err);
3478 /*************************************************************************
3479 Drops a database for MySQL. */
3482 row_drop_database_for_mysql(
3483 /*========================*/
3484 /* out: error code or DB_SUCCESS */
3485 const char* name, /* in: database name which ends to '/' */
3486 trx_t* trx) /* in: transaction handle */
3488 dict_table_t* table;
3489 char* table_name;
3490 int err = DB_SUCCESS;
3491 ulint namelen = strlen(name);
3493 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3494 ut_a(name != NULL);
3495 ut_a(name[namelen - 1] == '/');
3497 trx->op_info = "dropping database";
3499 trx_start_if_not_started(trx);
3500 loop:
3501 row_mysql_lock_data_dictionary(trx);
3503 while ((table_name = dict_get_first_table_name_in_db(name))) {
3504 ut_a(memcmp(table_name, name, namelen) == 0);
3506 table = dict_table_get_low(table_name);
3508 ut_a(table);
3510 /* Wait until MySQL does not have any queries running on
3511 the table */
3513 if (table->n_mysql_handles_opened > 0) {
3514 row_mysql_unlock_data_dictionary(trx);
3516 ut_print_timestamp(stderr);
3517 fputs(" InnoDB: Warning: MySQL is trying to"
3518 " drop database ", stderr);
3519 ut_print_name(stderr, trx, TRUE, name);
3520 fputs("\n"
3521 "InnoDB: though there are still"
3522 " open handles to table ", stderr);
3523 ut_print_name(stderr, trx, TRUE, table_name);
3524 fputs(".\n", stderr);
3526 os_thread_sleep(1000000);
3528 mem_free(table_name);
3530 goto loop;
3533 err = row_drop_table_for_mysql(table_name, trx, TRUE);
3535 if (err != DB_SUCCESS) {
3536 fputs("InnoDB: DROP DATABASE ", stderr);
3537 ut_print_name(stderr, trx, TRUE, name);
3538 fprintf(stderr, " failed with error %lu for table ",
3539 (ulint) err);
3540 ut_print_name(stderr, trx, TRUE, table_name);
3541 putc('\n', stderr);
3542 mem_free(table_name);
3543 break;
3546 mem_free(table_name);
3549 if (err == DB_SUCCESS) {
3550 /* after dropping all tables try to drop all leftover
3551 foreign keys in case orphaned ones exist */
3552 err = (int) drop_all_foreign_keys_in_db(name, trx);
3554 if (err != DB_SUCCESS) {
3555 fputs("InnoDB: DROP DATABASE ", stderr);
3556 ut_print_name(stderr, trx, TRUE, name);
3557 fprintf(stderr, " failed with error %d while "
3558 "dropping all foreign keys", err);
3562 trx_commit_for_mysql(trx);
3564 row_mysql_unlock_data_dictionary(trx);
3566 trx->op_info = "";
3568 return(err);
3571 /*************************************************************************
3572 Checks if a table name contains the string "/#sql" which denotes temporary
3573 tables in MySQL. */
3574 static
3575 ibool
3576 row_is_mysql_tmp_table_name(
3577 /*========================*/
3578 /* out: TRUE if temporary table */
3579 const char* name) /* in: table name in the form
3580 'database/tablename' */
3582 return(strstr(name, "/#sql") != NULL);
3583 /* return(strstr(name, "/@0023sql") != NULL); */
3586 /********************************************************************
3587 Delete a single constraint. */
3588 static
3590 row_delete_constraint_low(
3591 /*======================*/
3592 /* out: error code or DB_SUCCESS */
3593 const char* id, /* in: constraint id */
3594 trx_t* trx) /* in: transaction handle */
3596 pars_info_t* info = pars_info_create();
3598 pars_info_add_str_literal(info, "id", id);
3600 return((int) que_eval_sql(info,
3601 "PROCEDURE DELETE_CONSTRAINT () IS\n"
3602 "BEGIN\n"
3603 "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3604 "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3605 "END;\n"
3606 , FALSE, trx));
3609 /********************************************************************
3610 Delete a single constraint. */
3611 static
3613 row_delete_constraint(
3614 /*==================*/
3615 /* out: error code or DB_SUCCESS */
3616 const char* id, /* in: constraint id */
3617 const char* database_name, /* in: database name, with the
3618 trailing '/' */
3619 mem_heap_t* heap, /* in: memory heap */
3620 trx_t* trx) /* in: transaction handle */
3622 ulint err;
3624 /* New format constraints have ids <databasename>/<constraintname>. */
3625 err = row_delete_constraint_low(
3626 mem_heap_strcat(heap, database_name, id), trx);
3628 if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3629 /* Old format < 4.0.18 constraints have constraint ids
3630 <number>_<number>. We only try deleting them if the
3631 constraint name does not contain a '/' character, otherwise
3632 deleting a new format constraint named 'foo/bar' from
3633 database 'baz' would remove constraint 'bar' from database
3634 'foo', if it existed. */
3636 err = row_delete_constraint_low(id, trx);
3639 return((int) err);
3642 /*************************************************************************
3643 Renames a table for MySQL. */
3646 row_rename_table_for_mysql(
3647 /*=======================*/
3648 /* out: error code or DB_SUCCESS */
3649 const char* old_name, /* in: old table name */
3650 const char* new_name, /* in: new table name */
3651 trx_t* trx) /* in: transaction handle */
3653 dict_table_t* table;
3654 ulint err;
3655 mem_heap_t* heap = NULL;
3656 const char** constraints_to_drop = NULL;
3657 ulint n_constraints_to_drop = 0;
3658 ibool old_is_tmp, new_is_tmp;
3659 pars_info_t* info = NULL;
3660 ulint retry = 0;
3661 DBUG_ENTER("row_rename_table_for_mysql");
3663 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3664 ut_a(old_name != NULL);
3665 ut_a(new_name != NULL);
3667 if (srv_created_new_raw || srv_force_recovery) {
3668 fputs("InnoDB: A new raw disk partition was initialized or\n"
3669 "InnoDB: innodb_force_recovery is on: we do not allow\n"
3670 "InnoDB: database modifications by the user. Shut down\n"
3671 "InnoDB: mysqld and edit my.cnf so that newraw"
3672 " is replaced\n"
3673 "InnoDB: with raw, and innodb_force_... is removed.\n",
3674 stderr);
3676 trx_commit_for_mysql(trx);
3677 DBUG_RETURN(DB_ERROR);
3680 if (row_mysql_is_system_table(new_name)) {
3682 fprintf(stderr,
3683 "InnoDB: Error: trying to create a MySQL"
3684 " system table %s of type InnoDB.\n"
3685 "InnoDB: MySQL system tables must be"
3686 " of the MyISAM type!\n",
3687 new_name);
3689 trx_commit_for_mysql(trx);
3690 DBUG_RETURN(DB_ERROR);
3693 trx->op_info = "renaming table";
3694 trx_start_if_not_started(trx);
3696 old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3697 new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3699 /* Serialize data dictionary operations with dictionary mutex:
3700 no deadlocks can occur then in these operations */
3702 row_mysql_lock_data_dictionary(trx);
3704 table = dict_table_get_low(old_name);
3706 if (!table) {
3707 err = DB_TABLE_NOT_FOUND;
3708 ut_print_timestamp(stderr);
3710 fputs(" InnoDB: Error: table ", stderr);
3711 ut_print_name(stderr, trx, TRUE, old_name);
3712 fputs(" does not exist in the InnoDB internal\n"
3713 "InnoDB: data dictionary though MySQL is"
3714 " trying to rename the table.\n"
3715 "InnoDB: Have you copied the .frm file"
3716 " of the table to the\n"
3717 "InnoDB: MySQL database directory"
3718 " from another database?\n"
3719 "InnoDB: You can look for further help from\n"
3720 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3721 "innodb-troubleshooting.html\n",
3722 stderr);
3723 goto funct_exit;
3726 if (table->ibd_file_missing) {
3727 err = DB_TABLE_NOT_FOUND;
3728 ut_print_timestamp(stderr);
3730 fputs(" InnoDB: Error: table ", stderr);
3731 ut_print_name(stderr, trx, TRUE, old_name);
3732 fputs(" does not have an .ibd file"
3733 " in the database directory.\n"
3734 "InnoDB: You can look for further help from\n"
3735 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3736 "innodb-troubleshooting.html\n",
3737 stderr);
3738 goto funct_exit;
3741 if (new_is_tmp) {
3742 /* MySQL is doing an ALTER TABLE command and it renames the
3743 original table to a temporary table name. We want to preserve
3744 the original foreign key constraint definitions despite the
3745 name change. An exception is those constraints for which
3746 the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3748 heap = mem_heap_create(100);
3750 err = dict_foreign_parse_drop_constraints(
3751 heap, trx, table, &n_constraints_to_drop,
3752 &constraints_to_drop);
3754 if (err != DB_SUCCESS) {
3756 goto funct_exit;
3760 /* Is a foreign key check running on this table? */
3761 for (retry = 0; retry < 100
3762 && table->n_foreign_key_checks_running > 0; ++retry) {
3763 row_mysql_unlock_data_dictionary(trx);
3764 os_thread_yield();
3765 row_mysql_lock_data_dictionary(trx);
3768 if (table->n_foreign_key_checks_running > 0) {
3769 ut_print_timestamp(stderr);
3770 fputs(" InnoDB: Error: in ALTER TABLE ", stderr);
3771 ut_print_name(stderr, trx, TRUE, old_name);
3772 fprintf(stderr, "\n"
3773 "InnoDB: a FOREIGN KEY check is running.\n"
3774 "InnoDB: Cannot rename table.\n");
3775 err = DB_TABLE_IN_FK_CHECK;
3776 goto funct_exit;
3779 /* We use the private SQL parser of Innobase to generate the query
3780 graphs needed in deleting the dictionary data from system tables in
3781 Innobase. Deleting a row from SYS_INDEXES table also frees the file
3782 segments of the B-tree associated with the index. */
3784 info = pars_info_create();
3786 pars_info_add_str_literal(info, "new_table_name", new_name);
3787 pars_info_add_str_literal(info, "old_table_name", old_name);
3789 err = que_eval_sql(info,
3790 "PROCEDURE RENAME_TABLE () IS\n"
3791 "BEGIN\n"
3792 "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3793 " WHERE NAME = :old_table_name;\n"
3794 "END;\n"
3795 , FALSE, trx);
3797 if (err != DB_SUCCESS) {
3799 goto end;
3802 if (!new_is_tmp) {
3803 /* Rename all constraints. */
3804 char new_table_name[MAX_TABLE_NAME_LEN] = "";
3805 char old_table_utf8[MAX_TABLE_NAME_LEN] = "";
3806 uint errors = 0;
3808 strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
3809 innobase_convert_to_system_charset(
3810 strchr(old_table_utf8, '/') + 1,
3811 strchr(old_name, '/') +1,
3812 MAX_TABLE_NAME_LEN, &errors);
3814 if (errors) {
3815 /* Table name could not be converted from charset
3816 my_charset_filename to UTF-8. This means that the
3817 table name is already in UTF-8 (#mysql#50). */
3818 strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
3821 info = pars_info_create();
3823 pars_info_add_str_literal(info, "new_table_name", new_name);
3824 pars_info_add_str_literal(info, "old_table_name", old_name);
3825 pars_info_add_str_literal(info, "old_table_name_utf8",
3826 old_table_utf8);
3828 strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN);
3829 innobase_convert_to_system_charset(
3830 strchr(new_table_name, '/') + 1,
3831 strchr(new_name, '/') +1,
3832 MAX_TABLE_NAME_LEN, &errors);
3834 if (errors) {
3835 /* Table name could not be converted from charset
3836 my_charset_filename to UTF-8. This means that the
3837 table name is already in UTF-8 (#mysql#50). */
3838 strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN);
3841 pars_info_add_str_literal(info, "new_table_utf8", new_table_name);
3843 err = que_eval_sql(
3844 info,
3845 "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3846 "gen_constr_prefix CHAR;\n"
3847 "new_db_name CHAR;\n"
3848 "foreign_id CHAR;\n"
3849 "new_foreign_id CHAR;\n"
3850 "old_db_name_len INT;\n"
3851 "old_t_name_len INT;\n"
3852 "new_db_name_len INT;\n"
3853 "id_len INT;\n"
3854 "offset INT;\n"
3855 "found INT;\n"
3856 "BEGIN\n"
3857 "found := 1;\n"
3858 "old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3859 "new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3860 "new_db_name := SUBSTR(:new_table_name, 0,\n"
3861 " new_db_name_len);\n"
3862 "old_t_name_len := LENGTH(:old_table_name);\n"
3863 "gen_constr_prefix := CONCAT(:old_table_name_utf8,\n"
3864 " '_ibfk_');\n"
3865 "WHILE found = 1 LOOP\n"
3866 " SELECT ID INTO foreign_id\n"
3867 " FROM SYS_FOREIGN\n"
3868 " WHERE FOR_NAME = :old_table_name\n"
3869 " AND TO_BINARY(FOR_NAME)\n"
3870 " = TO_BINARY(:old_table_name)\n"
3871 " LOCK IN SHARE MODE;\n"
3872 " IF (SQL % NOTFOUND) THEN\n"
3873 " found := 0;\n"
3874 " ELSE\n"
3875 " UPDATE SYS_FOREIGN\n"
3876 " SET FOR_NAME = :new_table_name\n"
3877 " WHERE ID = foreign_id;\n"
3878 " id_len := LENGTH(foreign_id);\n"
3879 " IF (INSTR(foreign_id, '/') > 0) THEN\n"
3880 " IF (INSTR(foreign_id,\n"
3881 " gen_constr_prefix) > 0)\n"
3882 " THEN\n"
3883 " offset := INSTR(foreign_id, '_ibfk_') - 1;\n"
3884 " new_foreign_id :=\n"
3885 " CONCAT(:new_table_utf8,\n"
3886 " SUBSTR(foreign_id, offset, id_len - offset));\n"
3887 " ELSE\n"
3888 " new_foreign_id :=\n"
3889 " CONCAT(new_db_name,\n"
3890 " SUBSTR(foreign_id,\n"
3891 " old_db_name_len,\n"
3892 " id_len - old_db_name_len));\n"
3893 " END IF;\n"
3894 " UPDATE SYS_FOREIGN\n"
3895 " SET ID = new_foreign_id\n"
3896 " WHERE ID = foreign_id;\n"
3897 " UPDATE SYS_FOREIGN_COLS\n"
3898 " SET ID = new_foreign_id\n"
3899 " WHERE ID = foreign_id;\n"
3900 " END IF;\n"
3901 " END IF;\n"
3902 "END LOOP;\n"
3903 "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
3904 "WHERE REF_NAME = :old_table_name\n"
3905 " AND TO_BINARY(REF_NAME)\n"
3906 " = TO_BINARY(:old_table_name);\n"
3907 "END;\n"
3908 , FALSE, trx);
3910 } else if (n_constraints_to_drop > 0) {
3911 /* Drop some constraints of tmp tables. */
3913 ulint db_name_len = dict_get_db_name_len(old_name) + 1;
3914 char* db_name = mem_heap_strdupl(heap, old_name,
3915 db_name_len);
3916 ulint i;
3918 for (i = 0; i < n_constraints_to_drop; i++) {
3919 err = row_delete_constraint(constraints_to_drop[i],
3920 db_name, heap, trx);
3922 if (err != DB_SUCCESS) {
3923 break;
3928 end:
3929 if (err != DB_SUCCESS) {
3930 if (err == DB_DUPLICATE_KEY) {
3931 ut_print_timestamp(stderr);
3932 fputs(" InnoDB: Error; possible reasons:\n"
3933 "InnoDB: 1) Table rename would cause"
3934 " two FOREIGN KEY constraints\n"
3935 "InnoDB: to have the same internal name"
3936 " in case-insensitive comparison.\n"
3937 "InnoDB: 2) table ", stderr);
3938 ut_print_name(stderr, trx, TRUE, new_name);
3939 fputs(" exists in the InnoDB internal data\n"
3940 "InnoDB: dictionary though MySQL is"
3941 " trying to rename table ", stderr);
3942 ut_print_name(stderr, trx, TRUE, old_name);
3943 fputs(" to it.\n"
3944 "InnoDB: Have you deleted the .frm file"
3945 " and not used DROP TABLE?\n"
3946 "InnoDB: You can look for further help from\n"
3947 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3948 "innodb-troubleshooting.html\n"
3949 "InnoDB: If table ", stderr);
3950 ut_print_name(stderr, trx, TRUE, new_name);
3951 fputs(" is a temporary table #sql..., then"
3952 " it can be that\n"
3953 "InnoDB: there are still queries running"
3954 " on the table, and it will be\n"
3955 "InnoDB: dropped automatically when"
3956 " the queries end.\n"
3957 "InnoDB: You can drop the orphaned table"
3958 " inside InnoDB by\n"
3959 "InnoDB: creating an InnoDB table with"
3960 " the same name in another\n"
3961 "InnoDB: database and copying the .frm file"
3962 " to the current database.\n"
3963 "InnoDB: Then MySQL thinks the table exists,"
3964 " and DROP TABLE will\n"
3965 "InnoDB: succeed.\n", stderr);
3967 trx->error_state = DB_SUCCESS;
3968 trx_general_rollback_for_mysql(trx, FALSE, NULL);
3969 trx->error_state = DB_SUCCESS;
3970 } else {
3971 /* The following call will also rename the .ibd data file if
3972 the table is stored in a single-table tablespace */
3974 ibool success = dict_table_rename_in_cache(table, new_name,
3975 !new_is_tmp);
3977 if (!success) {
3978 trx->error_state = DB_SUCCESS;
3979 trx_general_rollback_for_mysql(trx, FALSE, NULL);
3980 trx->error_state = DB_SUCCESS;
3981 ut_print_timestamp(stderr);
3982 fputs(" InnoDB: Error in table rename,"
3983 " cannot rename ", stderr);
3984 ut_print_name(stderr, trx, TRUE, old_name);
3985 fputs(" to ", stderr);
3986 ut_print_name(stderr, trx, TRUE, new_name);
3987 putc('\n', stderr);
3988 err = DB_ERROR;
3990 goto funct_exit;
3993 /* We only want to switch off some of the type checking in
3994 an ALTER, not in a RENAME. */
3996 err = dict_load_foreigns(
3997 new_name, FALSE,
3998 old_is_tmp ? trx->check_foreigns : TRUE);
4000 if (err != DB_SUCCESS) {
4001 ut_print_timestamp(stderr);
4003 if (old_is_tmp) {
4004 fputs(" InnoDB: Error: in ALTER TABLE ",
4005 stderr);
4006 ut_print_name(stderr, trx, TRUE, new_name);
4007 fputs("\n"
4008 "InnoDB: has or is referenced"
4009 " in foreign key constraints\n"
4010 "InnoDB: which are not compatible"
4011 " with the new table definition.\n",
4012 stderr);
4013 } else {
4014 fputs(" InnoDB: Error: in RENAME TABLE"
4015 " table ",
4016 stderr);
4017 ut_print_name(stderr, trx, TRUE, new_name);
4018 fputs("\n"
4019 "InnoDB: is referenced in"
4020 " foreign key constraints\n"
4021 "InnoDB: which are not compatible"
4022 " with the new table definition.\n",
4023 stderr);
4026 ut_a(dict_table_rename_in_cache(table,
4027 old_name, FALSE));
4028 trx->error_state = DB_SUCCESS;
4029 trx_general_rollback_for_mysql(trx, FALSE, NULL);
4030 trx->error_state = DB_SUCCESS;
4034 funct_exit:
4035 trx_commit_for_mysql(trx);
4036 row_mysql_unlock_data_dictionary(trx);
4038 if (UNIV_LIKELY_NULL(heap)) {
4039 mem_heap_free(heap);
4042 trx->op_info = "";
4044 DBUG_RETURN((int) err);
4047 /*************************************************************************
4048 Checks that the index contains entries in an ascending order, unique
4049 constraint is not broken, and calculates the number of index entries
4050 in the read view of the current transaction. */
4051 static
4052 ibool
4053 row_scan_and_check_index(
4054 /*=====================*/
4055 /* out: TRUE if ok */
4056 row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL */
4057 dict_index_t* index, /* in: index */
4058 ulint* n_rows) /* out: number of entries seen in the
4059 current consistent read */
4061 dtuple_t* prev_entry = NULL;
4062 ulint matched_fields;
4063 ulint matched_bytes;
4064 byte* buf;
4065 ulint ret;
4066 rec_t* rec;
4067 ibool is_ok = TRUE;
4068 int cmp;
4069 ibool contains_null;
4070 ulint i;
4071 ulint cnt;
4072 mem_heap_t* heap = NULL;
4073 ulint offsets_[REC_OFFS_NORMAL_SIZE];
4074 ulint* offsets = offsets_;
4075 *offsets_ = (sizeof offsets_) / sizeof *offsets_;
4077 *n_rows = 0;
4079 buf = mem_alloc(UNIV_PAGE_SIZE);
4080 heap = mem_heap_create(100);
4082 /* Make a dummy template in prebuilt, which we will use
4083 in scanning the index entries */
4085 prebuilt->index = index;
4086 prebuilt->sql_stat_start = TRUE;
4087 prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
4088 prebuilt->n_template = 0;
4089 prebuilt->need_to_access_clustered = FALSE;
4091 dtuple_set_n_fields(prebuilt->search_tuple, 0);
4093 prebuilt->select_lock_type = LOCK_NONE;
4094 cnt = 1000;
4096 ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
4097 loop:
4098 /* Check thd->killed every 1,000 scanned rows */
4099 if (--cnt == 0) {
4100 if (trx_is_interrupted(prebuilt->trx)) {
4101 goto func_exit;
4103 cnt = 1000;
4105 if (ret != DB_SUCCESS) {
4106 func_exit:
4107 mem_free(buf);
4108 mem_heap_free(heap);
4110 return(is_ok);
4113 *n_rows = *n_rows + 1;
4115 /* row_search... returns the index record in buf, record origin offset
4116 within buf stored in the first 4 bytes, because we have built a dummy
4117 template */
4119 rec = buf + mach_read_from_4(buf);
4121 if (prev_entry != NULL) {
4122 matched_fields = 0;
4123 matched_bytes = 0;
4125 offsets = rec_get_offsets(rec, index, offsets,
4126 ULINT_UNDEFINED, &heap);
4127 cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
4128 &matched_fields,
4129 &matched_bytes);
4130 contains_null = FALSE;
4132 /* In a unique secondary index we allow equal key values if
4133 they contain SQL NULLs */
4135 for (i = 0;
4136 i < dict_index_get_n_ordering_defined_by_user(index);
4137 i++) {
4138 if (UNIV_SQL_NULL == dfield_get_len(
4139 dtuple_get_nth_field(prev_entry, i))) {
4141 contains_null = TRUE;
4145 if (cmp > 0) {
4146 fputs("InnoDB: index records in a wrong order in ",
4147 stderr);
4148 not_ok:
4149 dict_index_name_print(stderr,
4150 prebuilt->trx, index);
4151 fputs("\n"
4152 "InnoDB: prev record ", stderr);
4153 dtuple_print(stderr, prev_entry);
4154 fputs("\n"
4155 "InnoDB: record ", stderr);
4156 rec_print_new(stderr, rec, offsets);
4157 putc('\n', stderr);
4158 is_ok = FALSE;
4159 } else if ((index->type & DICT_UNIQUE)
4160 && !contains_null
4161 && matched_fields
4162 >= dict_index_get_n_ordering_defined_by_user(
4163 index)) {
4165 fputs("InnoDB: duplicate key in ", stderr);
4166 goto not_ok;
4170 mem_heap_empty(heap);
4171 offsets = offsets_;
4173 prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
4175 ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
4177 goto loop;
4180 /*************************************************************************
4181 Checks a table for corruption. */
4183 ulint
4184 row_check_table_for_mysql(
4185 /*======================*/
4186 /* out: DB_ERROR or DB_SUCCESS */
4187 row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
4188 handle */
4190 dict_table_t* table = prebuilt->table;
4191 dict_index_t* index;
4192 ulint n_rows;
4193 ulint n_rows_in_table = ULINT_UNDEFINED;
4194 ulint ret = DB_SUCCESS;
4195 ulint old_isolation_level;
4197 if (prebuilt->table->ibd_file_missing) {
4198 ut_print_timestamp(stderr);
4199 fprintf(stderr, " InnoDB: Error:\n"
4200 "InnoDB: MySQL is trying to use a table handle"
4201 " but the .ibd file for\n"
4202 "InnoDB: table %s does not exist.\n"
4203 "InnoDB: Have you deleted the .ibd file"
4204 " from the database directory under\n"
4205 "InnoDB: the MySQL datadir, or have you"
4206 " used DISCARD TABLESPACE?\n"
4207 "InnoDB: Look from\n"
4208 "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
4209 "innodb-troubleshooting.html\n"
4210 "InnoDB: how you can resolve the problem.\n",
4211 prebuilt->table->name);
4212 return(DB_ERROR);
4215 prebuilt->trx->op_info = "checking table";
4217 old_isolation_level = prebuilt->trx->isolation_level;
4219 /* We must run the index record counts at an isolation level
4220 >= READ COMMITTED, because a dirty read can see a wrong number
4221 of records in some index; to play safe, we use always
4222 REPEATABLE READ here */
4224 prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
4226 /* Enlarge the fatal lock wait timeout during CHECK TABLE. */
4227 mutex_enter(&kernel_mutex);
4228 srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION;
4229 mutex_exit(&kernel_mutex);
4231 index = dict_table_get_first_index(table);
4233 while (index != NULL) {
4234 /* fputs("Validating index ", stderr);
4235 ut_print_name(stderr, trx, FALSE, index->name);
4236 putc('\n', stderr); */
4238 if (!btr_validate_index(index, prebuilt->trx)) {
4239 ret = DB_ERROR;
4240 } else {
4241 if (!row_scan_and_check_index(prebuilt,
4242 index, &n_rows)) {
4243 ret = DB_ERROR;
4246 if (trx_is_interrupted(prebuilt->trx)) {
4247 break;
4250 /* fprintf(stderr, "%lu entries in index %s\n", n_rows,
4251 index->name); */
4253 if (index == dict_table_get_first_index(table)) {
4254 n_rows_in_table = n_rows;
4255 } else if (n_rows != n_rows_in_table) {
4257 ret = DB_ERROR;
4259 fputs("Error: ", stderr);
4260 dict_index_name_print(stderr,
4261 prebuilt->trx, index);
4262 fprintf(stderr,
4263 " contains %lu entries,"
4264 " should be %lu\n",
4265 (ulong) n_rows,
4266 (ulong) n_rows_in_table);
4270 index = dict_table_get_next_index(index);
4273 /* Restore the original isolation level */
4274 prebuilt->trx->isolation_level = old_isolation_level;
4276 /* We validate also the whole adaptive hash index for all tables
4277 at every CHECK TABLE */
4279 if (!btr_search_validate()) {
4281 ret = DB_ERROR;
4284 /* Restore the fatal lock wait timeout after CHECK TABLE. */
4285 mutex_enter(&kernel_mutex);
4286 srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION;
4287 mutex_exit(&kernel_mutex);
4289 prebuilt->trx->op_info = "";
4291 return(ret);
4294 /*************************************************************************
4295 Determines if a table is a magic monitor table. */
4297 ibool
4298 row_is_magic_monitor_table(
4299 /*=======================*/
4300 /* out: TRUE if monitor table */
4301 const char* table_name) /* in: name of the table, in the
4302 form database/table_name */
4304 const char* name; /* table_name without database/ */
4305 ulint len;
4307 name = strchr(table_name, '/');
4308 ut_a(name != NULL);
4309 name++;
4310 len = strlen(name) + 1;
4312 if (STR_EQ(name, len, S_innodb_monitor)
4313 || STR_EQ(name, len, S_innodb_lock_monitor)
4314 || STR_EQ(name, len, S_innodb_tablespace_monitor)
4315 || STR_EQ(name, len, S_innodb_table_monitor)
4316 || STR_EQ(name, len, S_innodb_mem_validate)) {
4318 return(TRUE);
4321 return(FALSE);