mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / innodb_plugin / row / row0mysql.c
blob57121448d11c525e93e1f1939037448d9d36cf88
1 /*****************************************************************************
3 Copyright (c) 2000, 2013, Oracle and/or its affiliates. All Rights Reserved.
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17 *****************************************************************************/
19 /**************************************************//**
20 @file row/row0mysql.c
21 Interface between Innobase row operations and MySQL.
22 Contains also create table and other data dictionary operations.
24 Created 9/17/2000 Heikki Tuuri
25 *******************************************************/
27 #include "row0mysql.h"
29 #ifdef UNIV_NONINL
30 #include "row0mysql.ic"
31 #endif
33 #include "row0ins.h"
34 #include "row0merge.h"
35 #include "row0sel.h"
36 #include "row0upd.h"
37 #include "row0row.h"
38 #include "que0que.h"
39 #include "pars0pars.h"
40 #include "dict0dict.h"
41 #include "dict0crea.h"
42 #include "dict0load.h"
43 #include "dict0boot.h"
44 #include "trx0roll.h"
45 #include "trx0purge.h"
46 #include "trx0rec.h"
47 #include "trx0undo.h"
48 #include "lock0lock.h"
49 #include "rem0cmp.h"
50 #include "log0log.h"
51 #include "btr0sea.h"
52 #include "fil0fil.h"
53 #include "ibuf0ibuf.h"
54 #include "ha_prototypes.h"
56 #ifdef __WIN__
57 /* error LNK2001: unresolved external symbol _debug_sync_C_callback_ptr */
58 # define DEBUG_SYNC_C(dummy) ((void) 0)
59 #else
60 # include "m_string.h" /* for my_sys.h */
61 # include "my_sys.h" /* DEBUG_SYNC_C */
62 #endif
64 /** Provide optional 4.x backwards compatibility for 5.0 and above */
65 UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
67 /** Chain node of the list of tables to drop in the background. */
68 typedef struct row_mysql_drop_struct row_mysql_drop_t;
70 /** Chain node of the list of tables to drop in the background. */
71 struct row_mysql_drop_struct{
72 char* table_name; /*!< table name */
73 UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
74 /*!< list chain node */
77 /** @brief List of tables we should drop in background.
79 ALTER TABLE in MySQL requires that the table handler can drop the
80 table in background when there are no queries to it any
81 more. Protected by kernel_mutex. */
82 static UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
83 /** Flag: has row_mysql_drop_list been initialized? */
84 static ibool row_mysql_drop_list_inited = FALSE;
86 /** Magic table names for invoking various monitor threads */
87 /* @{ */
88 static const char S_innodb_monitor[] = "innodb_monitor";
89 static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
90 static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
91 static const char S_innodb_table_monitor[] = "innodb_table_monitor";
92 static const char S_innodb_mem_validate[] = "innodb_mem_validate";
93 /* @} */
95 /** Evaluates to true if str1 equals str2_onstack, used for comparing
96 the magic table names.
97 @param str1 in: string to compare
98 @param str1_len in: length of str1, in bytes, including terminating NUL
99 @param str2_onstack in: char[] array containing a NUL terminated string
100 @return TRUE if str1 equals str2_onstack */
101 #define STR_EQ(str1, str1_len, str2_onstack) \
102 ((str1_len) == sizeof(str2_onstack) \
103 && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
105 /*******************************************************************//**
106 Determine if the given name is a name reserved for MySQL system tables.
107 @return TRUE if name is a MySQL system table name */
108 static
109 ibool
110 row_mysql_is_system_table(
111 /*======================*/
112 const char* name)
114 if (strncmp(name, "mysql/", 6) != 0) {
116 return(FALSE);
119 return(0 == strcmp(name + 6, "host")
120 || 0 == strcmp(name + 6, "user")
121 || 0 == strcmp(name + 6, "db"));
124 /*********************************************************************//**
125 If a table is not yet in the drop list, adds the table to the list of tables
126 which the master thread drops in background. We need this on Unix because in
127 ALTER TABLE MySQL may call drop table even if the table has running queries on
128 it. Also, if there are running foreign key checks on the table, we drop the
129 table lazily.
130 @return TRUE if the table was not yet in the drop list, and was added there */
131 static
132 ibool
133 row_add_table_to_background_drop_list(
134 /*==================================*/
135 const char* name); /*!< in: table name */
137 /*******************************************************************//**
138 Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
139 static
140 void
141 row_mysql_delay_if_needed(void)
142 /*===========================*/
144 if (srv_dml_needed_delay) {
145 os_thread_sleep(srv_dml_needed_delay);
149 /*******************************************************************//**
150 Frees the blob heap in prebuilt when no longer needed. */
151 UNIV_INTERN
152 void
153 row_mysql_prebuilt_free_blob_heap(
154 /*==============================*/
155 row_prebuilt_t* prebuilt) /*!< in: prebuilt struct of a
156 ha_innobase:: table handle */
158 mem_heap_free(prebuilt->blob_heap);
159 prebuilt->blob_heap = NULL;
162 /*******************************************************************//**
163 Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
164 format.
165 @return pointer to the data, we skip the 1 or 2 bytes at the start
166 that are used to store the len */
167 UNIV_INTERN
168 byte*
169 row_mysql_store_true_var_len(
170 /*=========================*/
171 byte* dest, /*!< in: where to store */
172 ulint len, /*!< in: length, must fit in two bytes */
173 ulint lenlen) /*!< in: storage length of len: either 1 or 2 bytes */
175 if (lenlen == 2) {
176 ut_a(len < 256 * 256);
178 mach_write_to_2_little_endian(dest, len);
180 return(dest + 2);
183 ut_a(lenlen == 1);
184 ut_a(len < 256);
186 mach_write_to_1(dest, len);
188 return(dest + 1);
191 /*******************************************************************//**
192 Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
193 returns a pointer to the data.
194 @return pointer to the data, we skip the 1 or 2 bytes at the start
195 that are used to store the len */
196 UNIV_INTERN
197 const byte*
198 row_mysql_read_true_varchar(
199 /*========================*/
200 ulint* len, /*!< out: variable-length field length */
201 const byte* field, /*!< in: field in the MySQL format */
202 ulint lenlen) /*!< in: storage length of len: either 1
203 or 2 bytes */
205 if (lenlen == 2) {
206 *len = mach_read_from_2_little_endian(field);
208 return(field + 2);
211 ut_a(lenlen == 1);
213 *len = mach_read_from_1(field);
215 return(field + 1);
218 /*******************************************************************//**
219 Stores a reference to a BLOB in the MySQL format. */
220 UNIV_INTERN
221 void
222 row_mysql_store_blob_ref(
223 /*=====================*/
224 byte* dest, /*!< in: where to store */
225 ulint col_len,/*!< in: dest buffer size: determines into
226 how many bytes the BLOB length is stored,
227 the space for the length may vary from 1
228 to 4 bytes */
229 const void* data, /*!< in: BLOB data; if the value to store
230 is SQL NULL this should be NULL pointer */
231 ulint len) /*!< in: BLOB length; if the value to store
232 is SQL NULL this should be 0; remember
233 also to set the NULL bit in the MySQL record
234 header! */
236 /* MySQL might assume the field is set to zero except the length and
237 the pointer fields */
239 memset(dest, '\0', col_len);
241 /* In dest there are 1 - 4 bytes reserved for the BLOB length,
242 and after that 8 bytes reserved for the pointer to the data.
243 In 32-bit architectures we only use the first 4 bytes of the pointer
244 slot. */
246 ut_a(col_len - 8 > 1 || len < 256);
247 ut_a(col_len - 8 > 2 || len < 256 * 256);
248 ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
250 mach_write_to_n_little_endian(dest, col_len - 8, len);
252 memcpy(dest + col_len - 8, &data, sizeof data);
255 /*******************************************************************//**
256 Reads a reference to a BLOB in the MySQL format.
257 @return pointer to BLOB data */
258 UNIV_INTERN
259 const byte*
260 row_mysql_read_blob_ref(
261 /*====================*/
262 ulint* len, /*!< out: BLOB length */
263 const byte* ref, /*!< in: BLOB reference in the
264 MySQL format */
265 ulint col_len) /*!< in: BLOB reference length
266 (not BLOB length) */
268 byte* data;
270 *len = mach_read_from_n_little_endian(ref, col_len - 8);
272 memcpy(&data, ref + col_len - 8, sizeof data);
274 return(data);
277 /**************************************************************//**
278 Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
279 The counterpart of this function is row_sel_field_store_in_mysql_format() in
280 row0sel.c.
281 @return up to which byte we used buf in the conversion */
282 UNIV_INTERN
283 byte*
284 row_mysql_store_col_in_innobase_format(
285 /*===================================*/
286 dfield_t* dfield, /*!< in/out: dfield where dtype
287 information must be already set when
288 this function is called! */
289 byte* buf, /*!< in/out: buffer for a converted
290 integer value; this must be at least
291 col_len long then! */
292 ibool row_format_col, /*!< TRUE if the mysql_data is from
293 a MySQL row, FALSE if from a MySQL
294 key value;
295 in MySQL, a true VARCHAR storage
296 format differs in a row and in a
297 key value: in a key value the length
298 is always stored in 2 bytes! */
299 const byte* mysql_data, /*!< in: MySQL column value, not
300 SQL NULL; NOTE that dfield may also
301 get a pointer to mysql_data,
302 therefore do not discard this as long
303 as dfield is used! */
304 ulint col_len, /*!< in: MySQL column length; NOTE that
305 this is the storage length of the
306 column in the MySQL format row, not
307 necessarily the length of the actual
308 payload data; if the column is a true
309 VARCHAR then this is irrelevant */
310 ulint comp) /*!< in: nonzero=compact format */
312 const byte* ptr = mysql_data;
313 const dtype_t* dtype;
314 ulint type;
315 ulint lenlen;
317 dtype = dfield_get_type(dfield);
319 type = dtype->mtype;
321 if (type == DATA_INT) {
322 /* Store integer data in Innobase in a big-endian format,
323 sign bit negated if the data is a signed integer. In MySQL,
324 integers are stored in a little-endian format. */
326 byte* p = buf + col_len;
328 for (;;) {
329 p--;
330 *p = *mysql_data;
331 if (p == buf) {
332 break;
334 mysql_data++;
337 if (!(dtype->prtype & DATA_UNSIGNED)) {
339 *buf ^= 128;
342 ptr = buf;
343 buf += col_len;
344 } else if ((type == DATA_VARCHAR
345 || type == DATA_VARMYSQL
346 || type == DATA_BINARY)) {
348 if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
349 /* The length of the actual data is stored to 1 or 2
350 bytes at the start of the field */
352 if (row_format_col) {
353 if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
354 lenlen = 2;
355 } else {
356 lenlen = 1;
358 } else {
359 /* In a MySQL key value, lenlen is always 2 */
360 lenlen = 2;
363 ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
364 lenlen);
365 } else {
366 /* Remove trailing spaces from old style VARCHAR
367 columns. */
369 /* Handle UCS2 strings differently. */
370 ulint mbminlen = dtype_get_mbminlen(dtype);
372 ptr = mysql_data;
374 if (mbminlen == 2) {
375 /* space=0x0020 */
376 /* Trim "half-chars", just in case. */
377 col_len &= ~1;
379 while (col_len >= 2 && ptr[col_len - 2] == 0x00
380 && ptr[col_len - 1] == 0x20) {
381 col_len -= 2;
383 } else {
384 ut_a(mbminlen == 1);
385 /* space=0x20 */
386 while (col_len > 0
387 && ptr[col_len - 1] == 0x20) {
388 col_len--;
392 } else if (comp && type == DATA_MYSQL
393 && dtype_get_mbminlen(dtype) == 1
394 && dtype_get_mbmaxlen(dtype) > 1) {
395 /* In some cases we strip trailing spaces from UTF-8 and other
396 multibyte charsets, from FIXED-length CHAR columns, to save
397 space. UTF-8 would otherwise normally use 3 * the string length
398 bytes to store an ASCII string! */
400 /* We assume that this CHAR field is encoded in a
401 variable-length character set where spaces have
402 1:1 correspondence to 0x20 bytes, such as UTF-8.
404 Consider a CHAR(n) field, a field of n characters.
405 It will contain between n * mbminlen and n * mbmaxlen bytes.
406 We will try to truncate it to n bytes by stripping
407 space padding. If the field contains single-byte
408 characters only, it will be truncated to n characters.
409 Consider a CHAR(5) field containing the string ".a "
410 where "." denotes a 3-byte character represented by
411 the bytes "$%&". After our stripping, the string will
412 be stored as "$%&a " (5 bytes). The string ".abc "
413 will be stored as "$%&abc" (6 bytes).
415 The space padding will be restored in row0sel.c, function
416 row_sel_field_store_in_mysql_format(). */
418 ulint n_chars;
420 ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
422 n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
424 /* Strip space padding. */
425 while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
426 col_len--;
428 } else if (type == DATA_BLOB && row_format_col) {
430 ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
433 dfield_set_data(dfield, ptr, col_len);
435 return(buf);
438 /**************************************************************//**
439 Convert a row in the MySQL format to a row in the Innobase format. Note that
440 the function to convert a MySQL format key value to an InnoDB dtuple is
441 row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
442 static
443 void
444 row_mysql_convert_row_to_innobase(
445 /*==============================*/
446 dtuple_t* row, /*!< in/out: Innobase row where the
447 field type information is already
448 copied there! */
449 row_prebuilt_t* prebuilt, /*!< in: prebuilt struct where template
450 must be of type ROW_MYSQL_WHOLE_ROW */
451 byte* mysql_rec) /*!< in: row in the MySQL format;
452 NOTE: do not discard as long as
453 row is used, as row may contain
454 pointers to this record! */
456 const mysql_row_templ_t*templ;
457 dfield_t* dfield;
458 ulint i;
460 ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
461 ut_ad(prebuilt->mysql_template);
463 for (i = 0; i < prebuilt->n_template; i++) {
465 templ = prebuilt->mysql_template + i;
466 dfield = dtuple_get_nth_field(row, i);
468 if (templ->mysql_null_bit_mask != 0) {
469 /* Column may be SQL NULL */
471 if (mysql_rec[templ->mysql_null_byte_offset]
472 & (byte) (templ->mysql_null_bit_mask)) {
474 /* It is SQL NULL */
476 dfield_set_null(dfield);
478 goto next_column;
482 row_mysql_store_col_in_innobase_format(
483 dfield,
484 prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
485 TRUE, /* MySQL row format data */
486 mysql_rec + templ->mysql_col_offset,
487 templ->mysql_col_len,
488 dict_table_is_comp(prebuilt->table));
489 next_column:
494 /****************************************************************//**
495 Handles user errors and lock waits detected by the database engine.
496 @return TRUE if it was a lock wait and we should continue running the
497 query thread and in that case the thr is ALREADY in the running state. */
498 UNIV_INTERN
499 ibool
500 row_mysql_handle_errors(
501 /*====================*/
502 ulint* new_err,/*!< out: possible new error encountered in
503 lock wait, or if no new error, the value
504 of trx->error_state at the entry of this
505 function */
506 trx_t* trx, /*!< in: transaction */
507 que_thr_t* thr, /*!< in: query thread */
508 trx_savept_t* savept) /*!< in: savepoint or NULL */
510 ulint err;
512 handle_new_error:
513 err = trx->error_state;
515 ut_a(err != DB_SUCCESS);
517 trx->error_state = DB_SUCCESS;
519 switch (err) {
520 case DB_LOCK_WAIT_TIMEOUT:
521 if (row_rollback_on_timeout) {
522 trx_general_rollback_for_mysql(trx, NULL);
523 break;
525 /* fall through */
526 case DB_DUPLICATE_KEY:
527 case DB_FOREIGN_DUPLICATE_KEY:
528 case DB_TOO_BIG_RECORD:
529 case DB_ROW_IS_REFERENCED:
530 case DB_NO_REFERENCED_ROW:
531 case DB_CANNOT_ADD_CONSTRAINT:
532 case DB_TOO_MANY_CONCURRENT_TRXS:
533 case DB_OUT_OF_FILE_SPACE:
534 case DB_INTERRUPTED:
535 if (savept) {
536 /* Roll back the latest, possibly incomplete
537 insertion or update */
539 trx_general_rollback_for_mysql(trx, savept);
541 /* MySQL will roll back the latest SQL statement */
542 break;
543 case DB_LOCK_WAIT:
544 srv_suspend_mysql_thread(thr);
546 if (trx->error_state != DB_SUCCESS) {
547 que_thr_stop_for_mysql(thr);
549 goto handle_new_error;
552 *new_err = err;
554 return(TRUE);
556 case DB_DEADLOCK:
557 case DB_LOCK_TABLE_FULL:
558 /* Roll back the whole transaction; this resolution was added
559 to version 3.23.43 */
561 trx_general_rollback_for_mysql(trx, NULL);
562 break;
564 case DB_MUST_GET_MORE_FILE_SPACE:
565 fputs("InnoDB: The database cannot continue"
566 " operation because of\n"
567 "InnoDB: lack of space. You must add"
568 " a new data file to\n"
569 "InnoDB: my.cnf and restart the database.\n", stderr);
571 exit(1);
573 case DB_CORRUPTION:
574 fputs("InnoDB: We detected index corruption"
575 " in an InnoDB type table.\n"
576 "InnoDB: You have to dump + drop + reimport"
577 " the table or, in\n"
578 "InnoDB: a case of widespread corruption,"
579 " dump all InnoDB\n"
580 "InnoDB: tables and recreate the"
581 " whole InnoDB tablespace.\n"
582 "InnoDB: If the mysqld server crashes"
583 " after the startup or when\n"
584 "InnoDB: you dump the tables, look at\n"
585 "InnoDB: " REFMAN "forcing-innodb-recovery.html"
586 " for help.\n", stderr);
587 break;
588 case DB_FOREIGN_EXCEED_MAX_CASCADE:
589 fprintf(stderr, "InnoDB: Cannot delete/update rows with"
590 " cascading foreign key constraints that exceed max"
591 " depth of %lu\n"
592 "Please drop excessive foreign constraints"
593 " and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
594 break;
595 default:
596 fprintf(stderr, "InnoDB: unknown error code %lu\n",
597 (ulong) err);
598 ut_error;
601 if (trx->error_state != DB_SUCCESS) {
602 *new_err = trx->error_state;
603 } else {
604 *new_err = err;
607 trx->error_state = DB_SUCCESS;
609 return(FALSE);
612 /********************************************************************//**
613 Create a prebuilt struct for a MySQL table handle.
614 @return own: a prebuilt struct */
615 UNIV_INTERN
616 row_prebuilt_t*
617 row_create_prebuilt(
618 /*================*/
619 dict_table_t* table) /*!< in: Innobase table handle */
621 row_prebuilt_t* prebuilt;
622 mem_heap_t* heap;
623 dict_index_t* clust_index;
624 dtuple_t* ref;
625 ulint ref_len;
627 heap = mem_heap_create(sizeof *prebuilt + 128);
629 prebuilt = mem_heap_zalloc(heap, sizeof *prebuilt);
631 prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
632 prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
634 prebuilt->table = table;
636 prebuilt->sql_stat_start = TRUE;
637 prebuilt->heap = heap;
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;
644 UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
645 sizeof prebuilt->stored_select_lock_type);
647 prebuilt->search_tuple = dtuple_create(
648 heap, 2 * dict_table_get_n_cols(table));
650 clust_index = dict_table_get_first_index(table);
652 /* Make sure that search_tuple is long enough for clustered index */
653 ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
655 ref_len = dict_index_get_n_unique(clust_index);
657 ref = dtuple_create(heap, ref_len);
659 dict_index_copy_types(ref, clust_index, ref_len);
661 prebuilt->clust_ref = ref;
663 prebuilt->autoinc_error = 0;
664 prebuilt->autoinc_offset = 0;
666 /* Default to 1, we will set the actual value later in
667 ha_innobase::get_auto_increment(). */
668 prebuilt->autoinc_increment = 1;
670 prebuilt->autoinc_last_value = 0;
672 return(prebuilt);
675 /********************************************************************//**
676 Free a prebuilt struct for a MySQL table handle. */
677 UNIV_INTERN
678 void
679 row_prebuilt_free(
680 /*==============*/
681 row_prebuilt_t* prebuilt, /*!< in, own: prebuilt struct */
682 ibool dict_locked) /*!< in: TRUE=data dictionary locked */
684 ulint i;
686 if (UNIV_UNLIKELY
687 (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
688 || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
690 fprintf(stderr,
691 "InnoDB: Error: trying to free a corrupt\n"
692 "InnoDB: table handle. Magic n %lu,"
693 " magic n2 %lu, table name ",
694 (ulong) prebuilt->magic_n,
695 (ulong) prebuilt->magic_n2);
696 ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
697 putc('\n', stderr);
699 mem_analyze_corruption(prebuilt);
701 ut_error;
704 prebuilt->magic_n = ROW_PREBUILT_FREED;
705 prebuilt->magic_n2 = ROW_PREBUILT_FREED;
707 btr_pcur_free_for_mysql(prebuilt->pcur);
708 btr_pcur_free_for_mysql(prebuilt->clust_pcur);
710 if (prebuilt->mysql_template) {
711 mem_free(prebuilt->mysql_template);
714 if (prebuilt->ins_graph) {
715 que_graph_free_recursive(prebuilt->ins_graph);
718 if (prebuilt->sel_graph) {
719 que_graph_free_recursive(prebuilt->sel_graph);
722 if (prebuilt->upd_graph) {
723 que_graph_free_recursive(prebuilt->upd_graph);
726 if (prebuilt->blob_heap) {
727 mem_heap_free(prebuilt->blob_heap);
730 if (prebuilt->old_vers_heap) {
731 mem_heap_free(prebuilt->old_vers_heap);
734 for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
735 if (prebuilt->fetch_cache[i] != NULL) {
737 if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
738 (prebuilt->fetch_cache[i]) - 4))
739 || (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
740 (prebuilt->fetch_cache[i])
741 + prebuilt->mysql_row_len))) {
742 fputs("InnoDB: Error: trying to free"
743 " a corrupt fetch buffer.\n", stderr);
745 mem_analyze_corruption(
746 prebuilt->fetch_cache[i]);
748 ut_error;
751 mem_free((prebuilt->fetch_cache[i]) - 4);
755 dict_table_decrement_handle_count(prebuilt->table, dict_locked);
757 mem_heap_free(prebuilt->heap);
760 /*********************************************************************//**
761 Updates the transaction pointers in query graphs stored in the prebuilt
762 struct. */
763 UNIV_INTERN
764 void
765 row_update_prebuilt_trx(
766 /*====================*/
767 row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct
768 in MySQL handle */
769 trx_t* trx) /*!< in: transaction handle */
771 if (trx->magic_n != TRX_MAGIC_N) {
772 fprintf(stderr,
773 "InnoDB: Error: trying to use a corrupt\n"
774 "InnoDB: trx handle. Magic n %lu\n",
775 (ulong) trx->magic_n);
777 mem_analyze_corruption(trx);
779 ut_error;
782 if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
783 fprintf(stderr,
784 "InnoDB: Error: trying to use a corrupt\n"
785 "InnoDB: table handle. Magic n %lu, table name ",
786 (ulong) prebuilt->magic_n);
787 ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
788 putc('\n', stderr);
790 mem_analyze_corruption(prebuilt);
792 ut_error;
795 prebuilt->trx = trx;
797 if (prebuilt->ins_graph) {
798 prebuilt->ins_graph->trx = trx;
801 if (prebuilt->upd_graph) {
802 prebuilt->upd_graph->trx = trx;
805 if (prebuilt->sel_graph) {
806 prebuilt->sel_graph->trx = trx;
810 /*********************************************************************//**
811 Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
812 has not yet been built in the prebuilt struct, then this function first
813 builds it.
814 @return prebuilt dtuple; the column type information is also set in it */
815 static
816 dtuple_t*
817 row_get_prebuilt_insert_row(
818 /*========================*/
819 row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
820 handle */
822 ins_node_t* node;
823 dtuple_t* row;
824 dict_table_t* table = prebuilt->table;
826 ut_ad(prebuilt && table && prebuilt->trx);
828 if (prebuilt->ins_node == NULL) {
830 /* Not called before for this handle: create an insert node
831 and query graph to the prebuilt struct */
833 node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
835 prebuilt->ins_node = node;
837 if (prebuilt->ins_upd_rec_buff == NULL) {
838 prebuilt->ins_upd_rec_buff = mem_heap_alloc(
839 prebuilt->heap, prebuilt->mysql_row_len);
842 row = dtuple_create(prebuilt->heap,
843 dict_table_get_n_cols(table));
845 dict_table_copy_types(row, table);
847 ins_node_set_new_row(node, row);
849 prebuilt->ins_graph = que_node_get_parent(
850 pars_complete_graph_for_exec(node,
851 prebuilt->trx,
852 prebuilt->heap));
853 prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
856 return(prebuilt->ins_node->row);
859 /*********************************************************************//**
860 Updates the table modification counter and calculates new estimates
861 for table and index statistics if necessary. */
862 UNIV_INLINE
863 void
864 row_update_statistics_if_needed(
865 /*============================*/
866 dict_table_t* table) /*!< in: table */
868 ulint counter;
870 counter = table->stat_modified_counter;
872 table->stat_modified_counter = counter + 1;
874 /* Calculate new statistics if 1 / 16 of table has been modified
875 since the last time a statistics batch was run, or if
876 stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
877 We calculate statistics at most every 16th round, since we may have
878 a counter table which is very small and updated very often. */
880 if (counter > 2000000000
881 || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
883 dict_update_statistics(table, FALSE /* update even if stats
884 are initialized */);
888 /*********************************************************************//**
889 Unlocks AUTO_INC type locks that were possibly reserved by a trx. This
890 function should be called at the the end of an SQL statement, by the
891 connection thread that owns the transaction (trx->mysql_thd). */
892 UNIV_INTERN
893 void
894 row_unlock_table_autoinc_for_mysql(
895 /*===============================*/
896 trx_t* trx) /*!< in/out: transaction */
898 if (lock_trx_holds_autoinc_locks(trx)) {
899 mutex_enter(&kernel_mutex);
901 lock_release_autoinc_locks(trx);
903 mutex_exit(&kernel_mutex);
907 /*********************************************************************//**
908 Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
909 AUTO_INC lock gives exclusive access to the auto-inc counter of the
910 table. The lock is reserved only for the duration of an SQL statement.
911 It is not compatible with another AUTO_INC or exclusive lock on the
912 table.
913 @return error code or DB_SUCCESS */
914 UNIV_INTERN
916 row_lock_table_autoinc_for_mysql(
917 /*=============================*/
918 row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in the MySQL
919 table handle */
921 trx_t* trx = prebuilt->trx;
922 ins_node_t* node = prebuilt->ins_node;
923 const dict_table_t* table = prebuilt->table;
924 que_thr_t* thr;
925 ulint err;
926 ibool was_lock_wait;
928 ut_ad(trx);
929 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
931 /* If we already hold an AUTOINC lock on the table then do nothing.
932 Note: We peek at the value of the current owner without acquiring
933 the kernel mutex. **/
934 if (trx == table->autoinc_trx) {
936 return(DB_SUCCESS);
939 trx->op_info = "setting auto-inc lock";
941 if (node == NULL) {
942 row_get_prebuilt_insert_row(prebuilt);
943 node = prebuilt->ins_node;
946 /* We use the insert query graph as the dummy graph needed
947 in the lock module call */
949 thr = que_fork_get_first_thr(prebuilt->ins_graph);
951 que_thr_move_to_run_state_for_mysql(thr, trx);
953 run_again:
954 thr->run_node = node;
955 thr->prev_node = node;
957 /* It may be that the current session has not yet started
958 its transaction, or it has been committed: */
960 trx_start_if_not_started(trx);
962 err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
964 trx->error_state = err;
966 if (err != DB_SUCCESS) {
967 que_thr_stop_for_mysql(thr);
969 was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
971 if (was_lock_wait) {
972 goto run_again;
975 trx->op_info = "";
977 return((int) err);
980 que_thr_stop_for_mysql_no_error(thr, trx);
982 trx->op_info = "";
984 return((int) err);
987 /*********************************************************************//**
988 Sets a table lock on the table mentioned in prebuilt.
989 @return error code or DB_SUCCESS */
990 UNIV_INTERN
992 row_lock_table_for_mysql(
993 /*=====================*/
994 row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in the MySQL
995 table handle */
996 dict_table_t* table, /*!< in: table to lock, or NULL
997 if prebuilt->table should be
998 locked as
999 prebuilt->select_lock_type */
1000 ulint mode) /*!< in: lock mode of table
1001 (ignored if table==NULL) */
1003 trx_t* trx = prebuilt->trx;
1004 que_thr_t* thr;
1005 ulint err;
1006 ibool was_lock_wait;
1008 ut_ad(trx);
1009 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1011 trx->op_info = "setting table lock";
1013 if (prebuilt->sel_graph == NULL) {
1014 /* Build a dummy select query graph */
1015 row_prebuild_sel_graph(prebuilt);
1018 /* We use the select query graph as the dummy graph needed
1019 in the lock module call */
1021 thr = que_fork_get_first_thr(prebuilt->sel_graph);
1023 que_thr_move_to_run_state_for_mysql(thr, trx);
1025 run_again:
1026 thr->run_node = thr;
1027 thr->prev_node = thr->common.parent;
1029 /* It may be that the current session has not yet started
1030 its transaction, or it has been committed: */
1032 trx_start_if_not_started(trx);
1034 if (table) {
1035 err = lock_table(0, table, mode, thr);
1036 } else {
1037 err = lock_table(0, prebuilt->table,
1038 prebuilt->select_lock_type, thr);
1041 trx->error_state = err;
1043 if (err != DB_SUCCESS) {
1044 que_thr_stop_for_mysql(thr);
1046 was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1048 if (was_lock_wait) {
1049 goto run_again;
1052 trx->op_info = "";
1054 return((int) err);
1057 que_thr_stop_for_mysql_no_error(thr, trx);
1059 trx->op_info = "";
1061 return((int) err);
1064 /*********************************************************************//**
1065 Does an insert for MySQL.
1066 @return error code or DB_SUCCESS */
1067 UNIV_INTERN
1069 row_insert_for_mysql(
1070 /*=================*/
1071 byte* mysql_rec, /*!< in: row in the MySQL format */
1072 row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1073 handle */
1075 trx_savept_t savept;
1076 que_thr_t* thr;
1077 ulint err;
1078 ibool was_lock_wait;
1079 trx_t* trx = prebuilt->trx;
1080 ins_node_t* node = prebuilt->ins_node;
1082 ut_ad(trx);
1083 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1085 if (prebuilt->table->ibd_file_missing) {
1086 ut_print_timestamp(stderr);
1087 fprintf(stderr, " InnoDB: Error:\n"
1088 "InnoDB: MySQL is trying to use a table handle"
1089 " but the .ibd file for\n"
1090 "InnoDB: table %s does not exist.\n"
1091 "InnoDB: Have you deleted the .ibd file"
1092 " from the database directory under\n"
1093 "InnoDB: the MySQL datadir, or have you"
1094 " used DISCARD TABLESPACE?\n"
1095 "InnoDB: Look from\n"
1096 "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1097 "InnoDB: how you can resolve the problem.\n",
1098 prebuilt->table->name);
1099 return(DB_ERROR);
1102 if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1103 fprintf(stderr,
1104 "InnoDB: Error: trying to free a corrupt\n"
1105 "InnoDB: table handle. Magic n %lu, table name ",
1106 (ulong) prebuilt->magic_n);
1107 ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1108 putc('\n', stderr);
1110 mem_analyze_corruption(prebuilt);
1112 ut_error;
1115 if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1116 fputs("InnoDB: A new raw disk partition was initialized or\n"
1117 "InnoDB: innodb_force_recovery is on: we do not allow\n"
1118 "InnoDB: database modifications by the user. Shut down\n"
1119 "InnoDB: mysqld and edit my.cnf so that"
1120 " newraw is replaced\n"
1121 "InnoDB: with raw, and innodb_force_... is removed.\n",
1122 stderr);
1124 return(DB_ERROR);
1127 trx->op_info = "inserting";
1129 row_mysql_delay_if_needed();
1131 trx_start_if_not_started(trx);
1133 if (node == NULL) {
1134 row_get_prebuilt_insert_row(prebuilt);
1135 node = prebuilt->ins_node;
1138 row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1140 savept = trx_savept_take(trx);
1142 thr = que_fork_get_first_thr(prebuilt->ins_graph);
1144 if (prebuilt->sql_stat_start) {
1145 node->state = INS_NODE_SET_IX_LOCK;
1146 prebuilt->sql_stat_start = FALSE;
1147 } else {
1148 node->state = INS_NODE_ALLOC_ROW_ID;
1151 que_thr_move_to_run_state_for_mysql(thr, trx);
1153 run_again:
1154 thr->run_node = node;
1155 thr->prev_node = node;
1157 row_ins_step(thr);
1159 err = trx->error_state;
1161 if (err != DB_SUCCESS) {
1162 que_thr_stop_for_mysql(thr);
1164 /* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1166 was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1167 &savept);
1168 thr->lock_state= QUE_THR_LOCK_NOLOCK;
1170 if (was_lock_wait) {
1171 goto run_again;
1174 trx->op_info = "";
1176 return((int) err);
1179 que_thr_stop_for_mysql_no_error(thr, trx);
1181 prebuilt->table->stat_n_rows++;
1183 srv_n_rows_inserted++;
1185 if (prebuilt->table->stat_n_rows == 0) {
1186 /* Avoid wrap-over */
1187 prebuilt->table->stat_n_rows--;
1190 row_update_statistics_if_needed(prebuilt->table);
1191 trx->op_info = "";
1193 return((int) err);
1196 /*********************************************************************//**
1197 Builds a dummy query graph used in selects. */
1198 UNIV_INTERN
1199 void
1200 row_prebuild_sel_graph(
1201 /*===================*/
1202 row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1203 handle */
1205 sel_node_t* node;
1207 ut_ad(prebuilt && prebuilt->trx);
1209 if (prebuilt->sel_graph == NULL) {
1211 node = sel_node_create(prebuilt->heap);
1213 prebuilt->sel_graph = que_node_get_parent(
1214 pars_complete_graph_for_exec(node,
1215 prebuilt->trx,
1216 prebuilt->heap));
1218 prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1222 /*********************************************************************//**
1223 Creates an query graph node of 'update' type to be used in the MySQL
1224 interface.
1225 @return own: update node */
1226 UNIV_INTERN
1227 upd_node_t*
1228 row_create_update_node_for_mysql(
1229 /*=============================*/
1230 dict_table_t* table, /*!< in: table to update */
1231 mem_heap_t* heap) /*!< in: mem heap from which allocated */
1233 upd_node_t* node;
1235 node = upd_node_create(heap);
1237 node->in_mysql_interface = TRUE;
1238 node->is_delete = FALSE;
1239 node->searched_update = FALSE;
1240 node->select = NULL;
1241 node->pcur = btr_pcur_create_for_mysql();
1242 node->table = table;
1244 node->update = upd_create(dict_table_get_n_cols(table), heap);
1246 node->update_n_fields = dict_table_get_n_cols(table);
1248 UT_LIST_INIT(node->columns);
1249 node->has_clust_rec_x_lock = TRUE;
1250 node->cmpl_info = 0;
1252 node->table_sym = NULL;
1253 node->col_assign_list = NULL;
1255 return(node);
1258 /*********************************************************************//**
1259 Gets pointer to a prebuilt update vector used in updates. If the update
1260 graph has not yet been built in the prebuilt struct, then this function
1261 first builds it.
1262 @return prebuilt update vector */
1263 UNIV_INTERN
1264 upd_t*
1265 row_get_prebuilt_update_vector(
1266 /*===========================*/
1267 row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1268 handle */
1270 dict_table_t* table = prebuilt->table;
1271 upd_node_t* node;
1273 ut_ad(prebuilt && table && prebuilt->trx);
1275 if (prebuilt->upd_node == NULL) {
1277 /* Not called before for this handle: create an update node
1278 and query graph to the prebuilt struct */
1280 node = row_create_update_node_for_mysql(table, prebuilt->heap);
1282 prebuilt->upd_node = node;
1284 prebuilt->upd_graph = que_node_get_parent(
1285 pars_complete_graph_for_exec(node,
1286 prebuilt->trx,
1287 prebuilt->heap));
1288 prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1291 return(prebuilt->upd_node->update);
1294 /*********************************************************************//**
1295 Does an update or delete of a row for MySQL.
1296 @return error code or DB_SUCCESS */
1297 UNIV_INTERN
1299 row_update_for_mysql(
1300 /*=================*/
1301 byte* mysql_rec, /*!< in: the row to be updated, in
1302 the MySQL format */
1303 row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1304 handle */
1306 trx_savept_t savept;
1307 ulint err;
1308 que_thr_t* thr;
1309 ibool was_lock_wait;
1310 dict_index_t* clust_index;
1311 /* ulint ref_len; */
1312 upd_node_t* node;
1313 dict_table_t* table = prebuilt->table;
1314 trx_t* trx = prebuilt->trx;
1316 ut_ad(prebuilt && trx);
1317 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1318 UT_NOT_USED(mysql_rec);
1320 if (prebuilt->table->ibd_file_missing) {
1321 ut_print_timestamp(stderr);
1322 fprintf(stderr, " InnoDB: Error:\n"
1323 "InnoDB: MySQL is trying to use a table handle"
1324 " but the .ibd file for\n"
1325 "InnoDB: table %s does not exist.\n"
1326 "InnoDB: Have you deleted the .ibd file"
1327 " from the database directory under\n"
1328 "InnoDB: the MySQL datadir, or have you"
1329 " used DISCARD TABLESPACE?\n"
1330 "InnoDB: Look from\n"
1331 "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1332 "InnoDB: how you can resolve the problem.\n",
1333 prebuilt->table->name);
1334 return(DB_ERROR);
1337 if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1338 fprintf(stderr,
1339 "InnoDB: Error: trying to free a corrupt\n"
1340 "InnoDB: table handle. Magic n %lu, table name ",
1341 (ulong) prebuilt->magic_n);
1342 ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1343 putc('\n', stderr);
1345 mem_analyze_corruption(prebuilt);
1347 ut_error;
1350 if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1351 fputs("InnoDB: A new raw disk partition was initialized or\n"
1352 "InnoDB: innodb_force_recovery is on: we do not allow\n"
1353 "InnoDB: database modifications by the user. Shut down\n"
1354 "InnoDB: mysqld and edit my.cnf so that newraw"
1355 " is replaced\n"
1356 "InnoDB: with raw, and innodb_force_... is removed.\n",
1357 stderr);
1359 return(DB_ERROR);
1362 DEBUG_SYNC_C("innodb_row_update_for_mysql_begin");
1364 trx->op_info = "updating or deleting";
1366 row_mysql_delay_if_needed();
1368 trx_start_if_not_started(trx);
1370 node = prebuilt->upd_node;
1372 clust_index = dict_table_get_first_index(table);
1374 if (prebuilt->pcur->btr_cur.index == clust_index) {
1375 btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1376 } else {
1377 btr_pcur_copy_stored_position(node->pcur,
1378 prebuilt->clust_pcur);
1381 ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1383 /* MySQL seems to call rnd_pos before updating each row it
1384 has cached: we can get the correct cursor position from
1385 prebuilt->pcur; NOTE that we cannot build the row reference
1386 from mysql_rec if the clustered index was automatically
1387 generated for the table: MySQL does not know anything about
1388 the row id used as the clustered index key */
1390 savept = trx_savept_take(trx);
1392 thr = que_fork_get_first_thr(prebuilt->upd_graph);
1394 node->state = UPD_NODE_UPDATE_CLUSTERED;
1396 ut_ad(!prebuilt->sql_stat_start);
1398 que_thr_move_to_run_state_for_mysql(thr, trx);
1400 run_again:
1401 thr->run_node = node;
1402 thr->prev_node = node;
1403 thr->fk_cascade_depth = 0;
1405 row_upd_step(thr);
1407 err = trx->error_state;
1409 /* Reset fk_cascade_depth back to 0 */
1410 thr->fk_cascade_depth = 0;
1412 if (err != DB_SUCCESS) {
1413 que_thr_stop_for_mysql(thr);
1415 if (err == DB_RECORD_NOT_FOUND) {
1416 trx->error_state = DB_SUCCESS;
1417 trx->op_info = "";
1419 return((int) err);
1422 thr->lock_state= QUE_THR_LOCK_ROW;
1423 was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1424 &savept);
1425 thr->lock_state= QUE_THR_LOCK_NOLOCK;
1427 if (was_lock_wait) {
1428 goto run_again;
1431 trx->op_info = "";
1433 return((int) err);
1436 que_thr_stop_for_mysql_no_error(thr, trx);
1438 if (node->is_delete) {
1439 if (prebuilt->table->stat_n_rows > 0) {
1440 prebuilt->table->stat_n_rows--;
1443 srv_n_rows_deleted++;
1444 } else {
1445 srv_n_rows_updated++;
1448 /* We update table statistics only if it is a DELETE or UPDATE
1449 that changes indexed columns, UPDATEs that change only non-indexed
1450 columns would not affect statistics. */
1451 if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1452 row_update_statistics_if_needed(prebuilt->table);
1455 trx->op_info = "";
1457 return((int) err);
1460 /*********************************************************************//**
1461 This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
1462 session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
1463 Before calling this function row_search_for_mysql() must have
1464 initialized prebuilt->new_rec_locks to store the information which new
1465 record locks really were set. This function removes a newly set
1466 clustered index record lock under prebuilt->pcur or
1467 prebuilt->clust_pcur. Thus, this implements a 'mini-rollback' that
1468 releases the latest clustered index record lock we set.
1469 @return error code or DB_SUCCESS */
1470 UNIV_INTERN
1472 row_unlock_for_mysql(
1473 /*=================*/
1474 row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct in MySQL
1475 handle */
1476 ibool has_latches_on_recs)/*!< in: TRUE if called so
1477 that we have the latches on
1478 the records under pcur and
1479 clust_pcur, and we do not need
1480 to reposition the cursors. */
1482 btr_pcur_t* pcur = prebuilt->pcur;
1483 btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
1484 trx_t* trx = prebuilt->trx;
1486 ut_ad(prebuilt && trx);
1487 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1489 if (UNIV_UNLIKELY
1490 (!srv_locks_unsafe_for_binlog
1491 && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
1493 fprintf(stderr,
1494 "InnoDB: Error: calling row_unlock_for_mysql though\n"
1495 "InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
1496 "InnoDB: this session is not using"
1497 " READ COMMITTED isolation level.\n");
1499 return(DB_SUCCESS);
1502 trx->op_info = "unlock_row";
1504 if (prebuilt->new_rec_locks >= 1) {
1506 const rec_t* rec;
1507 dict_index_t* index;
1508 trx_id_t rec_trx_id;
1509 mtr_t mtr;
1511 mtr_start(&mtr);
1513 /* Restore the cursor position and find the record */
1515 if (!has_latches_on_recs) {
1516 btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1519 rec = btr_pcur_get_rec(pcur);
1520 index = btr_pcur_get_btr_cur(pcur)->index;
1522 if (prebuilt->new_rec_locks >= 2) {
1523 /* Restore the cursor position and find the record
1524 in the clustered index. */
1526 if (!has_latches_on_recs) {
1527 btr_pcur_restore_position(BTR_SEARCH_LEAF,
1528 clust_pcur, &mtr);
1531 rec = btr_pcur_get_rec(clust_pcur);
1532 index = btr_pcur_get_btr_cur(clust_pcur)->index;
1535 if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
1536 /* This is not a clustered index record. We
1537 do not know how to unlock the record. */
1538 goto no_unlock;
1541 /* If the record has been modified by this
1542 transaction, do not unlock it. */
1544 if (index->trx_id_offset) {
1545 rec_trx_id = trx_read_trx_id(rec
1546 + index->trx_id_offset);
1547 } else {
1548 mem_heap_t* heap = NULL;
1549 ulint offsets_[REC_OFFS_NORMAL_SIZE];
1550 ulint* offsets = offsets_;
1552 rec_offs_init(offsets_);
1553 offsets = rec_get_offsets(rec, index, offsets,
1554 ULINT_UNDEFINED, &heap);
1556 rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1558 if (UNIV_LIKELY_NULL(heap)) {
1559 mem_heap_free(heap);
1563 if (ut_dulint_cmp(rec_trx_id, trx->id) != 0) {
1564 /* We did not update the record: unlock it */
1566 rec = btr_pcur_get_rec(pcur);
1567 index = btr_pcur_get_btr_cur(pcur)->index;
1569 lock_rec_unlock(trx, btr_pcur_get_block(pcur),
1570 rec, prebuilt->select_lock_type);
1572 if (prebuilt->new_rec_locks >= 2) {
1573 rec = btr_pcur_get_rec(clust_pcur);
1574 index = btr_pcur_get_btr_cur(clust_pcur)->index;
1576 lock_rec_unlock(trx,
1577 btr_pcur_get_block(clust_pcur),
1578 rec,
1579 prebuilt->select_lock_type);
1582 no_unlock:
1583 mtr_commit(&mtr);
1586 trx->op_info = "";
1588 return(DB_SUCCESS);
1591 /**********************************************************************//**
1592 Does a cascaded delete or set null in a foreign key operation.
1593 @return error code or DB_SUCCESS */
1594 UNIV_INTERN
1595 ulint
1596 row_update_cascade_for_mysql(
1597 /*=========================*/
1598 que_thr_t* thr, /*!< in: query thread */
1599 upd_node_t* node, /*!< in: update node used in the cascade
1600 or set null operation */
1601 dict_table_t* table) /*!< in: table where we do the operation */
1603 ulint err;
1604 trx_t* trx;
1606 trx = thr_get_trx(thr);
1608 /* Increment fk_cascade_depth to record the recursive call depth on
1609 a single update/delete that affects multiple tables chained
1610 together with foreign key relations. */
1611 thr->fk_cascade_depth++;
1613 if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
1614 return (DB_FOREIGN_EXCEED_MAX_CASCADE);
1616 run_again:
1617 thr->run_node = node;
1618 thr->prev_node = node;
1620 row_upd_step(thr);
1622 /* The recursive call for cascading update/delete happens
1623 in above row_upd_step(), reset the counter once we come
1624 out of the recursive call, so it does not accumulate for
1625 different row deletes */
1626 thr->fk_cascade_depth = 0;
1628 err = trx->error_state;
1630 /* Note that the cascade node is a subnode of another InnoDB
1631 query graph node. We do a normal lock wait in this node, but
1632 all errors are handled by the parent node. */
1634 if (err == DB_LOCK_WAIT) {
1635 /* Handle lock wait here */
1637 que_thr_stop_for_mysql(thr);
1639 srv_suspend_mysql_thread(thr);
1641 /* Note that a lock wait may also end in a lock wait timeout,
1642 or this transaction is picked as a victim in selective
1643 deadlock resolution */
1645 if (trx->error_state != DB_SUCCESS) {
1647 return(trx->error_state);
1650 /* Retry operation after a normal lock wait */
1652 goto run_again;
1655 if (err != DB_SUCCESS) {
1657 return(err);
1660 if (node->is_delete) {
1661 if (table->stat_n_rows > 0) {
1662 table->stat_n_rows--;
1665 srv_n_rows_deleted++;
1666 } else {
1667 srv_n_rows_updated++;
1670 row_update_statistics_if_needed(table);
1672 return(err);
1675 /*********************************************************************//**
1676 Checks if a table is such that we automatically created a clustered
1677 index on it (on row id).
1678 @return TRUE if the clustered index was generated automatically */
1679 UNIV_INTERN
1680 ibool
1681 row_table_got_default_clust_index(
1682 /*==============================*/
1683 const dict_table_t* table) /*!< in: table */
1685 const dict_index_t* clust_index;
1687 clust_index = dict_table_get_first_index(table);
1689 return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1692 /*********************************************************************//**
1693 Locks the data dictionary in shared mode from modifications, for performing
1694 foreign key check, rollback, or other operation invisible to MySQL. */
1695 UNIV_INTERN
1696 void
1697 row_mysql_freeze_data_dictionary_func(
1698 /*==================================*/
1699 trx_t* trx, /*!< in/out: transaction */
1700 const char* file, /*!< in: file name */
1701 ulint line) /*!< in: line number */
1703 ut_a(trx->dict_operation_lock_mode == 0);
1705 rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
1707 trx->dict_operation_lock_mode = RW_S_LATCH;
1710 /*********************************************************************//**
1711 Unlocks the data dictionary shared lock. */
1712 UNIV_INTERN
1713 void
1714 row_mysql_unfreeze_data_dictionary(
1715 /*===============================*/
1716 trx_t* trx) /*!< in/out: transaction */
1718 ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
1720 rw_lock_s_unlock(&dict_operation_lock);
1722 trx->dict_operation_lock_mode = 0;
1725 /*********************************************************************//**
1726 Locks the data dictionary exclusively for performing a table create or other
1727 data dictionary modification operation. */
1728 UNIV_INTERN
1729 void
1730 row_mysql_lock_data_dictionary_func(
1731 /*================================*/
1732 trx_t* trx, /*!< in/out: transaction */
1733 const char* file, /*!< in: file name */
1734 ulint line) /*!< in: line number */
1736 ut_a(trx->dict_operation_lock_mode == 0
1737 || trx->dict_operation_lock_mode == RW_X_LATCH);
1739 /* Serialize data dictionary operations with dictionary mutex:
1740 no deadlocks or lock waits can occur then in these operations */
1742 rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
1743 trx->dict_operation_lock_mode = RW_X_LATCH;
1745 mutex_enter(&(dict_sys->mutex));
1748 /*********************************************************************//**
1749 Unlocks the data dictionary exclusive lock. */
1750 UNIV_INTERN
1751 void
1752 row_mysql_unlock_data_dictionary(
1753 /*=============================*/
1754 trx_t* trx) /*!< in/out: transaction */
1756 ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1758 /* Serialize data dictionary operations with dictionary mutex:
1759 no deadlocks can occur then in these operations */
1761 mutex_exit(&(dict_sys->mutex));
1762 rw_lock_x_unlock(&dict_operation_lock);
1764 trx->dict_operation_lock_mode = 0;
1767 /*********************************************************************//**
1768 Creates a table for MySQL. If the name of the table ends in
1769 one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
1770 "innodb_table_monitor", then this will also start the printing of monitor
1771 output by the master thread. If the table name ends in "innodb_mem_validate",
1772 InnoDB will try to invoke mem_validate(). On failure the transaction will
1773 be rolled back and the 'table' object will be freed.
1774 @return error code or DB_SUCCESS */
1775 UNIV_INTERN
1777 row_create_table_for_mysql(
1778 /*=======================*/
1779 dict_table_t* table, /*!< in, own: table definition
1780 (will be freed) */
1781 trx_t* trx) /*!< in: transaction handle */
1783 tab_node_t* node;
1784 mem_heap_t* heap;
1785 que_thr_t* thr;
1786 const char* table_name;
1787 ulint table_name_len;
1788 ulint err;
1790 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1791 #ifdef UNIV_SYNC_DEBUG
1792 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1793 #endif /* UNIV_SYNC_DEBUG */
1794 ut_ad(mutex_own(&(dict_sys->mutex)));
1795 ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1797 if (srv_created_new_raw) {
1798 fputs("InnoDB: A new raw disk partition was initialized:\n"
1799 "InnoDB: we do not allow database modifications"
1800 " by the user.\n"
1801 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1802 " is replaced with raw.\n", stderr);
1803 err_exit:
1804 dict_mem_table_free(table);
1805 trx_commit_for_mysql(trx);
1807 return(DB_ERROR);
1810 trx->op_info = "creating table";
1812 if (row_mysql_is_system_table(table->name)) {
1814 fprintf(stderr,
1815 "InnoDB: Error: trying to create a MySQL system"
1816 " table %s of type InnoDB.\n"
1817 "InnoDB: MySQL system tables must be"
1818 " of the MyISAM type!\n",
1819 table->name);
1820 goto err_exit;
1823 trx_start_if_not_started(trx);
1825 /* The table name is prefixed with the database name and a '/'.
1826 Certain table names starting with 'innodb_' have their special
1827 meaning regardless of the database name. Thus, we need to
1828 ignore the database name prefix in the comparisons. */
1829 table_name = strchr(table->name, '/');
1830 ut_a(table_name);
1831 table_name++;
1832 table_name_len = strlen(table_name) + 1;
1834 if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
1836 /* Table equals "innodb_monitor":
1837 start monitor prints */
1839 srv_print_innodb_monitor = TRUE;
1841 /* The lock timeout monitor thread also takes care
1842 of InnoDB monitor prints */
1844 os_event_set(srv_lock_timeout_thread_event);
1845 } else if (STR_EQ(table_name, table_name_len,
1846 S_innodb_lock_monitor)) {
1848 srv_print_innodb_monitor = TRUE;
1849 srv_print_innodb_lock_monitor = TRUE;
1850 os_event_set(srv_lock_timeout_thread_event);
1851 } else if (STR_EQ(table_name, table_name_len,
1852 S_innodb_tablespace_monitor)) {
1854 srv_print_innodb_tablespace_monitor = TRUE;
1855 os_event_set(srv_lock_timeout_thread_event);
1856 } else if (STR_EQ(table_name, table_name_len,
1857 S_innodb_table_monitor)) {
1859 srv_print_innodb_table_monitor = TRUE;
1860 os_event_set(srv_lock_timeout_thread_event);
1861 } else if (STR_EQ(table_name, table_name_len,
1862 S_innodb_mem_validate)) {
1863 /* We define here a debugging feature intended for
1864 developers */
1866 fputs("Validating InnoDB memory:\n"
1867 "to use this feature you must compile InnoDB with\n"
1868 "UNIV_MEM_DEBUG defined in univ.i and"
1869 " the server must be\n"
1870 "quiet because allocation from a mem heap"
1871 " is not protected\n"
1872 "by any semaphore.\n", stderr);
1873 #ifdef UNIV_MEM_DEBUG
1874 ut_a(mem_validate());
1875 fputs("Memory validated\n", stderr);
1876 #else /* UNIV_MEM_DEBUG */
1877 fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1878 stderr);
1879 #endif /* UNIV_MEM_DEBUG */
1882 heap = mem_heap_create(512);
1884 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1886 node = tab_create_graph_create(table, heap);
1888 thr = pars_complete_graph_for_exec(node, trx, heap);
1890 ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1891 que_run_threads(thr);
1893 err = trx->error_state;
1895 switch (err) {
1896 case DB_SUCCESS:
1897 break;
1898 case DB_OUT_OF_FILE_SPACE:
1899 trx->error_state = DB_SUCCESS;
1900 trx_general_rollback_for_mysql(trx, NULL);
1902 ut_print_timestamp(stderr);
1903 fputs(" InnoDB: Warning: cannot create table ",
1904 stderr);
1905 ut_print_name(stderr, trx, TRUE, table->name);
1906 fputs(" because tablespace full\n", stderr);
1908 if (dict_table_get_low(table->name)) {
1910 row_drop_table_for_mysql(table->name, trx, FALSE);
1911 trx_commit_for_mysql(trx);
1912 } else {
1913 dict_mem_table_free(table);
1915 break;
1917 case DB_TOO_MANY_CONCURRENT_TRXS:
1918 /* We already have .ibd file here. it should be deleted. */
1920 if (table->space && !fil_delete_tablespace(table->space)) {
1921 ut_print_timestamp(stderr);
1922 fprintf(stderr,
1923 " InnoDB: Error: not able to"
1924 " delete tablespace %lu of table ",
1925 (ulong) table->space);
1926 ut_print_name(stderr, trx, TRUE, table->name);
1927 fputs("!\n", stderr);
1929 /* fall through */
1931 case DB_DUPLICATE_KEY:
1932 default:
1933 /* We may also get err == DB_ERROR if the .ibd file for the
1934 table already exists */
1936 trx->error_state = DB_SUCCESS;
1937 trx_general_rollback_for_mysql(trx, NULL);
1938 dict_mem_table_free(table);
1939 break;
1942 que_graph_free((que_t*) que_node_get_parent(thr));
1944 trx->op_info = "";
1946 return((int) err);
1949 /*********************************************************************//**
1950 Does an index creation operation for MySQL. TODO: currently failure
1951 to create an index results in dropping the whole table! This is no problem
1952 currently as all indexes must be created at the same time as the table.
1953 @return error number or DB_SUCCESS */
1954 UNIV_INTERN
1956 row_create_index_for_mysql(
1957 /*=======================*/
1958 dict_index_t* index, /*!< in, own: index definition
1959 (will be freed) */
1960 trx_t* trx, /*!< in: transaction handle */
1961 const ulint* field_lengths) /*!< in: if not NULL, must contain
1962 dict_index_get_n_fields(index)
1963 actual field lengths for the
1964 index columns, which are
1965 then checked for not being too
1966 large. */
1968 ind_node_t* node;
1969 mem_heap_t* heap;
1970 que_thr_t* thr;
1971 ulint err;
1972 ulint i;
1973 ulint len;
1974 char* table_name;
1976 #ifdef UNIV_SYNC_DEBUG
1977 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1978 #endif /* UNIV_SYNC_DEBUG */
1979 ut_ad(mutex_own(&(dict_sys->mutex)));
1980 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1982 trx->op_info = "creating index";
1984 /* Copy the table name because we may want to drop the
1985 table later, after the index object is freed (inside
1986 que_run_threads()) and thus index->table_name is not available. */
1987 table_name = mem_strdup(index->table_name);
1989 trx_start_if_not_started(trx);
1991 /* Check that the same column does not appear twice in the index.
1992 Starting from 4.0.14, InnoDB should be able to cope with that, but
1993 safer not to allow them. */
1995 for (i = 0; i < dict_index_get_n_fields(index); i++) {
1996 ulint j;
1998 for (j = 0; j < i; j++) {
1999 if (0 == ut_strcmp(
2000 dict_index_get_nth_field(index, j)->name,
2001 dict_index_get_nth_field(index, i)->name)) {
2002 ut_print_timestamp(stderr);
2004 fputs(" InnoDB: Error: column ", stderr);
2005 ut_print_name(stderr, trx, FALSE,
2006 dict_index_get_nth_field(
2007 index, i)->name);
2008 fputs(" appears twice in ", stderr);
2009 dict_index_name_print(stderr, trx, index);
2010 fputs("\n"
2011 "InnoDB: This is not allowed"
2012 " in InnoDB.\n", stderr);
2014 err = DB_COL_APPEARS_TWICE_IN_INDEX;
2016 goto error_handling;
2020 /* Check also that prefix_len and actual length
2021 < DICT_MAX_INDEX_COL_LEN */
2023 len = dict_index_get_nth_field(index, i)->prefix_len;
2025 if (field_lengths) {
2026 len = ut_max(len, field_lengths[i]);
2029 if (len >= DICT_MAX_INDEX_COL_LEN) {
2030 err = DB_TOO_BIG_RECORD;
2032 goto error_handling;
2036 heap = mem_heap_create(512);
2038 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2040 /* Note that the space id where we store the index is inherited from
2041 the table in dict_build_index_def_step() in dict0crea.c. */
2043 node = ind_create_graph_create(index, heap);
2045 thr = pars_complete_graph_for_exec(node, trx, heap);
2047 ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2048 que_run_threads(thr);
2050 err = trx->error_state;
2052 que_graph_free((que_t*) que_node_get_parent(thr));
2054 error_handling:
2055 if (err != DB_SUCCESS) {
2056 /* We have special error handling here */
2058 trx->error_state = DB_SUCCESS;
2060 trx_general_rollback_for_mysql(trx, NULL);
2062 row_drop_table_for_mysql(table_name, trx, FALSE);
2064 trx_commit_for_mysql(trx);
2066 trx->error_state = DB_SUCCESS;
2069 trx->op_info = "";
2071 mem_free(table_name);
2073 return((int) err);
2076 /*********************************************************************//**
2077 Scans a table create SQL string and adds to the data dictionary
2078 the foreign key constraints declared in the string. This function
2079 should be called after the indexes for a table have been created.
2080 Each foreign key constraint must be accompanied with indexes in
2081 both participating tables. The indexes are allowed to contain more
2082 fields than mentioned in the constraint. Check also that foreign key
2083 constraints which reference this table are ok.
2084 @return error code or DB_SUCCESS */
2085 UNIV_INTERN
2087 row_table_add_foreign_constraints(
2088 /*==============================*/
2089 trx_t* trx, /*!< in: transaction */
2090 const char* sql_string, /*!< in: table create statement where
2091 foreign keys are declared like:
2092 FOREIGN KEY (a, b) REFERENCES table2(c, d),
2093 table2 can be written also with the
2094 database name before it: test.table2 */
2095 size_t sql_length, /*!< in: length of sql_string */
2096 const char* name, /*!< in: table full name in the
2097 normalized form
2098 database_name/table_name */
2099 ibool reject_fks) /*!< in: if TRUE, fail with error
2100 code DB_CANNOT_ADD_CONSTRAINT if
2101 any foreign keys are found. */
2103 ulint err;
2105 ut_ad(mutex_own(&(dict_sys->mutex)));
2106 #ifdef UNIV_SYNC_DEBUG
2107 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2108 #endif /* UNIV_SYNC_DEBUG */
2109 ut_a(sql_string);
2111 trx->op_info = "adding foreign keys";
2113 trx_start_if_not_started(trx);
2115 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2117 err = dict_create_foreign_constraints(trx, sql_string, sql_length,
2118 name, reject_fks);
2119 if (err == DB_SUCCESS) {
2120 /* Check that also referencing constraints are ok */
2121 err = dict_load_foreigns(name, FALSE, TRUE);
2124 if (err != DB_SUCCESS) {
2125 /* We have special error handling here */
2127 trx->error_state = DB_SUCCESS;
2129 trx_general_rollback_for_mysql(trx, NULL);
2131 row_drop_table_for_mysql(name, trx, FALSE);
2133 trx_commit_for_mysql(trx);
2135 trx->error_state = DB_SUCCESS;
2138 return((int) err);
2141 /*********************************************************************//**
2142 Drops a table for MySQL as a background operation. MySQL relies on Unix
2143 in ALTER TABLE to the fact that the table handler does not remove the
2144 table before all handles to it has been removed. Furhermore, the MySQL's
2145 call to drop table must be non-blocking. Therefore we do the drop table
2146 as a background operation, which is taken care of by the master thread
2147 in srv0srv.c.
2148 @return error code or DB_SUCCESS */
2149 static
2151 row_drop_table_for_mysql_in_background(
2152 /*===================================*/
2153 const char* name) /*!< in: table name */
2155 ulint error;
2156 trx_t* trx;
2158 trx = trx_allocate_for_background();
2160 /* If the original transaction was dropping a table referenced by
2161 foreign keys, we must set the following to be able to drop the
2162 table: */
2164 trx->check_foreigns = FALSE;
2166 /* fputs("InnoDB: Error: Dropping table ", stderr);
2167 ut_print_name(stderr, trx, TRUE, name);
2168 fputs(" in background drop list\n", stderr); */
2170 /* Try to drop the table in InnoDB */
2172 error = row_drop_table_for_mysql(name, trx, FALSE);
2174 /* Flush the log to reduce probability that the .frm files and
2175 the InnoDB data dictionary get out-of-sync if the user runs
2176 with innodb_flush_log_at_trx_commit = 0 */
2178 log_buffer_flush_to_disk();
2180 trx_commit_for_mysql(trx);
2182 trx_free_for_background(trx);
2184 return((int) error);
2187 /*********************************************************************//**
2188 The master thread in srv0srv.c calls this regularly to drop tables which
2189 we must drop in background after queries to them have ended. Such lazy
2190 dropping of tables is needed in ALTER TABLE on Unix.
2191 @return how many tables dropped + remaining tables in list */
2192 UNIV_INTERN
2193 ulint
2194 row_drop_tables_for_mysql_in_background(void)
2195 /*=========================================*/
2197 row_mysql_drop_t* drop;
2198 dict_table_t* table;
2199 ulint n_tables;
2200 ulint n_tables_dropped = 0;
2201 loop:
2202 mutex_enter(&kernel_mutex);
2204 if (!row_mysql_drop_list_inited) {
2206 UT_LIST_INIT(row_mysql_drop_list);
2207 row_mysql_drop_list_inited = TRUE;
2210 drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2212 n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2214 mutex_exit(&kernel_mutex);
2216 if (drop == NULL) {
2217 /* All tables dropped */
2219 return(n_tables + n_tables_dropped);
2222 mutex_enter(&(dict_sys->mutex));
2223 table = dict_table_get_low(drop->table_name);
2224 mutex_exit(&(dict_sys->mutex));
2226 if (table == NULL) {
2227 /* If for some reason the table has already been dropped
2228 through some other mechanism, do not try to drop it */
2230 goto already_dropped;
2233 if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2234 drop->table_name)) {
2235 /* If the DROP fails for some table, we return, and let the
2236 main thread retry later */
2238 return(n_tables + n_tables_dropped);
2241 n_tables_dropped++;
2243 already_dropped:
2244 mutex_enter(&kernel_mutex);
2246 UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2248 ut_print_timestamp(stderr);
2249 fputs(" InnoDB: Dropped table ", stderr);
2250 ut_print_name(stderr, NULL, TRUE, drop->table_name);
2251 fputs(" in background drop queue.\n", stderr);
2253 mem_free(drop->table_name);
2255 mem_free(drop);
2257 mutex_exit(&kernel_mutex);
2259 goto loop;
2262 /*********************************************************************//**
2263 Get the background drop list length. NOTE: the caller must own the kernel
2264 mutex!
2265 @return how many tables in list */
2266 UNIV_INTERN
2267 ulint
2268 row_get_background_drop_list_len_low(void)
2269 /*======================================*/
2271 ut_ad(mutex_own(&kernel_mutex));
2273 if (!row_mysql_drop_list_inited) {
2275 UT_LIST_INIT(row_mysql_drop_list);
2276 row_mysql_drop_list_inited = TRUE;
2279 return(UT_LIST_GET_LEN(row_mysql_drop_list));
2282 /*********************************************************************//**
2283 If a table is not yet in the drop list, adds the table to the list of tables
2284 which the master thread drops in background. We need this on Unix because in
2285 ALTER TABLE MySQL may call drop table even if the table has running queries on
2286 it. Also, if there are running foreign key checks on the table, we drop the
2287 table lazily.
2288 @return TRUE if the table was not yet in the drop list, and was added there */
2289 static
2290 ibool
2291 row_add_table_to_background_drop_list(
2292 /*==================================*/
2293 const char* name) /*!< in: table name */
2295 row_mysql_drop_t* drop;
2297 mutex_enter(&kernel_mutex);
2299 if (!row_mysql_drop_list_inited) {
2301 UT_LIST_INIT(row_mysql_drop_list);
2302 row_mysql_drop_list_inited = TRUE;
2305 /* Look if the table already is in the drop list */
2306 drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2308 while (drop != NULL) {
2309 if (strcmp(drop->table_name, name) == 0) {
2310 /* Already in the list */
2312 mutex_exit(&kernel_mutex);
2314 return(FALSE);
2317 drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2320 drop = mem_alloc(sizeof(row_mysql_drop_t));
2322 drop->table_name = mem_strdup(name);
2324 UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2326 /* fputs("InnoDB: Adding table ", stderr);
2327 ut_print_name(stderr, trx, TRUE, drop->table_name);
2328 fputs(" to background drop list\n", stderr); */
2330 mutex_exit(&kernel_mutex);
2332 return(TRUE);
2335 /*********************************************************************//**
2336 Discards the tablespace of a table which stored in an .ibd file. Discarding
2337 means that this function deletes the .ibd file and assigns a new table id for
2338 the table. Also the flag table->ibd_file_missing is set TRUE.
2339 @return error code or DB_SUCCESS */
2340 UNIV_INTERN
2342 row_discard_tablespace_for_mysql(
2343 /*=============================*/
2344 const char* name, /*!< in: table name */
2345 trx_t* trx) /*!< in: transaction handle */
2347 dict_foreign_t* foreign;
2348 dulint new_id;
2349 dict_table_t* table;
2350 ibool success;
2351 ulint err;
2352 pars_info_t* info = NULL;
2354 /* How do we prevent crashes caused by ongoing operations on
2355 the table? Old operations could try to access non-existent
2356 pages.
2358 1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2359 MySQL table lock on the table before we can do DISCARD
2360 TABLESPACE. Then there are no running queries on the table.
2362 2) Purge and rollback: we assign a new table id for the
2363 table. Since purge and rollback look for the table based on
2364 the table id, they see the table as 'dropped' and discard
2365 their operations.
2367 3) Insert buffer: we remove all entries for the tablespace in
2368 the insert buffer tree; as long as the tablespace mem object
2369 does not exist, ongoing insert buffer page merges are
2370 discarded in buf0rea.c. If we recreate the tablespace mem
2371 object with IMPORT TABLESPACE later, then the tablespace will
2372 have the same id, but the tablespace_version field in the mem
2373 object is different, and ongoing old insert buffer page merges
2374 get discarded.
2376 4) Linear readahead and random readahead: we use the same
2377 method as in 3) to discard ongoing operations.
2379 5) FOREIGN KEY operations: if
2380 table->n_foreign_key_checks_running > 0, we do not allow the
2381 discard. We also reserve the data dictionary latch. */
2383 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2385 trx->op_info = "discarding tablespace";
2386 trx_start_if_not_started(trx);
2388 /* Serialize data dictionary operations with dictionary mutex:
2389 no deadlocks can occur then in these operations */
2391 row_mysql_lock_data_dictionary(trx);
2393 table = dict_table_get_low(name);
2395 if (!table) {
2396 err = DB_TABLE_NOT_FOUND;
2398 goto funct_exit;
2401 if (table->space == 0) {
2402 ut_print_timestamp(stderr);
2403 fputs(" InnoDB: Error: table ", stderr);
2404 ut_print_name(stderr, trx, TRUE, name);
2405 fputs("\n"
2406 "InnoDB: is in the system tablespace 0"
2407 " which cannot be discarded\n", stderr);
2408 err = DB_ERROR;
2410 goto funct_exit;
2413 if (table->n_foreign_key_checks_running > 0) {
2415 ut_print_timestamp(stderr);
2416 fputs(" InnoDB: You are trying to DISCARD table ", stderr);
2417 ut_print_name(stderr, trx, TRUE, table->name);
2418 fputs("\n"
2419 "InnoDB: though there is a foreign key check"
2420 " running on it.\n"
2421 "InnoDB: Cannot discard the table.\n",
2422 stderr);
2424 err = DB_ERROR;
2426 goto funct_exit;
2429 /* Check if the table is referenced by foreign key constraints from
2430 some other table (not the table itself) */
2432 foreign = UT_LIST_GET_FIRST(table->referenced_list);
2434 while (foreign && foreign->foreign_table == table) {
2435 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2438 if (foreign && trx->check_foreigns) {
2440 FILE* ef = dict_foreign_err_file;
2442 /* We only allow discarding a referenced table if
2443 FOREIGN_KEY_CHECKS is set to 0 */
2445 err = DB_CANNOT_DROP_CONSTRAINT;
2447 mutex_enter(&dict_foreign_err_mutex);
2448 rewind(ef);
2449 ut_print_timestamp(ef);
2451 fputs(" Cannot DISCARD table ", ef);
2452 ut_print_name(stderr, trx, TRUE, name);
2453 fputs("\n"
2454 "because it is referenced by ", ef);
2455 ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
2456 putc('\n', ef);
2457 mutex_exit(&dict_foreign_err_mutex);
2459 goto funct_exit;
2462 dict_hdr_get_new_id(&new_id, NULL, NULL);
2464 /* Remove all locks except the table-level S and X locks. */
2465 lock_remove_all_on_table(table, FALSE);
2467 info = pars_info_create();
2469 pars_info_add_str_literal(info, "table_name", name);
2470 pars_info_add_dulint_literal(info, "new_id", new_id);
2472 err = que_eval_sql(info,
2473 "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2474 "old_id CHAR;\n"
2475 "BEGIN\n"
2476 "SELECT ID INTO old_id\n"
2477 "FROM SYS_TABLES\n"
2478 "WHERE NAME = :table_name\n"
2479 "LOCK IN SHARE MODE;\n"
2480 "IF (SQL % NOTFOUND) THEN\n"
2481 " COMMIT WORK;\n"
2482 " RETURN;\n"
2483 "END IF;\n"
2484 "UPDATE SYS_TABLES SET ID = :new_id\n"
2485 " WHERE ID = old_id;\n"
2486 "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2487 " WHERE TABLE_ID = old_id;\n"
2488 "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2489 " WHERE TABLE_ID = old_id;\n"
2490 "COMMIT WORK;\n"
2491 "END;\n"
2492 , FALSE, trx);
2494 if (err != DB_SUCCESS) {
2495 trx->error_state = DB_SUCCESS;
2496 trx_general_rollback_for_mysql(trx, NULL);
2497 trx->error_state = DB_SUCCESS;
2498 } else {
2499 dict_table_change_id_in_cache(table, new_id);
2501 success = fil_discard_tablespace(table->space);
2503 if (!success) {
2504 trx->error_state = DB_SUCCESS;
2505 trx_general_rollback_for_mysql(trx, NULL);
2506 trx->error_state = DB_SUCCESS;
2508 err = DB_ERROR;
2509 } else {
2510 /* Set the flag which tells that now it is legal to
2511 IMPORT a tablespace for this table */
2512 table->tablespace_discarded = TRUE;
2513 table->ibd_file_missing = TRUE;
2517 funct_exit:
2518 trx_commit_for_mysql(trx);
2520 row_mysql_unlock_data_dictionary(trx);
2522 trx->op_info = "";
2524 return((int) err);
2527 /*****************************************************************//**
2528 Imports a tablespace. The space id in the .ibd file must match the space id
2529 of the table in the data dictionary.
2530 @return error code or DB_SUCCESS */
2531 UNIV_INTERN
2533 row_import_tablespace_for_mysql(
2534 /*============================*/
2535 const char* name, /*!< in: table name */
2536 trx_t* trx) /*!< in: transaction handle */
2538 dict_table_t* table;
2539 ibool success;
2540 ib_uint64_t current_lsn;
2541 ulint err = DB_SUCCESS;
2543 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2545 trx_start_if_not_started(trx);
2547 trx->op_info = "importing tablespace";
2549 current_lsn = log_get_lsn();
2551 /* It is possible, though very improbable, that the lsn's in the
2552 tablespace to be imported have risen above the current system lsn, if
2553 a lengthy purge, ibuf merge, or rollback was performed on a backup
2554 taken with ibbackup. If that is the case, reset page lsn's in the
2555 file. We assume that mysqld was shut down after it performed these
2556 cleanup operations on the .ibd file, so that it stamped the latest lsn
2557 to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2559 TODO: reset also the trx id's in clustered index records and write
2560 a new space id to each data page. That would allow us to import clean
2561 .ibd files from another MySQL installation. */
2563 success = fil_reset_too_high_lsns(name, current_lsn);
2565 if (!success) {
2566 ut_print_timestamp(stderr);
2567 fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
2568 ut_print_name(stderr, trx, TRUE, name);
2569 fputs("\n"
2570 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2571 stderr);
2573 err = DB_ERROR;
2575 row_mysql_lock_data_dictionary(trx);
2577 goto funct_exit;
2580 /* Serialize data dictionary operations with dictionary mutex:
2581 no deadlocks can occur then in these operations */
2583 row_mysql_lock_data_dictionary(trx);
2585 table = dict_table_get_low(name);
2587 if (!table) {
2588 ut_print_timestamp(stderr);
2589 fputs(" InnoDB: table ", stderr);
2590 ut_print_name(stderr, trx, TRUE, name);
2591 fputs("\n"
2592 "InnoDB: does not exist in the InnoDB data dictionary\n"
2593 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2594 stderr);
2596 err = DB_TABLE_NOT_FOUND;
2598 goto funct_exit;
2601 if (table->space == 0) {
2602 ut_print_timestamp(stderr);
2603 fputs(" InnoDB: Error: table ", stderr);
2604 ut_print_name(stderr, trx, TRUE, name);
2605 fputs("\n"
2606 "InnoDB: is in the system tablespace 0"
2607 " which cannot be imported\n", stderr);
2608 err = DB_ERROR;
2610 goto funct_exit;
2613 if (!table->tablespace_discarded) {
2614 ut_print_timestamp(stderr);
2615 fputs(" InnoDB: Error: you are trying to"
2616 " IMPORT a tablespace\n"
2617 "InnoDB: ", stderr);
2618 ut_print_name(stderr, trx, TRUE, name);
2619 fputs(", though you have not called DISCARD on it yet\n"
2620 "InnoDB: during the lifetime of the mysqld process!\n",
2621 stderr);
2623 err = DB_ERROR;
2625 goto funct_exit;
2628 /* Play safe and remove all insert buffer entries, though we should
2629 have removed them already when DISCARD TABLESPACE was called */
2631 ibuf_delete_for_discarded_space(table->space);
2633 success = fil_open_single_table_tablespace(
2634 TRUE, table->space,
2635 table->flags == DICT_TF_COMPACT ? 0 : table->flags,
2636 table->name);
2637 if (success) {
2638 table->ibd_file_missing = FALSE;
2639 table->tablespace_discarded = FALSE;
2640 } else {
2641 if (table->ibd_file_missing) {
2642 ut_print_timestamp(stderr);
2643 fputs(" InnoDB: cannot find or open in the"
2644 " database directory the .ibd file of\n"
2645 "InnoDB: table ", stderr);
2646 ut_print_name(stderr, trx, TRUE, name);
2647 fputs("\n"
2648 "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2649 stderr);
2652 err = DB_ERROR;
2655 funct_exit:
2656 trx_commit_for_mysql(trx);
2658 row_mysql_unlock_data_dictionary(trx);
2660 trx->op_info = "";
2662 return((int) err);
2665 /*********************************************************************//**
2666 Truncates a table for MySQL.
2667 @return error code or DB_SUCCESS */
2668 UNIV_INTERN
2670 row_truncate_table_for_mysql(
2671 /*=========================*/
2672 dict_table_t* table, /*!< in: table handle */
2673 trx_t* trx) /*!< in: transaction handle */
2675 dict_foreign_t* foreign;
2676 ulint err;
2677 mem_heap_t* heap;
2678 byte* buf;
2679 dtuple_t* tuple;
2680 dfield_t* dfield;
2681 dict_index_t* sys_index;
2682 btr_pcur_t pcur;
2683 mtr_t mtr;
2684 dulint new_id;
2685 ulint recreate_space = 0;
2686 pars_info_t* info = NULL;
2688 /* How do we prevent crashes caused by ongoing operations on
2689 the table? Old operations could try to access non-existent
2690 pages.
2692 1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2693 MySQL table lock on the table before we can do TRUNCATE
2694 TABLE. Then there are no running queries on the table. This is
2695 guaranteed, because in ha_innobase::store_lock(), we do not
2696 weaken the TL_WRITE lock requested by MySQL when executing
2697 SQLCOM_TRUNCATE.
2699 2) Purge and rollback: we assign a new table id for the
2700 table. Since purge and rollback look for the table based on
2701 the table id, they see the table as 'dropped' and discard
2702 their operations.
2704 3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2705 so we do not have to remove insert buffer records, as the
2706 insert buffer works at a low level. If a freed page is later
2707 reallocated, the allocator will remove the ibuf entries for
2710 When we truncate *.ibd files by recreating them (analogous to
2711 DISCARD TABLESPACE), we remove all entries for the table in the
2712 insert buffer tree. This is not strictly necessary, because
2713 in 6) we will assign a new tablespace identifier, but we can
2714 free up some space in the system tablespace.
2716 4) Linear readahead and random readahead: we use the same
2717 method as in 3) to discard ongoing operations. (This is only
2718 relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2720 5) FOREIGN KEY operations: if
2721 table->n_foreign_key_checks_running > 0, we do not allow the
2722 TRUNCATE. We also reserve the data dictionary latch.
2724 6) Crash recovery: To prevent the application of pre-truncation
2725 redo log records on the truncated tablespace, we will assign
2726 a new tablespace identifier to the truncated tablespace. */
2728 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2729 ut_ad(table);
2731 if (srv_created_new_raw) {
2732 fputs("InnoDB: A new raw disk partition was initialized:\n"
2733 "InnoDB: we do not allow database modifications"
2734 " by the user.\n"
2735 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2736 " is replaced with raw.\n", stderr);
2738 return(DB_ERROR);
2741 trx->op_info = "truncating table";
2743 trx_start_if_not_started(trx);
2745 /* Serialize data dictionary operations with dictionary mutex:
2746 no deadlocks can occur then in these operations */
2748 ut_a(trx->dict_operation_lock_mode == 0);
2749 /* Prevent foreign key checks etc. while we are truncating the
2750 table */
2752 row_mysql_lock_data_dictionary(trx);
2754 ut_ad(mutex_own(&(dict_sys->mutex)));
2755 #ifdef UNIV_SYNC_DEBUG
2756 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2757 #endif /* UNIV_SYNC_DEBUG */
2759 /* Check if the table is referenced by foreign key constraints from
2760 some other table (not the table itself) */
2762 foreign = UT_LIST_GET_FIRST(table->referenced_list);
2764 while (foreign && foreign->foreign_table == table) {
2765 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2768 if (foreign && trx->check_foreigns) {
2769 FILE* ef = dict_foreign_err_file;
2771 /* We only allow truncating a referenced table if
2772 FOREIGN_KEY_CHECKS is set to 0 */
2774 mutex_enter(&dict_foreign_err_mutex);
2775 rewind(ef);
2776 ut_print_timestamp(ef);
2778 fputs(" Cannot truncate table ", ef);
2779 ut_print_name(ef, trx, TRUE, table->name);
2780 fputs(" by DROP+CREATE\n"
2781 "InnoDB: because it is referenced by ", ef);
2782 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2783 putc('\n', ef);
2784 mutex_exit(&dict_foreign_err_mutex);
2786 err = DB_ERROR;
2787 goto funct_exit;
2790 /* TODO: could we replace the counter n_foreign_key_checks_running
2791 with lock checks on the table? Acquire here an exclusive lock on the
2792 table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2793 they can cope with the table having been truncated here? Foreign key
2794 checks take an IS or IX lock on the table. */
2796 if (table->n_foreign_key_checks_running > 0) {
2797 ut_print_timestamp(stderr);
2798 fputs(" InnoDB: Cannot truncate table ", stderr);
2799 ut_print_name(stderr, trx, TRUE, table->name);
2800 fputs(" by DROP+CREATE\n"
2801 "InnoDB: because there is a foreign key check"
2802 " running on it.\n",
2803 stderr);
2804 err = DB_ERROR;
2806 goto funct_exit;
2809 /* Remove all locks except the table-level S and X locks. */
2810 lock_remove_all_on_table(table, FALSE);
2812 trx->table_id = table->id;
2814 if (table->space && !table->dir_path_of_temp_table) {
2815 /* Discard and create the single-table tablespace. */
2816 ulint space = table->space;
2817 ulint flags = fil_space_get_flags(space);
2819 if (flags != ULINT_UNDEFINED
2820 && fil_discard_tablespace(space)) {
2822 dict_index_t* index;
2824 dict_hdr_get_new_id(NULL, NULL, &space);
2826 /* Lock all index trees for this table. We must
2827 do so after dict_hdr_get_new_id() to preserve
2828 the latch order */
2829 dict_table_x_lock_indexes(table);
2831 if (space == ULINT_UNDEFINED
2832 || fil_create_new_single_table_tablespace(
2833 space, table->name, FALSE, flags,
2834 FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
2835 dict_table_x_unlock_indexes(table);
2836 ut_print_timestamp(stderr);
2837 fprintf(stderr,
2838 " InnoDB: TRUNCATE TABLE %s failed to"
2839 " create a new tablespace\n",
2840 table->name);
2841 table->ibd_file_missing = 1;
2842 err = DB_ERROR;
2843 goto funct_exit;
2846 recreate_space = space;
2848 /* Replace the space_id in the data dictionary cache.
2849 The persisent data dictionary (SYS_TABLES.SPACE
2850 and SYS_INDEXES.SPACE) are updated later in this
2851 function. */
2852 table->space = space;
2853 index = dict_table_get_first_index(table);
2854 do {
2855 index->space = space;
2856 index = dict_table_get_next_index(index);
2857 } while (index);
2859 mtr_start(&mtr);
2860 fsp_header_init(space,
2861 FIL_IBD_FILE_INITIAL_SIZE, &mtr);
2862 mtr_commit(&mtr);
2864 } else {
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);
2875 /* scan SYS_INDEXES for all indexes of the table */
2876 heap = mem_heap_create(800);
2878 tuple = dtuple_create(heap, 1);
2879 dfield = dtuple_get_nth_field(tuple, 0);
2881 buf = mem_heap_alloc(heap, 8);
2882 mach_write_to_8(buf, table->id);
2884 dfield_set_data(dfield, buf, 8);
2885 sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2886 dict_index_copy_types(tuple, sys_index, 1);
2888 mtr_start(&mtr);
2889 btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2890 BTR_MODIFY_LEAF, &pcur, &mtr);
2891 for (;;) {
2892 rec_t* rec;
2893 const byte* field;
2894 ulint len;
2895 ulint root_page_no;
2897 if (!btr_pcur_is_on_user_rec(&pcur)) {
2898 /* The end of SYS_INDEXES has been reached. */
2899 break;
2902 rec = btr_pcur_get_rec(&pcur);
2904 field = rec_get_nth_field_old(rec, 0, &len);
2905 ut_ad(len == 8);
2907 if (memcmp(buf, field, len) != 0) {
2908 /* End of indexes for the table (TABLE_ID mismatch). */
2909 break;
2912 if (rec_get_deleted_flag(rec, FALSE)) {
2913 /* The index has been dropped. */
2914 goto next_rec;
2917 /* This call may commit and restart mtr
2918 and reposition pcur. */
2919 root_page_no = dict_truncate_index_tree(table, recreate_space,
2920 &pcur, &mtr);
2922 rec = btr_pcur_get_rec(&pcur);
2924 if (root_page_no != FIL_NULL) {
2925 page_rec_write_index_page_no(
2926 rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2927 root_page_no, &mtr);
2928 /* We will need to commit and restart the
2929 mini-transaction in order to avoid deadlocks.
2930 The dict_truncate_index_tree() call has allocated
2931 a page in this mini-transaction, and the rest of
2932 this loop could latch another index page. */
2933 mtr_commit(&mtr);
2934 mtr_start(&mtr);
2935 btr_pcur_restore_position(BTR_MODIFY_LEAF,
2936 &pcur, &mtr);
2939 next_rec:
2940 btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2943 btr_pcur_close(&pcur);
2944 mtr_commit(&mtr);
2946 mem_heap_free(heap);
2948 /* Done with index truncation, release index tree locks,
2949 subsequent work relates to table level metadata change */
2950 dict_table_x_unlock_indexes(table);
2952 dict_hdr_get_new_id(&new_id, NULL, NULL);
2954 info = pars_info_create();
2956 pars_info_add_int4_literal(info, "space", (lint) table->space);
2957 pars_info_add_dulint_literal(info, "old_id", table->id);
2958 pars_info_add_dulint_literal(info, "new_id", new_id);
2960 err = que_eval_sql(info,
2961 "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2962 "BEGIN\n"
2963 "UPDATE SYS_TABLES"
2964 " SET ID = :new_id, SPACE = :space\n"
2965 " WHERE ID = :old_id;\n"
2966 "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2967 " WHERE TABLE_ID = :old_id;\n"
2968 "UPDATE SYS_INDEXES"
2969 " SET TABLE_ID = :new_id, SPACE = :space\n"
2970 " WHERE TABLE_ID = :old_id;\n"
2971 "COMMIT WORK;\n"
2972 "END;\n"
2973 , FALSE, trx);
2975 if (err != DB_SUCCESS) {
2976 trx->error_state = DB_SUCCESS;
2977 trx_general_rollback_for_mysql(trx, NULL);
2978 trx->error_state = DB_SUCCESS;
2979 ut_print_timestamp(stderr);
2980 fputs(" InnoDB: Unable to assign a new identifier to table ",
2981 stderr);
2982 ut_print_name(stderr, trx, TRUE, table->name);
2983 fputs("\n"
2984 "InnoDB: after truncating it. Background processes"
2985 " may corrupt the table!\n", stderr);
2986 err = DB_ERROR;
2987 } else {
2988 dict_table_change_id_in_cache(table, new_id);
2991 /* MySQL calls ha_innobase::reset_auto_increment() which does
2992 the same thing. */
2993 dict_table_autoinc_lock(table);
2994 dict_table_autoinc_initialize(table, 1);
2995 dict_table_autoinc_unlock(table);
2996 dict_update_statistics(table, FALSE /* update even if stats are
2997 initialized */);
2999 trx_commit_for_mysql(trx);
3001 funct_exit:
3003 row_mysql_unlock_data_dictionary(trx);
3005 trx->op_info = "";
3007 srv_wake_master_thread();
3009 return((int) err);
3012 /*********************************************************************//**
3013 Drops a table for MySQL. If the name of the dropped table ends in
3014 one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
3015 "innodb_table_monitor", then this will also stop the printing of monitor
3016 output by the master thread. If the data dictionary was not already locked
3017 by the transaction, the transaction will be committed. Otherwise, the
3018 data dictionary will remain locked.
3019 @return error code or DB_SUCCESS */
3020 UNIV_INTERN
3022 row_drop_table_for_mysql(
3023 /*=====================*/
3024 const char* name, /*!< in: table name */
3025 trx_t* trx, /*!< in: transaction handle */
3026 ibool drop_db)/*!< in: TRUE=dropping whole database */
3028 dict_foreign_t* foreign;
3029 dict_table_t* table;
3030 dict_index_t* index;
3031 ulint space_id;
3032 ulint err;
3033 const char* table_name;
3034 ulint namelen;
3035 ibool locked_dictionary = FALSE;
3036 pars_info_t* info = NULL;
3038 ut_a(name != NULL);
3040 if (srv_created_new_raw) {
3041 fputs("InnoDB: A new raw disk partition was initialized:\n"
3042 "InnoDB: we do not allow database modifications"
3043 " by the user.\n"
3044 "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
3045 " is replaced with raw.\n", stderr);
3047 return(DB_ERROR);
3050 trx->op_info = "dropping table";
3052 trx_start_if_not_started(trx);
3054 /* The table name is prefixed with the database name and a '/'.
3055 Certain table names starting with 'innodb_' have their special
3056 meaning regardless of the database name. Thus, we need to
3057 ignore the database name prefix in the comparisons. */
3058 table_name = strchr(name, '/');
3059 ut_a(table_name);
3060 table_name++;
3061 namelen = strlen(table_name) + 1;
3063 if (namelen == sizeof S_innodb_monitor
3064 && !memcmp(table_name, S_innodb_monitor,
3065 sizeof S_innodb_monitor)) {
3067 /* Table name equals "innodb_monitor":
3068 stop monitor prints */
3070 srv_print_innodb_monitor = FALSE;
3071 srv_print_innodb_lock_monitor = FALSE;
3072 } else if (namelen == sizeof S_innodb_lock_monitor
3073 && !memcmp(table_name, S_innodb_lock_monitor,
3074 sizeof S_innodb_lock_monitor)) {
3075 srv_print_innodb_monitor = FALSE;
3076 srv_print_innodb_lock_monitor = FALSE;
3077 } else if (namelen == sizeof S_innodb_tablespace_monitor
3078 && !memcmp(table_name, S_innodb_tablespace_monitor,
3079 sizeof S_innodb_tablespace_monitor)) {
3081 srv_print_innodb_tablespace_monitor = FALSE;
3082 } else if (namelen == sizeof S_innodb_table_monitor
3083 && !memcmp(table_name, S_innodb_table_monitor,
3084 sizeof S_innodb_table_monitor)) {
3086 srv_print_innodb_table_monitor = FALSE;
3089 /* Serialize data dictionary operations with dictionary mutex:
3090 no deadlocks can occur then in these operations */
3092 if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3093 /* Prevent foreign key checks etc. while we are dropping the
3094 table */
3096 row_mysql_lock_data_dictionary(trx);
3098 locked_dictionary = TRUE;
3101 ut_ad(mutex_own(&(dict_sys->mutex)));
3102 #ifdef UNIV_SYNC_DEBUG
3103 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3104 #endif /* UNIV_SYNC_DEBUG */
3106 table = dict_table_get_low(name);
3108 if (!table) {
3109 err = DB_TABLE_NOT_FOUND;
3110 ut_print_timestamp(stderr);
3112 fputs(" InnoDB: Error: table ", stderr);
3113 ut_print_name(stderr, trx, TRUE, name);
3114 fputs(" does not exist in the InnoDB internal\n"
3115 "InnoDB: data dictionary though MySQL is"
3116 " trying to drop it.\n"
3117 "InnoDB: Have you copied the .frm file"
3118 " of the table to the\n"
3119 "InnoDB: MySQL database directory"
3120 " from another database?\n"
3121 "InnoDB: You can look for further help from\n"
3122 "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3123 stderr);
3124 goto funct_exit;
3127 /* Check if the table is referenced by foreign key constraints from
3128 some other table (not the table itself) */
3130 foreign = UT_LIST_GET_FIRST(table->referenced_list);
3132 while (foreign && foreign->foreign_table == table) {
3133 check_next_foreign:
3134 foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3137 if (foreign && trx->check_foreigns
3138 && !(drop_db && dict_tables_have_same_db(
3139 name, foreign->foreign_table_name))) {
3140 FILE* ef = dict_foreign_err_file;
3142 /* We only allow dropping a referenced table if
3143 FOREIGN_KEY_CHECKS is set to 0 */
3145 err = DB_CANNOT_DROP_CONSTRAINT;
3147 mutex_enter(&dict_foreign_err_mutex);
3148 rewind(ef);
3149 ut_print_timestamp(ef);
3151 fputs(" Cannot drop table ", ef);
3152 ut_print_name(ef, trx, TRUE, name);
3153 fputs("\n"
3154 "because it is referenced by ", ef);
3155 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3156 putc('\n', ef);
3157 mutex_exit(&dict_foreign_err_mutex);
3159 goto funct_exit;
3162 if (foreign && trx->check_foreigns) {
3163 goto check_next_foreign;
3166 if (table->n_mysql_handles_opened > 0) {
3167 ibool added;
3169 added = row_add_table_to_background_drop_list(table->name);
3171 if (added) {
3172 ut_print_timestamp(stderr);
3173 fputs(" InnoDB: Warning: MySQL is"
3174 " trying to drop table ", stderr);
3175 ut_print_name(stderr, trx, TRUE, table->name);
3176 fputs("\n"
3177 "InnoDB: though there are still"
3178 " open handles to it.\n"
3179 "InnoDB: Adding the table to the"
3180 " background drop queue.\n",
3181 stderr);
3183 /* We return DB_SUCCESS to MySQL though the drop will
3184 happen lazily later */
3185 err = DB_SUCCESS;
3186 } else {
3187 /* The table is already in the background drop list */
3188 err = DB_ERROR;
3191 goto funct_exit;
3194 /* TODO: could we replace the counter n_foreign_key_checks_running
3195 with lock checks on the table? Acquire here an exclusive lock on the
3196 table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3197 they can cope with the table having been dropped here? Foreign key
3198 checks take an IS or IX lock on the table. */
3200 if (table->n_foreign_key_checks_running > 0) {
3202 const char* table_name = table->name;
3203 ibool added;
3205 added = row_add_table_to_background_drop_list(table_name);
3207 if (added) {
3208 ut_print_timestamp(stderr);
3209 fputs(" InnoDB: You are trying to drop table ",
3210 stderr);
3211 ut_print_name(stderr, trx, TRUE, table_name);
3212 fputs("\n"
3213 "InnoDB: though there is a"
3214 " foreign key check running on it.\n"
3215 "InnoDB: Adding the table to"
3216 " the background drop queue.\n",
3217 stderr);
3219 /* We return DB_SUCCESS to MySQL though the drop will
3220 happen lazily later */
3222 err = DB_SUCCESS;
3223 } else {
3224 /* The table is already in the background drop list */
3225 err = DB_ERROR;
3228 goto funct_exit;
3231 /* Remove all locks there are on the table or its records */
3232 lock_remove_all_on_table(table, TRUE);
3234 trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
3235 trx->table_id = table->id;
3237 /* Mark all indexes unavailable in the data dictionary cache
3238 before starting to drop the table. */
3240 for (index = dict_table_get_first_index(table);
3241 index != NULL;
3242 index = dict_table_get_next_index(index)) {
3243 rw_lock_x_lock(dict_index_get_lock(index));
3244 ut_ad(!index->to_be_dropped);
3245 index->to_be_dropped = TRUE;
3246 rw_lock_x_unlock(dict_index_get_lock(index));
3249 /* We use the private SQL parser of Innobase to generate the
3250 query graphs needed in deleting the dictionary data from system
3251 tables in Innobase. Deleting a row from SYS_INDEXES table also
3252 frees the file segments of the B-tree associated with the index. */
3254 info = pars_info_create();
3256 pars_info_add_str_literal(info, "table_name", name);
3258 err = que_eval_sql(info,
3259 "PROCEDURE DROP_TABLE_PROC () IS\n"
3260 "sys_foreign_id CHAR;\n"
3261 "table_id CHAR;\n"
3262 "index_id CHAR;\n"
3263 "foreign_id CHAR;\n"
3264 "found INT;\n"
3266 "DECLARE CURSOR cur_fk IS\n"
3267 "SELECT ID FROM SYS_FOREIGN\n"
3268 "WHERE FOR_NAME = :table_name\n"
3269 "AND TO_BINARY(FOR_NAME)\n"
3270 " = TO_BINARY(:table_name)\n"
3271 "LOCK IN SHARE MODE;\n"
3273 "DECLARE CURSOR cur_idx IS\n"
3274 "SELECT ID FROM SYS_INDEXES\n"
3275 "WHERE TABLE_ID = table_id\n"
3276 "LOCK IN SHARE MODE;\n"
3278 "BEGIN\n"
3279 "SELECT ID INTO table_id\n"
3280 "FROM SYS_TABLES\n"
3281 "WHERE NAME = :table_name\n"
3282 "LOCK IN SHARE MODE;\n"
3283 "IF (SQL % NOTFOUND) THEN\n"
3284 " RETURN;\n"
3285 "END IF;\n"
3286 "found := 1;\n"
3287 "SELECT ID INTO sys_foreign_id\n"
3288 "FROM SYS_TABLES\n"
3289 "WHERE NAME = 'SYS_FOREIGN'\n"
3290 "LOCK IN SHARE MODE;\n"
3291 "IF (SQL % NOTFOUND) THEN\n"
3292 " found := 0;\n"
3293 "END IF;\n"
3294 "IF (:table_name = 'SYS_FOREIGN') THEN\n"
3295 " found := 0;\n"
3296 "END IF;\n"
3297 "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3298 " found := 0;\n"
3299 "END IF;\n"
3300 "OPEN cur_fk;\n"
3301 "WHILE found = 1 LOOP\n"
3302 " FETCH cur_fk INTO foreign_id;\n"
3303 " IF (SQL % NOTFOUND) THEN\n"
3304 " found := 0;\n"
3305 " ELSE\n"
3306 " DELETE FROM SYS_FOREIGN_COLS\n"
3307 " WHERE ID = foreign_id;\n"
3308 " DELETE FROM SYS_FOREIGN\n"
3309 " WHERE ID = foreign_id;\n"
3310 " END IF;\n"
3311 "END LOOP;\n"
3312 "CLOSE cur_fk;\n"
3313 "found := 1;\n"
3314 "OPEN cur_idx;\n"
3315 "WHILE found = 1 LOOP\n"
3316 " FETCH cur_idx INTO index_id;\n"
3317 " IF (SQL % NOTFOUND) THEN\n"
3318 " found := 0;\n"
3319 " ELSE\n"
3320 " DELETE FROM SYS_FIELDS\n"
3321 " WHERE INDEX_ID = index_id;\n"
3322 " DELETE FROM SYS_INDEXES\n"
3323 " WHERE ID = index_id\n"
3324 " AND TABLE_ID = table_id;\n"
3325 " END IF;\n"
3326 "END LOOP;\n"
3327 "CLOSE cur_idx;\n"
3328 "DELETE FROM SYS_COLUMNS\n"
3329 "WHERE TABLE_ID = table_id;\n"
3330 "DELETE FROM SYS_TABLES\n"
3331 "WHERE ID = table_id;\n"
3332 "END;\n"
3333 , FALSE, trx);
3335 switch (err) {
3336 ibool is_temp;
3337 const char* name_or_path;
3338 mem_heap_t* heap;
3340 case DB_SUCCESS:
3342 heap = mem_heap_create(200);
3344 /* Clone the name, in case it has been allocated
3345 from table->heap, which will be freed by
3346 dict_table_remove_from_cache(table) below. */
3347 name = mem_heap_strdup(heap, name);
3348 space_id = table->space;
3350 if (table->dir_path_of_temp_table != NULL) {
3351 name_or_path = mem_heap_strdup(
3352 heap, table->dir_path_of_temp_table);
3353 is_temp = TRUE;
3354 } else {
3355 name_or_path = name;
3356 is_temp = (table->flags >> DICT_TF2_SHIFT)
3357 & DICT_TF2_TEMPORARY;
3360 dict_table_remove_from_cache(table);
3362 if (dict_load_table(name) != NULL) {
3363 ut_print_timestamp(stderr);
3364 fputs(" InnoDB: Error: not able to remove table ",
3365 stderr);
3366 ut_print_name(stderr, trx, TRUE, name);
3367 fputs(" from the dictionary cache!\n", stderr);
3368 err = DB_ERROR;
3371 /* Do not drop possible .ibd tablespace if something went
3372 wrong: we do not want to delete valuable data of the user */
3374 if (err == DB_SUCCESS && space_id > 0) {
3375 if (!fil_space_for_table_exists_in_mem(space_id,
3376 name_or_path,
3377 is_temp, FALSE,
3378 !is_temp)) {
3379 err = DB_SUCCESS;
3381 fprintf(stderr,
3382 "InnoDB: We removed now the InnoDB"
3383 " internal data dictionary entry\n"
3384 "InnoDB: of table ");
3385 ut_print_name(stderr, trx, TRUE, name);
3386 fprintf(stderr, ".\n");
3387 } else if (!fil_delete_tablespace(space_id)) {
3388 fprintf(stderr,
3389 "InnoDB: We removed now the InnoDB"
3390 " internal data dictionary entry\n"
3391 "InnoDB: of table ");
3392 ut_print_name(stderr, trx, TRUE, name);
3393 fprintf(stderr, ".\n");
3395 ut_print_timestamp(stderr);
3396 fprintf(stderr,
3397 " InnoDB: Error: not able to"
3398 " delete tablespace %lu of table ",
3399 (ulong) space_id);
3400 ut_print_name(stderr, trx, TRUE, name);
3401 fputs("!\n", stderr);
3402 err = DB_ERROR;
3406 mem_heap_free(heap);
3407 break;
3409 case DB_TOO_MANY_CONCURRENT_TRXS:
3410 /* Cannot even find a free slot for the
3411 the undo log. We can directly exit here
3412 and return the DB_TOO_MANY_CONCURRENT_TRXS
3413 error. */
3415 /* Mark all indexes available in the data dictionary
3416 cache again. */
3418 for (index = dict_table_get_first_index(table);
3419 index != NULL;
3420 index = dict_table_get_next_index(index)) {
3421 rw_lock_x_lock(dict_index_get_lock(index));
3422 index->to_be_dropped = FALSE;
3423 rw_lock_x_unlock(dict_index_get_lock(index));
3425 break;
3427 case DB_OUT_OF_FILE_SPACE:
3428 err = DB_MUST_GET_MORE_FILE_SPACE;
3430 row_mysql_handle_errors(&err, trx, NULL, NULL);
3432 /* Fall through to raise error */
3434 default:
3435 /* No other possible error returns */
3436 ut_error;
3439 funct_exit:
3441 if (locked_dictionary) {
3442 trx_commit_for_mysql(trx);
3444 row_mysql_unlock_data_dictionary(trx);
3447 trx->op_info = "";
3449 srv_wake_master_thread();
3451 return((int) err);
3454 /*********************************************************************//**
3455 Drop all temporary tables during crash recovery. */
3456 UNIV_INTERN
3457 void
3458 row_mysql_drop_temp_tables(void)
3459 /*============================*/
3461 trx_t* trx;
3462 btr_pcur_t pcur;
3463 mtr_t mtr;
3464 mem_heap_t* heap;
3466 trx = trx_allocate_for_background();
3467 trx->op_info = "dropping temporary tables";
3468 row_mysql_lock_data_dictionary(trx);
3470 heap = mem_heap_create(200);
3472 mtr_start(&mtr);
3474 btr_pcur_open_at_index_side(
3475 TRUE,
3476 dict_table_get_first_index(dict_sys->sys_tables),
3477 BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3479 for (;;) {
3480 const rec_t* rec;
3481 const byte* field;
3482 ulint len;
3483 const char* table_name;
3484 dict_table_t* table;
3486 btr_pcur_move_to_next_user_rec(&pcur, &mtr);
3488 if (!btr_pcur_is_on_user_rec(&pcur)) {
3489 break;
3492 rec = btr_pcur_get_rec(&pcur);
3493 field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
3494 if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) {
3495 continue;
3498 /* Because this is not a ROW_FORMAT=REDUNDANT table,
3499 the is_temp flag is valid. Examine it. */
3501 field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len);
3502 if (len != 4
3503 || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
3504 continue;
3507 /* This is a temporary table. */
3508 field = rec_get_nth_field_old(rec, 0/*NAME*/, &len);
3509 if (len == UNIV_SQL_NULL || len == 0) {
3510 /* Corrupted SYS_TABLES.NAME */
3511 continue;
3514 table_name = mem_heap_strdupl(heap, (const char*) field, len);
3516 btr_pcur_store_position(&pcur, &mtr);
3517 btr_pcur_commit_specify_mtr(&pcur, &mtr);
3519 table = dict_load_table(table_name);
3521 if (table) {
3522 row_drop_table_for_mysql(table_name, trx, FALSE);
3523 trx_commit_for_mysql(trx);
3526 mtr_start(&mtr);
3527 btr_pcur_restore_position(BTR_SEARCH_LEAF,
3528 &pcur, &mtr);
3531 btr_pcur_close(&pcur);
3532 mtr_commit(&mtr);
3533 mem_heap_free(heap);
3534 row_mysql_unlock_data_dictionary(trx);
3535 trx_free_for_background(trx);
3538 /*******************************************************************//**
3539 Drop all foreign keys in a database, see Bug#18942.
3540 Called at the end of row_drop_database_for_mysql().
3541 @return error code or DB_SUCCESS */
3542 static
3543 ulint
3544 drop_all_foreign_keys_in_db(
3545 /*========================*/
3546 const char* name, /*!< in: database name which ends to '/' */
3547 trx_t* trx) /*!< in: transaction handle */
3549 pars_info_t* pinfo;
3550 ulint err;
3552 ut_a(name[strlen(name) - 1] == '/');
3554 pinfo = pars_info_create();
3556 pars_info_add_str_literal(pinfo, "dbname", name);
3558 /** true if for_name is not prefixed with dbname */
3559 #define TABLE_NOT_IN_THIS_DB \
3560 "SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
3562 err = que_eval_sql(pinfo,
3563 "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
3564 "foreign_id CHAR;\n"
3565 "for_name CHAR;\n"
3566 "found INT;\n"
3567 "DECLARE CURSOR cur IS\n"
3568 "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
3569 "WHERE FOR_NAME >= :dbname\n"
3570 "LOCK IN SHARE MODE\n"
3571 "ORDER BY FOR_NAME;\n"
3572 "BEGIN\n"
3573 "found := 1;\n"
3574 "OPEN cur;\n"
3575 "WHILE found = 1 LOOP\n"
3576 " FETCH cur INTO foreign_id, for_name;\n"
3577 " IF (SQL % NOTFOUND) THEN\n"
3578 " found := 0;\n"
3579 " ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
3580 " found := 0;\n"
3581 " ELSIF (1=1) THEN\n"
3582 " DELETE FROM SYS_FOREIGN_COLS\n"
3583 " WHERE ID = foreign_id;\n"
3584 " DELETE FROM SYS_FOREIGN\n"
3585 " WHERE ID = foreign_id;\n"
3586 " END IF;\n"
3587 "END LOOP;\n"
3588 "CLOSE cur;\n"
3589 "COMMIT WORK;\n"
3590 "END;\n",
3591 FALSE, /* do not reserve dict mutex,
3592 we are already holding it */
3593 trx);
3595 return(err);
3598 /*********************************************************************//**
3599 Drops a database for MySQL.
3600 @return error code or DB_SUCCESS */
3601 UNIV_INTERN
3603 row_drop_database_for_mysql(
3604 /*========================*/
3605 const char* name, /*!< in: database name which ends to '/' */
3606 trx_t* trx) /*!< in: transaction handle */
3608 dict_table_t* table;
3609 char* table_name;
3610 int err = DB_SUCCESS;
3611 ulint namelen = strlen(name);
3613 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3614 ut_a(name != NULL);
3615 ut_a(name[namelen - 1] == '/');
3617 trx->op_info = "dropping database";
3619 trx_start_if_not_started(trx);
3620 loop:
3621 row_mysql_lock_data_dictionary(trx);
3623 while ((table_name = dict_get_first_table_name_in_db(name))) {
3624 ut_a(memcmp(table_name, name, namelen) == 0);
3626 table = dict_table_get_low(table_name);
3628 ut_a(table);
3630 /* Wait until MySQL does not have any queries running on
3631 the table */
3633 if (table->n_mysql_handles_opened > 0) {
3634 row_mysql_unlock_data_dictionary(trx);
3636 ut_print_timestamp(stderr);
3637 fputs(" InnoDB: Warning: MySQL is trying to"
3638 " drop database ", stderr);
3639 ut_print_name(stderr, trx, TRUE, name);
3640 fputs("\n"
3641 "InnoDB: though there are still"
3642 " open handles to table ", stderr);
3643 ut_print_name(stderr, trx, TRUE, table_name);
3644 fputs(".\n", stderr);
3646 os_thread_sleep(1000000);
3648 mem_free(table_name);
3650 goto loop;
3653 err = row_drop_table_for_mysql(table_name, trx, TRUE);
3654 trx_commit_for_mysql(trx);
3656 if (err != DB_SUCCESS) {
3657 fputs("InnoDB: DROP DATABASE ", stderr);
3658 ut_print_name(stderr, trx, TRUE, name);
3659 fprintf(stderr, " failed with error %lu for table ",
3660 (ulint) err);
3661 ut_print_name(stderr, trx, TRUE, table_name);
3662 putc('\n', stderr);
3663 mem_free(table_name);
3664 break;
3667 mem_free(table_name);
3670 if (err == DB_SUCCESS) {
3671 /* after dropping all tables try to drop all leftover
3672 foreign keys in case orphaned ones exist */
3673 err = (int) drop_all_foreign_keys_in_db(name, trx);
3675 if (err != DB_SUCCESS) {
3676 fputs("InnoDB: DROP DATABASE ", stderr);
3677 ut_print_name(stderr, trx, TRUE, name);
3678 fprintf(stderr, " failed with error %d while "
3679 "dropping all foreign keys", err);
3683 trx_commit_for_mysql(trx);
3685 row_mysql_unlock_data_dictionary(trx);
3687 trx->op_info = "";
3689 return(err);
3692 /*********************************************************************//**
3693 Checks if a table name contains the string "/#sql" which denotes temporary
3694 tables in MySQL.
3695 @return TRUE if temporary table */
3696 static
3697 ibool
3698 row_is_mysql_tmp_table_name(
3699 /*========================*/
3700 const char* name) /*!< in: table name in the form
3701 'database/tablename' */
3703 return(strstr(name, "/#sql") != NULL);
3704 /* return(strstr(name, "/@0023sql") != NULL); */
3707 /****************************************************************//**
3708 Delete a single constraint.
3709 @return error code or DB_SUCCESS */
3710 static
3712 row_delete_constraint_low(
3713 /*======================*/
3714 const char* id, /*!< in: constraint id */
3715 trx_t* trx) /*!< in: transaction handle */
3717 pars_info_t* info = pars_info_create();
3719 pars_info_add_str_literal(info, "id", id);
3721 return((int) que_eval_sql(info,
3722 "PROCEDURE DELETE_CONSTRAINT () IS\n"
3723 "BEGIN\n"
3724 "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3725 "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3726 "END;\n"
3727 , FALSE, trx));
3730 /****************************************************************//**
3731 Delete a single constraint.
3732 @return error code or DB_SUCCESS */
3733 static
3735 row_delete_constraint(
3736 /*==================*/
3737 const char* id, /*!< in: constraint id */
3738 const char* database_name, /*!< in: database name, with the
3739 trailing '/' */
3740 mem_heap_t* heap, /*!< in: memory heap */
3741 trx_t* trx) /*!< in: transaction handle */
3743 ulint err;
3745 /* New format constraints have ids <databasename>/<constraintname>. */
3746 err = row_delete_constraint_low(
3747 mem_heap_strcat(heap, database_name, id), trx);
3749 if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3750 /* Old format < 4.0.18 constraints have constraint ids
3751 NUMBER_NUMBER. We only try deleting them if the
3752 constraint name does not contain a '/' character, otherwise
3753 deleting a new format constraint named 'foo/bar' from
3754 database 'baz' would remove constraint 'bar' from database
3755 'foo', if it existed. */
3757 err = row_delete_constraint_low(id, trx);
3760 return((int) err);
3763 /*********************************************************************//**
3764 Renames a table for MySQL.
3765 @return error code or DB_SUCCESS */
3766 UNIV_INTERN
3767 ulint
3768 row_rename_table_for_mysql(
3769 /*=======================*/
3770 const char* old_name, /*!< in: old table name */
3771 const char* new_name, /*!< in: new table name */
3772 trx_t* trx, /*!< in: transaction handle */
3773 ibool commit) /*!< in: if TRUE then commit trx */
3775 dict_table_t* table;
3776 ulint err = DB_ERROR;
3777 mem_heap_t* heap = NULL;
3778 const char** constraints_to_drop = NULL;
3779 ulint n_constraints_to_drop = 0;
3780 ibool old_is_tmp, new_is_tmp;
3781 pars_info_t* info = NULL;
3782 ulint retry = 0;
3784 ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3785 ut_a(old_name != NULL);
3786 ut_a(new_name != NULL);
3788 if (srv_created_new_raw || srv_force_recovery) {
3789 fputs("InnoDB: A new raw disk partition was initialized or\n"
3790 "InnoDB: innodb_force_recovery is on: we do not allow\n"
3791 "InnoDB: database modifications by the user. Shut down\n"
3792 "InnoDB: mysqld and edit my.cnf so that newraw"
3793 " is replaced\n"
3794 "InnoDB: with raw, and innodb_force_... is removed.\n",
3795 stderr);
3797 goto funct_exit;
3798 } else if (row_mysql_is_system_table(new_name)) {
3800 fprintf(stderr,
3801 "InnoDB: Error: trying to create a MySQL"
3802 " system table %s of type InnoDB.\n"
3803 "InnoDB: MySQL system tables must be"
3804 " of the MyISAM type!\n",
3805 new_name);
3807 goto funct_exit;
3810 trx->op_info = "renaming table";
3811 trx_start_if_not_started(trx);
3813 old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3814 new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3816 table = dict_table_get_low(old_name);
3818 if (!table) {
3819 err = DB_TABLE_NOT_FOUND;
3820 ut_print_timestamp(stderr);
3822 fputs(" InnoDB: Error: table ", stderr);
3823 ut_print_name(stderr, trx, TRUE, old_name);
3824 fputs(" does not exist in the InnoDB internal\n"
3825 "InnoDB: data dictionary though MySQL is"
3826 " trying to rename the table.\n"
3827 "InnoDB: Have you copied the .frm file"
3828 " of the table to the\n"
3829 "InnoDB: MySQL database directory"
3830 " from another database?\n"
3831 "InnoDB: You can look for further help from\n"
3832 "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3833 stderr);
3834 goto funct_exit;
3835 } else if (table->ibd_file_missing) {
3836 err = DB_TABLE_NOT_FOUND;
3837 ut_print_timestamp(stderr);
3839 fputs(" InnoDB: Error: table ", stderr);
3840 ut_print_name(stderr, trx, TRUE, old_name);
3841 fputs(" does not have an .ibd file"
3842 " in the database directory.\n"
3843 "InnoDB: You can look for further help from\n"
3844 "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3845 stderr);
3846 goto funct_exit;
3847 } else if (new_is_tmp) {
3848 /* MySQL is doing an ALTER TABLE command and it renames the
3849 original table to a temporary table name. We want to preserve
3850 the original foreign key constraint definitions despite the
3851 name change. An exception is those constraints for which
3852 the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3854 heap = mem_heap_create(100);
3856 err = dict_foreign_parse_drop_constraints(
3857 heap, trx, table, &n_constraints_to_drop,
3858 &constraints_to_drop);
3860 if (err != DB_SUCCESS) {
3862 goto funct_exit;
3866 /* Is a foreign key check running on this table? */
3867 for (retry = 0; retry < 100
3868 && table->n_foreign_key_checks_running > 0; ++retry) {
3869 row_mysql_unlock_data_dictionary(trx);
3870 os_thread_yield();
3871 row_mysql_lock_data_dictionary(trx);
3874 if (table->n_foreign_key_checks_running > 0) {
3875 ut_print_timestamp(stderr);
3876 fputs(" InnoDB: Error: in ALTER TABLE ", stderr);
3877 ut_print_name(stderr, trx, TRUE, old_name);
3878 fprintf(stderr, "\n"
3879 "InnoDB: a FOREIGN KEY check is running.\n"
3880 "InnoDB: Cannot rename table.\n");
3881 err = DB_TABLE_IN_FK_CHECK;
3882 goto funct_exit;
3885 /* We use the private SQL parser of Innobase to generate the query
3886 graphs needed in updating the dictionary data from system tables. */
3888 info = pars_info_create();
3890 pars_info_add_str_literal(info, "new_table_name", new_name);
3891 pars_info_add_str_literal(info, "old_table_name", old_name);
3893 err = que_eval_sql(info,
3894 "PROCEDURE RENAME_TABLE () IS\n"
3895 "BEGIN\n"
3896 "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3897 " WHERE NAME = :old_table_name;\n"
3898 "END;\n"
3899 , FALSE, trx);
3901 if (err != DB_SUCCESS) {
3903 goto end;
3904 } else if (!new_is_tmp) {
3905 /* Rename all constraints. */
3906 char new_table_name[MAX_TABLE_NAME_LEN] = "";
3907 char old_table_utf8[MAX_TABLE_NAME_LEN] = "";
3908 uint errors = 0;
3910 strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
3911 innobase_convert_to_system_charset(
3912 strchr(old_table_utf8, '/') + 1,
3913 strchr(old_name, '/') +1,
3914 MAX_TABLE_NAME_LEN, &errors);
3916 if (errors) {
3917 /* Table name could not be converted from charset
3918 my_charset_filename to UTF-8. This means that the
3919 table name is already in UTF-8 (#mysql#50). */
3920 strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
3923 info = pars_info_create();
3925 pars_info_add_str_literal(info, "new_table_name", new_name);
3926 pars_info_add_str_literal(info, "old_table_name", old_name);
3927 pars_info_add_str_literal(info, "old_table_name_utf8",
3928 old_table_utf8);
3930 strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN);
3931 innobase_convert_to_system_charset(
3932 strchr(new_table_name, '/') + 1,
3933 strchr(new_name, '/') +1,
3934 MAX_TABLE_NAME_LEN, &errors);
3936 if (errors) {
3937 /* Table name could not be converted from charset
3938 my_charset_filename to UTF-8. This means that the
3939 table name is already in UTF-8 (#mysql#50). */
3940 strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN);
3943 pars_info_add_str_literal(info, "new_table_utf8", new_table_name);
3945 err = que_eval_sql(
3946 info,
3947 "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3948 "gen_constr_prefix CHAR;\n"
3949 "new_db_name CHAR;\n"
3950 "foreign_id CHAR;\n"
3951 "new_foreign_id CHAR;\n"
3952 "old_db_name_len INT;\n"
3953 "old_t_name_len INT;\n"
3954 "new_db_name_len INT;\n"
3955 "id_len INT;\n"
3956 "offset INT;\n"
3957 "found INT;\n"
3958 "BEGIN\n"
3959 "found := 1;\n"
3960 "old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3961 "new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3962 "new_db_name := SUBSTR(:new_table_name, 0,\n"
3963 " new_db_name_len);\n"
3964 "old_t_name_len := LENGTH(:old_table_name);\n"
3965 "gen_constr_prefix := CONCAT(:old_table_name_utf8,\n"
3966 " '_ibfk_');\n"
3967 "WHILE found = 1 LOOP\n"
3968 " SELECT ID INTO foreign_id\n"
3969 " FROM SYS_FOREIGN\n"
3970 " WHERE FOR_NAME = :old_table_name\n"
3971 " AND TO_BINARY(FOR_NAME)\n"
3972 " = TO_BINARY(:old_table_name)\n"
3973 " LOCK IN SHARE MODE;\n"
3974 " IF (SQL % NOTFOUND) THEN\n"
3975 " found := 0;\n"
3976 " ELSE\n"
3977 " UPDATE SYS_FOREIGN\n"
3978 " SET FOR_NAME = :new_table_name\n"
3979 " WHERE ID = foreign_id;\n"
3980 " id_len := LENGTH(foreign_id);\n"
3981 " IF (INSTR(foreign_id, '/') > 0) THEN\n"
3982 " IF (INSTR(foreign_id,\n"
3983 " gen_constr_prefix) > 0)\n"
3984 " THEN\n"
3985 " offset := INSTR(foreign_id, '_ibfk_') - 1;\n"
3986 " new_foreign_id :=\n"
3987 " CONCAT(:new_table_utf8,\n"
3988 " SUBSTR(foreign_id, offset,\n"
3989 " id_len - offset));\n"
3990 " ELSE\n"
3991 " new_foreign_id :=\n"
3992 " CONCAT(new_db_name,\n"
3993 " SUBSTR(foreign_id,\n"
3994 " old_db_name_len,\n"
3995 " id_len - old_db_name_len));\n"
3996 " END IF;\n"
3997 " UPDATE SYS_FOREIGN\n"
3998 " SET ID = new_foreign_id\n"
3999 " WHERE ID = foreign_id;\n"
4000 " UPDATE SYS_FOREIGN_COLS\n"
4001 " SET ID = new_foreign_id\n"
4002 " WHERE ID = foreign_id;\n"
4003 " END IF;\n"
4004 " END IF;\n"
4005 "END LOOP;\n"
4006 "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
4007 "WHERE REF_NAME = :old_table_name\n"
4008 " AND TO_BINARY(REF_NAME)\n"
4009 " = TO_BINARY(:old_table_name);\n"
4010 "END;\n"
4011 , FALSE, trx);
4013 } else if (n_constraints_to_drop > 0) {
4014 /* Drop some constraints of tmp tables. */
4016 ulint db_name_len = dict_get_db_name_len(old_name) + 1;
4017 char* db_name = mem_heap_strdupl(heap, old_name,
4018 db_name_len);
4019 ulint i;
4021 for (i = 0; i < n_constraints_to_drop; i++) {
4022 err = row_delete_constraint(constraints_to_drop[i],
4023 db_name, heap, trx);
4025 if (err != DB_SUCCESS) {
4026 break;
4031 end:
4032 if (err != DB_SUCCESS) {
4033 if (err == DB_DUPLICATE_KEY) {
4034 ut_print_timestamp(stderr);
4035 fputs(" InnoDB: Error; possible reasons:\n"
4036 "InnoDB: 1) Table rename would cause"
4037 " two FOREIGN KEY constraints\n"
4038 "InnoDB: to have the same internal name"
4039 " in case-insensitive comparison.\n"
4040 "InnoDB: 2) table ", stderr);
4041 ut_print_name(stderr, trx, TRUE, new_name);
4042 fputs(" exists in the InnoDB internal data\n"
4043 "InnoDB: dictionary though MySQL is"
4044 " trying to rename table ", stderr);
4045 ut_print_name(stderr, trx, TRUE, old_name);
4046 fputs(" to it.\n"
4047 "InnoDB: Have you deleted the .frm file"
4048 " and not used DROP TABLE?\n"
4049 "InnoDB: You can look for further help from\n"
4050 "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
4051 "InnoDB: If table ", stderr);
4052 ut_print_name(stderr, trx, TRUE, new_name);
4053 fputs(" is a temporary table #sql..., then"
4054 " it can be that\n"
4055 "InnoDB: there are still queries running"
4056 " on the table, and it will be\n"
4057 "InnoDB: dropped automatically when"
4058 " the queries end.\n"
4059 "InnoDB: You can drop the orphaned table"
4060 " inside InnoDB by\n"
4061 "InnoDB: creating an InnoDB table with"
4062 " the same name in another\n"
4063 "InnoDB: database and copying the .frm file"
4064 " to the current database.\n"
4065 "InnoDB: Then MySQL thinks the table exists,"
4066 " and DROP TABLE will\n"
4067 "InnoDB: succeed.\n", stderr);
4069 trx->error_state = DB_SUCCESS;
4070 trx_general_rollback_for_mysql(trx, NULL);
4071 trx->error_state = DB_SUCCESS;
4072 } else {
4073 /* The following call will also rename the .ibd data file if
4074 the table is stored in a single-table tablespace */
4076 if (!dict_table_rename_in_cache(table, new_name,
4077 !new_is_tmp)) {
4078 trx->error_state = DB_SUCCESS;
4079 trx_general_rollback_for_mysql(trx, NULL);
4080 trx->error_state = DB_SUCCESS;
4081 err = DB_ERROR;
4082 goto funct_exit;
4085 /* We only want to switch off some of the type checking in
4086 an ALTER, not in a RENAME. */
4088 err = dict_load_foreigns(
4089 new_name, FALSE, !old_is_tmp || trx->check_foreigns);
4091 if (err != DB_SUCCESS) {
4092 ut_print_timestamp(stderr);
4094 if (old_is_tmp) {
4095 fputs(" InnoDB: Error: in ALTER TABLE ",
4096 stderr);
4097 ut_print_name(stderr, trx, TRUE, new_name);
4098 fputs("\n"
4099 "InnoDB: has or is referenced"
4100 " in foreign key constraints\n"
4101 "InnoDB: which are not compatible"
4102 " with the new table definition.\n",
4103 stderr);
4104 } else {
4105 fputs(" InnoDB: Error: in RENAME TABLE"
4106 " table ",
4107 stderr);
4108 ut_print_name(stderr, trx, TRUE, new_name);
4109 fputs("\n"
4110 "InnoDB: is referenced in"
4111 " foreign key constraints\n"
4112 "InnoDB: which are not compatible"
4113 " with the new table definition.\n",
4114 stderr);
4117 ut_a(dict_table_rename_in_cache(table,
4118 old_name, FALSE));
4119 trx->error_state = DB_SUCCESS;
4120 trx_general_rollback_for_mysql(trx, NULL);
4121 trx->error_state = DB_SUCCESS;
4122 } else {
4123 if (old_is_tmp && !new_is_tmp) {
4124 /* After ALTER TABLE the table statistics
4125 needs to be rebuilt. It will be rebuilt
4126 when the table is loaded again. */
4127 table->stat_initialized = FALSE;
4132 funct_exit:
4134 if (commit) {
4135 trx_commit_for_mysql(trx);
4138 if (UNIV_LIKELY_NULL(heap)) {
4139 mem_heap_free(heap);
4142 trx->op_info = "";
4144 return(err);
4147 /*********************************************************************//**
4148 Checks that the index contains entries in an ascending order, unique
4149 constraint is not broken, and calculates the number of index entries
4150 in the read view of the current transaction.
4151 @return TRUE if ok */
4152 UNIV_INTERN
4153 ibool
4154 row_check_index_for_mysql(
4155 /*======================*/
4156 row_prebuilt_t* prebuilt, /*!< in: prebuilt struct
4157 in MySQL handle */
4158 const dict_index_t* index, /*!< in: index */
4159 ulint* n_rows) /*!< out: number of entries
4160 seen in the consistent read */
4162 dtuple_t* prev_entry = NULL;
4163 ulint matched_fields;
4164 ulint matched_bytes;
4165 byte* buf;
4166 ulint ret;
4167 rec_t* rec;
4168 ibool is_ok = TRUE;
4169 int cmp;
4170 ibool contains_null;
4171 ulint i;
4172 ulint cnt;
4173 mem_heap_t* heap = NULL;
4174 ulint n_ext;
4175 ulint offsets_[REC_OFFS_NORMAL_SIZE];
4176 ulint* offsets;
4177 rec_offs_init(offsets_);
4179 *n_rows = 0;
4181 buf = mem_alloc(UNIV_PAGE_SIZE);
4182 heap = mem_heap_create(100);
4184 cnt = 1000;
4186 ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
4187 loop:
4188 /* Check thd->killed every 1,000 scanned rows */
4189 if (--cnt == 0) {
4190 if (trx_is_interrupted(prebuilt->trx)) {
4191 goto func_exit;
4193 cnt = 1000;
4196 switch (ret) {
4197 case DB_SUCCESS:
4198 break;
4199 default:
4200 ut_print_timestamp(stderr);
4201 fputs(" InnoDB: Warning: CHECK TABLE on ", stderr);
4202 dict_index_name_print(stderr, prebuilt->trx, index);
4203 fprintf(stderr, " returned %lu\n", ret);
4204 /* fall through (this error is ignored by CHECK TABLE) */
4205 case DB_END_OF_INDEX:
4206 func_exit:
4207 mem_free(buf);
4208 mem_heap_free(heap);
4210 return(is_ok);
4213 *n_rows = *n_rows + 1;
4215 /* row_search... returns the index record in buf, record origin offset
4216 within buf stored in the first 4 bytes, because we have built a dummy
4217 template */
4219 rec = buf + mach_read_from_4(buf);
4221 offsets = rec_get_offsets(rec, index, offsets_,
4222 ULINT_UNDEFINED, &heap);
4224 if (prev_entry != NULL) {
4225 matched_fields = 0;
4226 matched_bytes = 0;
4228 cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
4229 &matched_fields,
4230 &matched_bytes);
4231 contains_null = FALSE;
4233 /* In a unique secondary index we allow equal key values if
4234 they contain SQL NULLs */
4236 for (i = 0;
4237 i < dict_index_get_n_ordering_defined_by_user(index);
4238 i++) {
4239 if (UNIV_SQL_NULL == dfield_get_len(
4240 dtuple_get_nth_field(prev_entry, i))) {
4242 contains_null = TRUE;
4246 if (cmp > 0) {
4247 fputs("InnoDB: index records in a wrong order in ",
4248 stderr);
4249 not_ok:
4250 dict_index_name_print(stderr,
4251 prebuilt->trx, index);
4252 fputs("\n"
4253 "InnoDB: prev record ", stderr);
4254 dtuple_print(stderr, prev_entry);
4255 fputs("\n"
4256 "InnoDB: record ", stderr);
4257 rec_print_new(stderr, rec, offsets);
4258 putc('\n', stderr);
4259 is_ok = FALSE;
4260 } else if (dict_index_is_unique(index)
4261 && !contains_null
4262 && matched_fields
4263 >= dict_index_get_n_ordering_defined_by_user(
4264 index)) {
4266 fputs("InnoDB: duplicate key in ", stderr);
4267 goto not_ok;
4272 mem_heap_t* tmp_heap = NULL;
4274 /* Empty the heap on each round. But preserve offsets[]
4275 for the row_rec_to_index_entry() call, by copying them
4276 into a separate memory heap when needed. */
4277 if (UNIV_UNLIKELY(offsets != offsets_)) {
4278 ulint size = rec_offs_get_n_alloc(offsets)
4279 * sizeof *offsets;
4281 tmp_heap = mem_heap_create(size);
4282 offsets = mem_heap_dup(tmp_heap, offsets, size);
4285 mem_heap_empty(heap);
4287 prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
4288 index, offsets,
4289 &n_ext, heap);
4291 if (UNIV_LIKELY_NULL(tmp_heap)) {
4292 mem_heap_free(tmp_heap);
4296 ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
4298 goto loop;
4301 /*********************************************************************//**
4302 Determines if a table is a magic monitor table.
4303 @return TRUE if monitor table */
4304 UNIV_INTERN
4305 ibool
4306 row_is_magic_monitor_table(
4307 /*=======================*/
4308 const char* table_name) /*!< in: name of the table, in the
4309 form database/table_name */
4311 const char* name; /* table_name without database/ */
4312 ulint len;
4314 name = strchr(table_name, '/');
4315 ut_a(name != NULL);
4316 name++;
4317 len = strlen(name) + 1;
4319 if (STR_EQ(name, len, S_innodb_monitor)
4320 || STR_EQ(name, len, S_innodb_lock_monitor)
4321 || STR_EQ(name, len, S_innodb_tablespace_monitor)
4322 || STR_EQ(name, len, S_innodb_table_monitor)
4323 || STR_EQ(name, len, S_innodb_mem_validate)) {
4325 return(TRUE);
4328 return(FALSE);