1
/*****************************************************************************
3
Copyright (c) 2000, 2009, 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., 59 Temple
15
Place, Suite 330, Boston, MA 02111-1307 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"
55
/** Provide optional 4.x backwards compatibility for 5.0 and above */
56
UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
58
/** Chain node of the list of tables to drop in the background. */
59
typedef struct row_mysql_drop_struct row_mysql_drop_t;
61
/** Chain node of the list of tables to drop in the background. */
62
struct row_mysql_drop_struct{
63
char* table_name; /*!< table name */
64
UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
65
/*!< list chain node */
68
/** @brief List of tables we should drop in background.
70
ALTER TABLE in MySQL requires that the table handler can drop the
71
table in background when there are no queries to it any
72
more. Protected by kernel_mutex. */
73
static UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
74
/** Flag: has row_mysql_drop_list been initialized? */
75
static ibool row_mysql_drop_list_inited = FALSE;
77
/** Magic table names for invoking various monitor threads */
79
static const char S_innodb_monitor[] = "innodb_monitor";
80
static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
81
static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
82
static const char S_innodb_table_monitor[] = "innodb_table_monitor";
83
static const char S_innodb_mem_validate[] = "innodb_mem_validate";
86
/** Evaluates to true if str1 equals str2_onstack, used for comparing
87
the magic table names.
88
@param str1 in: string to compare
89
@param str1_len in: length of str1, in bytes, including terminating NUL
90
@param str2_onstack in: char[] array containing a NUL terminated string
91
@return TRUE if str1 equals str2_onstack */
92
#define STR_EQ(str1, str1_len, str2_onstack) \
93
((str1_len) == sizeof(str2_onstack) \
94
&& memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
96
/*******************************************************************//**
97
Determine if the given name is a name reserved for MySQL system tables.
98
@return TRUE if name is a MySQL system table name */
101
row_mysql_is_system_table(
102
/*======================*/
105
if (strncmp(name, "mysql/", 6) != 0) {
110
return(0 == strcmp(name + 6, "host")
111
|| 0 == strcmp(name + 6, "user")
112
|| 0 == strcmp(name + 6, "db"));
115
/*********************************************************************//**
116
If a table is not yet in the drop list, adds the table to the list of tables
117
which the master thread drops in background. We need this on Unix because in
118
ALTER TABLE MySQL may call drop table even if the table has running queries on
119
it. Also, if there are running foreign key checks on the table, we drop the
121
@return TRUE if the table was not yet in the drop list, and was added there */
124
row_add_table_to_background_drop_list(
125
/*==================================*/
126
const char* name); /*!< in: table name */
128
/*******************************************************************//**
129
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
132
row_mysql_delay_if_needed(void)
133
/*===========================*/
135
if (srv_dml_needed_delay) {
136
os_thread_sleep(srv_dml_needed_delay);
140
/*******************************************************************//**
141
Frees the blob heap in prebuilt when no longer needed. */
144
row_mysql_prebuilt_free_blob_heap(
145
/*==============================*/
146
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct of a
147
ha_innobase:: table handle */
149
mem_heap_free(prebuilt->blob_heap);
150
prebuilt->blob_heap = NULL;
153
/*******************************************************************//**
154
Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
156
@return pointer to the data, we skip the 1 or 2 bytes at the start
157
that are used to store the len */
160
row_mysql_store_true_var_len(
161
/*=========================*/
162
byte* dest, /*!< in: where to store */
163
ulint len, /*!< in: length, must fit in two bytes */
164
ulint lenlen) /*!< in: storage length of len: either 1 or 2 bytes */
167
ut_a(len < 256 * 256);
169
mach_write_to_2_little_endian(dest, len);
177
mach_write_to_1(dest, len);
182
/*******************************************************************//**
183
Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
184
returns a pointer to the data.
185
@return pointer to the data, we skip the 1 or 2 bytes at the start
186
that are used to store the len */
189
row_mysql_read_true_varchar(
190
/*========================*/
191
ulint* len, /*!< out: variable-length field length */
192
const byte* field, /*!< in: field in the MySQL format */
193
ulint lenlen) /*!< in: storage length of len: either 1
197
*len = mach_read_from_2_little_endian(field);
204
*len = mach_read_from_1(field);
209
/*******************************************************************//**
210
Stores a reference to a BLOB in the MySQL format. */
213
row_mysql_store_blob_ref(
214
/*=====================*/
215
byte* dest, /*!< in: where to store */
216
ulint col_len,/*!< in: dest buffer size: determines into
217
how many bytes the BLOB length is stored,
218
the space for the length may vary from 1
220
const void* data, /*!< in: BLOB data; if the value to store
221
is SQL NULL this should be NULL pointer */
222
ulint len) /*!< in: BLOB length; if the value to store
223
is SQL NULL this should be 0; remember
224
also to set the NULL bit in the MySQL record
227
/* MySQL might assume the field is set to zero except the length and
228
the pointer fields */
230
memset(dest, '\0', col_len);
232
/* In dest there are 1 - 4 bytes reserved for the BLOB length,
233
and after that 8 bytes reserved for the pointer to the data.
234
In 32-bit architectures we only use the first 4 bytes of the pointer
237
ut_a(col_len - 8 > 1 || len < 256);
238
ut_a(col_len - 8 > 2 || len < 256 * 256);
239
ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
241
mach_write_to_n_little_endian(dest, col_len - 8, len);
243
memcpy(dest + col_len - 8, &data, sizeof data);
246
/*******************************************************************//**
247
Reads a reference to a BLOB in the MySQL format.
248
@return pointer to BLOB data */
251
row_mysql_read_blob_ref(
252
/*====================*/
253
ulint* len, /*!< out: BLOB length */
254
const byte* ref, /*!< in: BLOB reference in the
256
ulint col_len) /*!< in: BLOB reference length
261
*len = mach_read_from_n_little_endian(ref, col_len - 8);
263
memcpy(&data, ref + col_len - 8, sizeof data);
268
/**************************************************************//**
269
Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
270
The counterpart of this function is row_sel_field_store_in_mysql_format() in
272
@return up to which byte we used buf in the conversion */
275
row_mysql_store_col_in_innobase_format(
276
/*===================================*/
277
dfield_t* dfield, /*!< in/out: dfield where dtype
278
information must be already set when
279
this function is called! */
280
byte* buf, /*!< in/out: buffer for a converted
281
integer value; this must be at least
282
col_len long then! */
283
ibool row_format_col, /*!< TRUE if the mysql_data is from
284
a MySQL row, FALSE if from a MySQL
286
in MySQL, a true VARCHAR storage
287
format differs in a row and in a
288
key value: in a key value the length
289
is always stored in 2 bytes! */
290
const byte* mysql_data, /*!< in: MySQL column value, not
291
SQL NULL; NOTE that dfield may also
292
get a pointer to mysql_data,
293
therefore do not discard this as long
294
as dfield is used! */
295
ulint col_len, /*!< in: MySQL column length; NOTE that
296
this is the storage length of the
297
column in the MySQL format row, not
298
necessarily the length of the actual
299
payload data; if the column is a true
300
VARCHAR then this is irrelevant */
301
ulint comp) /*!< in: nonzero=compact format */
303
const byte* ptr = mysql_data;
304
const dtype_t* dtype;
308
dtype = dfield_get_type(dfield);
312
if (type == DATA_INT) {
313
/* Store integer data in Innobase in a big-endian format,
314
sign bit negated if the data is a signed integer. In MySQL,
315
integers are stored in a little-endian format. */
317
byte* p = buf + col_len;
328
if (!(dtype->prtype & DATA_UNSIGNED)) {
335
} else if ((type == DATA_VARCHAR
336
|| type == DATA_VARMYSQL
337
|| type == DATA_BINARY)) {
339
if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
340
/* The length of the actual data is stored to 1 or 2
341
bytes at the start of the field */
343
if (row_format_col) {
344
if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
350
/* In a MySQL key value, lenlen is always 2 */
354
ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
357
/* Remove trailing spaces from old style VARCHAR
360
/* Handle UCS2 strings differently. */
361
ulint mbminlen = dtype_get_mbminlen(dtype);
367
/* Trim "half-chars", just in case. */
370
while (col_len >= 2 && ptr[col_len - 2] == 0x00
371
&& ptr[col_len - 1] == 0x20) {
378
&& ptr[col_len - 1] == 0x20) {
383
} else if (comp && type == DATA_MYSQL
384
&& dtype_get_mbminlen(dtype) == 1
385
&& dtype_get_mbmaxlen(dtype) > 1) {
386
/* In some cases we strip trailing spaces from UTF-8 and other
387
multibyte charsets, from FIXED-length CHAR columns, to save
388
space. UTF-8 would otherwise normally use 3 * the string length
389
bytes to store an ASCII string! */
391
/* We assume that this CHAR field is encoded in a
392
variable-length character set where spaces have
393
1:1 correspondence to 0x20 bytes, such as UTF-8.
395
Consider a CHAR(n) field, a field of n characters.
396
It will contain between n * mbminlen and n * mbmaxlen bytes.
397
We will try to truncate it to n bytes by stripping
398
space padding. If the field contains single-byte
399
characters only, it will be truncated to n characters.
400
Consider a CHAR(5) field containing the string ".a "
401
where "." denotes a 3-byte character represented by
402
the bytes "$%&". After our stripping, the string will
403
be stored as "$%&a " (5 bytes). The string ".abc "
404
will be stored as "$%&abc" (6 bytes).
406
The space padding will be restored in row0sel.c, function
407
row_sel_field_store_in_mysql_format(). */
411
ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
413
n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
415
/* Strip space padding. */
416
while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
419
} else if (type == DATA_BLOB && row_format_col) {
421
ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
424
dfield_set_data(dfield, ptr, col_len);
429
/**************************************************************//**
430
Convert a row in the MySQL format to a row in the Innobase format. Note that
431
the function to convert a MySQL format key value to an InnoDB dtuple is
432
row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
435
row_mysql_convert_row_to_innobase(
436
/*==============================*/
437
dtuple_t* row, /*!< in/out: Innobase row where the
438
field type information is already
440
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct where template
441
must be of type ROW_MYSQL_WHOLE_ROW */
442
byte* mysql_rec) /*!< in: row in the MySQL format;
443
NOTE: do not discard as long as
444
row is used, as row may contain
445
pointers to this record! */
447
mysql_row_templ_t* templ;
451
ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
452
ut_ad(prebuilt->mysql_template);
454
for (i = 0; i < prebuilt->n_template; i++) {
456
templ = prebuilt->mysql_template + i;
457
dfield = dtuple_get_nth_field(row, i);
459
if (templ->mysql_null_bit_mask != 0) {
460
/* Column may be SQL NULL */
462
if (mysql_rec[templ->mysql_null_byte_offset]
463
& (byte) (templ->mysql_null_bit_mask)) {
467
dfield_set_null(dfield);
473
row_mysql_store_col_in_innobase_format(
475
prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
476
TRUE, /* MySQL row format data */
477
mysql_rec + templ->mysql_col_offset,
478
templ->mysql_col_len,
479
dict_table_is_comp(prebuilt->table));
485
/****************************************************************//**
486
Handles user errors and lock waits detected by the database engine.
487
@return TRUE if it was a lock wait and we should continue running the
491
row_mysql_handle_errors(
492
/*====================*/
493
ulint* new_err,/*!< out: possible new error encountered in
494
lock wait, or if no new error, the value
495
of trx->error_state at the entry of this
497
trx_t* trx, /*!< in: transaction */
498
que_thr_t* thr, /*!< in: query thread */
499
trx_savept_t* savept) /*!< in: savepoint or NULL */
504
err = trx->error_state;
506
ut_a(err != DB_SUCCESS);
508
trx->error_state = DB_SUCCESS;
511
case DB_LOCK_WAIT_TIMEOUT:
512
if (row_rollback_on_timeout) {
513
trx_general_rollback_for_mysql(trx, NULL);
517
case DB_DUPLICATE_KEY:
518
case DB_FOREIGN_DUPLICATE_KEY:
519
case DB_TOO_BIG_RECORD:
520
case DB_ROW_IS_REFERENCED:
521
case DB_NO_REFERENCED_ROW:
522
case DB_CANNOT_ADD_CONSTRAINT:
523
case DB_TOO_MANY_CONCURRENT_TRXS:
524
case DB_OUT_OF_FILE_SPACE:
526
/* Roll back the latest, possibly incomplete
527
insertion or update */
529
trx_general_rollback_for_mysql(trx, savept);
531
/* MySQL will roll back the latest SQL statement */
534
srv_suspend_mysql_thread(thr);
536
if (trx->error_state != DB_SUCCESS) {
537
que_thr_stop_for_mysql(thr);
539
goto handle_new_error;
547
case DB_LOCK_TABLE_FULL:
548
/* Roll back the whole transaction; this resolution was added
549
to version 3.23.43 */
551
trx_general_rollback_for_mysql(trx, NULL);
554
case DB_MUST_GET_MORE_FILE_SPACE:
555
fputs("InnoDB: The database cannot continue"
556
" operation because of\n"
557
"InnoDB: lack of space. You must add"
558
" a new data file to\n"
559
"InnoDB: my.cnf and restart the database.\n", stderr);
564
fputs("InnoDB: We detected index corruption"
565
" in an InnoDB type table.\n"
566
"InnoDB: You have to dump + drop + reimport"
567
" the table or, in\n"
568
"InnoDB: a case of widespread corruption,"
570
"InnoDB: tables and recreate the"
571
" whole InnoDB tablespace.\n"
572
"InnoDB: If the mysqld server crashes"
573
" after the startup or when\n"
574
"InnoDB: you dump the tables, look at\n"
575
"InnoDB: " REFMAN "forcing-recovery.html"
576
" for help.\n", stderr);
579
fprintf(stderr, "InnoDB: unknown error code %lu\n",
584
if (trx->error_state != DB_SUCCESS) {
585
*new_err = trx->error_state;
590
trx->error_state = DB_SUCCESS;
595
/********************************************************************//**
596
Create a prebuilt struct for a MySQL table handle.
597
@return own: a prebuilt struct */
602
dict_table_t* table) /*!< in: Innobase table handle */
604
row_prebuilt_t* prebuilt;
606
dict_index_t* clust_index;
610
heap = mem_heap_create(sizeof *prebuilt + 128);
612
prebuilt = mem_heap_zalloc(heap, sizeof *prebuilt);
614
prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
615
prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
617
prebuilt->table = table;
619
prebuilt->sql_stat_start = TRUE;
620
prebuilt->heap = heap;
622
prebuilt->pcur = btr_pcur_create_for_mysql();
623
prebuilt->clust_pcur = btr_pcur_create_for_mysql();
625
prebuilt->select_lock_type = LOCK_NONE;
626
prebuilt->stored_select_lock_type = 99999999;
628
prebuilt->search_tuple = dtuple_create(
629
heap, 2 * dict_table_get_n_cols(table));
631
clust_index = dict_table_get_first_index(table);
633
/* Make sure that search_tuple is long enough for clustered index */
634
ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
636
ref_len = dict_index_get_n_unique(clust_index);
638
ref = dtuple_create(heap, ref_len);
640
dict_index_copy_types(ref, clust_index, ref_len);
642
prebuilt->clust_ref = ref;
644
prebuilt->autoinc_error = 0;
645
prebuilt->autoinc_offset = 0;
647
/* Default to 1, we will set the actual value later in
648
ha_innobase::get_auto_increment(). */
649
prebuilt->autoinc_increment = 1;
651
prebuilt->autoinc_last_value = 0;
656
/********************************************************************//**
657
Free a prebuilt struct for a MySQL table handle. */
662
row_prebuilt_t* prebuilt, /*!< in, own: prebuilt struct */
663
ibool dict_locked) /*!< in: TRUE=data dictionary locked */
668
(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
669
|| prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
672
"InnoDB: Error: trying to free a corrupt\n"
673
"InnoDB: table handle. Magic n %lu,"
674
" magic n2 %lu, table name ",
675
(ulong) prebuilt->magic_n,
676
(ulong) prebuilt->magic_n2);
677
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
680
mem_analyze_corruption(prebuilt);
685
prebuilt->magic_n = ROW_PREBUILT_FREED;
686
prebuilt->magic_n2 = ROW_PREBUILT_FREED;
688
btr_pcur_free_for_mysql(prebuilt->pcur);
689
btr_pcur_free_for_mysql(prebuilt->clust_pcur);
691
if (prebuilt->mysql_template) {
692
mem_free(prebuilt->mysql_template);
695
if (prebuilt->ins_graph) {
696
que_graph_free_recursive(prebuilt->ins_graph);
699
if (prebuilt->sel_graph) {
700
que_graph_free_recursive(prebuilt->sel_graph);
703
if (prebuilt->upd_graph) {
704
que_graph_free_recursive(prebuilt->upd_graph);
707
if (prebuilt->blob_heap) {
708
mem_heap_free(prebuilt->blob_heap);
711
if (prebuilt->old_vers_heap) {
712
mem_heap_free(prebuilt->old_vers_heap);
715
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
716
if (prebuilt->fetch_cache[i] != NULL) {
718
if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
719
(prebuilt->fetch_cache[i]) - 4))
720
|| (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
721
(prebuilt->fetch_cache[i])
722
+ prebuilt->mysql_row_len))) {
723
fputs("InnoDB: Error: trying to free"
724
" a corrupt fetch buffer.\n", stderr);
726
mem_analyze_corruption(
727
prebuilt->fetch_cache[i]);
732
mem_free((prebuilt->fetch_cache[i]) - 4);
736
dict_table_decrement_handle_count(prebuilt->table, dict_locked);
738
mem_heap_free(prebuilt->heap);
741
/*********************************************************************//**
742
Updates the transaction pointers in query graphs stored in the prebuilt
746
row_update_prebuilt_trx(
747
/*====================*/
748
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct
750
trx_t* trx) /*!< in: transaction handle */
752
if (trx->magic_n != TRX_MAGIC_N) {
754
"InnoDB: Error: trying to use a corrupt\n"
755
"InnoDB: trx handle. Magic n %lu\n",
756
(ulong) trx->magic_n);
758
mem_analyze_corruption(trx);
763
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
765
"InnoDB: Error: trying to use a corrupt\n"
766
"InnoDB: table handle. Magic n %lu, table name ",
767
(ulong) prebuilt->magic_n);
768
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
771
mem_analyze_corruption(prebuilt);
778
if (prebuilt->ins_graph) {
779
prebuilt->ins_graph->trx = trx;
782
if (prebuilt->upd_graph) {
783
prebuilt->upd_graph->trx = trx;
786
if (prebuilt->sel_graph) {
787
prebuilt->sel_graph->trx = trx;
791
/*********************************************************************//**
792
Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
793
has not yet been built in the prebuilt struct, then this function first
795
@return prebuilt dtuple; the column type information is also set in it */
798
row_get_prebuilt_insert_row(
799
/*========================*/
800
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
805
dict_table_t* table = prebuilt->table;
807
ut_ad(prebuilt && table && prebuilt->trx);
809
if (prebuilt->ins_node == NULL) {
811
/* Not called before for this handle: create an insert node
812
and query graph to the prebuilt struct */
814
node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
816
prebuilt->ins_node = node;
818
if (prebuilt->ins_upd_rec_buff == NULL) {
819
prebuilt->ins_upd_rec_buff = mem_heap_alloc(
820
prebuilt->heap, prebuilt->mysql_row_len);
823
row = dtuple_create(prebuilt->heap,
824
dict_table_get_n_cols(table));
826
dict_table_copy_types(row, table);
828
ins_node_set_new_row(node, row);
830
prebuilt->ins_graph = que_node_get_parent(
831
pars_complete_graph_for_exec(node,
834
prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
837
return(prebuilt->ins_node->row);
840
/*********************************************************************//**
841
Updates the table modification counter and calculates new estimates
842
for table and index statistics if necessary. */
845
row_update_statistics_if_needed(
846
/*============================*/
847
dict_table_t* table) /*!< in: table */
851
counter = table->stat_modified_counter;
853
table->stat_modified_counter = counter + 1;
855
/* Calculate new statistics if 1 / 16 of table has been modified
856
since the last time a statistics batch was run, or if
857
stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
858
We calculate statistics at most every 16th round, since we may have
859
a counter table which is very small and updated very often. */
861
if (counter > 2000000000
862
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
864
dict_update_statistics(table);
868
/*********************************************************************//**
869
Unlocks AUTO_INC type locks that were possibly reserved by a trx. This
870
function should be called at the the end of an SQL statement, by the
871
connection thread that owns the transaction (trx->mysql_thd). */
874
row_unlock_table_autoinc_for_mysql(
875
/*===============================*/
876
trx_t* trx) /*!< in/out: transaction */
878
if (lock_trx_holds_autoinc_locks(trx)) {
879
mutex_enter(&kernel_mutex);
881
lock_release_autoinc_locks(trx);
883
mutex_exit(&kernel_mutex);
887
/*********************************************************************//**
888
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
889
AUTO_INC lock gives exclusive access to the auto-inc counter of the
890
table. The lock is reserved only for the duration of an SQL statement.
891
It is not compatible with another AUTO_INC or exclusive lock on the
893
@return error code or DB_SUCCESS */
896
row_lock_table_autoinc_for_mysql(
897
/*=============================*/
898
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in the MySQL
901
trx_t* trx = prebuilt->trx;
902
ins_node_t* node = prebuilt->ins_node;
903
const dict_table_t* table = prebuilt->table;
909
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
911
/* If we already hold an AUTOINC lock on the table then do nothing.
912
Note: We peek at the value of the current owner without acquiring
913
the kernel mutex. **/
914
if (trx == table->autoinc_trx) {
919
trx->op_info = "setting auto-inc lock";
922
row_get_prebuilt_insert_row(prebuilt);
923
node = prebuilt->ins_node;
926
/* We use the insert query graph as the dummy graph needed
927
in the lock module call */
929
thr = que_fork_get_first_thr(prebuilt->ins_graph);
931
que_thr_move_to_run_state_for_mysql(thr, trx);
934
thr->run_node = node;
935
thr->prev_node = node;
937
/* It may be that the current session has not yet started
938
its transaction, or it has been committed: */
940
trx_start_if_not_started(trx);
942
err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
944
trx->error_state = err;
946
if (err != DB_SUCCESS) {
947
que_thr_stop_for_mysql(thr);
949
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
960
que_thr_stop_for_mysql_no_error(thr, trx);
967
/*********************************************************************//**
968
Sets a table lock on the table mentioned in prebuilt.
969
@return error code or DB_SUCCESS */
972
row_lock_table_for_mysql(
973
/*=====================*/
974
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in the MySQL
976
dict_table_t* table, /*!< in: table to lock, or NULL
977
if prebuilt->table should be
979
prebuilt->select_lock_type */
980
ulint mode) /*!< in: lock mode of table
981
(ignored if table==NULL) */
983
trx_t* trx = prebuilt->trx;
989
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
991
trx->op_info = "setting table lock";
993
if (prebuilt->sel_graph == NULL) {
994
/* Build a dummy select query graph */
995
row_prebuild_sel_graph(prebuilt);
998
/* We use the select query graph as the dummy graph needed
999
in the lock module call */
1001
thr = que_fork_get_first_thr(prebuilt->sel_graph);
1003
que_thr_move_to_run_state_for_mysql(thr, trx);
1006
thr->run_node = thr;
1007
thr->prev_node = thr->common.parent;
1009
/* It may be that the current session has not yet started
1010
its transaction, or it has been committed: */
1012
trx_start_if_not_started(trx);
1015
err = lock_table(0, table, mode, thr);
1017
err = lock_table(0, prebuilt->table,
1018
prebuilt->select_lock_type, thr);
1021
trx->error_state = err;
1023
if (err != DB_SUCCESS) {
1024
que_thr_stop_for_mysql(thr);
1026
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1028
if (was_lock_wait) {
1037
que_thr_stop_for_mysql_no_error(thr, trx);
1044
/*********************************************************************//**
1045
Does an insert for MySQL.
1046
@return error code or DB_SUCCESS */
1049
row_insert_for_mysql(
1050
/*=================*/
1051
byte* mysql_rec, /*!< in: row in the MySQL format */
1052
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1055
trx_savept_t savept;
1058
ibool was_lock_wait;
1059
trx_t* trx = prebuilt->trx;
1060
ins_node_t* node = prebuilt->ins_node;
1063
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1065
if (prebuilt->table->ibd_file_missing) {
1066
ut_print_timestamp(stderr);
1067
fprintf(stderr, " InnoDB: Error:\n"
1068
"InnoDB: MySQL is trying to use a table handle"
1069
" but the .ibd file for\n"
1070
"InnoDB: table %s does not exist.\n"
1071
"InnoDB: Have you deleted the .ibd file"
1072
" from the database directory under\n"
1073
"InnoDB: the MySQL datadir, or have you"
1074
" used DISCARD TABLESPACE?\n"
1075
"InnoDB: Look from\n"
1076
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1077
"InnoDB: how you can resolve the problem.\n",
1078
prebuilt->table->name);
1082
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1084
"InnoDB: Error: trying to free a corrupt\n"
1085
"InnoDB: table handle. Magic n %lu, table name ",
1086
(ulong) prebuilt->magic_n);
1087
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1090
mem_analyze_corruption(prebuilt);
1095
if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1096
fputs("InnoDB: A new raw disk partition was initialized or\n"
1097
"InnoDB: innodb_force_recovery is on: we do not allow\n"
1098
"InnoDB: database modifications by the user. Shut down\n"
1099
"InnoDB: mysqld and edit my.cnf so that"
1100
" newraw is replaced\n"
1101
"InnoDB: with raw, and innodb_force_... is removed.\n",
1107
trx->op_info = "inserting";
1109
row_mysql_delay_if_needed();
1111
trx_start_if_not_started(trx);
1114
row_get_prebuilt_insert_row(prebuilt);
1115
node = prebuilt->ins_node;
1118
row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1120
savept = trx_savept_take(trx);
1122
thr = que_fork_get_first_thr(prebuilt->ins_graph);
1124
if (prebuilt->sql_stat_start) {
1125
node->state = INS_NODE_SET_IX_LOCK;
1126
prebuilt->sql_stat_start = FALSE;
1128
node->state = INS_NODE_ALLOC_ROW_ID;
1131
que_thr_move_to_run_state_for_mysql(thr, trx);
1134
thr->run_node = node;
1135
thr->prev_node = node;
1139
err = trx->error_state;
1141
if (err != DB_SUCCESS) {
1142
que_thr_stop_for_mysql(thr);
1144
/* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1146
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1148
thr->lock_state= QUE_THR_LOCK_NOLOCK;
1150
if (was_lock_wait) {
1159
que_thr_stop_for_mysql_no_error(thr, trx);
1161
prebuilt->table->stat_n_rows++;
1163
srv_n_rows_inserted++;
1165
if (prebuilt->table->stat_n_rows == 0) {
1166
/* Avoid wrap-over */
1167
prebuilt->table->stat_n_rows--;
1170
row_update_statistics_if_needed(prebuilt->table);
1176
/*********************************************************************//**
1177
Builds a dummy query graph used in selects. */
1180
row_prebuild_sel_graph(
1181
/*===================*/
1182
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1187
ut_ad(prebuilt && prebuilt->trx);
1189
if (prebuilt->sel_graph == NULL) {
1191
node = sel_node_create(prebuilt->heap);
1193
prebuilt->sel_graph = que_node_get_parent(
1194
pars_complete_graph_for_exec(node,
1198
prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1202
/*********************************************************************//**
1203
Creates an query graph node of 'update' type to be used in the MySQL
1205
@return own: update node */
1208
row_create_update_node_for_mysql(
1209
/*=============================*/
1210
dict_table_t* table, /*!< in: table to update */
1211
mem_heap_t* heap) /*!< in: mem heap from which allocated */
1215
node = upd_node_create(heap);
1217
node->in_mysql_interface = TRUE;
1218
node->is_delete = FALSE;
1219
node->searched_update = FALSE;
1220
node->select = NULL;
1221
node->pcur = btr_pcur_create_for_mysql();
1222
node->table = table;
1224
node->update = upd_create(dict_table_get_n_cols(table), heap);
1226
node->update_n_fields = dict_table_get_n_cols(table);
1228
UT_LIST_INIT(node->columns);
1229
node->has_clust_rec_x_lock = TRUE;
1230
node->cmpl_info = 0;
1232
node->table_sym = NULL;
1233
node->col_assign_list = NULL;
1238
/*********************************************************************//**
1239
Gets pointer to a prebuilt update vector used in updates. If the update
1240
graph has not yet been built in the prebuilt struct, then this function
1242
@return prebuilt update vector */
1245
row_get_prebuilt_update_vector(
1246
/*===========================*/
1247
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1250
dict_table_t* table = prebuilt->table;
1253
ut_ad(prebuilt && table && prebuilt->trx);
1255
if (prebuilt->upd_node == NULL) {
1257
/* Not called before for this handle: create an update node
1258
and query graph to the prebuilt struct */
1260
node = row_create_update_node_for_mysql(table, prebuilt->heap);
1262
prebuilt->upd_node = node;
1264
prebuilt->upd_graph = que_node_get_parent(
1265
pars_complete_graph_for_exec(node,
1268
prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1271
return(prebuilt->upd_node->update);
1274
/*********************************************************************//**
1275
Does an update or delete of a row for MySQL.
1276
@return error code or DB_SUCCESS */
1279
row_update_for_mysql(
1280
/*=================*/
1281
byte* mysql_rec, /*!< in: the row to be updated, in
1283
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1286
trx_savept_t savept;
1289
ibool was_lock_wait;
1290
dict_index_t* clust_index;
1291
/* ulint ref_len; */
1293
dict_table_t* table = prebuilt->table;
1294
trx_t* trx = prebuilt->trx;
1296
ut_ad(prebuilt && trx);
1297
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1298
UT_NOT_USED(mysql_rec);
1300
if (prebuilt->table->ibd_file_missing) {
1301
ut_print_timestamp(stderr);
1302
fprintf(stderr, " InnoDB: Error:\n"
1303
"InnoDB: MySQL is trying to use a table handle"
1304
" but the .ibd file for\n"
1305
"InnoDB: table %s does not exist.\n"
1306
"InnoDB: Have you deleted the .ibd file"
1307
" from the database directory under\n"
1308
"InnoDB: the MySQL datadir, or have you"
1309
" used DISCARD TABLESPACE?\n"
1310
"InnoDB: Look from\n"
1311
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1312
"InnoDB: how you can resolve the problem.\n",
1313
prebuilt->table->name);
1317
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1319
"InnoDB: Error: trying to free a corrupt\n"
1320
"InnoDB: table handle. Magic n %lu, table name ",
1321
(ulong) prebuilt->magic_n);
1322
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1325
mem_analyze_corruption(prebuilt);
1330
if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1331
fputs("InnoDB: A new raw disk partition was initialized or\n"
1332
"InnoDB: innodb_force_recovery is on: we do not allow\n"
1333
"InnoDB: database modifications by the user. Shut down\n"
1334
"InnoDB: mysqld and edit my.cnf so that newraw"
1336
"InnoDB: with raw, and innodb_force_... is removed.\n",
1342
trx->op_info = "updating or deleting";
1344
row_mysql_delay_if_needed();
1346
trx_start_if_not_started(trx);
1348
node = prebuilt->upd_node;
1350
clust_index = dict_table_get_first_index(table);
1352
if (prebuilt->pcur->btr_cur.index == clust_index) {
1353
btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1355
btr_pcur_copy_stored_position(node->pcur,
1356
prebuilt->clust_pcur);
1359
ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1361
/* MySQL seems to call rnd_pos before updating each row it
1362
has cached: we can get the correct cursor position from
1363
prebuilt->pcur; NOTE that we cannot build the row reference
1364
from mysql_rec if the clustered index was automatically
1365
generated for the table: MySQL does not know anything about
1366
the row id used as the clustered index key */
1368
savept = trx_savept_take(trx);
1370
thr = que_fork_get_first_thr(prebuilt->upd_graph);
1372
node->state = UPD_NODE_UPDATE_CLUSTERED;
1374
ut_ad(!prebuilt->sql_stat_start);
1376
que_thr_move_to_run_state_for_mysql(thr, trx);
1379
thr->run_node = node;
1380
thr->prev_node = node;
1384
err = trx->error_state;
1386
if (err != DB_SUCCESS) {
1387
que_thr_stop_for_mysql(thr);
1389
if (err == DB_RECORD_NOT_FOUND) {
1390
trx->error_state = DB_SUCCESS;
1396
thr->lock_state= QUE_THR_LOCK_ROW;
1397
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1399
thr->lock_state= QUE_THR_LOCK_NOLOCK;
1401
if (was_lock_wait) {
1410
que_thr_stop_for_mysql_no_error(thr, trx);
1412
if (node->is_delete) {
1413
if (prebuilt->table->stat_n_rows > 0) {
1414
prebuilt->table->stat_n_rows--;
1417
srv_n_rows_deleted++;
1419
srv_n_rows_updated++;
1422
row_update_statistics_if_needed(prebuilt->table);
1429
/*********************************************************************//**
1430
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
1431
this session is using a READ COMMITTED isolation level. Before
1432
calling this function we must use trx_reset_new_rec_lock_info() and
1433
trx_register_new_rec_lock() to store the information which new record locks
1434
really were set. This function removes a newly set lock under prebuilt->pcur,
1435
and also under prebuilt->clust_pcur. Currently, this is only used and tested
1436
in the case of an UPDATE or a DELETE statement, where the row lock is of the
1438
Thus, this implements a 'mini-rollback' that releases the latest record
1440
@return error code or DB_SUCCESS */
1443
row_unlock_for_mysql(
1444
/*=================*/
1445
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL
1447
ibool has_latches_on_recs)/*!< TRUE if called so that we have
1448
the latches on the records under pcur
1449
and clust_pcur, and we do not need to
1450
reposition the cursors. */
1452
btr_pcur_t* pcur = prebuilt->pcur;
1453
btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
1454
trx_t* trx = prebuilt->trx;
1456
ut_ad(prebuilt && trx);
1457
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1460
(!srv_locks_unsafe_for_binlog
1461
&& trx->isolation_level != TRX_ISO_READ_COMMITTED)) {
1464
"InnoDB: Error: calling row_unlock_for_mysql though\n"
1465
"InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
1466
"InnoDB: this session is not using"
1467
" READ COMMITTED isolation level.\n");
1472
trx->op_info = "unlock_row";
1474
if (prebuilt->new_rec_locks >= 1) {
1477
dict_index_t* index;
1478
trx_id_t rec_trx_id;
1483
/* Restore the cursor position and find the record */
1485
if (!has_latches_on_recs) {
1486
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1489
rec = btr_pcur_get_rec(pcur);
1490
index = btr_pcur_get_btr_cur(pcur)->index;
1492
if (prebuilt->new_rec_locks >= 2) {
1493
/* Restore the cursor position and find the record
1494
in the clustered index. */
1496
if (!has_latches_on_recs) {
1497
btr_pcur_restore_position(BTR_SEARCH_LEAF,
1501
rec = btr_pcur_get_rec(clust_pcur);
1502
index = btr_pcur_get_btr_cur(clust_pcur)->index;
1505
if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
1506
/* This is not a clustered index record. We
1507
do not know how to unlock the record. */
1511
/* If the record has been modified by this
1512
transaction, do not unlock it. */
1514
if (index->trx_id_offset) {
1515
rec_trx_id = trx_read_trx_id(rec
1516
+ index->trx_id_offset);
1518
mem_heap_t* heap = NULL;
1519
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1520
ulint* offsets = offsets_;
1522
rec_offs_init(offsets_);
1523
offsets = rec_get_offsets(rec, index, offsets,
1524
ULINT_UNDEFINED, &heap);
1526
rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1528
if (UNIV_LIKELY_NULL(heap)) {
1529
mem_heap_free(heap);
1533
if (ut_dulint_cmp(rec_trx_id, trx->id) != 0) {
1534
/* We did not update the record: unlock it */
1536
rec = btr_pcur_get_rec(pcur);
1537
index = btr_pcur_get_btr_cur(pcur)->index;
1539
lock_rec_unlock(trx, btr_pcur_get_block(pcur),
1540
rec, prebuilt->select_lock_type);
1542
if (prebuilt->new_rec_locks >= 2) {
1543
rec = btr_pcur_get_rec(clust_pcur);
1544
index = btr_pcur_get_btr_cur(clust_pcur)->index;
1546
lock_rec_unlock(trx,
1547
btr_pcur_get_block(clust_pcur),
1549
prebuilt->select_lock_type);
1561
/**********************************************************************//**
1562
Does a cascaded delete or set null in a foreign key operation.
1563
@return error code or DB_SUCCESS */
1566
row_update_cascade_for_mysql(
1567
/*=========================*/
1568
que_thr_t* thr, /*!< in: query thread */
1569
upd_node_t* node, /*!< in: update node used in the cascade
1570
or set null operation */
1571
dict_table_t* table) /*!< in: table where we do the operation */
1576
trx = thr_get_trx(thr);
1578
thr->run_node = node;
1579
thr->prev_node = node;
1583
err = trx->error_state;
1585
/* Note that the cascade node is a subnode of another InnoDB
1586
query graph node. We do a normal lock wait in this node, but
1587
all errors are handled by the parent node. */
1589
if (err == DB_LOCK_WAIT) {
1590
/* Handle lock wait here */
1592
que_thr_stop_for_mysql(thr);
1594
srv_suspend_mysql_thread(thr);
1596
/* Note that a lock wait may also end in a lock wait timeout,
1597
or this transaction is picked as a victim in selective
1598
deadlock resolution */
1600
if (trx->error_state != DB_SUCCESS) {
1602
return(trx->error_state);
1605
/* Retry operation after a normal lock wait */
1610
if (err != DB_SUCCESS) {
1615
if (node->is_delete) {
1616
if (table->stat_n_rows > 0) {
1617
table->stat_n_rows--;
1620
srv_n_rows_deleted++;
1622
srv_n_rows_updated++;
1625
row_update_statistics_if_needed(table);
1630
/*********************************************************************//**
1631
Checks if a table is such that we automatically created a clustered
1632
index on it (on row id).
1633
@return TRUE if the clustered index was generated automatically */
1636
row_table_got_default_clust_index(
1637
/*==============================*/
1638
const dict_table_t* table) /*!< in: table */
1640
const dict_index_t* clust_index;
1642
clust_index = dict_table_get_first_index(table);
1644
return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1647
/*********************************************************************//**
1648
Calculates the key number used inside MySQL for an Innobase index. We have
1649
to take into account if we generated a default clustered index for the table
1650
@return the key number used inside MySQL */
1653
row_get_mysql_key_number_for_index(
1654
/*===============================*/
1655
const dict_index_t* index) /*!< in: index */
1657
const dict_index_t* ind;
1663
ind = dict_table_get_first_index(index->table);
1665
while (index != ind) {
1666
ind = dict_table_get_next_index(ind);
1670
if (row_table_got_default_clust_index(index->table)) {
1678
/*********************************************************************//**
1679
Locks the data dictionary in shared mode from modifications, for performing
1680
foreign key check, rollback, or other operation invisible to MySQL. */
1683
row_mysql_freeze_data_dictionary_func(
1684
/*==================================*/
1685
trx_t* trx, /*!< in/out: transaction */
1686
const char* file, /*!< in: file name */
1687
ulint line) /*!< in: line number */
1689
ut_a(trx->dict_operation_lock_mode == 0);
1691
rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
1693
trx->dict_operation_lock_mode = RW_S_LATCH;
1696
/*********************************************************************//**
1697
Unlocks the data dictionary shared lock. */
1700
row_mysql_unfreeze_data_dictionary(
1701
/*===============================*/
1702
trx_t* trx) /*!< in/out: transaction */
1704
ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
1706
rw_lock_s_unlock(&dict_operation_lock);
1708
trx->dict_operation_lock_mode = 0;
1711
/*********************************************************************//**
1712
Locks the data dictionary exclusively for performing a table create or other
1713
data dictionary modification operation. */
1716
row_mysql_lock_data_dictionary_func(
1717
/*================================*/
1718
trx_t* trx, /*!< in/out: transaction */
1719
const char* file, /*!< in: file name */
1720
ulint line) /*!< in: line number */
1722
ut_a(trx->dict_operation_lock_mode == 0
1723
|| trx->dict_operation_lock_mode == RW_X_LATCH);
1725
/* Serialize data dictionary operations with dictionary mutex:
1726
no deadlocks or lock waits can occur then in these operations */
1728
rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
1729
trx->dict_operation_lock_mode = RW_X_LATCH;
1731
mutex_enter(&(dict_sys->mutex));
1734
/*********************************************************************//**
1735
Unlocks the data dictionary exclusive lock. */
1738
row_mysql_unlock_data_dictionary(
1739
/*=============================*/
1740
trx_t* trx) /*!< in/out: transaction */
1742
ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1744
/* Serialize data dictionary operations with dictionary mutex:
1745
no deadlocks can occur then in these operations */
1747
mutex_exit(&(dict_sys->mutex));
1748
rw_lock_x_unlock(&dict_operation_lock);
1750
trx->dict_operation_lock_mode = 0;
1753
/*********************************************************************//**
1754
Creates a table for MySQL. If the name of the table ends in
1755
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
1756
"innodb_table_monitor", then this will also start the printing of monitor
1757
output by the master thread. If the table name ends in "innodb_mem_validate",
1758
InnoDB will try to invoke mem_validate().
1759
@return error code or DB_SUCCESS */
1762
row_create_table_for_mysql(
1763
/*=======================*/
1764
dict_table_t* table, /*!< in, own: table definition
1766
trx_t* trx) /*!< in: transaction handle */
1771
const char* table_name;
1772
ulint table_name_len;
1775
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1776
#ifdef UNIV_SYNC_DEBUG
1777
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1778
#endif /* UNIV_SYNC_DEBUG */
1779
ut_ad(mutex_own(&(dict_sys->mutex)));
1780
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1782
if (srv_created_new_raw) {
1783
fputs("InnoDB: A new raw disk partition was initialized:\n"
1784
"InnoDB: we do not allow database modifications"
1786
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1787
" is replaced with raw.\n", stderr);
1789
dict_mem_table_free(table);
1790
trx_commit_for_mysql(trx);
1795
trx->op_info = "creating table";
1797
if (row_mysql_is_system_table(table->name)) {
1800
"InnoDB: Error: trying to create a MySQL system"
1801
" table %s of type InnoDB.\n"
1802
"InnoDB: MySQL system tables must be"
1803
" of the MyISAM type!\n",
1808
trx_start_if_not_started(trx);
1810
/* The table name is prefixed with the database name and a '/'.
1811
Certain table names starting with 'innodb_' have their special
1812
meaning regardless of the database name. Thus, we need to
1813
ignore the database name prefix in the comparisons. */
1814
table_name = strchr(table->name, '/');
1817
table_name_len = strlen(table_name) + 1;
1819
if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
1821
/* Table equals "innodb_monitor":
1822
start monitor prints */
1824
srv_print_innodb_monitor = TRUE;
1826
/* The lock timeout monitor thread also takes care
1827
of InnoDB monitor prints */
1829
os_event_set(srv_lock_timeout_thread_event);
1830
} else if (STR_EQ(table_name, table_name_len,
1831
S_innodb_lock_monitor)) {
1833
srv_print_innodb_monitor = TRUE;
1834
srv_print_innodb_lock_monitor = TRUE;
1835
os_event_set(srv_lock_timeout_thread_event);
1836
} else if (STR_EQ(table_name, table_name_len,
1837
S_innodb_tablespace_monitor)) {
1839
srv_print_innodb_tablespace_monitor = TRUE;
1840
os_event_set(srv_lock_timeout_thread_event);
1841
} else if (STR_EQ(table_name, table_name_len,
1842
S_innodb_table_monitor)) {
1844
srv_print_innodb_table_monitor = TRUE;
1845
os_event_set(srv_lock_timeout_thread_event);
1846
} else if (STR_EQ(table_name, table_name_len,
1847
S_innodb_mem_validate)) {
1848
/* We define here a debugging feature intended for
1851
fputs("Validating InnoDB memory:\n"
1852
"to use this feature you must compile InnoDB with\n"
1853
"UNIV_MEM_DEBUG defined in univ.i and"
1854
" the server must be\n"
1855
"quiet because allocation from a mem heap"
1856
" is not protected\n"
1857
"by any semaphore.\n", stderr);
1858
#ifdef UNIV_MEM_DEBUG
1859
ut_a(mem_validate());
1860
fputs("Memory validated\n", stderr);
1861
#else /* UNIV_MEM_DEBUG */
1862
fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1864
#endif /* UNIV_MEM_DEBUG */
1867
heap = mem_heap_create(512);
1869
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1871
node = tab_create_graph_create(table, heap);
1873
thr = pars_complete_graph_for_exec(node, trx, heap);
1875
ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1876
que_run_threads(thr);
1878
err = trx->error_state;
1880
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
1881
trx->error_state = DB_SUCCESS;
1882
trx_general_rollback_for_mysql(trx, NULL);
1883
/* TO DO: free table? The code below will dereference
1884
table->name, though. */
1888
case DB_OUT_OF_FILE_SPACE:
1889
ut_print_timestamp(stderr);
1890
fputs(" InnoDB: Warning: cannot create table ",
1892
ut_print_name(stderr, trx, TRUE, table->name);
1893
fputs(" because tablespace full\n", stderr);
1895
if (dict_table_get_low(table->name)) {
1897
row_drop_table_for_mysql(table->name, trx, FALSE);
1898
trx_commit_for_mysql(trx);
1902
case DB_DUPLICATE_KEY:
1903
/* We may also get err == DB_ERROR if the .ibd file for the
1904
table already exists */
1909
que_graph_free((que_t*) que_node_get_parent(thr));
1916
/*********************************************************************//**
1917
Does an index creation operation for MySQL. TODO: currently failure
1918
to create an index results in dropping the whole table! This is no problem
1919
currently as all indexes must be created at the same time as the table.
1920
@return error number or DB_SUCCESS */
1923
row_create_index_for_mysql(
1924
/*=======================*/
1925
dict_index_t* index, /*!< in, own: index definition
1927
trx_t* trx, /*!< in: transaction handle */
1928
const ulint* field_lengths) /*!< in: if not NULL, must contain
1929
dict_index_get_n_fields(index)
1930
actual field lengths for the
1931
index columns, which are
1932
then checked for not being too
1943
#ifdef UNIV_SYNC_DEBUG
1944
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1945
#endif /* UNIV_SYNC_DEBUG */
1946
ut_ad(mutex_own(&(dict_sys->mutex)));
1947
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1949
trx->op_info = "creating index";
1951
/* Copy the table name because we may want to drop the
1952
table later, after the index object is freed (inside
1953
que_run_threads()) and thus index->table_name is not available. */
1954
table_name = mem_strdup(index->table_name);
1956
trx_start_if_not_started(trx);
1958
/* Check that the same column does not appear twice in the index.
1959
Starting from 4.0.14, InnoDB should be able to cope with that, but
1960
safer not to allow them. */
1962
for (i = 0; i < dict_index_get_n_fields(index); i++) {
1965
for (j = 0; j < i; j++) {
1967
dict_index_get_nth_field(index, j)->name,
1968
dict_index_get_nth_field(index, i)->name)) {
1969
ut_print_timestamp(stderr);
1971
fputs(" InnoDB: Error: column ", stderr);
1972
ut_print_name(stderr, trx, FALSE,
1973
dict_index_get_nth_field(
1975
fputs(" appears twice in ", stderr);
1976
dict_index_name_print(stderr, trx, index);
1978
"InnoDB: This is not allowed"
1979
" in InnoDB.\n", stderr);
1981
err = DB_COL_APPEARS_TWICE_IN_INDEX;
1983
goto error_handling;
1987
/* Check also that prefix_len and actual length
1988
< DICT_MAX_INDEX_COL_LEN */
1990
len = dict_index_get_nth_field(index, i)->prefix_len;
1992
if (field_lengths) {
1993
len = ut_max(len, field_lengths[i]);
1996
if (len >= DICT_MAX_INDEX_COL_LEN) {
1997
err = DB_TOO_BIG_RECORD;
1999
goto error_handling;
2003
heap = mem_heap_create(512);
2005
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2007
/* Note that the space id where we store the index is inherited from
2008
the table in dict_build_index_def_step() in dict0crea.c. */
2010
node = ind_create_graph_create(index, heap);
2012
thr = pars_complete_graph_for_exec(node, trx, heap);
2014
ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2015
que_run_threads(thr);
2017
err = trx->error_state;
2019
que_graph_free((que_t*) que_node_get_parent(thr));
2022
if (err != DB_SUCCESS) {
2023
/* We have special error handling here */
2025
trx->error_state = DB_SUCCESS;
2027
trx_general_rollback_for_mysql(trx, NULL);
2029
row_drop_table_for_mysql(table_name, trx, FALSE);
2031
trx_commit_for_mysql(trx);
2033
trx->error_state = DB_SUCCESS;
2038
mem_free(table_name);
2043
/*********************************************************************//**
2044
Scans a table create SQL string and adds to the data dictionary
2045
the foreign key constraints declared in the string. This function
2046
should be called after the indexes for a table have been created.
2047
Each foreign key constraint must be accompanied with indexes in
2048
both participating tables. The indexes are allowed to contain more
2049
fields than mentioned in the constraint. Check also that foreign key
2050
constraints which reference this table are ok.
2051
@return error code or DB_SUCCESS */
2054
row_table_add_foreign_constraints(
2055
/*==============================*/
2056
trx_t* trx, /*!< in: transaction */
2057
const char* sql_string, /*!< in: table create statement where
2058
foreign keys are declared like:
2059
FOREIGN KEY (a, b) REFERENCES table2(c, d),
2060
table2 can be written also with the
2061
database name before it: test.table2 */
2062
const char* name, /*!< in: table full name in the
2064
database_name/table_name */
2065
ibool reject_fks) /*!< in: if TRUE, fail with error
2066
code DB_CANNOT_ADD_CONSTRAINT if
2067
any foreign keys are found. */
2071
ut_ad(mutex_own(&(dict_sys->mutex)));
2072
#ifdef UNIV_SYNC_DEBUG
2073
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2074
#endif /* UNIV_SYNC_DEBUG */
2077
trx->op_info = "adding foreign keys";
2079
trx_start_if_not_started(trx);
2081
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2083
err = dict_create_foreign_constraints(trx, sql_string, name,
2085
if (err == DB_SUCCESS) {
2086
/* Check that also referencing constraints are ok */
2087
err = dict_load_foreigns(name, TRUE);
2090
if (err != DB_SUCCESS) {
2091
/* We have special error handling here */
2093
trx->error_state = DB_SUCCESS;
2095
trx_general_rollback_for_mysql(trx, NULL);
2097
row_drop_table_for_mysql(name, trx, FALSE);
2099
trx_commit_for_mysql(trx);
2101
trx->error_state = DB_SUCCESS;
2107
/*********************************************************************//**
2108
Drops a table for MySQL as a background operation. MySQL relies on Unix
2109
in ALTER TABLE to the fact that the table handler does not remove the
2110
table before all handles to it has been removed. Furhermore, the MySQL's
2111
call to drop table must be non-blocking. Therefore we do the drop table
2112
as a background operation, which is taken care of by the master thread
2114
@return error code or DB_SUCCESS */
2117
row_drop_table_for_mysql_in_background(
2118
/*===================================*/
2119
const char* name) /*!< in: table name */
2124
trx = trx_allocate_for_background();
2126
/* If the original transaction was dropping a table referenced by
2127
foreign keys, we must set the following to be able to drop the
2130
trx->check_foreigns = FALSE;
2132
/* fputs("InnoDB: Error: Dropping table ", stderr);
2133
ut_print_name(stderr, trx, TRUE, name);
2134
fputs(" in background drop list\n", stderr); */
2136
/* Try to drop the table in InnoDB */
2138
error = row_drop_table_for_mysql(name, trx, FALSE);
2140
/* Flush the log to reduce probability that the .frm files and
2141
the InnoDB data dictionary get out-of-sync if the user runs
2142
with innodb_flush_log_at_trx_commit = 0 */
2144
log_buffer_flush_to_disk();
2146
trx_commit_for_mysql(trx);
2148
trx_free_for_background(trx);
2150
return((int) error);
2153
/*********************************************************************//**
2154
The master thread in srv0srv.c calls this regularly to drop tables which
2155
we must drop in background after queries to them have ended. Such lazy
2156
dropping of tables is needed in ALTER TABLE on Unix.
2157
@return how many tables dropped + remaining tables in list */
2160
row_drop_tables_for_mysql_in_background(void)
2161
/*=========================================*/
2163
row_mysql_drop_t* drop;
2164
dict_table_t* table;
2166
ulint n_tables_dropped = 0;
2168
mutex_enter(&kernel_mutex);
2170
if (!row_mysql_drop_list_inited) {
2172
UT_LIST_INIT(row_mysql_drop_list);
2173
row_mysql_drop_list_inited = TRUE;
2176
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2178
n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2180
mutex_exit(&kernel_mutex);
2183
/* All tables dropped */
2185
return(n_tables + n_tables_dropped);
2188
mutex_enter(&(dict_sys->mutex));
2189
table = dict_table_get_low(drop->table_name);
2190
mutex_exit(&(dict_sys->mutex));
2192
if (table == NULL) {
2193
/* If for some reason the table has already been dropped
2194
through some other mechanism, do not try to drop it */
2196
goto already_dropped;
2199
if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2200
drop->table_name)) {
2201
/* If the DROP fails for some table, we return, and let the
2202
main thread retry later */
2204
return(n_tables + n_tables_dropped);
2210
mutex_enter(&kernel_mutex);
2212
UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2214
ut_print_timestamp(stderr);
2215
fputs(" InnoDB: Dropped table ", stderr);
2216
ut_print_name(stderr, NULL, TRUE, drop->table_name);
2217
fputs(" in background drop queue.\n", stderr);
2219
mem_free(drop->table_name);
2223
mutex_exit(&kernel_mutex);
2228
/*********************************************************************//**
2229
Get the background drop list length. NOTE: the caller must own the kernel
2231
@return how many tables in list */
2234
row_get_background_drop_list_len_low(void)
2235
/*======================================*/
2237
ut_ad(mutex_own(&kernel_mutex));
2239
if (!row_mysql_drop_list_inited) {
2241
UT_LIST_INIT(row_mysql_drop_list);
2242
row_mysql_drop_list_inited = TRUE;
2245
return(UT_LIST_GET_LEN(row_mysql_drop_list));
2248
/*********************************************************************//**
2249
If a table is not yet in the drop list, adds the table to the list of tables
2250
which the master thread drops in background. We need this on Unix because in
2251
ALTER TABLE MySQL may call drop table even if the table has running queries on
2252
it. Also, if there are running foreign key checks on the table, we drop the
2254
@return TRUE if the table was not yet in the drop list, and was added there */
2257
row_add_table_to_background_drop_list(
2258
/*==================================*/
2259
const char* name) /*!< in: table name */
2261
row_mysql_drop_t* drop;
2263
mutex_enter(&kernel_mutex);
2265
if (!row_mysql_drop_list_inited) {
2267
UT_LIST_INIT(row_mysql_drop_list);
2268
row_mysql_drop_list_inited = TRUE;
2271
/* Look if the table already is in the drop list */
2272
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2274
while (drop != NULL) {
2275
if (strcmp(drop->table_name, name) == 0) {
2276
/* Already in the list */
2278
mutex_exit(&kernel_mutex);
2283
drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2286
drop = mem_alloc(sizeof(row_mysql_drop_t));
2288
drop->table_name = mem_strdup(name);
2290
UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2292
/* fputs("InnoDB: Adding table ", stderr);
2293
ut_print_name(stderr, trx, TRUE, drop->table_name);
2294
fputs(" to background drop list\n", stderr); */
2296
mutex_exit(&kernel_mutex);
2301
/*********************************************************************//**
2302
Discards the tablespace of a table which stored in an .ibd file. Discarding
2303
means that this function deletes the .ibd file and assigns a new table id for
2304
the table. Also the flag table->ibd_file_missing is set TRUE.
2305
@return error code or DB_SUCCESS */
2308
row_discard_tablespace_for_mysql(
2309
/*=============================*/
2310
const char* name, /*!< in: table name */
2311
trx_t* trx) /*!< in: transaction handle */
2313
dict_foreign_t* foreign;
2315
dict_table_t* table;
2318
pars_info_t* info = NULL;
2320
/* How do we prevent crashes caused by ongoing operations on
2321
the table? Old operations could try to access non-existent
2324
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2325
MySQL table lock on the table before we can do DISCARD
2326
TABLESPACE. Then there are no running queries on the table.
2328
2) Purge and rollback: we assign a new table id for the
2329
table. Since purge and rollback look for the table based on
2330
the table id, they see the table as 'dropped' and discard
2333
3) Insert buffer: we remove all entries for the tablespace in
2334
the insert buffer tree; as long as the tablespace mem object
2335
does not exist, ongoing insert buffer page merges are
2336
discarded in buf0rea.c. If we recreate the tablespace mem
2337
object with IMPORT TABLESPACE later, then the tablespace will
2338
have the same id, but the tablespace_version field in the mem
2339
object is different, and ongoing old insert buffer page merges
2342
4) Linear readahead and random readahead: we use the same
2343
method as in 3) to discard ongoing operations.
2345
5) FOREIGN KEY operations: if
2346
table->n_foreign_key_checks_running > 0, we do not allow the
2347
discard. We also reserve the data dictionary latch. */
2349
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2351
trx->op_info = "discarding tablespace";
2352
trx_start_if_not_started(trx);
2354
/* Serialize data dictionary operations with dictionary mutex:
2355
no deadlocks can occur then in these operations */
2357
row_mysql_lock_data_dictionary(trx);
2359
table = dict_table_get_low(name);
2362
err = DB_TABLE_NOT_FOUND;
2367
if (table->space == 0) {
2368
ut_print_timestamp(stderr);
2369
fputs(" InnoDB: Error: table ", stderr);
2370
ut_print_name(stderr, trx, TRUE, name);
2372
"InnoDB: is in the system tablespace 0"
2373
" which cannot be discarded\n", stderr);
2379
if (table->n_foreign_key_checks_running > 0) {
2381
ut_print_timestamp(stderr);
2382
fputs(" InnoDB: You are trying to DISCARD table ", stderr);
2383
ut_print_name(stderr, trx, TRUE, table->name);
2385
"InnoDB: though there is a foreign key check"
2387
"InnoDB: Cannot discard the table.\n",
2395
/* Check if the table is referenced by foreign key constraints from
2396
some other table (not the table itself) */
2398
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2400
while (foreign && foreign->foreign_table == table) {
2401
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2404
if (foreign && trx->check_foreigns) {
2406
FILE* ef = dict_foreign_err_file;
2408
/* We only allow discarding a referenced table if
2409
FOREIGN_KEY_CHECKS is set to 0 */
2411
err = DB_CANNOT_DROP_CONSTRAINT;
2413
mutex_enter(&dict_foreign_err_mutex);
2415
ut_print_timestamp(ef);
2417
fputs(" Cannot DISCARD table ", ef);
2418
ut_print_name(stderr, trx, TRUE, name);
2420
"because it is referenced by ", ef);
2421
ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
2423
mutex_exit(&dict_foreign_err_mutex);
2428
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2430
/* Remove all locks except the table-level S and X locks. */
2431
lock_remove_all_on_table(table, FALSE);
2433
info = pars_info_create();
2435
pars_info_add_str_literal(info, "table_name", name);
2436
pars_info_add_dulint_literal(info, "new_id", new_id);
2438
err = que_eval_sql(info,
2439
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2442
"SELECT ID INTO old_id\n"
2444
"WHERE NAME = :table_name\n"
2445
"LOCK IN SHARE MODE;\n"
2446
"IF (SQL % NOTFOUND) THEN\n"
2450
"UPDATE SYS_TABLES SET ID = :new_id\n"
2451
" WHERE ID = old_id;\n"
2452
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2453
" WHERE TABLE_ID = old_id;\n"
2454
"UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2455
" WHERE TABLE_ID = old_id;\n"
2460
if (err != DB_SUCCESS) {
2461
trx->error_state = DB_SUCCESS;
2462
trx_general_rollback_for_mysql(trx, NULL);
2463
trx->error_state = DB_SUCCESS;
2465
dict_table_change_id_in_cache(table, new_id);
2467
success = fil_discard_tablespace(table->space);
2470
trx->error_state = DB_SUCCESS;
2471
trx_general_rollback_for_mysql(trx, NULL);
2472
trx->error_state = DB_SUCCESS;
2476
/* Set the flag which tells that now it is legal to
2477
IMPORT a tablespace for this table */
2478
table->tablespace_discarded = TRUE;
2479
table->ibd_file_missing = TRUE;
2484
trx_commit_for_mysql(trx);
2486
row_mysql_unlock_data_dictionary(trx);
2493
/*****************************************************************//**
2494
Imports a tablespace. The space id in the .ibd file must match the space id
2495
of the table in the data dictionary.
2496
@return error code or DB_SUCCESS */
2499
row_import_tablespace_for_mysql(
2500
/*============================*/
2501
const char* name, /*!< in: table name */
2502
trx_t* trx) /*!< in: transaction handle */
2504
dict_table_t* table;
2506
ib_uint64_t current_lsn;
2507
ulint err = DB_SUCCESS;
2509
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2511
trx_start_if_not_started(trx);
2513
trx->op_info = "importing tablespace";
2515
current_lsn = log_get_lsn();
2517
/* It is possible, though very improbable, that the lsn's in the
2518
tablespace to be imported have risen above the current system lsn, if
2519
a lengthy purge, ibuf merge, or rollback was performed on a backup
2520
taken with ibbackup. If that is the case, reset page lsn's in the
2521
file. We assume that mysqld was shut down after it performed these
2522
cleanup operations on the .ibd file, so that it stamped the latest lsn
2523
to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2525
TODO: reset also the trx id's in clustered index records and write
2526
a new space id to each data page. That would allow us to import clean
2527
.ibd files from another MySQL installation. */
2529
success = fil_reset_too_high_lsns(name, current_lsn);
2532
ut_print_timestamp(stderr);
2533
fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
2534
ut_print_name(stderr, trx, TRUE, name);
2536
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2541
row_mysql_lock_data_dictionary(trx);
2546
/* Serialize data dictionary operations with dictionary mutex:
2547
no deadlocks can occur then in these operations */
2549
row_mysql_lock_data_dictionary(trx);
2551
table = dict_table_get_low(name);
2554
ut_print_timestamp(stderr);
2555
fputs(" InnoDB: table ", stderr);
2556
ut_print_name(stderr, trx, TRUE, name);
2558
"InnoDB: does not exist in the InnoDB data dictionary\n"
2559
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2562
err = DB_TABLE_NOT_FOUND;
2567
if (table->space == 0) {
2568
ut_print_timestamp(stderr);
2569
fputs(" InnoDB: Error: table ", stderr);
2570
ut_print_name(stderr, trx, TRUE, name);
2572
"InnoDB: is in the system tablespace 0"
2573
" which cannot be imported\n", stderr);
2579
if (!table->tablespace_discarded) {
2580
ut_print_timestamp(stderr);
2581
fputs(" InnoDB: Error: you are trying to"
2582
" IMPORT a tablespace\n"
2583
"InnoDB: ", stderr);
2584
ut_print_name(stderr, trx, TRUE, name);
2585
fputs(", though you have not called DISCARD on it yet\n"
2586
"InnoDB: during the lifetime of the mysqld process!\n",
2594
/* Play safe and remove all insert buffer entries, though we should
2595
have removed them already when DISCARD TABLESPACE was called */
2597
ibuf_delete_for_discarded_space(table->space);
2599
success = fil_open_single_table_tablespace(
2601
table->flags == DICT_TF_COMPACT ? 0 : table->flags,
2604
table->ibd_file_missing = FALSE;
2605
table->tablespace_discarded = FALSE;
2607
if (table->ibd_file_missing) {
2608
ut_print_timestamp(stderr);
2609
fputs(" InnoDB: cannot find or open in the"
2610
" database directory the .ibd file of\n"
2611
"InnoDB: table ", stderr);
2612
ut_print_name(stderr, trx, TRUE, name);
2614
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2622
trx_commit_for_mysql(trx);
2624
row_mysql_unlock_data_dictionary(trx);
2631
/*********************************************************************//**
2632
Truncates a table for MySQL.
2633
@return error code or DB_SUCCESS */
2636
row_truncate_table_for_mysql(
2637
/*=========================*/
2638
dict_table_t* table, /*!< in: table handle */
2639
trx_t* trx) /*!< in: transaction handle */
2641
dict_foreign_t* foreign;
2647
dict_index_t* sys_index;
2651
ulint recreate_space = 0;
2652
pars_info_t* info = NULL;
2654
/* How do we prevent crashes caused by ongoing operations on
2655
the table? Old operations could try to access non-existent
2658
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2659
MySQL table lock on the table before we can do TRUNCATE
2660
TABLE. Then there are no running queries on the table. This is
2661
guaranteed, because in ha_innobase::store_lock(), we do not
2662
weaken the TL_WRITE lock requested by MySQL when executing
2665
2) Purge and rollback: we assign a new table id for the
2666
table. Since purge and rollback look for the table based on
2667
the table id, they see the table as 'dropped' and discard
2670
3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2671
so we do not have to remove insert buffer records, as the
2672
insert buffer works at a low level. If a freed page is later
2673
reallocated, the allocator will remove the ibuf entries for
2676
When we truncate *.ibd files by recreating them (analogous to
2677
DISCARD TABLESPACE), we remove all entries for the table in the
2678
insert buffer tree. This is not strictly necessary, because
2679
in 6) we will assign a new tablespace identifier, but we can
2680
free up some space in the system tablespace.
2682
4) Linear readahead and random readahead: we use the same
2683
method as in 3) to discard ongoing operations. (This is only
2684
relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2686
5) FOREIGN KEY operations: if
2687
table->n_foreign_key_checks_running > 0, we do not allow the
2688
TRUNCATE. We also reserve the data dictionary latch.
2690
6) Crash recovery: To prevent the application of pre-truncation
2691
redo log records on the truncated tablespace, we will assign
2692
a new tablespace identifier to the truncated tablespace. */
2694
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2697
if (srv_created_new_raw) {
2698
fputs("InnoDB: A new raw disk partition was initialized:\n"
2699
"InnoDB: we do not allow database modifications"
2701
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2702
" is replaced with raw.\n", stderr);
2707
trx->op_info = "truncating table";
2709
trx_start_if_not_started(trx);
2711
/* Serialize data dictionary operations with dictionary mutex:
2712
no deadlocks can occur then in these operations */
2714
ut_a(trx->dict_operation_lock_mode == 0);
2715
/* Prevent foreign key checks etc. while we are truncating the
2718
row_mysql_lock_data_dictionary(trx);
2720
ut_ad(mutex_own(&(dict_sys->mutex)));
2721
#ifdef UNIV_SYNC_DEBUG
2722
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2723
#endif /* UNIV_SYNC_DEBUG */
2725
/* Check if the table is referenced by foreign key constraints from
2726
some other table (not the table itself) */
2728
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2730
while (foreign && foreign->foreign_table == table) {
2731
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2734
if (foreign && trx->check_foreigns) {
2735
FILE* ef = dict_foreign_err_file;
2737
/* We only allow truncating a referenced table if
2738
FOREIGN_KEY_CHECKS is set to 0 */
2740
mutex_enter(&dict_foreign_err_mutex);
2742
ut_print_timestamp(ef);
2744
fputs(" Cannot truncate table ", ef);
2745
ut_print_name(ef, trx, TRUE, table->name);
2746
fputs(" by DROP+CREATE\n"
2747
"InnoDB: because it is referenced by ", ef);
2748
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2750
mutex_exit(&dict_foreign_err_mutex);
2756
/* TODO: could we replace the counter n_foreign_key_checks_running
2757
with lock checks on the table? Acquire here an exclusive lock on the
2758
table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2759
they can cope with the table having been truncated here? Foreign key
2760
checks take an IS or IX lock on the table. */
2762
if (table->n_foreign_key_checks_running > 0) {
2763
ut_print_timestamp(stderr);
2764
fputs(" InnoDB: Cannot truncate table ", stderr);
2765
ut_print_name(stderr, trx, TRUE, table->name);
2766
fputs(" by DROP+CREATE\n"
2767
"InnoDB: because there is a foreign key check"
2768
" running on it.\n",
2775
/* Remove all locks except the table-level S and X locks. */
2776
lock_remove_all_on_table(table, FALSE);
2778
trx->table_id = table->id;
2780
if (table->space && !table->dir_path_of_temp_table) {
2781
/* Discard and create the single-table tablespace. */
2782
ulint space = table->space;
2783
ulint flags = fil_space_get_flags(space);
2785
if (flags != ULINT_UNDEFINED
2786
&& fil_discard_tablespace(space)) {
2788
dict_index_t* index;
2792
if (fil_create_new_single_table_tablespace(
2793
&space, table->name, FALSE, flags,
2794
FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
2795
ut_print_timestamp(stderr);
2797
" InnoDB: TRUNCATE TABLE %s failed to"
2798
" create a new tablespace\n",
2800
table->ibd_file_missing = 1;
2805
recreate_space = space;
2807
/* Replace the space_id in the data dictionary cache.
2808
The persisent data dictionary (SYS_TABLES.SPACE
2809
and SYS_INDEXES.SPACE) are updated later in this
2811
table->space = space;
2812
index = dict_table_get_first_index(table);
2814
index->space = space;
2815
index = dict_table_get_next_index(index);
2819
fsp_header_init(space,
2820
FIL_IBD_FILE_INITIAL_SIZE, &mtr);
2825
/* scan SYS_INDEXES for all indexes of the table */
2826
heap = mem_heap_create(800);
2828
tuple = dtuple_create(heap, 1);
2829
dfield = dtuple_get_nth_field(tuple, 0);
2831
buf = mem_heap_alloc(heap, 8);
2832
mach_write_to_8(buf, table->id);
2834
dfield_set_data(dfield, buf, 8);
2835
sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2836
dict_index_copy_types(tuple, sys_index, 1);
2839
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2840
BTR_MODIFY_LEAF, &pcur, &mtr);
2847
if (!btr_pcur_is_on_user_rec(&pcur)) {
2848
/* The end of SYS_INDEXES has been reached. */
2852
rec = btr_pcur_get_rec(&pcur);
2854
field = rec_get_nth_field_old(rec, 0, &len);
2857
if (memcmp(buf, field, len) != 0) {
2858
/* End of indexes for the table (TABLE_ID mismatch). */
2862
if (rec_get_deleted_flag(rec, FALSE)) {
2863
/* The index has been dropped. */
2867
/* This call may commit and restart mtr
2868
and reposition pcur. */
2869
root_page_no = dict_truncate_index_tree(table, recreate_space,
2872
rec = btr_pcur_get_rec(&pcur);
2874
if (root_page_no != FIL_NULL) {
2875
page_rec_write_index_page_no(
2876
rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2877
root_page_no, &mtr);
2878
/* We will need to commit and restart the
2879
mini-transaction in order to avoid deadlocks.
2880
The dict_truncate_index_tree() call has allocated
2881
a page in this mini-transaction, and the rest of
2882
this loop could latch another index page. */
2885
btr_pcur_restore_position(BTR_MODIFY_LEAF,
2890
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2893
btr_pcur_close(&pcur);
2896
mem_heap_free(heap);
2898
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2900
info = pars_info_create();
2902
pars_info_add_int4_literal(info, "space", (lint) table->space);
2903
pars_info_add_dulint_literal(info, "old_id", table->id);
2904
pars_info_add_dulint_literal(info, "new_id", new_id);
2906
err = que_eval_sql(info,
2907
"PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2910
" SET ID = :new_id, SPACE = :space\n"
2911
" WHERE ID = :old_id;\n"
2912
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2913
" WHERE TABLE_ID = :old_id;\n"
2914
"UPDATE SYS_INDEXES"
2915
" SET TABLE_ID = :new_id, SPACE = :space\n"
2916
" WHERE TABLE_ID = :old_id;\n"
2921
if (err != DB_SUCCESS) {
2922
trx->error_state = DB_SUCCESS;
2923
trx_general_rollback_for_mysql(trx, NULL);
2924
trx->error_state = DB_SUCCESS;
2925
ut_print_timestamp(stderr);
2926
fputs(" InnoDB: Unable to assign a new identifier to table ",
2928
ut_print_name(stderr, trx, TRUE, table->name);
2930
"InnoDB: after truncating it. Background processes"
2931
" may corrupt the table!\n", stderr);
2934
dict_table_change_id_in_cache(table, new_id);
2937
/* MySQL calls ha_innobase::reset_auto_increment() which does
2939
dict_table_autoinc_lock(table);
2940
dict_table_autoinc_initialize(table, 1);
2941
dict_table_autoinc_unlock(table);
2942
dict_update_statistics(table);
2944
trx_commit_for_mysql(trx);
2948
row_mysql_unlock_data_dictionary(trx);
2952
srv_wake_master_thread();
2957
/*********************************************************************//**
2958
Drops a table for MySQL. If the name of the dropped table ends in
2959
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
2960
"innodb_table_monitor", then this will also stop the printing of monitor
2961
output by the master thread. If the data dictionary was not already locked
2962
by the transaction, the transaction will be committed. Otherwise, the
2963
data dictionary will remain locked.
2964
@return error code or DB_SUCCESS */
2967
row_drop_table_for_mysql(
2968
/*=====================*/
2969
const char* name, /*!< in: table name */
2970
trx_t* trx, /*!< in: transaction handle */
2971
ibool drop_db)/*!< in: TRUE=dropping whole database */
2973
dict_foreign_t* foreign;
2974
dict_table_t* table;
2977
const char* table_name;
2979
ibool locked_dictionary = FALSE;
2980
pars_info_t* info = NULL;
2984
if (srv_created_new_raw) {
2985
fputs("InnoDB: A new raw disk partition was initialized:\n"
2986
"InnoDB: we do not allow database modifications"
2988
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2989
" is replaced with raw.\n", stderr);
2994
trx->op_info = "dropping table";
2996
trx_start_if_not_started(trx);
2998
/* The table name is prefixed with the database name and a '/'.
2999
Certain table names starting with 'innodb_' have their special
3000
meaning regardless of the database name. Thus, we need to
3001
ignore the database name prefix in the comparisons. */
3002
table_name = strchr(name, '/');
3005
namelen = strlen(table_name) + 1;
3007
if (namelen == sizeof S_innodb_monitor
3008
&& !memcmp(table_name, S_innodb_monitor,
3009
sizeof S_innodb_monitor)) {
3011
/* Table name equals "innodb_monitor":
3012
stop monitor prints */
3014
srv_print_innodb_monitor = FALSE;
3015
srv_print_innodb_lock_monitor = FALSE;
3016
} else if (namelen == sizeof S_innodb_lock_monitor
3017
&& !memcmp(table_name, S_innodb_lock_monitor,
3018
sizeof S_innodb_lock_monitor)) {
3019
srv_print_innodb_monitor = FALSE;
3020
srv_print_innodb_lock_monitor = FALSE;
3021
} else if (namelen == sizeof S_innodb_tablespace_monitor
3022
&& !memcmp(table_name, S_innodb_tablespace_monitor,
3023
sizeof S_innodb_tablespace_monitor)) {
3025
srv_print_innodb_tablespace_monitor = FALSE;
3026
} else if (namelen == sizeof S_innodb_table_monitor
3027
&& !memcmp(table_name, S_innodb_table_monitor,
3028
sizeof S_innodb_table_monitor)) {
3030
srv_print_innodb_table_monitor = FALSE;
3033
/* Serialize data dictionary operations with dictionary mutex:
3034
no deadlocks can occur then in these operations */
3036
if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3037
/* Prevent foreign key checks etc. while we are dropping the
3040
row_mysql_lock_data_dictionary(trx);
3042
locked_dictionary = TRUE;
3045
ut_ad(mutex_own(&(dict_sys->mutex)));
3046
#ifdef UNIV_SYNC_DEBUG
3047
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3048
#endif /* UNIV_SYNC_DEBUG */
3050
table = dict_table_get_low(name);
3053
err = DB_TABLE_NOT_FOUND;
3054
ut_print_timestamp(stderr);
3056
fputs(" InnoDB: Error: table ", stderr);
3057
ut_print_name(stderr, trx, TRUE, name);
3058
fputs(" does not exist in the InnoDB internal\n"
3059
"InnoDB: data dictionary though MySQL is"
3060
" trying to drop it.\n"
3061
"InnoDB: Have you copied the .frm file"
3062
" of the table to the\n"
3063
"InnoDB: MySQL database directory"
3064
" from another database?\n"
3065
"InnoDB: You can look for further help from\n"
3066
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3071
/* Check if the table is referenced by foreign key constraints from
3072
some other table (not the table itself) */
3074
foreign = UT_LIST_GET_FIRST(table->referenced_list);
3076
while (foreign && foreign->foreign_table == table) {
3078
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3081
if (foreign && trx->check_foreigns
3082
&& !(drop_db && dict_tables_have_same_db(
3083
name, foreign->foreign_table_name))) {
3084
FILE* ef = dict_foreign_err_file;
3086
/* We only allow dropping a referenced table if
3087
FOREIGN_KEY_CHECKS is set to 0 */
3089
err = DB_CANNOT_DROP_CONSTRAINT;
3091
mutex_enter(&dict_foreign_err_mutex);
3093
ut_print_timestamp(ef);
3095
fputs(" Cannot drop table ", ef);
3096
ut_print_name(ef, trx, TRUE, name);
3098
"because it is referenced by ", ef);
3099
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3101
mutex_exit(&dict_foreign_err_mutex);
3106
if (foreign && trx->check_foreigns) {
3107
goto check_next_foreign;
3110
if (table->n_mysql_handles_opened > 0) {
3113
added = row_add_table_to_background_drop_list(table->name);
3116
ut_print_timestamp(stderr);
3117
fputs(" InnoDB: Warning: MySQL is"
3118
" trying to drop table ", stderr);
3119
ut_print_name(stderr, trx, TRUE, table->name);
3121
"InnoDB: though there are still"
3122
" open handles to it.\n"
3123
"InnoDB: Adding the table to the"
3124
" background drop queue.\n",
3127
/* We return DB_SUCCESS to MySQL though the drop will
3128
happen lazily later */
3131
/* The table is already in the background drop list */
3138
/* TODO: could we replace the counter n_foreign_key_checks_running
3139
with lock checks on the table? Acquire here an exclusive lock on the
3140
table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3141
they can cope with the table having been dropped here? Foreign key
3142
checks take an IS or IX lock on the table. */
3144
if (table->n_foreign_key_checks_running > 0) {
3146
const char* table_name = table->name;
3149
added = row_add_table_to_background_drop_list(table_name);
3152
ut_print_timestamp(stderr);
3153
fputs(" InnoDB: You are trying to drop table ",
3155
ut_print_name(stderr, trx, TRUE, table_name);
3157
"InnoDB: though there is a"
3158
" foreign key check running on it.\n"
3159
"InnoDB: Adding the table to"
3160
" the background drop queue.\n",
3163
/* We return DB_SUCCESS to MySQL though the drop will
3164
happen lazily later */
3168
/* The table is already in the background drop list */
3175
/* Remove all locks there are on the table or its records */
3176
lock_remove_all_on_table(table, TRUE);
3178
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
3179
trx->table_id = table->id;
3181
/* We use the private SQL parser of Innobase to generate the
3182
query graphs needed in deleting the dictionary data from system
3183
tables in Innobase. Deleting a row from SYS_INDEXES table also
3184
frees the file segments of the B-tree associated with the index. */
3186
info = pars_info_create();
3188
pars_info_add_str_literal(info, "table_name", name);
3190
err = que_eval_sql(info,
3191
"PROCEDURE DROP_TABLE_PROC () IS\n"
3192
"sys_foreign_id CHAR;\n"
3195
"foreign_id CHAR;\n"
3198
"SELECT ID INTO table_id\n"
3200
"WHERE NAME = :table_name\n"
3201
"LOCK IN SHARE MODE;\n"
3202
"IF (SQL % NOTFOUND) THEN\n"
3206
"SELECT ID INTO sys_foreign_id\n"
3208
"WHERE NAME = 'SYS_FOREIGN'\n"
3209
"LOCK IN SHARE MODE;\n"
3210
"IF (SQL % NOTFOUND) THEN\n"
3213
"IF (:table_name = 'SYS_FOREIGN') THEN\n"
3216
"IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3219
"WHILE found = 1 LOOP\n"
3220
" SELECT ID INTO foreign_id\n"
3221
" FROM SYS_FOREIGN\n"
3222
" WHERE FOR_NAME = :table_name\n"
3223
" AND TO_BINARY(FOR_NAME)\n"
3224
" = TO_BINARY(:table_name)\n"
3225
" LOCK IN SHARE MODE;\n"
3226
" IF (SQL % NOTFOUND) THEN\n"
3229
" DELETE FROM SYS_FOREIGN_COLS\n"
3230
" WHERE ID = foreign_id;\n"
3231
" DELETE FROM SYS_FOREIGN\n"
3232
" WHERE ID = foreign_id;\n"
3236
"WHILE found = 1 LOOP\n"
3237
" SELECT ID INTO index_id\n"
3238
" FROM SYS_INDEXES\n"
3239
" WHERE TABLE_ID = table_id\n"
3240
" LOCK IN SHARE MODE;\n"
3241
" IF (SQL % NOTFOUND) THEN\n"
3244
" DELETE FROM SYS_FIELDS\n"
3245
" WHERE INDEX_ID = index_id;\n"
3246
" DELETE FROM SYS_INDEXES\n"
3247
" WHERE ID = index_id\n"
3248
" AND TABLE_ID = table_id;\n"
3251
"DELETE FROM SYS_COLUMNS\n"
3252
"WHERE TABLE_ID = table_id;\n"
3253
"DELETE FROM SYS_TABLES\n"
3254
"WHERE ID = table_id;\n"
3258
if (err != DB_SUCCESS) {
3259
ut_a(err == DB_OUT_OF_FILE_SPACE);
3261
err = DB_MUST_GET_MORE_FILE_SPACE;
3263
row_mysql_handle_errors(&err, trx, NULL, NULL);
3268
const char* name_or_path;
3271
heap = mem_heap_create(200);
3273
/* Clone the name, in case it has been allocated
3274
from table->heap, which will be freed by
3275
dict_table_remove_from_cache(table) below. */
3276
name = mem_heap_strdup(heap, name);
3277
space_id = table->space;
3279
if (table->dir_path_of_temp_table != NULL) {
3281
name_or_path = mem_heap_strdup(
3282
heap, table->dir_path_of_temp_table);
3285
name_or_path = name;
3288
dict_table_remove_from_cache(table);
3290
if (dict_load_table(name) != NULL) {
3291
ut_print_timestamp(stderr);
3292
fputs(" InnoDB: Error: not able to remove table ",
3294
ut_print_name(stderr, trx, TRUE, name);
3295
fputs(" from the dictionary cache!\n", stderr);
3299
/* Do not drop possible .ibd tablespace if something went
3300
wrong: we do not want to delete valuable data of the user */
3302
if (err == DB_SUCCESS && space_id > 0) {
3303
if (!fil_space_for_table_exists_in_mem(space_id,
3310
"InnoDB: We removed now the InnoDB"
3311
" internal data dictionary entry\n"
3312
"InnoDB: of table ");
3313
ut_print_name(stderr, trx, TRUE, name);
3314
fprintf(stderr, ".\n");
3315
} else if (!fil_delete_tablespace(space_id)) {
3317
"InnoDB: We removed now the InnoDB"
3318
" internal data dictionary entry\n"
3319
"InnoDB: of table ");
3320
ut_print_name(stderr, trx, TRUE, name);
3321
fprintf(stderr, ".\n");
3323
ut_print_timestamp(stderr);
3325
" InnoDB: Error: not able to"
3326
" delete tablespace %lu of table ",
3328
ut_print_name(stderr, trx, TRUE, name);
3329
fputs("!\n", stderr);
3334
mem_heap_free(heap);
3338
if (locked_dictionary) {
3339
trx_commit_for_mysql(trx);
3341
row_mysql_unlock_data_dictionary(trx);
3346
srv_wake_master_thread();
3351
/*******************************************************************//**
3352
Drop all foreign keys in a database, see Bug#18942.
3353
Called at the end of row_drop_database_for_mysql().
3354
@return error code or DB_SUCCESS */
3357
drop_all_foreign_keys_in_db(
3358
/*========================*/
3359
const char* name, /*!< in: database name which ends to '/' */
3360
trx_t* trx) /*!< in: transaction handle */
3365
ut_a(name[strlen(name) - 1] == '/');
3367
pinfo = pars_info_create();
3369
pars_info_add_str_literal(pinfo, "dbname", name);
3371
/** true if for_name is not prefixed with dbname */
3372
#define TABLE_NOT_IN_THIS_DB \
3373
"SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
3375
err = que_eval_sql(pinfo,
3376
"PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
3377
"foreign_id CHAR;\n"
3380
"DECLARE CURSOR cur IS\n"
3381
"SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
3382
"WHERE FOR_NAME >= :dbname\n"
3383
"LOCK IN SHARE MODE\n"
3384
"ORDER BY FOR_NAME;\n"
3388
"WHILE found = 1 LOOP\n"
3389
" FETCH cur INTO foreign_id, for_name;\n"
3390
" IF (SQL % NOTFOUND) THEN\n"
3392
" ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
3394
" ELSIF (1=1) THEN\n"
3395
" DELETE FROM SYS_FOREIGN_COLS\n"
3396
" WHERE ID = foreign_id;\n"
3397
" DELETE FROM SYS_FOREIGN\n"
3398
" WHERE ID = foreign_id;\n"
3404
FALSE, /* do not reserve dict mutex,
3405
we are already holding it */
3411
/*********************************************************************//**
3412
Drops a database for MySQL.
3413
@return error code or DB_SUCCESS */
3416
row_drop_database_for_mysql(
3417
/*========================*/
3418
const char* name, /*!< in: database name which ends to '/' */
3419
trx_t* trx) /*!< in: transaction handle */
3421
dict_table_t* table;
3423
int err = DB_SUCCESS;
3424
ulint namelen = strlen(name);
3426
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3428
ut_a(name[namelen - 1] == '/');
3430
trx->op_info = "dropping database";
3432
trx_start_if_not_started(trx);
3434
row_mysql_lock_data_dictionary(trx);
3436
while ((table_name = dict_get_first_table_name_in_db(name))) {
3437
ut_a(memcmp(table_name, name, namelen) == 0);
3439
table = dict_table_get_low(table_name);
3443
/* Wait until MySQL does not have any queries running on
3446
if (table->n_mysql_handles_opened > 0) {
3447
row_mysql_unlock_data_dictionary(trx);
3449
ut_print_timestamp(stderr);
3450
fputs(" InnoDB: Warning: MySQL is trying to"
3451
" drop database ", stderr);
3452
ut_print_name(stderr, trx, TRUE, name);
3454
"InnoDB: though there are still"
3455
" open handles to table ", stderr);
3456
ut_print_name(stderr, trx, TRUE, table_name);
3457
fputs(".\n", stderr);
3459
os_thread_sleep(1000000);
3461
mem_free(table_name);
3466
err = row_drop_table_for_mysql(table_name, trx, TRUE);
3467
trx_commit_for_mysql(trx);
3469
if (err != DB_SUCCESS) {
3470
fputs("InnoDB: DROP DATABASE ", stderr);
3471
ut_print_name(stderr, trx, TRUE, name);
3472
fprintf(stderr, " failed with error %lu for table ",
3474
ut_print_name(stderr, trx, TRUE, table_name);
3476
mem_free(table_name);
3480
mem_free(table_name);
3483
if (err == DB_SUCCESS) {
3484
/* after dropping all tables try to drop all leftover
3485
foreign keys in case orphaned ones exist */
3486
err = (int) drop_all_foreign_keys_in_db(name, trx);
3488
if (err != DB_SUCCESS) {
3489
fputs("InnoDB: DROP DATABASE ", stderr);
3490
ut_print_name(stderr, trx, TRUE, name);
3491
fprintf(stderr, " failed with error %d while "
3492
"dropping all foreign keys", err);
3496
trx_commit_for_mysql(trx);
3498
row_mysql_unlock_data_dictionary(trx);
3505
/*********************************************************************//**
3506
Checks if a table name contains the string "/#sql" which denotes temporary
3508
@return TRUE if temporary table */
3511
row_is_mysql_tmp_table_name(
3512
/*========================*/
3513
const char* name) /*!< in: table name in the form
3514
'database/tablename' */
3516
return(strstr(name, "/#sql") != NULL);
3517
/* return(strstr(name, "/@0023sql") != NULL); */
3520
/****************************************************************//**
3521
Delete a single constraint.
3522
@return error code or DB_SUCCESS */
3525
row_delete_constraint_low(
3526
/*======================*/
3527
const char* id, /*!< in: constraint id */
3528
trx_t* trx) /*!< in: transaction handle */
3530
pars_info_t* info = pars_info_create();
3532
pars_info_add_str_literal(info, "id", id);
3534
return((int) que_eval_sql(info,
3535
"PROCEDURE DELETE_CONSTRAINT () IS\n"
3537
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3538
"DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3543
/****************************************************************//**
3544
Delete a single constraint.
3545
@return error code or DB_SUCCESS */
3548
row_delete_constraint(
3549
/*==================*/
3550
const char* id, /*!< in: constraint id */
3551
const char* database_name, /*!< in: database name, with the
3553
mem_heap_t* heap, /*!< in: memory heap */
3554
trx_t* trx) /*!< in: transaction handle */
3558
/* New format constraints have ids <databasename>/<constraintname>. */
3559
err = row_delete_constraint_low(
3560
mem_heap_strcat(heap, database_name, id), trx);
3562
if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3563
/* Old format < 4.0.18 constraints have constraint ids
3564
NUMBER_NUMBER. We only try deleting them if the
3565
constraint name does not contain a '/' character, otherwise
3566
deleting a new format constraint named 'foo/bar' from
3567
database 'baz' would remove constraint 'bar' from database
3568
'foo', if it existed. */
3570
err = row_delete_constraint_low(id, trx);
3576
/*********************************************************************//**
3577
Renames a table for MySQL.
3578
@return error code or DB_SUCCESS */
3581
row_rename_table_for_mysql(
3582
/*=======================*/
3583
const char* old_name, /*!< in: old table name */
3584
const char* new_name, /*!< in: new table name */
3585
trx_t* trx, /*!< in: transaction handle */
3586
ibool commit) /*!< in: if TRUE then commit trx */
3588
dict_table_t* table;
3589
ulint err = DB_ERROR;
3590
mem_heap_t* heap = NULL;
3591
const char** constraints_to_drop = NULL;
3592
ulint n_constraints_to_drop = 0;
3593
ibool old_is_tmp, new_is_tmp;
3594
pars_info_t* info = NULL;
3596
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3597
ut_a(old_name != NULL);
3598
ut_a(new_name != NULL);
3600
if (srv_created_new_raw || srv_force_recovery) {
3601
fputs("InnoDB: A new raw disk partition was initialized or\n"
3602
"InnoDB: innodb_force_recovery is on: we do not allow\n"
3603
"InnoDB: database modifications by the user. Shut down\n"
3604
"InnoDB: mysqld and edit my.cnf so that newraw"
3606
"InnoDB: with raw, and innodb_force_... is removed.\n",
3610
} else if (row_mysql_is_system_table(new_name)) {
3613
"InnoDB: Error: trying to create a MySQL"
3614
" system table %s of type InnoDB.\n"
3615
"InnoDB: MySQL system tables must be"
3616
" of the MyISAM type!\n",
3622
trx->op_info = "renaming table";
3623
trx_start_if_not_started(trx);
3625
old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3626
new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3628
table = dict_table_get_low(old_name);
3631
err = DB_TABLE_NOT_FOUND;
3632
ut_print_timestamp(stderr);
3634
fputs(" InnoDB: Error: table ", stderr);
3635
ut_print_name(stderr, trx, TRUE, old_name);
3636
fputs(" does not exist in the InnoDB internal\n"
3637
"InnoDB: data dictionary though MySQL is"
3638
" trying to rename the table.\n"
3639
"InnoDB: Have you copied the .frm file"
3640
" of the table to the\n"
3641
"InnoDB: MySQL database directory"
3642
" from another database?\n"
3643
"InnoDB: You can look for further help from\n"
3644
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3647
} else if (table->ibd_file_missing) {
3648
err = DB_TABLE_NOT_FOUND;
3649
ut_print_timestamp(stderr);
3651
fputs(" InnoDB: Error: table ", stderr);
3652
ut_print_name(stderr, trx, TRUE, old_name);
3653
fputs(" does not have an .ibd file"
3654
" in the database directory.\n"
3655
"InnoDB: You can look for further help from\n"
3656
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3659
} else if (new_is_tmp) {
3660
/* MySQL is doing an ALTER TABLE command and it renames the
3661
original table to a temporary table name. We want to preserve
3662
the original foreign key constraint definitions despite the
3663
name change. An exception is those constraints for which
3664
the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3666
heap = mem_heap_create(100);
3668
err = dict_foreign_parse_drop_constraints(
3669
heap, trx, table, &n_constraints_to_drop,
3670
&constraints_to_drop);
3672
if (err != DB_SUCCESS) {
3678
/* We use the private SQL parser of Innobase to generate the query
3679
graphs needed in updating the dictionary data from system tables. */
3681
info = pars_info_create();
3683
pars_info_add_str_literal(info, "new_table_name", new_name);
3684
pars_info_add_str_literal(info, "old_table_name", old_name);
3686
err = que_eval_sql(info,
3687
"PROCEDURE RENAME_TABLE () IS\n"
3689
"UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3690
" WHERE NAME = :old_table_name;\n"
3694
if (err != DB_SUCCESS) {
3697
} else if (!new_is_tmp) {
3698
/* Rename all constraints. */
3700
info = pars_info_create();
3702
pars_info_add_str_literal(info, "new_table_name", new_name);
3703
pars_info_add_str_literal(info, "old_table_name", old_name);
3707
"PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3708
"gen_constr_prefix CHAR;\n"
3709
"new_db_name CHAR;\n"
3710
"foreign_id CHAR;\n"
3711
"new_foreign_id CHAR;\n"
3712
"old_db_name_len INT;\n"
3713
"old_t_name_len INT;\n"
3714
"new_db_name_len INT;\n"
3719
"old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3720
"new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3721
"new_db_name := SUBSTR(:new_table_name, 0,\n"
3722
" new_db_name_len);\n"
3723
"old_t_name_len := LENGTH(:old_table_name);\n"
3724
"gen_constr_prefix := CONCAT(:old_table_name,\n"
3726
"WHILE found = 1 LOOP\n"
3727
" SELECT ID INTO foreign_id\n"
3728
" FROM SYS_FOREIGN\n"
3729
" WHERE FOR_NAME = :old_table_name\n"
3730
" AND TO_BINARY(FOR_NAME)\n"
3731
" = TO_BINARY(:old_table_name)\n"
3732
" LOCK IN SHARE MODE;\n"
3733
" IF (SQL % NOTFOUND) THEN\n"
3736
" UPDATE SYS_FOREIGN\n"
3737
" SET FOR_NAME = :new_table_name\n"
3738
" WHERE ID = foreign_id;\n"
3739
" id_len := LENGTH(foreign_id);\n"
3740
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
3741
" IF (INSTR(foreign_id,\n"
3742
" gen_constr_prefix) > 0)\n"
3744
" new_foreign_id :=\n"
3745
" CONCAT(:new_table_name,\n"
3746
" SUBSTR(foreign_id, old_t_name_len,\n"
3747
" id_len - old_t_name_len));\n"
3749
" new_foreign_id :=\n"
3750
" CONCAT(new_db_name,\n"
3751
" SUBSTR(foreign_id,\n"
3752
" old_db_name_len,\n"
3753
" id_len - old_db_name_len));\n"
3755
" UPDATE SYS_FOREIGN\n"
3756
" SET ID = new_foreign_id\n"
3757
" WHERE ID = foreign_id;\n"
3758
" UPDATE SYS_FOREIGN_COLS\n"
3759
" SET ID = new_foreign_id\n"
3760
" WHERE ID = foreign_id;\n"
3764
"UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
3765
"WHERE REF_NAME = :old_table_name\n"
3766
" AND TO_BINARY(REF_NAME)\n"
3767
" = TO_BINARY(:old_table_name);\n"
3771
} else if (n_constraints_to_drop > 0) {
3772
/* Drop some constraints of tmp tables. */
3774
ulint db_name_len = dict_get_db_name_len(old_name) + 1;
3775
char* db_name = mem_heap_strdupl(heap, old_name,
3779
for (i = 0; i < n_constraints_to_drop; i++) {
3780
err = row_delete_constraint(constraints_to_drop[i],
3781
db_name, heap, trx);
3783
if (err != DB_SUCCESS) {
3790
if (err != DB_SUCCESS) {
3791
if (err == DB_DUPLICATE_KEY) {
3792
ut_print_timestamp(stderr);
3793
fputs(" InnoDB: Error; possible reasons:\n"
3794
"InnoDB: 1) Table rename would cause"
3795
" two FOREIGN KEY constraints\n"
3796
"InnoDB: to have the same internal name"
3797
" in case-insensitive comparison.\n"
3798
"InnoDB: 2) table ", stderr);
3799
ut_print_name(stderr, trx, TRUE, new_name);
3800
fputs(" exists in the InnoDB internal data\n"
3801
"InnoDB: dictionary though MySQL is"
3802
" trying to rename table ", stderr);
3803
ut_print_name(stderr, trx, TRUE, old_name);
3805
"InnoDB: Have you deleted the .frm file"
3806
" and not used DROP TABLE?\n"
3807
"InnoDB: You can look for further help from\n"
3808
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
3809
"InnoDB: If table ", stderr);
3810
ut_print_name(stderr, trx, TRUE, new_name);
3811
fputs(" is a temporary table #sql..., then"
3813
"InnoDB: there are still queries running"
3814
" on the table, and it will be\n"
3815
"InnoDB: dropped automatically when"
3816
" the queries end.\n"
3817
"InnoDB: You can drop the orphaned table"
3818
" inside InnoDB by\n"
3819
"InnoDB: creating an InnoDB table with"
3820
" the same name in another\n"
3821
"InnoDB: database and copying the .frm file"
3822
" to the current database.\n"
3823
"InnoDB: Then MySQL thinks the table exists,"
3824
" and DROP TABLE will\n"
3825
"InnoDB: succeed.\n", stderr);
3827
trx->error_state = DB_SUCCESS;
3828
trx_general_rollback_for_mysql(trx, NULL);
3829
trx->error_state = DB_SUCCESS;
3831
/* The following call will also rename the .ibd data file if
3832
the table is stored in a single-table tablespace */
3834
if (!dict_table_rename_in_cache(table, new_name,
3836
trx->error_state = DB_SUCCESS;
3837
trx_general_rollback_for_mysql(trx, NULL);
3838
trx->error_state = DB_SUCCESS;
3842
/* We only want to switch off some of the type checking in
3843
an ALTER, not in a RENAME. */
3845
err = dict_load_foreigns(
3846
new_name, !old_is_tmp || trx->check_foreigns);
3848
if (err != DB_SUCCESS) {
3849
ut_print_timestamp(stderr);
3852
fputs(" InnoDB: Error: in ALTER TABLE ",
3854
ut_print_name(stderr, trx, TRUE, new_name);
3856
"InnoDB: has or is referenced"
3857
" in foreign key constraints\n"
3858
"InnoDB: which are not compatible"
3859
" with the new table definition.\n",
3862
fputs(" InnoDB: Error: in RENAME TABLE"
3865
ut_print_name(stderr, trx, TRUE, new_name);
3867
"InnoDB: is referenced in"
3868
" foreign key constraints\n"
3869
"InnoDB: which are not compatible"
3870
" with the new table definition.\n",
3874
ut_a(dict_table_rename_in_cache(table,
3876
trx->error_state = DB_SUCCESS;
3877
trx_general_rollback_for_mysql(trx, NULL);
3878
trx->error_state = DB_SUCCESS;
3885
trx_commit_for_mysql(trx);
3888
if (UNIV_LIKELY_NULL(heap)) {
3889
mem_heap_free(heap);
3897
/*********************************************************************//**
3898
Checks that the index contains entries in an ascending order, unique
3899
constraint is not broken, and calculates the number of index entries
3900
in the read view of the current transaction.
3901
@return TRUE if ok */
3904
row_scan_and_check_index(
3905
/*=====================*/
3906
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL */
3907
dict_index_t* index, /*!< in: index */
3908
ulint* n_rows) /*!< out: number of entries seen in the
3909
current consistent read */
3911
dtuple_t* prev_entry = NULL;
3912
ulint matched_fields;
3913
ulint matched_bytes;
3919
ibool contains_null;
3922
mem_heap_t* heap = NULL;
3924
ulint offsets_[REC_OFFS_NORMAL_SIZE];
3926
rec_offs_init(offsets_);
3930
if (!row_merge_is_index_usable(prebuilt->trx, index)) {
3931
/* A newly created index may lack some delete-marked
3932
records that may exist in the read view of
3933
prebuilt->trx. Thus, such indexes must not be
3934
accessed by consistent read. */
3938
buf = mem_alloc(UNIV_PAGE_SIZE);
3939
heap = mem_heap_create(100);
3941
/* Make a dummy template in prebuilt, which we will use
3942
in scanning the index entries */
3944
prebuilt->index = index;
3945
/* row_merge_is_index_usable() was already checked above. */
3946
prebuilt->index_usable = TRUE;
3947
prebuilt->sql_stat_start = TRUE;
3948
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
3949
prebuilt->n_template = 0;
3950
prebuilt->need_to_access_clustered = FALSE;
3952
dtuple_set_n_fields(prebuilt->search_tuple, 0);
3954
prebuilt->select_lock_type = LOCK_NONE;
3957
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
3959
/* Check thd->killed every 1,000 scanned rows */
3961
if (trx_is_interrupted(prebuilt->trx)) {
3971
ut_print_timestamp(stderr);
3972
fputs(" InnoDB: Warning: CHECK TABLE on ", stderr);
3973
dict_index_name_print(stderr, prebuilt->trx, index);
3974
fprintf(stderr, " returned %lu\n", ret);
3975
/* fall through (this error is ignored by CHECK TABLE) */
3976
case DB_END_OF_INDEX:
3979
mem_heap_free(heap);
3984
*n_rows = *n_rows + 1;
3986
/* row_search... returns the index record in buf, record origin offset
3987
within buf stored in the first 4 bytes, because we have built a dummy
3990
rec = buf + mach_read_from_4(buf);
3992
offsets = rec_get_offsets(rec, index, offsets_,
3993
ULINT_UNDEFINED, &heap);
3995
if (prev_entry != NULL) {
3999
cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
4002
contains_null = FALSE;
4004
/* In a unique secondary index we allow equal key values if
4005
they contain SQL NULLs */
4008
i < dict_index_get_n_ordering_defined_by_user(index);
4010
if (UNIV_SQL_NULL == dfield_get_len(
4011
dtuple_get_nth_field(prev_entry, i))) {
4013
contains_null = TRUE;
4018
fputs("InnoDB: index records in a wrong order in ",
4021
dict_index_name_print(stderr,
4022
prebuilt->trx, index);
4024
"InnoDB: prev record ", stderr);
4025
dtuple_print(stderr, prev_entry);
4027
"InnoDB: record ", stderr);
4028
rec_print_new(stderr, rec, offsets);
4031
} else if (dict_index_is_unique(index)
4034
>= dict_index_get_n_ordering_defined_by_user(
4037
fputs("InnoDB: duplicate key in ", stderr);
4043
mem_heap_t* tmp_heap = NULL;
4045
/* Empty the heap on each round. But preserve offsets[]
4046
for the row_rec_to_index_entry() call, by copying them
4047
into a separate memory heap when needed. */
4048
if (UNIV_UNLIKELY(offsets != offsets_)) {
4049
ulint size = rec_offs_get_n_alloc(offsets)
4052
tmp_heap = mem_heap_create(size);
4053
offsets = mem_heap_dup(tmp_heap, offsets, size);
4056
mem_heap_empty(heap);
4058
prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
4062
if (UNIV_LIKELY_NULL(tmp_heap)) {
4063
mem_heap_free(tmp_heap);
4067
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
4072
/*********************************************************************//**
4073
Checks a table for corruption.
4074
@return DB_ERROR or DB_SUCCESS */
4077
row_check_table_for_mysql(
4078
/*======================*/
4079
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
4082
dict_table_t* table = prebuilt->table;
4083
dict_index_t* index;
4085
ulint n_rows_in_table = ULINT_UNDEFINED;
4086
ulint ret = DB_SUCCESS;
4087
ulint old_isolation_level;
4089
if (table->ibd_file_missing) {
4090
ut_print_timestamp(stderr);
4091
fprintf(stderr, " InnoDB: Error:\n"
4092
"InnoDB: MySQL is trying to use a table handle"
4093
" but the .ibd file for\n"
4094
"InnoDB: table %s does not exist.\n"
4095
"InnoDB: Have you deleted the .ibd file"
4096
" from the database directory under\n"
4097
"InnoDB: the MySQL datadir, or have you"
4098
" used DISCARD TABLESPACE?\n"
4099
"InnoDB: Look from\n"
4100
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
4101
"InnoDB: how you can resolve the problem.\n",
4106
prebuilt->trx->op_info = "checking table";
4108
old_isolation_level = prebuilt->trx->isolation_level;
4110
/* We must run the index record counts at an isolation level
4111
>= READ COMMITTED, because a dirty read can see a wrong number
4112
of records in some index; to play safe, we use always
4113
REPEATABLE READ here */
4115
prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
4117
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
4118
mutex_enter(&kernel_mutex);
4119
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
4120
mutex_exit(&kernel_mutex);
4122
index = dict_table_get_first_index(table);
4124
while (index != NULL) {
4125
/* fputs("Validating index ", stderr);
4126
ut_print_name(stderr, trx, FALSE, index->name);
4127
putc('\n', stderr); */
4129
if (!btr_validate_index(index, prebuilt->trx)) {
4132
if (!row_scan_and_check_index(prebuilt,index, &n_rows)){
4136
if (trx_is_interrupted(prebuilt->trx)) {
4137
ret = DB_INTERRUPTED;
4141
/* fprintf(stderr, "%lu entries in index %s\n", n_rows,
4144
if (index == dict_table_get_first_index(table)) {
4145
n_rows_in_table = n_rows;
4146
} else if (n_rows != n_rows_in_table) {
4150
fputs("Error: ", stderr);
4151
dict_index_name_print(stderr,
4152
prebuilt->trx, index);
4154
" contains %lu entries,"
4157
(ulong) n_rows_in_table);
4161
index = dict_table_get_next_index(index);
4164
/* Restore the original isolation level */
4165
prebuilt->trx->isolation_level = old_isolation_level;
4167
/* We validate also the whole adaptive hash index for all tables
4168
at every CHECK TABLE */
4170
if (!btr_search_validate()) {
4175
/* Restore the fatal lock wait timeout after CHECK TABLE. */
4176
mutex_enter(&kernel_mutex);
4177
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
4178
mutex_exit(&kernel_mutex);
4180
prebuilt->trx->op_info = "";
4185
/*********************************************************************//**
4186
Determines if a table is a magic monitor table.
4187
@return TRUE if monitor table */
4190
row_is_magic_monitor_table(
4191
/*=======================*/
4192
const char* table_name) /*!< in: name of the table, in the
4193
form database/table_name */
4195
const char* name; /* table_name without database/ */
4198
name = strchr(table_name, '/');
4201
len = strlen(name) + 1;
4203
if (STR_EQ(name, len, S_innodb_monitor)
4204
|| STR_EQ(name, len, S_innodb_lock_monitor)
4205
|| STR_EQ(name, len, S_innodb_tablespace_monitor)
4206
|| STR_EQ(name, len, S_innodb_table_monitor)
4207
|| STR_EQ(name, len, S_innodb_mem_validate)) {