1
/*****************************************************************************
3
Copyright (C) 2000, 2010, Innobase Oy. 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., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
17
*****************************************************************************/
19
/**************************************************//**
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"
30
#include "row0mysql.ic"
34
#include "row0merge.h"
39
#include "pars0pars.h"
40
#include "dict0dict.h"
41
#include "dict0crea.h"
42
#include "dict0load.h"
43
#include "dict0boot.h"
45
#include "trx0purge.h"
48
#include "lock0lock.h"
53
#include "ibuf0ibuf.h"
57
/** Provide optional 4.x backwards compatibility for 5.0 and above */
58
UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
60
/** Chain node of the list of tables to drop in the background. */
61
typedef struct row_mysql_drop_struct row_mysql_drop_t;
63
/** Chain node of the list of tables to drop in the background. */
64
struct row_mysql_drop_struct{
65
char* table_name; /*!< table name */
66
UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
67
/*!< list chain node */
70
/** @brief List of tables we should drop in background.
72
ALTER TABLE in MySQL requires that the table handler can drop the
73
table in background when there are no queries to it any
74
more. Protected by kernel_mutex. */
75
static UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
76
/** Flag: has row_mysql_drop_list been initialized? */
77
static ibool row_mysql_drop_list_inited = FALSE;
79
/** Magic table names for invoking various monitor threads */
81
static const char S_innodb_monitor[] = "innodb_monitor";
82
static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
83
static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
84
static const char S_innodb_table_monitor[] = "innodb_table_monitor";
85
static const char S_innodb_mem_validate[] = "innodb_mem_validate";
88
/** Evaluates to true if str1 equals str2_onstack, used for comparing
89
the magic table names.
90
@param str1 in: string to compare
91
@param str1_len in: length of str1, in bytes, including terminating NUL
92
@param str2_onstack in: char[] array containing a NUL terminated string
93
@return TRUE if str1 equals str2_onstack */
94
#define STR_EQ(str1, str1_len, str2_onstack) \
95
((str1_len) == sizeof(str2_onstack) \
96
&& memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
98
/*********************************************************************//**
99
If a table is not yet in the drop list, adds the table to the list of tables
100
which the master thread drops in background. We need this on Unix because in
101
ALTER TABLE MySQL may call drop table even if the table has running queries on
102
it. Also, if there are running foreign key checks on the table, we drop the
104
@return TRUE if the table was not yet in the drop list, and was added there */
107
row_add_table_to_background_drop_list(
108
/*==================================*/
109
const char* name); /*!< in: table name */
111
/*******************************************************************//**
112
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
115
row_mysql_delay_if_needed(void)
116
/*===========================*/
118
if (srv_dml_needed_delay) {
119
os_thread_sleep(srv_dml_needed_delay);
123
/*******************************************************************//**
124
Frees the blob heap in prebuilt when no longer needed. */
127
row_mysql_prebuilt_free_blob_heap(
128
/*==============================*/
129
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct of a
130
ha_innobase:: table handle */
132
mem_heap_free(prebuilt->blob_heap);
133
prebuilt->blob_heap = NULL;
136
/*******************************************************************//**
137
Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
139
@return pointer to the data, we skip the 1 or 2 bytes at the start
140
that are used to store the len */
143
row_mysql_store_true_var_len(
144
/*=========================*/
145
byte* dest, /*!< in: where to store */
146
ulint len, /*!< in: length, must fit in two bytes */
147
ulint lenlen) /*!< in: storage length of len: either 1 or 2 bytes */
150
ut_a(len < 256 * 256);
152
mach_write_to_2_little_endian(dest, len);
160
mach_write_to_1(dest, len);
165
/*******************************************************************//**
166
Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
167
returns a pointer to the data.
168
@return pointer to the data, we skip the 1 or 2 bytes at the start
169
that are used to store the len */
172
row_mysql_read_true_varchar(
173
/*========================*/
174
ulint* len, /*!< out: variable-length field length */
175
const byte* field, /*!< in: field in the MySQL format */
176
ulint lenlen) /*!< in: storage length of len: either 1
180
*len = mach_read_from_2_little_endian(field);
187
*len = mach_read_from_1(field);
192
/*******************************************************************//**
193
Stores a reference to a BLOB in the MySQL format. */
196
row_mysql_store_blob_ref(
197
/*=====================*/
198
byte* dest, /*!< in: where to store */
199
ulint col_len,/*!< in: dest buffer size: determines into
200
how many bytes the BLOB length is stored,
201
the space for the length may vary from 1
203
const void* data, /*!< in: BLOB data; if the value to store
204
is SQL NULL this should be NULL pointer */
205
ulint len) /*!< in: BLOB length; if the value to store
206
is SQL NULL this should be 0; remember
207
also to set the NULL bit in the MySQL record
210
/* MySQL might assume the field is set to zero except the length and
211
the pointer fields */
213
memset(dest, '\0', col_len);
215
/* In dest there are 1 - 4 bytes reserved for the BLOB length,
216
and after that 8 bytes reserved for the pointer to the data.
217
In 32-bit architectures we only use the first 4 bytes of the pointer
220
ut_a(col_len - 8 > 1 || len < 256);
221
ut_a(col_len - 8 > 2 || len < 256 * 256);
222
ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
224
mach_write_to_n_little_endian(dest, col_len - 8, len);
226
memcpy(dest + col_len - 8, &data, sizeof data);
229
/*******************************************************************//**
230
Reads a reference to a BLOB in the MySQL format.
231
@return pointer to BLOB data */
234
row_mysql_read_blob_ref(
235
/*====================*/
236
ulint* len, /*!< out: BLOB length */
237
const byte* ref, /*!< in: BLOB reference in the
239
ulint col_len) /*!< in: BLOB reference length
244
*len = mach_read_from_n_little_endian(ref, col_len - 8);
246
memcpy(&data, ref + col_len - 8, sizeof data);
251
/**************************************************************//**
252
Pad a column with spaces. */
257
ulint mbminlen, /*!< in: minimum size of a character,
259
byte* pad, /*!< out: padded buffer */
260
ulint len) /*!< in: number of bytes to pad */
264
switch (UNIV_EXPECT(mbminlen, 1)) {
269
memset(pad, 0x20, len);
278
} while (pad < pad_end);
281
/* space=0x00000020 */
289
} while (pad < pad_end);
294
/**************************************************************//**
295
Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
296
The counterpart of this function is row_sel_field_store_in_mysql_format() in
298
@return up to which byte we used buf in the conversion */
301
row_mysql_store_col_in_innobase_format(
302
/*===================================*/
303
dfield_t* dfield, /*!< in/out: dfield where dtype
304
information must be already set when
305
this function is called! */
306
byte* buf, /*!< in/out: buffer for a converted
307
integer value; this must be at least
308
col_len long then! */
309
ibool row_format_col, /*!< TRUE if the mysql_data is from
310
a MySQL row, FALSE if from a MySQL
312
in MySQL, a true VARCHAR storage
313
format differs in a row and in a
314
key value: in a key value the length
315
is always stored in 2 bytes! */
316
const byte* mysql_data, /*!< in: MySQL column value, not
317
SQL NULL; NOTE that dfield may also
318
get a pointer to mysql_data,
319
therefore do not discard this as long
320
as dfield is used! */
321
ulint col_len, /*!< in: MySQL column length; NOTE that
322
this is the storage length of the
323
column in the MySQL format row, not
324
necessarily the length of the actual
325
payload data; if the column is a true
326
VARCHAR then this is irrelevant */
327
ulint comp) /*!< in: nonzero=compact format */
329
const byte* ptr = mysql_data;
330
const dtype_t* dtype;
334
dtype = dfield_get_type(dfield);
338
if (type == DATA_INT) {
339
/* Store integer data in Innobase in a big-endian format,
340
sign bit negated if the data is a signed integer. In MySQL,
341
integers are stored in a little-endian format. */
343
byte* p = buf + col_len;
354
if (!(dtype->prtype & DATA_UNSIGNED)) {
361
} else if ((type == DATA_VARCHAR
362
|| type == DATA_VARMYSQL
363
|| type == DATA_BINARY)) {
365
if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
366
/* The length of the actual data is stored to 1 or 2
367
bytes at the start of the field */
369
if (row_format_col) {
370
if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
376
/* In a MySQL key value, lenlen is always 2 */
380
ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
383
/* Remove trailing spaces from old style VARCHAR
386
/* Handle Unicode strings differently. */
387
ulint mbminlen = dtype_get_mbminlen(dtype);
395
/* space=0x00000020 */
396
/* Trim "half-chars", just in case. */
400
&& ptr[col_len - 4] == 0x00
401
&& ptr[col_len - 3] == 0x00
402
&& ptr[col_len - 2] == 0x00
403
&& ptr[col_len - 1] == 0x20) {
409
/* Trim "half-chars", just in case. */
412
while (col_len >= 2 && ptr[col_len - 2] == 0x00
413
&& ptr[col_len - 1] == 0x20) {
420
&& ptr[col_len - 1] == 0x20) {
425
} else if (comp && type == DATA_MYSQL
426
&& dtype_get_mbminlen(dtype) == 1
427
&& dtype_get_mbmaxlen(dtype) > 1) {
428
/* In some cases we strip trailing spaces from UTF-8 and other
429
multibyte charsets, from FIXED-length CHAR columns, to save
430
space. UTF-8 would otherwise normally use 3 * the string length
431
bytes to store an ASCII string! */
433
/* We assume that this CHAR field is encoded in a
434
variable-length character set where spaces have
435
1:1 correspondence to 0x20 bytes, such as UTF-8.
437
Consider a CHAR(n) field, a field of n characters.
438
It will contain between n * mbminlen and n * mbmaxlen bytes.
439
We will try to truncate it to n bytes by stripping
440
space padding. If the field contains single-byte
441
characters only, it will be truncated to n characters.
442
Consider a CHAR(5) field containing the string ".a "
443
where "." denotes a 3-byte character represented by
444
the bytes "$%&". After our stripping, the string will
445
be stored as "$%&a " (5 bytes). The string ".abc "
446
will be stored as "$%&abc" (6 bytes).
448
The space padding will be restored in row0sel.c, function
449
row_sel_field_store_in_mysql_format(). */
453
ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
455
n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
457
/* Strip space padding. */
458
while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
461
} else if (type == DATA_BLOB && row_format_col) {
463
ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
466
dfield_set_data(dfield, ptr, col_len);
471
/**************************************************************//**
472
Convert a row in the MySQL format to a row in the Innobase format. Note that
473
the function to convert a MySQL format key value to an InnoDB dtuple is
474
row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
477
row_mysql_convert_row_to_innobase(
478
/*==============================*/
479
dtuple_t* row, /*!< in/out: Innobase row where the
480
field type information is already
482
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct where template
483
must be of type ROW_MYSQL_WHOLE_ROW */
484
byte* mysql_rec) /*!< in: row in the MySQL format;
485
NOTE: do not discard as long as
486
row is used, as row may contain
487
pointers to this record! */
489
const mysql_row_templ_t*templ;
493
ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
494
ut_ad(prebuilt->mysql_template);
496
for (i = 0; i < prebuilt->n_template; i++) {
498
templ = prebuilt->mysql_template + i;
499
dfield = dtuple_get_nth_field(row, i);
501
if (templ->mysql_null_bit_mask != 0) {
502
/* Column may be SQL NULL */
504
if (mysql_rec[templ->mysql_null_byte_offset]
505
& (byte) (templ->mysql_null_bit_mask)) {
509
dfield_set_null(dfield);
515
row_mysql_store_col_in_innobase_format(
517
prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
518
TRUE, /* MySQL row format data */
519
mysql_rec + templ->mysql_col_offset,
520
templ->mysql_col_len,
521
dict_table_is_comp(prebuilt->table));
527
/****************************************************************//**
528
Handles user errors and lock waits detected by the database engine.
529
@return TRUE if it was a lock wait and we should continue running the
530
query thread and in that case the thr is ALREADY in the running state. */
533
row_mysql_handle_errors(
534
/*====================*/
535
ulint* new_err,/*!< out: possible new error encountered in
536
lock wait, or if no new error, the value
537
of trx->error_state at the entry of this
539
trx_t* trx, /*!< in: transaction */
540
que_thr_t* thr, /*!< in: query thread */
541
trx_savept_t* savept) /*!< in: savepoint or NULL */
546
err = trx->error_state;
548
ut_a(err != DB_SUCCESS);
550
trx->error_state = DB_SUCCESS;
553
case DB_LOCK_WAIT_TIMEOUT:
554
if (row_rollback_on_timeout) {
555
trx_general_rollback_for_mysql(trx, NULL);
559
case DB_DUPLICATE_KEY:
560
case DB_FOREIGN_DUPLICATE_KEY:
561
case DB_TOO_BIG_RECORD:
562
case DB_ROW_IS_REFERENCED:
563
case DB_NO_REFERENCED_ROW:
564
case DB_CANNOT_ADD_CONSTRAINT:
565
case DB_TOO_MANY_CONCURRENT_TRXS:
566
case DB_OUT_OF_FILE_SPACE:
569
/* Roll back the latest, possibly incomplete
570
insertion or update */
572
trx_general_rollback_for_mysql(trx, savept);
574
/* MySQL will roll back the latest SQL statement */
577
srv_suspend_mysql_thread(thr);
579
if (trx->error_state != DB_SUCCESS) {
580
que_thr_stop_for_mysql(thr);
582
goto handle_new_error;
590
case DB_LOCK_TABLE_FULL:
591
/* Roll back the whole transaction; this resolution was added
592
to version 3.23.43 */
594
trx_general_rollback_for_mysql(trx, NULL);
597
case DB_MUST_GET_MORE_FILE_SPACE:
598
fputs("InnoDB: The database cannot continue"
599
" operation because of\n"
600
"InnoDB: lack of space. You must add"
601
" a new data file to\n"
602
"InnoDB: my.cnf and restart the database.\n", stderr);
607
fputs("InnoDB: We detected index corruption"
608
" in an InnoDB type table.\n"
609
"InnoDB: You have to dump + drop + reimport"
610
" the table or, in\n"
611
"InnoDB: a case of widespread corruption,"
613
"InnoDB: tables and recreate the"
614
" whole InnoDB tablespace.\n"
615
"InnoDB: If the mysqld server crashes"
616
" after the startup or when\n"
617
"InnoDB: you dump the tables, look at\n"
618
"InnoDB: " REFMAN "forcing-recovery.html"
619
" for help.\n", stderr);
621
case DB_FOREIGN_EXCEED_MAX_CASCADE:
622
fprintf(stderr, "InnoDB: Cannot delete/update rows with"
623
" cascading foreign key constraints that exceed max"
625
"Please drop excessive foreign constraints"
626
" and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
629
fprintf(stderr, "InnoDB: unknown error code %lu\n",
634
if (trx->error_state != DB_SUCCESS) {
635
*new_err = trx->error_state;
640
trx->error_state = DB_SUCCESS;
645
/********************************************************************//**
646
Create a prebuilt struct for a MySQL table handle.
647
@return own: a prebuilt struct */
652
dict_table_t* table) /*!< in: Innobase table handle */
654
row_prebuilt_t* prebuilt;
656
dict_index_t* clust_index;
660
heap = mem_heap_create(sizeof *prebuilt + 128);
662
prebuilt = static_cast<row_prebuilt_t *>(mem_heap_zalloc(heap, sizeof *prebuilt));
664
prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
665
prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
667
prebuilt->table = table;
669
prebuilt->sql_stat_start = TRUE;
670
prebuilt->heap = heap;
672
prebuilt->pcur = btr_pcur_create_for_mysql();
673
prebuilt->clust_pcur = btr_pcur_create_for_mysql();
675
prebuilt->select_lock_type = LOCK_NONE;
676
prebuilt->stored_select_lock_type = 99999999;
677
UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
678
sizeof prebuilt->stored_select_lock_type);
680
prebuilt->search_tuple = dtuple_create(
681
heap, 2 * dict_table_get_n_cols(table));
683
clust_index = dict_table_get_first_index(table);
685
/* Make sure that search_tuple is long enough for clustered index */
686
ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
688
ref_len = dict_index_get_n_unique(clust_index);
690
ref = dtuple_create(heap, ref_len);
692
dict_index_copy_types(ref, clust_index, ref_len);
694
prebuilt->clust_ref = ref;
696
prebuilt->autoinc_error = 0;
697
prebuilt->autoinc_offset = 0;
699
/* Default to 1, we will set the actual value later in
700
ha_innobase::get_auto_increment(). */
701
prebuilt->autoinc_increment = 1;
703
prebuilt->autoinc_last_value = 0;
708
/********************************************************************//**
709
Free a prebuilt struct for a MySQL table handle. */
714
row_prebuilt_t* prebuilt, /*!< in, own: prebuilt struct */
715
ibool dict_locked) /*!< in: TRUE=data dictionary locked */
720
(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
721
|| prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
724
"InnoDB: Error: trying to free a corrupt\n"
725
"InnoDB: table handle. Magic n %lu,"
726
" magic n2 %lu, table name ",
727
(ulong) prebuilt->magic_n,
728
(ulong) prebuilt->magic_n2);
729
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
732
mem_analyze_corruption(prebuilt);
737
prebuilt->magic_n = ROW_PREBUILT_FREED;
738
prebuilt->magic_n2 = ROW_PREBUILT_FREED;
740
btr_pcur_free_for_mysql(prebuilt->pcur);
741
btr_pcur_free_for_mysql(prebuilt->clust_pcur);
743
if (prebuilt->mysql_template) {
744
mem_free(prebuilt->mysql_template);
747
if (prebuilt->ins_graph) {
748
que_graph_free_recursive(prebuilt->ins_graph);
751
if (prebuilt->sel_graph) {
752
que_graph_free_recursive(prebuilt->sel_graph);
755
if (prebuilt->upd_graph) {
756
que_graph_free_recursive(prebuilt->upd_graph);
759
if (prebuilt->blob_heap) {
760
mem_heap_free(prebuilt->blob_heap);
763
if (prebuilt->old_vers_heap) {
764
mem_heap_free(prebuilt->old_vers_heap);
767
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
768
if (prebuilt->fetch_cache[i] != NULL) {
770
if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
771
(prebuilt->fetch_cache[i]) - 4))
772
|| (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
773
(prebuilt->fetch_cache[i])
774
+ prebuilt->mysql_row_len))) {
775
fputs("InnoDB: Error: trying to free"
776
" a corrupt fetch buffer.\n", stderr);
778
mem_analyze_corruption(
779
prebuilt->fetch_cache[i]);
784
mem_free((prebuilt->fetch_cache[i]) - 4);
788
dict_table_decrement_handle_count(prebuilt->table, dict_locked);
790
mem_heap_free(prebuilt->heap);
793
/*********************************************************************//**
794
Updates the transaction pointers in query graphs stored in the prebuilt
798
row_update_prebuilt_trx(
799
/*====================*/
800
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct
802
trx_t* trx) /*!< in: transaction handle */
804
if (trx->magic_n != TRX_MAGIC_N) {
806
"InnoDB: Error: trying to use a corrupt\n"
807
"InnoDB: trx handle. Magic n %lu\n",
808
(ulong) trx->magic_n);
810
mem_analyze_corruption(trx);
815
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
817
"InnoDB: Error: trying to use a corrupt\n"
818
"InnoDB: table handle. Magic n %lu, table name ",
819
(ulong) prebuilt->magic_n);
820
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
823
mem_analyze_corruption(prebuilt);
830
if (prebuilt->ins_graph) {
831
prebuilt->ins_graph->trx = trx;
834
if (prebuilt->upd_graph) {
835
prebuilt->upd_graph->trx = trx;
838
if (prebuilt->sel_graph) {
839
prebuilt->sel_graph->trx = trx;
843
dtuple_t* row_get_prebuilt_insert_row(row_prebuilt_t* prebuilt);
845
/*********************************************************************//**
846
Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
847
has not yet been built in the prebuilt struct, then this function first
849
@return prebuilt dtuple; the column type information is also set in it */
851
row_get_prebuilt_insert_row(
852
/*========================*/
853
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
858
dict_table_t* table = prebuilt->table;
860
ut_ad(prebuilt && table && prebuilt->trx);
862
if (prebuilt->ins_node == NULL) {
864
/* Not called before for this handle: create an insert node
865
and query graph to the prebuilt struct */
867
node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
869
prebuilt->ins_node = node;
871
if (prebuilt->ins_upd_rec_buff == NULL) {
872
prebuilt->ins_upd_rec_buff = static_cast<byte *>(mem_heap_alloc(
873
prebuilt->heap, prebuilt->mysql_row_len));
876
row = dtuple_create(prebuilt->heap,
877
dict_table_get_n_cols(table));
879
dict_table_copy_types(row, table);
881
ins_node_set_new_row(node, row);
883
prebuilt->ins_graph = static_cast<que_fork_t *>(que_node_get_parent(
884
pars_complete_graph_for_exec(node,
887
prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
890
return(prebuilt->ins_node->row);
893
/*********************************************************************//**
894
Updates the table modification counter and calculates new estimates
895
for table and index statistics if necessary. */
898
row_update_statistics_if_needed(
899
/*============================*/
900
dict_table_t* table) /*!< in: table */
904
counter = table->stat_modified_counter;
906
table->stat_modified_counter = counter + 1;
908
/* Calculate new statistics if 1 / 16 of table has been modified
909
since the last time a statistics batch was run, or if
910
stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
911
We calculate statistics at most every 16th round, since we may have
912
a counter table which is very small and updated very often. */
914
if (counter > 2000000000
915
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
917
dict_update_statistics(table, FALSE /* update even if stats
922
/*********************************************************************//**
923
Unlocks AUTO_INC type locks that were possibly reserved by a trx. This
924
function should be called at the the end of an SQL statement, by the
925
connection thread that owns the transaction (trx->mysql_thd). */
928
row_unlock_table_autoinc_for_mysql(
929
/*===============================*/
930
trx_t* trx) /*!< in/out: transaction */
932
if (lock_trx_holds_autoinc_locks(trx)) {
933
mutex_enter(&kernel_mutex);
935
lock_release_autoinc_locks(trx);
937
mutex_exit(&kernel_mutex);
941
/*********************************************************************//**
942
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
943
AUTO_INC lock gives exclusive access to the auto-inc counter of the
944
table. The lock is reserved only for the duration of an SQL statement.
945
It is not compatible with another AUTO_INC or exclusive lock on the
947
@return error code or DB_SUCCESS */
950
row_lock_table_autoinc_for_mysql(
951
/*=============================*/
952
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in the MySQL
955
trx_t* trx = prebuilt->trx;
956
ins_node_t* node = prebuilt->ins_node;
957
const dict_table_t* table = prebuilt->table;
963
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
965
/* If we already hold an AUTOINC lock on the table then do nothing.
966
Note: We peek at the value of the current owner without acquiring
967
the kernel mutex. **/
968
if (trx == table->autoinc_trx) {
973
trx->op_info = "setting auto-inc lock";
976
row_get_prebuilt_insert_row(prebuilt);
977
node = prebuilt->ins_node;
980
/* We use the insert query graph as the dummy graph needed
981
in the lock module call */
983
thr = que_fork_get_first_thr(prebuilt->ins_graph);
985
que_thr_move_to_run_state_for_mysql(thr, trx);
988
thr->run_node = node;
989
thr->prev_node = node;
991
/* It may be that the current session has not yet started
992
its transaction, or it has been committed: */
994
trx_start_if_not_started(trx);
996
err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
998
trx->error_state = err;
1000
if (err != DB_SUCCESS) {
1001
que_thr_stop_for_mysql(thr);
1003
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1005
if (was_lock_wait) {
1014
que_thr_stop_for_mysql_no_error(thr, trx);
1021
/*********************************************************************//**
1022
Sets a table lock on the table mentioned in prebuilt.
1023
@return error code or DB_SUCCESS */
1026
row_lock_table_for_mysql(
1027
/*=====================*/
1028
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in the MySQL
1030
dict_table_t* table, /*!< in: table to lock, or NULL
1031
if prebuilt->table should be
1033
prebuilt->select_lock_type */
1034
ulint mode) /*!< in: lock mode of table
1035
(ignored if table==NULL) */
1037
trx_t* trx = prebuilt->trx;
1040
ibool was_lock_wait;
1043
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1045
trx->op_info = "setting table lock";
1047
if (prebuilt->sel_graph == NULL) {
1048
/* Build a dummy select query graph */
1049
row_prebuild_sel_graph(prebuilt);
1052
/* We use the select query graph as the dummy graph needed
1053
in the lock module call */
1055
thr = que_fork_get_first_thr(prebuilt->sel_graph);
1057
que_thr_move_to_run_state_for_mysql(thr, trx);
1060
thr->run_node = thr;
1061
thr->prev_node = thr->common.parent;
1063
/* It may be that the current session has not yet started
1064
its transaction, or it has been committed: */
1066
trx_start_if_not_started(trx);
1069
err = lock_table(0, table, static_cast<lock_mode>(mode), thr);
1071
err = lock_table(0, prebuilt->table,
1072
static_cast<lock_mode>(prebuilt->select_lock_type), thr);
1075
trx->error_state = err;
1077
if (err != DB_SUCCESS) {
1078
que_thr_stop_for_mysql(thr);
1080
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1082
if (was_lock_wait) {
1091
que_thr_stop_for_mysql_no_error(thr, trx);
1098
/*********************************************************************//**
1099
Does an insert for MySQL.
1100
@return error code or DB_SUCCESS */
1103
row_insert_for_mysql(
1104
/*=================*/
1105
byte* mysql_rec, /*!< in: row in the MySQL format */
1106
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1109
trx_savept_t savept;
1112
ibool was_lock_wait;
1113
trx_t* trx = prebuilt->trx;
1114
ins_node_t* node = prebuilt->ins_node;
1117
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1119
if (prebuilt->table->ibd_file_missing) {
1120
ut_print_timestamp(stderr);
1121
fprintf(stderr, " InnoDB: Error:\n"
1122
"InnoDB: MySQL is trying to use a table handle"
1123
" but the .ibd file for\n"
1124
"InnoDB: table %s does not exist.\n"
1125
"InnoDB: Have you deleted the .ibd file"
1126
" from the database directory under\n"
1127
"InnoDB: the MySQL datadir, or have you"
1128
" used DISCARD TABLESPACE?\n"
1129
"InnoDB: Look from\n"
1130
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1131
"InnoDB: how you can resolve the problem.\n",
1132
prebuilt->table->name);
1136
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1138
"InnoDB: Error: trying to free a corrupt\n"
1139
"InnoDB: table handle. Magic n %lu, table name ",
1140
(ulong) prebuilt->magic_n);
1141
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1144
mem_analyze_corruption(prebuilt);
1149
if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1150
fputs("InnoDB: A new raw disk partition was initialized or\n"
1151
"InnoDB: innodb_force_recovery is on: we do not allow\n"
1152
"InnoDB: database modifications by the user. Shut down\n"
1153
"InnoDB: mysqld and edit my.cnf so that"
1154
" newraw is replaced\n"
1155
"InnoDB: with raw, and innodb_force_... is removed.\n",
1161
trx->op_info = "inserting";
1163
row_mysql_delay_if_needed();
1165
trx_start_if_not_started(trx);
1168
row_get_prebuilt_insert_row(prebuilt);
1169
node = prebuilt->ins_node;
1172
row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1174
savept = trx_savept_take(trx);
1176
thr = que_fork_get_first_thr(prebuilt->ins_graph);
1178
if (prebuilt->sql_stat_start) {
1179
node->state = INS_NODE_SET_IX_LOCK;
1180
prebuilt->sql_stat_start = FALSE;
1182
node->state = INS_NODE_ALLOC_ROW_ID;
1185
que_thr_move_to_run_state_for_mysql(thr, trx);
1188
thr->run_node = node;
1189
thr->prev_node = node;
1193
err = trx->error_state;
1195
if (err != DB_SUCCESS) {
1196
que_thr_stop_for_mysql(thr);
1198
/* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1200
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1202
thr->lock_state= QUE_THR_LOCK_NOLOCK;
1204
if (was_lock_wait) {
1213
que_thr_stop_for_mysql_no_error(thr, trx);
1215
prebuilt->table->stat_n_rows++;
1217
srv_n_rows_inserted++;
1219
if (prebuilt->table->stat_n_rows == 0) {
1220
/* Avoid wrap-over */
1221
prebuilt->table->stat_n_rows--;
1224
row_update_statistics_if_needed(prebuilt->table);
1230
/*********************************************************************//**
1231
Builds a dummy query graph used in selects. */
1234
row_prebuild_sel_graph(
1235
/*===================*/
1236
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1241
ut_ad(prebuilt && prebuilt->trx);
1243
if (prebuilt->sel_graph == NULL) {
1245
node = sel_node_create(prebuilt->heap);
1247
prebuilt->sel_graph = static_cast<que_fork_t *>(que_node_get_parent(
1248
pars_complete_graph_for_exec(node,
1252
prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1256
/*********************************************************************//**
1257
Creates an query graph node of 'update' type to be used in the MySQL
1259
@return own: update node */
1262
row_create_update_node_for_mysql(
1263
/*=============================*/
1264
dict_table_t* table, /*!< in: table to update */
1265
mem_heap_t* heap) /*!< in: mem heap from which allocated */
1269
node = upd_node_create(heap);
1271
node->in_mysql_interface = TRUE;
1272
node->is_delete = FALSE;
1273
node->searched_update = FALSE;
1274
node->select = NULL;
1275
node->pcur = btr_pcur_create_for_mysql();
1276
node->table = table;
1278
node->update = upd_create(dict_table_get_n_cols(table), heap);
1280
node->update_n_fields = dict_table_get_n_cols(table);
1282
UT_LIST_INIT(node->columns);
1283
node->has_clust_rec_x_lock = TRUE;
1284
node->cmpl_info = 0;
1286
node->table_sym = NULL;
1287
node->col_assign_list = NULL;
1292
/*********************************************************************//**
1293
Gets pointer to a prebuilt update vector used in updates. If the update
1294
graph has not yet been built in the prebuilt struct, then this function
1296
@return prebuilt update vector */
1299
row_get_prebuilt_update_vector(
1300
/*===========================*/
1301
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1304
dict_table_t* table = prebuilt->table;
1307
ut_ad(prebuilt && table && prebuilt->trx);
1309
if (prebuilt->upd_node == NULL) {
1311
/* Not called before for this handle: create an update node
1312
and query graph to the prebuilt struct */
1314
node = row_create_update_node_for_mysql(table, prebuilt->heap);
1316
prebuilt->upd_node = node;
1318
prebuilt->upd_graph = static_cast<que_fork_t *>(que_node_get_parent(
1319
pars_complete_graph_for_exec(node,
1322
prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1325
return(prebuilt->upd_node->update);
1328
/*********************************************************************//**
1329
Does an update or delete of a row for MySQL.
1330
@return error code or DB_SUCCESS */
1333
row_update_for_mysql(
1334
/*=================*/
1335
byte* mysql_rec, /*!< in: the row to be updated, in
1337
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1340
trx_savept_t savept;
1343
ibool was_lock_wait;
1344
dict_index_t* clust_index;
1345
/* ulint ref_len; */
1347
dict_table_t* table = prebuilt->table;
1348
trx_t* trx = prebuilt->trx;
1350
ut_ad(prebuilt && trx);
1351
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1352
UT_NOT_USED(mysql_rec);
1354
if (prebuilt->table->ibd_file_missing) {
1355
ut_print_timestamp(stderr);
1356
fprintf(stderr, " InnoDB: Error:\n"
1357
"InnoDB: MySQL is trying to use a table handle"
1358
" but the .ibd file for\n"
1359
"InnoDB: table %s does not exist.\n"
1360
"InnoDB: Have you deleted the .ibd file"
1361
" from the database directory under\n"
1362
"InnoDB: the MySQL datadir, or have you"
1363
" used DISCARD TABLESPACE?\n"
1364
"InnoDB: Look from\n"
1365
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1366
"InnoDB: how you can resolve the problem.\n",
1367
prebuilt->table->name);
1371
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1373
"InnoDB: Error: trying to free a corrupt\n"
1374
"InnoDB: table handle. Magic n %lu, table name ",
1375
(ulong) prebuilt->magic_n);
1376
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1379
mem_analyze_corruption(prebuilt);
1384
if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1385
fputs("InnoDB: A new raw disk partition was initialized or\n"
1386
"InnoDB: innodb_force_recovery is on: we do not allow\n"
1387
"InnoDB: database modifications by the user. Shut down\n"
1388
"InnoDB: mysqld and edit my.cnf so that newraw"
1390
"InnoDB: with raw, and innodb_force_... is removed.\n",
1396
trx->op_info = "updating or deleting";
1398
row_mysql_delay_if_needed();
1400
trx_start_if_not_started(trx);
1402
node = prebuilt->upd_node;
1404
clust_index = dict_table_get_first_index(table);
1406
if (prebuilt->pcur->btr_cur.index == clust_index) {
1407
btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1409
btr_pcur_copy_stored_position(node->pcur,
1410
prebuilt->clust_pcur);
1413
ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1415
/* MySQL seems to call rnd_pos before updating each row it
1416
has cached: we can get the correct cursor position from
1417
prebuilt->pcur; NOTE that we cannot build the row reference
1418
from mysql_rec if the clustered index was automatically
1419
generated for the table: MySQL does not know anything about
1420
the row id used as the clustered index key */
1422
savept = trx_savept_take(trx);
1424
thr = que_fork_get_first_thr(prebuilt->upd_graph);
1426
node->state = UPD_NODE_UPDATE_CLUSTERED;
1428
ut_ad(!prebuilt->sql_stat_start);
1430
que_thr_move_to_run_state_for_mysql(thr, trx);
1433
thr->run_node = node;
1434
thr->prev_node = node;
1435
thr->fk_cascade_depth = 0;
1439
/* The recursive call for cascading update/delete happens
1440
in above row_upd_step(), reset the counter once we come
1441
out of the recursive call, so it does not accumulate for
1442
different row deletes */
1443
thr->fk_cascade_depth = 0;
1445
err = trx->error_state;
1447
/* Reset fk_cascade_depth back to 0 */
1448
thr->fk_cascade_depth = 0;
1450
if (err != DB_SUCCESS) {
1451
que_thr_stop_for_mysql(thr);
1453
if (err == DB_RECORD_NOT_FOUND) {
1454
trx->error_state = DB_SUCCESS;
1460
thr->lock_state= QUE_THR_LOCK_ROW;
1461
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1463
thr->lock_state= QUE_THR_LOCK_NOLOCK;
1465
if (was_lock_wait) {
1474
que_thr_stop_for_mysql_no_error(thr, trx);
1476
if (node->is_delete) {
1477
if (prebuilt->table->stat_n_rows > 0) {
1478
prebuilt->table->stat_n_rows--;
1481
srv_n_rows_deleted++;
1483
srv_n_rows_updated++;
1486
/* We update table statistics only if it is a DELETE or UPDATE
1487
that changes indexed columns, UPDATEs that change only non-indexed
1488
columns would not affect statistics. */
1489
if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1490
row_update_statistics_if_needed(prebuilt->table);
1498
/*********************************************************************//**
1499
This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
1500
session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
1501
Before calling this function row_search_for_mysql() must have
1502
initialized prebuilt->new_rec_locks to store the information which new
1503
record locks really were set. This function removes a newly set
1504
clustered index record lock under prebuilt->pcur or
1505
prebuilt->clust_pcur. Thus, this implements a 'mini-rollback' that
1506
releases the latest clustered index record lock we set.
1507
@return error code or DB_SUCCESS */
1510
row_unlock_for_mysql(
1511
/*=================*/
1512
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct in MySQL
1514
ibool has_latches_on_recs)/*!< in: TRUE if called so
1515
that we have the latches on
1516
the records under pcur and
1517
clust_pcur, and we do not need
1518
to reposition the cursors. */
1520
btr_pcur_t* pcur = prebuilt->pcur;
1521
btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
1522
trx_t* trx = prebuilt->trx;
1524
ut_ad(prebuilt && trx);
1525
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1528
(!srv_locks_unsafe_for_binlog
1529
&& trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
1532
"InnoDB: Error: calling row_unlock_for_mysql though\n"
1533
"InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
1534
"InnoDB: this session is not using"
1535
" READ COMMITTED isolation level.\n");
1540
trx->op_info = "unlock_row";
1542
if (prebuilt->new_rec_locks >= 1) {
1545
dict_index_t* index;
1546
trx_id_t rec_trx_id;
1551
/* Restore the cursor position and find the record */
1553
if (!has_latches_on_recs) {
1554
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1557
rec = btr_pcur_get_rec(pcur);
1558
index = btr_pcur_get_btr_cur(pcur)->index;
1560
if (prebuilt->new_rec_locks >= 2) {
1561
/* Restore the cursor position and find the record
1562
in the clustered index. */
1564
if (!has_latches_on_recs) {
1565
btr_pcur_restore_position(BTR_SEARCH_LEAF,
1569
rec = btr_pcur_get_rec(clust_pcur);
1570
index = btr_pcur_get_btr_cur(clust_pcur)->index;
1573
if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
1574
/* This is not a clustered index record. We
1575
do not know how to unlock the record. */
1579
/* If the record has been modified by this
1580
transaction, do not unlock it. */
1582
if (index->trx_id_offset) {
1583
rec_trx_id = trx_read_trx_id(rec
1584
+ index->trx_id_offset);
1586
mem_heap_t* heap = NULL;
1587
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1588
ulint* offsets = offsets_;
1590
rec_offs_init(offsets_);
1591
offsets = rec_get_offsets(rec, index, offsets,
1592
ULINT_UNDEFINED, &heap);
1594
rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1596
if (UNIV_LIKELY_NULL(heap)) {
1597
mem_heap_free(heap);
1601
if (rec_trx_id != trx->id) {
1602
/* We did not update the record: unlock it */
1604
rec = btr_pcur_get_rec(pcur);
1605
index = btr_pcur_get_btr_cur(pcur)->index;
1607
lock_rec_unlock(trx, btr_pcur_get_block(pcur),
1608
rec, static_cast<lock_mode>(prebuilt->select_lock_type));
1610
if (prebuilt->new_rec_locks >= 2) {
1611
rec = btr_pcur_get_rec(clust_pcur);
1612
index = btr_pcur_get_btr_cur(clust_pcur)->index;
1614
lock_rec_unlock(trx,
1615
btr_pcur_get_block(clust_pcur),
1617
static_cast<lock_mode>(prebuilt->select_lock_type));
1629
/**********************************************************************//**
1630
Does a cascaded delete or set null in a foreign key operation.
1631
@return error code or DB_SUCCESS */
1634
row_update_cascade_for_mysql(
1635
/*=========================*/
1636
que_thr_t* thr, /*!< in: query thread */
1637
upd_node_t* node, /*!< in: update node used in the cascade
1638
or set null operation */
1639
dict_table_t* table) /*!< in: table where we do the operation */
1644
trx = thr_get_trx(thr);
1646
/* Increment fk_cascade_depth to record the recursive call depth on
1647
a single update/delete that affects multiple tables chained
1648
together with foreign key relations. */
1649
thr->fk_cascade_depth++;
1651
if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
1652
return (DB_FOREIGN_EXCEED_MAX_CASCADE);
1655
thr->run_node = node;
1656
thr->prev_node = node;
1660
/* The recursive call for cascading update/delete happens
1661
in above row_upd_step(), reset the counter once we come
1662
out of the recursive call, so it does not accumulate for
1663
different row deletes */
1664
thr->fk_cascade_depth = 0;
1666
err = trx->error_state;
1668
/* Note that the cascade node is a subnode of another InnoDB
1669
query graph node. We do a normal lock wait in this node, but
1670
all errors are handled by the parent node. */
1672
if (err == DB_LOCK_WAIT) {
1673
/* Handle lock wait here */
1675
que_thr_stop_for_mysql(thr);
1677
srv_suspend_mysql_thread(thr);
1679
/* Note that a lock wait may also end in a lock wait timeout,
1680
or this transaction is picked as a victim in selective
1681
deadlock resolution */
1683
if (trx->error_state != DB_SUCCESS) {
1685
return(trx->error_state);
1688
/* Retry operation after a normal lock wait */
1693
if (err != DB_SUCCESS) {
1698
if (node->is_delete) {
1699
if (table->stat_n_rows > 0) {
1700
table->stat_n_rows--;
1703
srv_n_rows_deleted++;
1705
srv_n_rows_updated++;
1708
row_update_statistics_if_needed(table);
1713
/*********************************************************************//**
1714
Checks if a table is such that we automatically created a clustered
1715
index on it (on row id).
1716
@return TRUE if the clustered index was generated automatically */
1719
row_table_got_default_clust_index(
1720
/*==============================*/
1721
const dict_table_t* table) /*!< in: table */
1723
const dict_index_t* clust_index;
1725
clust_index = dict_table_get_first_index(table);
1727
return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1730
/*********************************************************************//**
1731
Locks the data dictionary in shared mode from modifications, for performing
1732
foreign key check, rollback, or other operation invisible to MySQL. */
1735
row_mysql_freeze_data_dictionary_func(
1736
/*==================================*/
1737
trx_t* trx, /*!< in/out: transaction */
1738
const char* file, /*!< in: file name */
1739
ulint line) /*!< in: line number */
1741
ut_a(trx->dict_operation_lock_mode == 0);
1743
rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
1745
trx->dict_operation_lock_mode = RW_S_LATCH;
1748
/*********************************************************************//**
1749
Unlocks the data dictionary shared lock. */
1752
row_mysql_unfreeze_data_dictionary(
1753
/*===============================*/
1754
trx_t* trx) /*!< in/out: transaction */
1756
ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
1758
rw_lock_s_unlock(&dict_operation_lock);
1760
trx->dict_operation_lock_mode = 0;
1763
/*********************************************************************//**
1764
Locks the data dictionary exclusively for performing a table create or other
1765
data dictionary modification operation. */
1768
row_mysql_lock_data_dictionary_func(
1769
/*================================*/
1770
trx_t* trx, /*!< in/out: transaction */
1771
const char* file, /*!< in: file name */
1772
ulint line) /*!< in: line number */
1774
ut_a(trx->dict_operation_lock_mode == 0
1775
|| trx->dict_operation_lock_mode == RW_X_LATCH);
1777
/* Serialize data dictionary operations with dictionary mutex:
1778
no deadlocks or lock waits can occur then in these operations */
1780
rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
1781
trx->dict_operation_lock_mode = RW_X_LATCH;
1783
mutex_enter(&(dict_sys->mutex));
1786
/*********************************************************************//**
1787
Unlocks the data dictionary exclusive lock. */
1790
row_mysql_unlock_data_dictionary(
1791
/*=============================*/
1792
trx_t* trx) /*!< in/out: transaction */
1794
ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1796
/* Serialize data dictionary operations with dictionary mutex:
1797
no deadlocks can occur then in these operations */
1799
mutex_exit(&(dict_sys->mutex));
1800
rw_lock_x_unlock(&dict_operation_lock);
1802
trx->dict_operation_lock_mode = 0;
1805
/*********************************************************************//**
1806
Creates a table for MySQL. If the name of the table ends in
1807
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
1808
"innodb_table_monitor", then this will also start the printing of monitor
1809
output by the master thread. If the table name ends in "innodb_mem_validate",
1810
InnoDB will try to invoke mem_validate().
1811
@return error code or DB_SUCCESS */
1814
row_create_table_for_mysql(
1815
/*=======================*/
1816
dict_table_t* table, /*!< in, own: table definition
1818
trx_t* trx) /*!< in: transaction handle */
1823
const char* table_name;
1824
ulint table_name_len;
1827
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1828
#ifdef UNIV_SYNC_DEBUG
1829
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1830
#endif /* UNIV_SYNC_DEBUG */
1831
ut_ad(mutex_own(&(dict_sys->mutex)));
1832
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1834
if (srv_created_new_raw) {
1835
fputs("InnoDB: A new raw disk partition was initialized:\n"
1836
"InnoDB: we do not allow database modifications"
1838
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1839
" is replaced with raw.\n", stderr);
1840
dict_mem_table_free(table);
1841
trx_commit_for_mysql(trx);
1846
trx->op_info = "creating table";
1848
trx_start_if_not_started(trx);
1850
/* The table name is prefixed with the database name and a '/'.
1851
Certain table names starting with 'innodb_' have their special
1852
meaning regardless of the database name. Thus, we need to
1853
ignore the database name prefix in the comparisons. */
1854
table_name = strchr(table->name, '/');
1857
table_name_len = strlen(table_name) + 1;
1859
if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
1861
/* Table equals "innodb_monitor":
1862
start monitor prints */
1864
srv_print_innodb_monitor = TRUE;
1866
/* The lock timeout monitor thread also takes care
1867
of InnoDB monitor prints */
1869
os_event_set(srv_lock_timeout_thread_event);
1870
} else if (STR_EQ(table_name, table_name_len,
1871
S_innodb_lock_monitor)) {
1873
srv_print_innodb_monitor = TRUE;
1874
srv_print_innodb_lock_monitor = TRUE;
1875
os_event_set(srv_lock_timeout_thread_event);
1876
} else if (STR_EQ(table_name, table_name_len,
1877
S_innodb_tablespace_monitor)) {
1879
srv_print_innodb_tablespace_monitor = TRUE;
1880
os_event_set(srv_lock_timeout_thread_event);
1881
} else if (STR_EQ(table_name, table_name_len,
1882
S_innodb_table_monitor)) {
1884
srv_print_innodb_table_monitor = TRUE;
1885
os_event_set(srv_lock_timeout_thread_event);
1886
} else if (STR_EQ(table_name, table_name_len,
1887
S_innodb_mem_validate)) {
1888
/* We define here a debugging feature intended for
1891
fputs("Validating InnoDB memory:\n"
1892
"to use this feature you must compile InnoDB with\n"
1893
"UNIV_MEM_DEBUG defined in univ.i and"
1894
" the server must be\n"
1895
"quiet because allocation from a mem heap"
1896
" is not protected\n"
1897
"by any semaphore.\n", stderr);
1898
#ifdef UNIV_MEM_DEBUG
1899
ut_a(mem_validate());
1900
fputs("Memory validated\n", stderr);
1901
#else /* UNIV_MEM_DEBUG */
1902
fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1904
#endif /* UNIV_MEM_DEBUG */
1907
heap = mem_heap_create(512);
1909
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1911
node = tab_create_graph_create(table, heap);
1913
thr = pars_complete_graph_for_exec(node, trx, heap);
1915
ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
1916
que_run_threads(thr);
1918
err = trx->error_state;
1923
case DB_OUT_OF_FILE_SPACE:
1924
trx->error_state = DB_SUCCESS;
1925
trx_general_rollback_for_mysql(trx, NULL);
1927
ut_print_timestamp(stderr);
1928
fputs(" InnoDB: Warning: cannot create table ",
1930
ut_print_name(stderr, trx, TRUE, table->name);
1931
fputs(" because tablespace full\n", stderr);
1933
if (dict_table_get_low(table->name)) {
1935
row_drop_table_for_mysql(table->name, trx, FALSE);
1936
trx_commit_for_mysql(trx);
1940
case DB_DUPLICATE_KEY:
1942
/* We may also get err == DB_ERROR if the .ibd file for the
1943
table already exists */
1945
trx->error_state = DB_SUCCESS;
1946
trx_general_rollback_for_mysql(trx, NULL);
1947
dict_mem_table_free(table);
1951
que_graph_free((que_t*) que_node_get_parent(thr));
1958
/*********************************************************************//**
1959
Does an index creation operation for MySQL. TODO: currently failure
1960
to create an index results in dropping the whole table! This is no problem
1961
currently as all indexes must be created at the same time as the table.
1962
@return error number or DB_SUCCESS */
1965
row_create_index_for_mysql(
1966
/*=======================*/
1967
dict_index_t* index, /*!< in, own: index definition
1969
trx_t* trx, /*!< in: transaction handle */
1970
const ulint* field_lengths) /*!< in: if not NULL, must contain
1971
dict_index_get_n_fields(index)
1972
actual field lengths for the
1973
index columns, which are
1974
then checked for not being too
1985
#ifdef UNIV_SYNC_DEBUG
1986
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1987
#endif /* UNIV_SYNC_DEBUG */
1988
ut_ad(mutex_own(&(dict_sys->mutex)));
1989
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1991
trx->op_info = "creating index";
1993
/* Copy the table name because we may want to drop the
1994
table later, after the index object is freed (inside
1995
que_run_threads()) and thus index->table_name is not available. */
1996
table_name = mem_strdup(index->table_name);
1998
trx_start_if_not_started(trx);
2000
/* Check that the same column does not appear twice in the index.
2001
Starting from 4.0.14, InnoDB should be able to cope with that, but
2002
safer not to allow them. */
2004
for (i = 0; i < dict_index_get_n_fields(index); i++) {
2007
for (j = 0; j < i; j++) {
2009
dict_index_get_nth_field(index, j)->name,
2010
dict_index_get_nth_field(index, i)->name)) {
2011
ut_print_timestamp(stderr);
2013
fputs(" InnoDB: Error: column ", stderr);
2014
ut_print_name(stderr, trx, FALSE,
2015
dict_index_get_nth_field(
2017
fputs(" appears twice in ", stderr);
2018
dict_index_name_print(stderr, trx, index);
2020
"InnoDB: This is not allowed"
2021
" in InnoDB.\n", stderr);
2023
err = DB_COL_APPEARS_TWICE_IN_INDEX;
2025
goto error_handling;
2029
/* Check also that prefix_len and actual length
2030
< DICT_MAX_INDEX_COL_LEN */
2032
len = dict_index_get_nth_field(index, i)->prefix_len;
2034
if (field_lengths) {
2035
len = ut_max(len, field_lengths[i]);
2038
if (len >= DICT_MAX_INDEX_COL_LEN) {
2039
err = DB_TOO_BIG_RECORD;
2041
goto error_handling;
2045
heap = mem_heap_create(512);
2047
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2049
/* Note that the space id where we store the index is inherited from
2050
the table in dict_build_index_def_step() in dict0crea.c. */
2052
node = ind_create_graph_create(index, heap);
2054
thr = pars_complete_graph_for_exec(node, trx, heap);
2056
ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
2057
que_run_threads(thr);
2059
err = trx->error_state;
2061
que_graph_free((que_t*) que_node_get_parent(thr));
2064
if (err != DB_SUCCESS) {
2065
/* We have special error handling here */
2067
trx->error_state = DB_SUCCESS;
2069
trx_general_rollback_for_mysql(trx, NULL);
2071
row_drop_table_for_mysql(table_name, trx, FALSE);
2073
trx_commit_for_mysql(trx);
2075
trx->error_state = DB_SUCCESS;
2080
mem_free(table_name);
2085
/*********************************************************************//**
2086
Scans a table create SQL string and adds to the data dictionary
2087
the foreign key constraints declared in the string. This function
2088
should be called after the indexes for a table have been created.
2089
Each foreign key constraint must be accompanied with indexes in
2090
both participating tables. The indexes are allowed to contain more
2091
fields than mentioned in the constraint. Check also that foreign key
2092
constraints which reference this table are ok.
2093
@return error code or DB_SUCCESS */
2096
row_table_add_foreign_constraints(
2097
/*==============================*/
2098
trx_t* trx, /*!< in: transaction */
2099
const char* sql_string, /*!< in: table create statement where
2100
foreign keys are declared like:
2101
FOREIGN KEY (a, b) REFERENCES table2(c, d),
2102
table2 can be written also with the
2103
database name before it: test.table2 */
2104
size_t sql_length, /*!< in: length of sql_string */
2105
const char* name, /*!< in: table full name in the
2107
database_name/table_name */
2108
ibool reject_fks) /*!< in: if TRUE, fail with error
2109
code DB_CANNOT_ADD_CONSTRAINT if
2110
any foreign keys are found. */
2114
ut_ad(mutex_own(&(dict_sys->mutex)));
2115
#ifdef UNIV_SYNC_DEBUG
2116
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2117
#endif /* UNIV_SYNC_DEBUG */
2120
trx->op_info = "adding foreign keys";
2122
trx_start_if_not_started(trx);
2124
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2126
err = dict_create_foreign_constraints(trx, sql_string, sql_length,
2128
if (err == DB_SUCCESS) {
2129
/* Check that also referencing constraints are ok */
2130
err = dict_load_foreigns(name, FALSE, TRUE);
2133
if (err != DB_SUCCESS) {
2134
/* We have special error handling here */
2136
trx->error_state = DB_SUCCESS;
2138
trx_general_rollback_for_mysql(trx, NULL);
2140
row_drop_table_for_mysql(name, trx, FALSE);
2142
trx_commit_for_mysql(trx);
2144
trx->error_state = DB_SUCCESS;
2150
/*********************************************************************//**
2151
Drops a table for MySQL as a background operation. MySQL relies on Unix
2152
in ALTER TABLE to the fact that the table handler does not remove the
2153
table before all handles to it has been removed. Furhermore, the MySQL's
2154
call to drop table must be non-blocking. Therefore we do the drop table
2155
as a background operation, which is taken care of by the master thread
2157
@return error code or DB_SUCCESS */
2160
row_drop_table_for_mysql_in_background(
2161
/*===================================*/
2162
const char* name) /*!< in: table name */
2167
trx = trx_allocate_for_background();
2169
/* If the original transaction was dropping a table referenced by
2170
foreign keys, we must set the following to be able to drop the
2173
trx->check_foreigns = FALSE;
2175
/* fputs("InnoDB: Error: Dropping table ", stderr);
2176
ut_print_name(stderr, trx, TRUE, name);
2177
fputs(" in background drop list\n", stderr); */
2179
/* Try to drop the table in InnoDB */
2181
error = row_drop_table_for_mysql(name, trx, FALSE);
2183
/* Flush the log to reduce probability that the .frm files and
2184
the InnoDB data dictionary get out-of-sync if the user runs
2185
with innodb_flush_log_at_trx_commit = 0 */
2187
log_buffer_flush_to_disk();
2189
trx_commit_for_mysql(trx);
2191
trx_free_for_background(trx);
2193
return((int) error);
2196
/*********************************************************************//**
2197
The master thread in srv0srv.c calls this regularly to drop tables which
2198
we must drop in background after queries to them have ended. Such lazy
2199
dropping of tables is needed in ALTER TABLE on Unix.
2200
@return how many tables dropped + remaining tables in list */
2203
row_drop_tables_for_mysql_in_background(void)
2204
/*=========================================*/
2206
row_mysql_drop_t* drop;
2207
dict_table_t* table;
2209
ulint n_tables_dropped = 0;
2211
mutex_enter(&kernel_mutex);
2213
if (!row_mysql_drop_list_inited) {
2215
UT_LIST_INIT(row_mysql_drop_list);
2216
row_mysql_drop_list_inited = TRUE;
2219
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2221
n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2223
mutex_exit(&kernel_mutex);
2226
/* All tables dropped */
2228
return(n_tables + n_tables_dropped);
2231
mutex_enter(&(dict_sys->mutex));
2232
table = dict_table_get_low(drop->table_name);
2233
mutex_exit(&(dict_sys->mutex));
2235
if (table == NULL) {
2236
/* If for some reason the table has already been dropped
2237
through some other mechanism, do not try to drop it */
2239
goto already_dropped;
2242
if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2243
drop->table_name)) {
2244
/* If the DROP fails for some table, we return, and let the
2245
main thread retry later */
2247
return(n_tables + n_tables_dropped);
2253
mutex_enter(&kernel_mutex);
2255
UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2257
ut_print_timestamp(stderr);
2258
fputs(" InnoDB: Dropped table ", stderr);
2259
ut_print_name(stderr, NULL, TRUE, drop->table_name);
2260
fputs(" in background drop queue.\n", stderr);
2262
mem_free(drop->table_name);
2266
mutex_exit(&kernel_mutex);
2271
/*********************************************************************//**
2272
Get the background drop list length. NOTE: the caller must own the kernel
2274
@return how many tables in list */
2277
row_get_background_drop_list_len_low(void)
2278
/*======================================*/
2280
ut_ad(mutex_own(&kernel_mutex));
2282
if (!row_mysql_drop_list_inited) {
2284
UT_LIST_INIT(row_mysql_drop_list);
2285
row_mysql_drop_list_inited = TRUE;
2288
return(UT_LIST_GET_LEN(row_mysql_drop_list));
2291
/*********************************************************************//**
2292
If a table is not yet in the drop list, adds the table to the list of tables
2293
which the master thread drops in background. We need this on Unix because in
2294
ALTER TABLE MySQL may call drop table even if the table has running queries on
2295
it. Also, if there are running foreign key checks on the table, we drop the
2297
@return TRUE if the table was not yet in the drop list, and was added there */
2300
row_add_table_to_background_drop_list(
2301
/*==================================*/
2302
const char* name) /*!< in: table name */
2304
row_mysql_drop_t* drop;
2306
mutex_enter(&kernel_mutex);
2308
if (!row_mysql_drop_list_inited) {
2310
UT_LIST_INIT(row_mysql_drop_list);
2311
row_mysql_drop_list_inited = TRUE;
2314
/* Look if the table already is in the drop list */
2315
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2317
while (drop != NULL) {
2318
if (strcmp(drop->table_name, name) == 0) {
2319
/* Already in the list */
2321
mutex_exit(&kernel_mutex);
2326
drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2329
drop = static_cast<row_mysql_drop_t *>(mem_alloc(sizeof(row_mysql_drop_t)));
2331
drop->table_name = mem_strdup(name);
2333
UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2335
/* fputs("InnoDB: Adding table ", stderr);
2336
ut_print_name(stderr, trx, TRUE, drop->table_name);
2337
fputs(" to background drop list\n", stderr); */
2339
mutex_exit(&kernel_mutex);
2344
/*********************************************************************//**
2345
Discards the tablespace of a table which stored in an .ibd file. Discarding
2346
means that this function deletes the .ibd file and assigns a new table id for
2347
the table. Also the flag table->ibd_file_missing is set TRUE.
2348
@return error code or DB_SUCCESS */
2351
row_discard_tablespace_for_mysql(
2352
/*=============================*/
2353
const char* name, /*!< in: table name */
2354
trx_t* trx) /*!< in: transaction handle */
2356
dict_foreign_t* foreign;
2358
dict_table_t* table;
2361
pars_info_t* info = NULL;
2363
/* How do we prevent crashes caused by ongoing operations on
2364
the table? Old operations could try to access non-existent
2367
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2368
MySQL table lock on the table before we can do DISCARD
2369
TABLESPACE. Then there are no running queries on the table.
2371
2) Purge and rollback: we assign a new table id for the
2372
table. Since purge and rollback look for the table based on
2373
the table id, they see the table as 'dropped' and discard
2376
3) Insert buffer: we remove all entries for the tablespace in
2377
the insert buffer tree; as long as the tablespace mem object
2378
does not exist, ongoing insert buffer page merges are
2379
discarded in buf0rea.c. If we recreate the tablespace mem
2380
object with IMPORT TABLESPACE later, then the tablespace will
2381
have the same id, but the tablespace_version field in the mem
2382
object is different, and ongoing old insert buffer page merges
2385
4) Linear readahead and random readahead: we use the same
2386
method as in 3) to discard ongoing operations.
2388
5) FOREIGN KEY operations: if
2389
table->n_foreign_key_checks_running > 0, we do not allow the
2390
discard. We also reserve the data dictionary latch. */
2392
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2394
trx->op_info = "discarding tablespace";
2395
trx_start_if_not_started(trx);
2397
/* Serialize data dictionary operations with dictionary mutex:
2398
no deadlocks can occur then in these operations */
2400
row_mysql_lock_data_dictionary(trx);
2402
table = dict_table_get_low(name);
2405
err = DB_TABLE_NOT_FOUND;
2410
if (table->space == 0) {
2411
ut_print_timestamp(stderr);
2412
fputs(" InnoDB: Error: table ", stderr);
2413
ut_print_name(stderr, trx, TRUE, name);
2415
"InnoDB: is in the system tablespace 0"
2416
" which cannot be discarded\n", stderr);
2422
if (table->n_foreign_key_checks_running > 0) {
2424
ut_print_timestamp(stderr);
2425
fputs(" InnoDB: You are trying to DISCARD table ", stderr);
2426
ut_print_name(stderr, trx, TRUE, table->name);
2428
"InnoDB: though there is a foreign key check"
2430
"InnoDB: Cannot discard the table.\n",
2438
/* Check if the table is referenced by foreign key constraints from
2439
some other table (not the table itself) */
2441
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2443
while (foreign && foreign->foreign_table == table) {
2444
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2447
if (foreign && trx->check_foreigns) {
2449
FILE* ef = dict_foreign_err_file;
2451
/* We only allow discarding a referenced table if
2452
FOREIGN_KEY_CHECKS is set to 0 */
2454
err = DB_CANNOT_DROP_CONSTRAINT;
2456
mutex_enter(&dict_foreign_err_mutex);
2458
ut_print_timestamp(ef);
2460
fputs(" Cannot DISCARD table ", ef);
2461
ut_print_name(stderr, trx, TRUE, name);
2463
"because it is referenced by ", ef);
2464
ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
2466
mutex_exit(&dict_foreign_err_mutex);
2471
dict_hdr_get_new_id(&new_id, NULL, NULL);
2473
/* Remove all locks except the table-level S and X locks. */
2474
lock_remove_all_on_table(table, FALSE);
2476
info = pars_info_create();
2478
pars_info_add_str_literal(info, "table_name", name);
2479
pars_info_add_ull_literal(info, "new_id", new_id);
2481
err = que_eval_sql(info,
2482
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2485
"SELECT ID INTO old_id\n"
2487
"WHERE NAME = :table_name\n"
2488
"LOCK IN SHARE MODE;\n"
2489
"IF (SQL % NOTFOUND) THEN\n"
2493
"UPDATE SYS_TABLES SET ID = :new_id\n"
2494
" WHERE ID = old_id;\n"
2495
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2496
" WHERE TABLE_ID = old_id;\n"
2497
"UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2498
" WHERE TABLE_ID = old_id;\n"
2503
if (err != DB_SUCCESS) {
2504
trx->error_state = DB_SUCCESS;
2505
trx_general_rollback_for_mysql(trx, NULL);
2506
trx->error_state = DB_SUCCESS;
2508
dict_table_change_id_in_cache(table, new_id);
2510
success = fil_discard_tablespace(table->space);
2513
trx->error_state = DB_SUCCESS;
2514
trx_general_rollback_for_mysql(trx, NULL);
2515
trx->error_state = DB_SUCCESS;
2519
/* Set the flag which tells that now it is legal to
2520
IMPORT a tablespace for this table */
2521
table->tablespace_discarded = TRUE;
2522
table->ibd_file_missing = TRUE;
2527
trx_commit_for_mysql(trx);
2529
row_mysql_unlock_data_dictionary(trx);
2536
/*****************************************************************//**
2537
Imports a tablespace. The space id in the .ibd file must match the space id
2538
of the table in the data dictionary.
2539
@return error code or DB_SUCCESS */
2542
row_import_tablespace_for_mysql(
2543
/*============================*/
2544
const char* name, /*!< in: table name */
2545
trx_t* trx) /*!< in: transaction handle */
2547
dict_table_t* table;
2549
ib_uint64_t current_lsn;
2550
ulint err = DB_SUCCESS;
2552
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2554
trx_start_if_not_started(trx);
2556
trx->op_info = "importing tablespace";
2558
current_lsn = log_get_lsn();
2560
/* It is possible, though very improbable, that the lsn's in the
2561
tablespace to be imported have risen above the current system lsn, if
2562
a lengthy purge, ibuf merge, or rollback was performed on a backup
2563
taken with ibbackup. If that is the case, reset page lsn's in the
2564
file. We assume that mysqld was shut down after it performed these
2565
cleanup operations on the .ibd file, so that it stamped the latest lsn
2566
to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2568
TODO: reset also the trx id's in clustered index records and write
2569
a new space id to each data page. That would allow us to import clean
2570
.ibd files from another MySQL installation. */
2572
success = fil_reset_too_high_lsns(name, current_lsn);
2575
ut_print_timestamp(stderr);
2576
fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
2577
ut_print_name(stderr, trx, TRUE, name);
2579
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2584
row_mysql_lock_data_dictionary(trx);
2589
/* Serialize data dictionary operations with dictionary mutex:
2590
no deadlocks can occur then in these operations */
2592
row_mysql_lock_data_dictionary(trx);
2594
table = dict_table_get_low(name);
2597
ut_print_timestamp(stderr);
2598
fputs(" InnoDB: table ", stderr);
2599
ut_print_name(stderr, trx, TRUE, name);
2601
"InnoDB: does not exist in the InnoDB data dictionary\n"
2602
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2605
err = DB_TABLE_NOT_FOUND;
2610
if (table->space == 0) {
2611
ut_print_timestamp(stderr);
2612
fputs(" InnoDB: Error: table ", stderr);
2613
ut_print_name(stderr, trx, TRUE, name);
2615
"InnoDB: is in the system tablespace 0"
2616
" which cannot be imported\n", stderr);
2622
if (!table->tablespace_discarded) {
2623
ut_print_timestamp(stderr);
2624
fputs(" InnoDB: Error: you are trying to"
2625
" IMPORT a tablespace\n"
2626
"InnoDB: ", stderr);
2627
ut_print_name(stderr, trx, TRUE, name);
2628
fputs(", though you have not called DISCARD on it yet\n"
2629
"InnoDB: during the lifetime of the mysqld process!\n",
2637
/* Play safe and remove all insert buffer entries, though we should
2638
have removed them already when DISCARD TABLESPACE was called */
2640
ibuf_delete_for_discarded_space(table->space);
2642
success = fil_open_single_table_tablespace(
2644
table->flags == DICT_TF_COMPACT ? 0 : table->flags,
2647
table->ibd_file_missing = FALSE;
2648
table->tablespace_discarded = FALSE;
2650
if (table->ibd_file_missing) {
2651
ut_print_timestamp(stderr);
2652
fputs(" InnoDB: cannot find or open in the"
2653
" database directory the .ibd file of\n"
2654
"InnoDB: table ", stderr);
2655
ut_print_name(stderr, trx, TRUE, name);
2657
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2665
trx_commit_for_mysql(trx);
2667
row_mysql_unlock_data_dictionary(trx);
2674
/*********************************************************************//**
2675
Truncates a table for MySQL.
2676
@return error code or DB_SUCCESS */
2679
row_truncate_table_for_mysql(
2680
/*=========================*/
2681
dict_table_t* table, /*!< in: table handle */
2682
trx_t* trx) /*!< in: transaction handle */
2684
dict_foreign_t* foreign;
2690
dict_index_t* sys_index;
2694
ulint recreate_space = 0;
2695
pars_info_t* info = NULL;
2697
/* How do we prevent crashes caused by ongoing operations on
2698
the table? Old operations could try to access non-existent
2701
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2702
MySQL table lock on the table before we can do TRUNCATE
2703
TABLE. Then there are no running queries on the table. This is
2704
guaranteed, because in ha_innobase::store_lock(), we do not
2705
weaken the TL_WRITE lock requested by MySQL when executing
2708
2) Purge and rollback: we assign a new table id for the
2709
table. Since purge and rollback look for the table based on
2710
the table id, they see the table as 'dropped' and discard
2713
3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2714
so we do not have to remove insert buffer records, as the
2715
insert buffer works at a low level. If a freed page is later
2716
reallocated, the allocator will remove the ibuf entries for
2719
When we truncate *.ibd files by recreating them (analogous to
2720
DISCARD TABLESPACE), we remove all entries for the table in the
2721
insert buffer tree. This is not strictly necessary, because
2722
in 6) we will assign a new tablespace identifier, but we can
2723
free up some space in the system tablespace.
2725
4) Linear readahead and random readahead: we use the same
2726
method as in 3) to discard ongoing operations. (This is only
2727
relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2729
5) FOREIGN KEY operations: if
2730
table->n_foreign_key_checks_running > 0, we do not allow the
2731
TRUNCATE. We also reserve the data dictionary latch.
2733
6) Crash recovery: To prevent the application of pre-truncation
2734
redo log records on the truncated tablespace, we will assign
2735
a new tablespace identifier to the truncated tablespace. */
2737
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2740
if (srv_created_new_raw) {
2741
fputs("InnoDB: A new raw disk partition was initialized:\n"
2742
"InnoDB: we do not allow database modifications"
2744
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2745
" is replaced with raw.\n", stderr);
2750
trx->op_info = "truncating table";
2752
trx_start_if_not_started(trx);
2754
/* Serialize data dictionary operations with dictionary mutex:
2755
no deadlocks can occur then in these operations */
2757
ut_a(trx->dict_operation_lock_mode == 0);
2758
/* Prevent foreign key checks etc. while we are truncating the
2761
row_mysql_lock_data_dictionary(trx);
2763
ut_ad(mutex_own(&(dict_sys->mutex)));
2764
#ifdef UNIV_SYNC_DEBUG
2765
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2766
#endif /* UNIV_SYNC_DEBUG */
2768
/* Check if the table is referenced by foreign key constraints from
2769
some other table (not the table itself) */
2771
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2773
while (foreign && foreign->foreign_table == table) {
2774
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2777
if (foreign && trx->check_foreigns) {
2778
FILE* ef = dict_foreign_err_file;
2780
/* We only allow truncating a referenced table if
2781
FOREIGN_KEY_CHECKS is set to 0 */
2783
mutex_enter(&dict_foreign_err_mutex);
2785
ut_print_timestamp(ef);
2787
fputs(" Cannot truncate table ", ef);
2788
ut_print_name(ef, trx, TRUE, table->name);
2789
fputs(" by DROP+CREATE\n"
2790
"InnoDB: because it is referenced by ", ef);
2791
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2793
mutex_exit(&dict_foreign_err_mutex);
2799
/* TODO: could we replace the counter n_foreign_key_checks_running
2800
with lock checks on the table? Acquire here an exclusive lock on the
2801
table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2802
they can cope with the table having been truncated here? Foreign key
2803
checks take an IS or IX lock on the table. */
2805
if (table->n_foreign_key_checks_running > 0) {
2806
ut_print_timestamp(stderr);
2807
fputs(" InnoDB: Cannot truncate table ", stderr);
2808
ut_print_name(stderr, trx, TRUE, table->name);
2809
fputs(" by DROP+CREATE\n"
2810
"InnoDB: because there is a foreign key check"
2811
" running on it.\n",
2818
/* Remove all locks except the table-level S and X locks. */
2819
lock_remove_all_on_table(table, FALSE);
2821
trx->table_id = table->id;
2823
if (table->space && !table->dir_path_of_temp_table) {
2824
/* Discard and create the single-table tablespace. */
2825
ulint space = table->space;
2826
ulint flags = fil_space_get_flags(space);
2828
if (flags != ULINT_UNDEFINED
2829
&& fil_discard_tablespace(space)) {
2831
dict_index_t* index;
2833
dict_hdr_get_new_id(NULL, NULL, &space);
2835
/* Lock all index trees for this table. We must
2836
do so after dict_hdr_get_new_id() to preserve
2838
dict_table_x_lock_indexes(table);
2840
if (space == ULINT_UNDEFINED
2841
|| fil_create_new_single_table_tablespace(
2842
space, table->name, FALSE, flags,
2843
FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
2844
dict_table_x_unlock_indexes(table);
2845
ut_print_timestamp(stderr);
2847
" InnoDB: TRUNCATE TABLE %s failed to"
2848
" create a new tablespace\n",
2850
table->ibd_file_missing = 1;
2855
recreate_space = space;
2857
/* Replace the space_id in the data dictionary cache.
2858
The persisent data dictionary (SYS_TABLES.SPACE
2859
and SYS_INDEXES.SPACE) are updated later in this
2861
table->space = space;
2862
index = dict_table_get_first_index(table);
2864
index->space = space;
2865
index = dict_table_get_next_index(index);
2869
fsp_header_init(space,
2870
FIL_IBD_FILE_INITIAL_SIZE, &mtr);
2874
/* Lock all index trees for this table, as we will
2875
truncate the table/index and possibly change their metadata.
2876
All DML/DDL are blocked by table level lock, with
2877
a few exceptions such as queries into information schema
2878
about the table, MySQL could try to access index stats
2879
for this kind of query, we need to use index locks to
2881
dict_table_x_lock_indexes(table);
2884
/* scan SYS_INDEXES for all indexes of the table */
2885
heap = mem_heap_create(800);
2887
tuple = dtuple_create(heap, 1);
2888
dfield = dtuple_get_nth_field(tuple, 0);
2890
buf = static_cast<byte *>(mem_heap_alloc(heap, 8));
2891
mach_write_to_8(buf, table->id);
2893
dfield_set_data(dfield, buf, 8);
2894
sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2895
dict_index_copy_types(tuple, sys_index, 1);
2898
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2899
BTR_MODIFY_LEAF, &pcur, &mtr);
2906
if (!btr_pcur_is_on_user_rec(&pcur)) {
2907
/* The end of SYS_INDEXES has been reached. */
2911
rec = btr_pcur_get_rec(&pcur);
2913
field = rec_get_nth_field_old(rec, 0, &len);
2916
if (memcmp(buf, field, len) != 0) {
2917
/* End of indexes for the table (TABLE_ID mismatch). */
2921
if (rec_get_deleted_flag(rec, FALSE)) {
2922
/* The index has been dropped. */
2926
/* This call may commit and restart mtr
2927
and reposition pcur. */
2928
root_page_no = dict_truncate_index_tree(table, recreate_space,
2931
rec = btr_pcur_get_rec(&pcur);
2933
if (root_page_no != FIL_NULL) {
2934
page_rec_write_index_page_no(
2935
rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2936
root_page_no, &mtr);
2937
/* We will need to commit and restart the
2938
mini-transaction in order to avoid deadlocks.
2939
The dict_truncate_index_tree() call has allocated
2940
a page in this mini-transaction, and the rest of
2941
this loop could latch another index page. */
2944
btr_pcur_restore_position(BTR_MODIFY_LEAF,
2949
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2952
btr_pcur_close(&pcur);
2955
mem_heap_free(heap);
2957
/* Done with index truncation, release index tree locks,
2958
subsequent work relates to table level metadata change */
2959
dict_table_x_unlock_indexes(table);
2961
dict_hdr_get_new_id(&new_id, NULL, NULL);
2963
info = pars_info_create();
2965
pars_info_add_int4_literal(info, "space", (lint) table->space);
2966
pars_info_add_ull_literal(info, "old_id", table->id);
2967
pars_info_add_ull_literal(info, "new_id", new_id);
2969
err = que_eval_sql(info,
2970
"PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2973
" SET ID = :new_id, SPACE = :space\n"
2974
" WHERE ID = :old_id;\n"
2975
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2976
" WHERE TABLE_ID = :old_id;\n"
2977
"UPDATE SYS_INDEXES"
2978
" SET TABLE_ID = :new_id, SPACE = :space\n"
2979
" WHERE TABLE_ID = :old_id;\n"
2984
if (err != DB_SUCCESS) {
2985
trx->error_state = DB_SUCCESS;
2986
trx_general_rollback_for_mysql(trx, NULL);
2987
trx->error_state = DB_SUCCESS;
2988
ut_print_timestamp(stderr);
2989
fputs(" InnoDB: Unable to assign a new identifier to table ",
2991
ut_print_name(stderr, trx, TRUE, table->name);
2993
"InnoDB: after truncating it. Background processes"
2994
" may corrupt the table!\n", stderr);
2997
dict_table_change_id_in_cache(table, new_id);
3001
MySQL calls ha_innobase::reset_auto_increment() which does
3004
dict_table_autoinc_lock(table);
3005
dict_table_autoinc_initialize(table, 1);
3006
dict_table_autoinc_unlock(table);
3007
dict_update_statistics(table, FALSE /* update even if stats are
3010
trx_commit_for_mysql(trx);
3014
row_mysql_unlock_data_dictionary(trx);
3018
srv_wake_master_thread();
3023
/*********************************************************************//**
3024
Drops a table for MySQL. If the name of the dropped table ends in
3025
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
3026
"innodb_table_monitor", then this will also stop the printing of monitor
3027
output by the master thread. If the data dictionary was not already locked
3028
by the transaction, the transaction will be committed. Otherwise, the
3029
data dictionary will remain locked.
3030
@return error code or DB_SUCCESS */
3033
row_drop_table_for_mysql(
3034
/*=====================*/
3035
const char* name, /*!< in: table name */
3036
trx_t* trx, /*!< in: transaction handle */
3037
ibool drop_db)/*!< in: TRUE=dropping whole database */
3039
dict_foreign_t* foreign;
3040
dict_table_t* table;
3043
const char* table_name;
3045
ibool locked_dictionary = FALSE;
3046
pars_info_t* info = NULL;
3050
if (srv_created_new_raw) {
3051
fputs("InnoDB: A new raw disk partition was initialized:\n"
3052
"InnoDB: we do not allow database modifications"
3054
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
3055
" is replaced with raw.\n", stderr);
3060
trx->op_info = "dropping table";
3062
trx_start_if_not_started(trx);
3064
/* The table name is prefixed with the database name and a '/'.
3065
Certain table names starting with 'innodb_' have their special
3066
meaning regardless of the database name. Thus, we need to
3067
ignore the database name prefix in the comparisons. */
3068
table_name = strchr(name, '/');
3071
namelen = strlen(table_name) + 1;
3073
if (namelen == sizeof S_innodb_monitor
3074
&& !memcmp(table_name, S_innodb_monitor,
3075
sizeof S_innodb_monitor)) {
3077
/* Table name equals "innodb_monitor":
3078
stop monitor prints */
3080
srv_print_innodb_monitor = FALSE;
3081
srv_print_innodb_lock_monitor = FALSE;
3082
} else if (namelen == sizeof S_innodb_lock_monitor
3083
&& !memcmp(table_name, S_innodb_lock_monitor,
3084
sizeof S_innodb_lock_monitor)) {
3085
srv_print_innodb_monitor = FALSE;
3086
srv_print_innodb_lock_monitor = FALSE;
3087
} else if (namelen == sizeof S_innodb_tablespace_monitor
3088
&& !memcmp(table_name, S_innodb_tablespace_monitor,
3089
sizeof S_innodb_tablespace_monitor)) {
3091
srv_print_innodb_tablespace_monitor = FALSE;
3092
} else if (namelen == sizeof S_innodb_table_monitor
3093
&& !memcmp(table_name, S_innodb_table_monitor,
3094
sizeof S_innodb_table_monitor)) {
3096
srv_print_innodb_table_monitor = FALSE;
3099
/* Serialize data dictionary operations with dictionary mutex:
3100
no deadlocks can occur then in these operations */
3102
if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3103
/* Prevent foreign key checks etc. while we are dropping the
3106
row_mysql_lock_data_dictionary(trx);
3108
locked_dictionary = TRUE;
3111
ut_ad(mutex_own(&(dict_sys->mutex)));
3112
#ifdef UNIV_SYNC_DEBUG
3113
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3114
#endif /* UNIV_SYNC_DEBUG */
3116
table = dict_table_get_low(name);
3119
#if defined(BUILD_DRIZZLE)
3122
err = DB_TABLE_NOT_FOUND;
3123
ut_print_timestamp(stderr);
3125
fputs(" InnoDB: Error: table ", stderr);
3126
ut_print_name(stderr, trx, TRUE, name);
3127
fputs(" does not exist in the InnoDB internal\n"
3128
"InnoDB: data dictionary though MySQL is"
3129
" trying to drop it.\n"
3130
"InnoDB: Have you copied the .frm file"
3131
" of the table to the\n"
3132
"InnoDB: MySQL database directory"
3133
" from another database?\n"
3134
"InnoDB: You can look for further help from\n"
3135
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3137
#endif /* BUILD_DRIZZLE */
3141
/* Check if the table is referenced by foreign key constraints from
3142
some other table (not the table itself) */
3144
foreign = UT_LIST_GET_FIRST(table->referenced_list);
3146
while (foreign && foreign->foreign_table == table) {
3148
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3151
if (foreign && trx->check_foreigns
3152
&& !(drop_db && dict_tables_have_same_db(
3153
name, foreign->foreign_table_name))) {
3154
FILE* ef = dict_foreign_err_file;
3156
/* We only allow dropping a referenced table if
3157
FOREIGN_KEY_CHECKS is set to 0 */
3159
err = DB_CANNOT_DROP_CONSTRAINT;
3161
mutex_enter(&dict_foreign_err_mutex);
3163
ut_print_timestamp(ef);
3165
fputs(" Cannot drop table ", ef);
3166
ut_print_name(ef, trx, TRUE, name);
3168
"because it is referenced by ", ef);
3169
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3171
mutex_exit(&dict_foreign_err_mutex);
3176
if (foreign && trx->check_foreigns) {
3177
goto check_next_foreign;
3180
if (table->n_mysql_handles_opened > 0) {
3183
added = row_add_table_to_background_drop_list(table->name);
3186
ut_print_timestamp(stderr);
3187
fputs(" InnoDB: Warning: MySQL is"
3188
" trying to drop table ", stderr);
3189
ut_print_name(stderr, trx, TRUE, table->name);
3191
"InnoDB: though there are still"
3192
" open handles to it.\n"
3193
"InnoDB: Adding the table to the"
3194
" background drop queue.\n",
3197
/* We return DB_SUCCESS to MySQL though the drop will
3198
happen lazily later */
3201
/* The table is already in the background drop list */
3208
/* TODO: could we replace the counter n_foreign_key_checks_running
3209
with lock checks on the table? Acquire here an exclusive lock on the
3210
table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3211
they can cope with the table having been dropped here? Foreign key
3212
checks take an IS or IX lock on the table. */
3214
if (table->n_foreign_key_checks_running > 0) {
3216
const char* i_table_name = table->name;
3219
added = row_add_table_to_background_drop_list(i_table_name);
3222
ut_print_timestamp(stderr);
3223
fputs(" InnoDB: You are trying to drop table ",
3225
ut_print_name(stderr, trx, TRUE, i_table_name);
3227
"InnoDB: though there is a"
3228
" foreign key check running on it.\n"
3229
"InnoDB: Adding the table to"
3230
" the background drop queue.\n",
3233
/* We return DB_SUCCESS to MySQL though the drop will
3234
happen lazily later */
3238
/* The table is already in the background drop list */
3245
/* Remove all locks there are on the table or its records */
3246
lock_remove_all_on_table(table, TRUE);
3248
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
3249
trx->table_id = table->id;
3251
/* We use the private SQL parser of Innobase to generate the
3252
query graphs needed in deleting the dictionary data from system
3253
tables in Innobase. Deleting a row from SYS_INDEXES table also
3254
frees the file segments of the B-tree associated with the index. */
3256
info = pars_info_create();
3258
pars_info_add_str_literal(info, "table_name", name);
3260
err = que_eval_sql(info,
3261
"PROCEDURE DROP_TABLE_PROC () IS\n"
3262
"sys_foreign_id CHAR;\n"
3265
"foreign_id CHAR;\n"
3268
"SELECT ID INTO table_id\n"
3270
"WHERE NAME = :table_name\n"
3271
"LOCK IN SHARE MODE;\n"
3272
"IF (SQL % NOTFOUND) THEN\n"
3276
"SELECT ID INTO sys_foreign_id\n"
3278
"WHERE NAME = 'SYS_FOREIGN'\n"
3279
"LOCK IN SHARE MODE;\n"
3280
"IF (SQL % NOTFOUND) THEN\n"
3283
"IF (:table_name = 'SYS_FOREIGN') THEN\n"
3286
"IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3289
"WHILE found = 1 LOOP\n"
3290
" SELECT ID INTO foreign_id\n"
3291
" FROM SYS_FOREIGN\n"
3292
" WHERE FOR_NAME = :table_name\n"
3293
" AND TO_BINARY(FOR_NAME)\n"
3294
" = TO_BINARY(:table_name)\n"
3295
" LOCK IN SHARE MODE;\n"
3296
" IF (SQL % NOTFOUND) THEN\n"
3299
" DELETE FROM SYS_FOREIGN_COLS\n"
3300
" WHERE ID = foreign_id;\n"
3301
" DELETE FROM SYS_FOREIGN\n"
3302
" WHERE ID = foreign_id;\n"
3306
"WHILE found = 1 LOOP\n"
3307
" SELECT ID INTO index_id\n"
3308
" FROM SYS_INDEXES\n"
3309
" WHERE TABLE_ID = table_id\n"
3310
" LOCK IN SHARE MODE;\n"
3311
" IF (SQL % NOTFOUND) THEN\n"
3314
" DELETE FROM SYS_FIELDS\n"
3315
" WHERE INDEX_ID = index_id;\n"
3316
" DELETE FROM SYS_INDEXES\n"
3317
" WHERE ID = index_id\n"
3318
" AND TABLE_ID = table_id;\n"
3321
"DELETE FROM SYS_COLUMNS\n"
3322
"WHERE TABLE_ID = table_id;\n"
3323
"DELETE FROM SYS_TABLES\n"
3324
"WHERE ID = table_id;\n"
3330
const char* name_or_path;
3335
heap = mem_heap_create(200);
3337
/* Clone the name, in case it has been allocated
3338
from table->heap, which will be freed by
3339
dict_table_remove_from_cache(table) below. */
3340
name = mem_heap_strdup(heap, name);
3341
space_id = table->space;
3343
if (table->dir_path_of_temp_table != NULL) {
3344
name_or_path = mem_heap_strdup(
3345
heap, table->dir_path_of_temp_table);
3348
name_or_path = name;
3349
is_temp = (table->flags >> DICT_TF2_SHIFT)
3350
& DICT_TF2_TEMPORARY;
3353
dict_table_remove_from_cache(table);
3355
if (dict_load_table(name, TRUE) != NULL) {
3356
ut_print_timestamp(stderr);
3357
fputs(" InnoDB: Error: not able to remove table ",
3359
ut_print_name(stderr, trx, TRUE, name);
3360
fputs(" from the dictionary cache!\n", stderr);
3364
/* Do not drop possible .ibd tablespace if something went
3365
wrong: we do not want to delete valuable data of the user */
3367
if (err == DB_SUCCESS && space_id > 0) {
3368
if (!fil_space_for_table_exists_in_mem(space_id,
3375
"InnoDB: We removed now the InnoDB"
3376
" internal data dictionary entry\n"
3377
"InnoDB: of table ");
3378
ut_print_name(stderr, trx, TRUE, name);
3379
fprintf(stderr, ".\n");
3380
} else if (!fil_delete_tablespace(space_id)) {
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");
3388
ut_print_timestamp(stderr);
3390
" InnoDB: Error: not able to"
3391
" delete tablespace %lu of table ",
3393
ut_print_name(stderr, trx, TRUE, name);
3394
fputs("!\n", stderr);
3399
mem_heap_free(heap);
3402
case DB_TOO_MANY_CONCURRENT_TRXS:
3403
/* Cannot even find a free slot for the
3404
the undo log. We can directly exit here
3405
and return the DB_TOO_MANY_CONCURRENT_TRXS
3409
case DB_OUT_OF_FILE_SPACE:
3410
err = DB_MUST_GET_MORE_FILE_SPACE;
3412
row_mysql_handle_errors(&err, trx, NULL, NULL);
3414
/* Fall through to raise error */
3417
/* No other possible error returns */
3423
if (locked_dictionary) {
3424
trx_commit_for_mysql(trx);
3426
row_mysql_unlock_data_dictionary(trx);
3431
srv_wake_master_thread();
3436
/*********************************************************************//**
3437
Drop all temporary tables during crash recovery. */
3440
row_mysql_drop_temp_tables(void)
3441
/*============================*/
3448
trx = trx_allocate_for_background();
3449
trx->op_info = "dropping temporary tables";
3450
row_mysql_lock_data_dictionary(trx);
3452
heap = mem_heap_create(200);
3456
btr_pcur_open_at_index_side(
3458
dict_table_get_first_index(dict_sys->sys_tables),
3459
BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3465
const char* table_name;
3466
dict_table_t* table;
3468
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
3470
if (!btr_pcur_is_on_user_rec(&pcur)) {
3474
rec = btr_pcur_get_rec(&pcur);
3475
field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
3476
if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) {
3480
/* Because this is not a ROW_FORMAT=REDUNDANT table,
3481
the is_temp flag is valid. Examine it. */
3483
field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len);
3485
|| !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
3489
/* This is a temporary table. */
3490
field = rec_get_nth_field_old(rec, 0/*NAME*/, &len);
3491
if (len == UNIV_SQL_NULL || len == 0) {
3492
/* Corrupted SYS_TABLES.NAME */
3496
table_name = mem_heap_strdupl(heap, (const char*) field, len);
3498
btr_pcur_store_position(&pcur, &mtr);
3499
btr_pcur_commit_specify_mtr(&pcur, &mtr);
3501
table = dict_load_table(table_name, TRUE);
3504
row_drop_table_for_mysql(table_name, trx, FALSE);
3505
trx_commit_for_mysql(trx);
3509
btr_pcur_restore_position(BTR_SEARCH_LEAF,
3513
btr_pcur_close(&pcur);
3515
mem_heap_free(heap);
3516
row_mysql_unlock_data_dictionary(trx);
3517
trx_free_for_background(trx);
3520
/*******************************************************************//**
3521
Drop all foreign keys in a database, see Bug#18942.
3522
Called at the end of row_drop_database_for_mysql().
3523
@return error code or DB_SUCCESS */
3526
drop_all_foreign_keys_in_db(
3527
/*========================*/
3528
const char* name, /*!< in: database name which ends to '/' */
3529
trx_t* trx) /*!< in: transaction handle */
3534
ut_a(name[strlen(name) - 1] == '/');
3536
pinfo = pars_info_create();
3538
pars_info_add_str_literal(pinfo, "dbname", name);
3540
/** true if for_name is not prefixed with dbname */
3541
#define TABLE_NOT_IN_THIS_DB \
3542
"SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
3544
err = que_eval_sql(pinfo,
3545
"PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
3546
"foreign_id CHAR;\n"
3549
"DECLARE CURSOR cur IS\n"
3550
"SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
3551
"WHERE FOR_NAME >= :dbname\n"
3552
"LOCK IN SHARE MODE\n"
3553
"ORDER BY FOR_NAME;\n"
3557
"WHILE found = 1 LOOP\n"
3558
" FETCH cur INTO foreign_id, for_name;\n"
3559
" IF (SQL % NOTFOUND) THEN\n"
3561
" ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
3563
" ELSIF (1=1) THEN\n"
3564
" DELETE FROM SYS_FOREIGN_COLS\n"
3565
" WHERE ID = foreign_id;\n"
3566
" DELETE FROM SYS_FOREIGN\n"
3567
" WHERE ID = foreign_id;\n"
3573
FALSE, /* do not reserve dict mutex,
3574
we are already holding it */
3580
/*********************************************************************//**
3581
Drops a database for MySQL.
3582
@return error code or DB_SUCCESS */
3585
row_drop_database_for_mysql(
3586
/*========================*/
3587
const char* name, /*!< in: database name which ends to '/' */
3588
trx_t* trx) /*!< in: transaction handle */
3590
dict_table_t* table;
3592
int err = DB_SUCCESS;
3593
ulint namelen = strlen(name);
3595
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3597
ut_a(name[namelen - 1] == '/');
3599
trx->op_info = "dropping database";
3601
trx_start_if_not_started(trx);
3603
row_mysql_lock_data_dictionary(trx);
3605
while ((table_name = dict_get_first_table_name_in_db(name))) {
3606
ut_a(memcmp(table_name, name, namelen) == 0);
3608
// For the time being I would like to see how often we see
3609
// lost temporary tables. --Brian
3610
fprintf(stderr, "Dropping lost temporary table %s\n", table_name);
3612
table = dict_table_get_low(table_name);
3616
/* Wait until MySQL does not have any queries running on
3619
if (table->n_mysql_handles_opened > 0) {
3620
row_mysql_unlock_data_dictionary(trx);
3622
ut_print_timestamp(stderr);
3623
fputs(" InnoDB: Warning: MySQL is trying to"
3624
" drop database ", stderr);
3625
ut_print_name(stderr, trx, TRUE, name);
3627
"InnoDB: though there are still"
3628
" open handles to table ", stderr);
3629
ut_print_name(stderr, trx, TRUE, table_name);
3630
fputs(".\n", stderr);
3632
os_thread_sleep(1000000);
3634
mem_free(table_name);
3639
err = row_drop_table_for_mysql(table_name, trx, TRUE);
3640
trx_commit_for_mysql(trx);
3642
if (err != DB_SUCCESS) {
3643
fputs("InnoDB: DROP DATABASE ", stderr);
3644
ut_print_name(stderr, trx, TRUE, name);
3645
fprintf(stderr, " failed with error %lu for table ",
3647
ut_print_name(stderr, trx, TRUE, table_name);
3649
mem_free(table_name);
3653
mem_free(table_name);
3656
if (err == DB_SUCCESS) {
3657
/* after dropping all tables try to drop all leftover
3658
foreign keys in case orphaned ones exist */
3659
err = (int) drop_all_foreign_keys_in_db(name, trx);
3661
if (err != DB_SUCCESS) {
3662
fputs("InnoDB: DROP DATABASE ", stderr);
3663
ut_print_name(stderr, trx, TRUE, name);
3664
fprintf(stderr, " failed with error %d while "
3665
"dropping all foreign keys", err);
3669
trx_commit_for_mysql(trx);
3671
row_mysql_unlock_data_dictionary(trx);
3678
/*********************************************************************//**
3679
Checks if a table name contains the string "/#sql" which denotes temporary
3681
@return TRUE if temporary table */
3684
row_is_mysql_tmp_table_name(
3685
/*========================*/
3686
const char* name) /*!< in: table name in the form
3687
'database/tablename' */
3689
return(strstr(name, "/#sql") != NULL);
3690
/* return(strstr(name, "/@0023sql") != NULL); */
3693
/****************************************************************//**
3694
Delete a single constraint.
3695
@return error code or DB_SUCCESS */
3698
row_delete_constraint_low(
3699
/*======================*/
3700
const char* id, /*!< in: constraint id */
3701
trx_t* trx) /*!< in: transaction handle */
3703
pars_info_t* info = pars_info_create();
3705
pars_info_add_str_literal(info, "id", id);
3707
return((int) que_eval_sql(info,
3708
"PROCEDURE DELETE_CONSTRAINT () IS\n"
3710
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3711
"DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3716
/****************************************************************//**
3717
Delete a single constraint.
3718
@return error code or DB_SUCCESS */
3721
row_delete_constraint(
3722
/*==================*/
3723
const char* id, /*!< in: constraint id */
3724
const char* database_name, /*!< in: database name, with the
3726
mem_heap_t* heap, /*!< in: memory heap */
3727
trx_t* trx) /*!< in: transaction handle */
3731
/* New format constraints have ids <databasename>/<constraintname>. */
3732
err = row_delete_constraint_low(
3733
mem_heap_strcat(heap, database_name, id), trx);
3735
if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3736
/* Old format < 4.0.18 constraints have constraint ids
3737
<number>_<number>. We only try deleting them if the
3738
constraint name does not contain a '/' character, otherwise
3739
deleting a new format constraint named 'foo/bar' from
3740
database 'baz' would remove constraint 'bar' from database
3741
'foo', if it existed. */
3743
err = row_delete_constraint_low(id, trx);
3749
/*********************************************************************//**
3750
Renames a table for MySQL.
3751
@return error code or DB_SUCCESS */
3754
row_rename_table_for_mysql(
3755
/*=======================*/
3756
const char* old_name, /*!< in: old table name */
3757
const char* new_name, /*!< in: new table name */
3758
trx_t* trx, /*!< in: transaction handle */
3759
ibool commit) /*!< in: if TRUE then commit trx */
3761
dict_table_t* table;
3762
ulint err = DB_ERROR;
3763
mem_heap_t* heap = NULL;
3764
const char** constraints_to_drop = NULL;
3765
ulint n_constraints_to_drop = 0;
3766
ibool old_is_tmp, new_is_tmp;
3767
pars_info_t* info = NULL;
3769
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3770
ut_a(old_name != NULL);
3771
ut_a(new_name != NULL);
3773
if (srv_created_new_raw || srv_force_recovery) {
3774
fputs("InnoDB: A new raw disk partition was initialized or\n"
3775
"InnoDB: innodb_force_recovery is on: we do not allow\n"
3776
"InnoDB: database modifications by the user. Shut down\n"
3777
"InnoDB: mysqld and edit my.cnf so that newraw"
3779
"InnoDB: with raw, and innodb_force_... is removed.\n",
3785
trx->op_info = "renaming table";
3786
trx_start_if_not_started(trx);
3788
old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3789
new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3791
table = dict_table_get_low(old_name);
3794
#if defined(BUILD_DRIZZLE)
3797
err = DB_TABLE_NOT_FOUND;
3798
ut_print_timestamp(stderr);
3800
fputs(" InnoDB: Error: table ", stderr);
3801
ut_print_name(stderr, trx, TRUE, old_name);
3802
fputs(" does not exist in the InnoDB internal\n"
3803
"InnoDB: data dictionary though MySQL is"
3804
" trying to rename the table.\n"
3805
"InnoDB: Have you copied the .frm file"
3806
" of the table to the\n"
3807
"InnoDB: MySQL database directory"
3808
" from another database?\n"
3809
"InnoDB: You can look for further help from\n"
3810
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3812
#endif /* BUILD_DRIZZLE */
3814
} else if (table->ibd_file_missing) {
3815
err = DB_TABLE_NOT_FOUND;
3816
ut_print_timestamp(stderr);
3818
fputs(" InnoDB: Error: table ", stderr);
3819
ut_print_name(stderr, trx, TRUE, old_name);
3820
fputs(" does not have an .ibd file"
3821
" in the database directory.\n"
3822
"InnoDB: You can look for further help from\n"
3823
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3826
} else if (new_is_tmp) {
3827
/* MySQL is doing an ALTER TABLE command and it renames the
3828
original table to a temporary table name. We want to preserve
3829
the original foreign key constraint definitions despite the
3830
name change. An exception is those constraints for which
3831
the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3833
heap = mem_heap_create(100);
3835
err = dict_foreign_parse_drop_constraints(
3836
heap, trx, table, &n_constraints_to_drop,
3837
&constraints_to_drop);
3839
if (err != DB_SUCCESS) {
3845
/* We use the private SQL parser of Innobase to generate the query
3846
graphs needed in updating the dictionary data from system tables. */
3848
info = pars_info_create();
3850
pars_info_add_str_literal(info, "new_table_name", new_name);
3851
pars_info_add_str_literal(info, "old_table_name", old_name);
3853
err = que_eval_sql(info,
3854
"PROCEDURE RENAME_TABLE () IS\n"
3856
"UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3857
" WHERE NAME = :old_table_name;\n"
3861
if (err != DB_SUCCESS) {
3864
} else if (!new_is_tmp) {
3865
/* Rename all constraints. */
3867
info = pars_info_create();
3869
pars_info_add_str_literal(info, "new_table_name", new_name);
3870
pars_info_add_str_literal(info, "old_table_name", old_name);
3874
"PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3875
"gen_constr_prefix CHAR;\n"
3876
"new_db_name CHAR;\n"
3877
"foreign_id CHAR;\n"
3878
"new_foreign_id CHAR;\n"
3879
"old_db_name_len INT;\n"
3880
"old_t_name_len INT;\n"
3881
"new_db_name_len INT;\n"
3886
"old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3887
"new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3888
"new_db_name := SUBSTR(:new_table_name, 0,\n"
3889
" new_db_name_len);\n"
3890
"old_t_name_len := LENGTH(:old_table_name);\n"
3891
"gen_constr_prefix := CONCAT(:old_table_name,\n"
3893
"WHILE found = 1 LOOP\n"
3894
" SELECT ID INTO foreign_id\n"
3895
" FROM SYS_FOREIGN\n"
3896
" WHERE FOR_NAME = :old_table_name\n"
3897
" AND TO_BINARY(FOR_NAME)\n"
3898
" = TO_BINARY(:old_table_name)\n"
3899
" LOCK IN SHARE MODE;\n"
3900
" IF (SQL % NOTFOUND) THEN\n"
3903
" UPDATE SYS_FOREIGN\n"
3904
" SET FOR_NAME = :new_table_name\n"
3905
" WHERE ID = foreign_id;\n"
3906
" id_len := LENGTH(foreign_id);\n"
3907
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
3908
" IF (INSTR(foreign_id,\n"
3909
" gen_constr_prefix) > 0)\n"
3911
" new_foreign_id :=\n"
3912
" CONCAT(:new_table_name,\n"
3913
" SUBSTR(foreign_id, old_t_name_len,\n"
3914
" id_len - old_t_name_len));\n"
3916
" new_foreign_id :=\n"
3917
" CONCAT(new_db_name,\n"
3918
" SUBSTR(foreign_id,\n"
3919
" old_db_name_len,\n"
3920
" id_len - old_db_name_len));\n"
3922
" UPDATE SYS_FOREIGN\n"
3923
" SET ID = new_foreign_id\n"
3924
" WHERE ID = foreign_id;\n"
3925
" UPDATE SYS_FOREIGN_COLS\n"
3926
" SET ID = new_foreign_id\n"
3927
" WHERE ID = foreign_id;\n"
3931
"UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
3932
"WHERE REF_NAME = :old_table_name\n"
3933
" AND TO_BINARY(REF_NAME)\n"
3934
" = TO_BINARY(:old_table_name);\n"
3938
} else if (n_constraints_to_drop > 0) {
3939
/* Drop some constraints of tmp tables. */
3941
ulint db_name_len = dict_get_db_name_len(old_name) + 1;
3942
char* db_name = mem_heap_strdupl(heap, old_name,
3946
for (i = 0; i < n_constraints_to_drop; i++) {
3947
err = row_delete_constraint(constraints_to_drop[i],
3948
db_name, heap, trx);
3950
if (err != DB_SUCCESS) {
3957
if (err != DB_SUCCESS) {
3958
if (err == DB_DUPLICATE_KEY) {
3959
ut_print_timestamp(stderr);
3960
fputs(" InnoDB: Error; possible reasons:\n"
3961
"InnoDB: 1) Table rename would cause"
3962
" two FOREIGN KEY constraints\n"
3963
"InnoDB: to have the same internal name"
3964
" in case-insensitive comparison.\n"
3965
"InnoDB: 2) table ", stderr);
3966
ut_print_name(stderr, trx, TRUE, new_name);
3967
fputs(" exists in the InnoDB internal data\n"
3968
"InnoDB: dictionary though MySQL is"
3969
" trying to rename table ", stderr);
3970
ut_print_name(stderr, trx, TRUE, old_name);
3972
"InnoDB: Have you deleted the .frm file"
3973
" and not used DROP TABLE?\n"
3974
"InnoDB: You can look for further help from\n"
3975
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
3976
"InnoDB: If table ", stderr);
3977
ut_print_name(stderr, trx, TRUE, new_name);
3978
fputs(" is a temporary table #sql..., then"
3980
"InnoDB: there are still queries running"
3981
" on the table, and it will be\n"
3982
"InnoDB: dropped automatically when"
3983
" the queries end.\n"
3984
"InnoDB: You can drop the orphaned table"
3985
" inside InnoDB by\n"
3986
"InnoDB: creating an InnoDB table with"
3987
" the same name in another\n"
3988
"InnoDB: database and copying the .frm file"
3989
" to the current database.\n"
3990
"InnoDB: Then MySQL thinks the table exists,"
3991
" and DROP TABLE will\n"
3992
"InnoDB: succeed.\n", stderr);
3994
trx->error_state = DB_SUCCESS;
3995
trx_general_rollback_for_mysql(trx, NULL);
3996
trx->error_state = DB_SUCCESS;
3998
/* The following call will also rename the .ibd data file if
3999
the table is stored in a single-table tablespace */
4001
if (!dict_table_rename_in_cache(table, new_name,
4003
trx->error_state = DB_SUCCESS;
4004
trx_general_rollback_for_mysql(trx, NULL);
4005
trx->error_state = DB_SUCCESS;
4009
/* We only want to switch off some of the type checking in
4010
an ALTER, not in a RENAME. */
4012
err = dict_load_foreigns(
4013
new_name, FALSE, !old_is_tmp || trx->check_foreigns);
4015
if (err != DB_SUCCESS) {
4016
ut_print_timestamp(stderr);
4019
fputs(" InnoDB: Error: in ALTER TABLE ",
4021
ut_print_name(stderr, trx, TRUE, new_name);
4023
"InnoDB: has or is referenced"
4024
" in foreign key constraints\n"
4025
"InnoDB: which are not compatible"
4026
" with the new table definition.\n",
4029
fputs(" InnoDB: Error: in RENAME TABLE"
4032
ut_print_name(stderr, trx, TRUE, new_name);
4034
"InnoDB: is referenced in"
4035
" foreign key constraints\n"
4036
"InnoDB: which are not compatible"
4037
" with the new table definition.\n",
4041
ut_a(dict_table_rename_in_cache(table,
4043
trx->error_state = DB_SUCCESS;
4044
trx_general_rollback_for_mysql(trx, NULL);
4045
trx->error_state = DB_SUCCESS;
4052
trx_commit_for_mysql(trx);
4055
if (UNIV_LIKELY_NULL(heap)) {
4056
mem_heap_free(heap);
4064
/*********************************************************************//**
4065
Checks that the index contains entries in an ascending order, unique
4066
constraint is not broken, and calculates the number of index entries
4067
in the read view of the current transaction.
4068
@return TRUE if ok */
4071
row_check_index_for_mysql(
4072
/*======================*/
4073
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct
4075
const dict_index_t* index, /*!< in: index */
4076
ulint* n_rows) /*!< out: number of entries
4077
seen in the consistent read */
4079
dtuple_t* prev_entry = NULL;
4080
ulint matched_fields;
4081
ulint matched_bytes;
4087
ibool contains_null;
4090
mem_heap_t* heap = NULL;
4092
ulint offsets_[REC_OFFS_NORMAL_SIZE];
4094
rec_offs_init(offsets_);
4098
buf = static_cast<byte *>(mem_alloc(UNIV_PAGE_SIZE));
4099
heap = mem_heap_create(100);
4103
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
4105
/* Check thd->killed every 1,000 scanned rows */
4107
if (trx_is_interrupted(prebuilt->trx)) {
4117
ut_print_timestamp(stderr);
4118
fputs(" InnoDB: Warning: CHECK TABLE on ", stderr);
4119
dict_index_name_print(stderr, prebuilt->trx, index);
4120
fprintf(stderr, " returned %lu\n", ret);
4121
/* fall through (this error is ignored by CHECK TABLE) */
4122
case DB_END_OF_INDEX:
4125
mem_heap_free(heap);
4130
*n_rows = *n_rows + 1;
4132
/* row_search... returns the index record in buf, record origin offset
4133
within buf stored in the first 4 bytes, because we have built a dummy
4136
rec = buf + mach_read_from_4(buf);
4138
offsets = rec_get_offsets(rec, index, offsets_,
4139
ULINT_UNDEFINED, &heap);
4141
if (prev_entry != NULL) {
4145
cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
4148
contains_null = FALSE;
4150
/* In a unique secondary index we allow equal key values if
4151
they contain SQL NULLs */
4154
i < dict_index_get_n_ordering_defined_by_user(index);
4156
if (UNIV_SQL_NULL == dfield_get_len(
4157
dtuple_get_nth_field(prev_entry, i))) {
4159
contains_null = TRUE;
4164
fputs("InnoDB: index records in a wrong order in ",
4167
dict_index_name_print(stderr,
4168
prebuilt->trx, index);
4170
"InnoDB: prev record ", stderr);
4171
dtuple_print(stderr, prev_entry);
4173
"InnoDB: record ", stderr);
4174
rec_print_new(stderr, rec, offsets);
4177
} else if (dict_index_is_unique(index)
4180
>= dict_index_get_n_ordering_defined_by_user(
4183
fputs("InnoDB: duplicate key in ", stderr);
4189
mem_heap_t* tmp_heap = NULL;
4191
/* Empty the heap on each round. But preserve offsets[]
4192
for the row_rec_to_index_entry() call, by copying them
4193
into a separate memory heap when needed. */
4194
if (UNIV_UNLIKELY(offsets != offsets_)) {
4195
ulint size = rec_offs_get_n_alloc(offsets)
4198
tmp_heap = mem_heap_create(size);
4199
offsets = static_cast<ulint *>(mem_heap_dup(tmp_heap, offsets, size));
4202
mem_heap_empty(heap);
4204
prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
4208
if (UNIV_LIKELY_NULL(tmp_heap)) {
4209
mem_heap_free(tmp_heap);
4213
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
4218
/*********************************************************************//**
4219
Determines if a table is a magic monitor table.
4220
@return TRUE if monitor table */
4223
row_is_magic_monitor_table(
4224
/*=======================*/
4225
const char* table_name) /*!< in: name of the table, in the
4226
form database/table_name */
4228
const char* name; /* table_name without database/ */
4231
name = strchr(table_name, '/');
4234
len = strlen(name) + 1;
4236
if (STR_EQ(name, len, S_innodb_monitor)
4237
|| STR_EQ(name, len, S_innodb_lock_monitor)
4238
|| STR_EQ(name, len, S_innodb_tablespace_monitor)
4239
|| STR_EQ(name, len, S_innodb_table_monitor)
4240
|| STR_EQ(name, len, S_innodb_mem_validate)) {