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"
57
/** Provide optional 4.x backwards compatibility for 5.0 and above */
58
UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
60
/** Chain node of the list of tables to drop in the background. */
61
typedef struct row_mysql_drop_struct row_mysql_drop_t;
63
/** Chain node of the list of tables to drop in the background. */
64
struct row_mysql_drop_struct{
65
char* table_name; /*!< table name */
66
UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
67
/*!< list chain node */
70
/** @brief List of tables we should drop in background.
72
ALTER TABLE in MySQL requires that the table handler can drop the
73
table in background when there are no queries to it any
74
more. Protected by kernel_mutex. */
75
static UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
76
/** Flag: has row_mysql_drop_list been initialized? */
77
static ibool row_mysql_drop_list_inited = FALSE;
79
/** Magic table names for invoking various monitor threads */
81
static const char S_innodb_monitor[] = "innodb_monitor";
82
static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
83
static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
84
static const char S_innodb_table_monitor[] = "innodb_table_monitor";
85
static const char S_innodb_mem_validate[] = "innodb_mem_validate";
88
/** Evaluates to true if str1 equals str2_onstack, used for comparing
89
the magic table names.
90
@param str1 in: string to compare
91
@param str1_len in: length of str1, in bytes, including terminating NUL
92
@param str2_onstack in: char[] array containing a NUL terminated string
93
@return TRUE if str1 equals str2_onstack */
94
#define STR_EQ(str1, str1_len, str2_onstack) \
95
((str1_len) == sizeof(str2_onstack) \
96
&& memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
98
/*********************************************************************//**
99
If a table is not yet in the drop list, adds the table to the list of tables
100
which the master thread drops in background. We need this on Unix because in
101
ALTER TABLE MySQL may call drop table even if the table has running queries on
102
it. Also, if there are running foreign key checks on the table, we drop the
104
@return TRUE if the table was not yet in the drop list, and was added there */
107
row_add_table_to_background_drop_list(
108
/*==================================*/
109
const char* name); /*!< in: table name */
111
/*******************************************************************//**
112
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
115
row_mysql_delay_if_needed(void)
116
/*===========================*/
118
if (srv_dml_needed_delay) {
119
os_thread_sleep(srv_dml_needed_delay);
123
/*******************************************************************//**
124
Frees the blob heap in prebuilt when no longer needed. */
127
row_mysql_prebuilt_free_blob_heap(
128
/*==============================*/
129
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct of a
130
ha_innobase:: table handle */
132
mem_heap_free(prebuilt->blob_heap);
133
prebuilt->blob_heap = NULL;
136
/*******************************************************************//**
137
Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
139
@return pointer to the data, we skip the 1 or 2 bytes at the start
140
that are used to store the len */
143
row_mysql_store_true_var_len(
144
/*=========================*/
145
byte* dest, /*!< in: where to store */
146
ulint len, /*!< in: length, must fit in two bytes */
147
ulint lenlen) /*!< in: storage length of len: either 1 or 2 bytes */
150
ut_a(len < 256 * 256);
152
mach_write_to_2_little_endian(dest, len);
160
mach_write_to_1(dest, len);
165
/*******************************************************************//**
166
Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
167
returns a pointer to the data.
168
@return pointer to the data, we skip the 1 or 2 bytes at the start
169
that are used to store the len */
172
row_mysql_read_true_varchar(
173
/*========================*/
174
ulint* len, /*!< out: variable-length field length */
175
const byte* field, /*!< in: field in the MySQL format */
176
ulint lenlen) /*!< in: storage length of len: either 1
180
*len = mach_read_from_2_little_endian(field);
187
*len = mach_read_from_1(field);
192
/*******************************************************************//**
193
Stores a reference to a BLOB in the MySQL format. */
196
row_mysql_store_blob_ref(
197
/*=====================*/
198
byte* dest, /*!< in: where to store */
199
ulint col_len,/*!< in: dest buffer size: determines into
200
how many bytes the BLOB length is stored,
201
the space for the length may vary from 1
203
const void* data, /*!< in: BLOB data; if the value to store
204
is SQL NULL this should be NULL pointer */
205
ulint len) /*!< in: BLOB length; if the value to store
206
is SQL NULL this should be 0; remember
207
also to set the NULL bit in the MySQL record
210
/* MySQL might assume the field is set to zero except the length and
211
the pointer fields */
213
memset(dest, '\0', col_len);
215
/* In dest there are 1 - 4 bytes reserved for the BLOB length,
216
and after that 8 bytes reserved for the pointer to the data.
217
In 32-bit architectures we only use the first 4 bytes of the pointer
220
ut_a(col_len - 8 > 1 || len < 256);
221
ut_a(col_len - 8 > 2 || len < 256 * 256);
222
ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
224
mach_write_to_n_little_endian(dest, col_len - 8, len);
226
memcpy(dest + col_len - 8, &data, sizeof data);
229
/*******************************************************************//**
230
Reads a reference to a BLOB in the MySQL format.
231
@return pointer to BLOB data */
234
row_mysql_read_blob_ref(
235
/*====================*/
236
ulint* len, /*!< out: BLOB length */
237
const byte* ref, /*!< in: BLOB reference in the
239
ulint col_len) /*!< in: BLOB reference length
244
*len = mach_read_from_n_little_endian(ref, col_len - 8);
246
memcpy(&data, ref + col_len - 8, sizeof data);
251
/**************************************************************//**
252
Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
253
The counterpart of this function is row_sel_field_store_in_mysql_format() in
255
@return up to which byte we used buf in the conversion */
258
row_mysql_store_col_in_innobase_format(
259
/*===================================*/
260
dfield_t* dfield, /*!< in/out: dfield where dtype
261
information must be already set when
262
this function is called! */
263
byte* buf, /*!< in/out: buffer for a converted
264
integer value; this must be at least
265
col_len long then! */
266
ibool row_format_col, /*!< TRUE if the mysql_data is from
267
a MySQL row, FALSE if from a MySQL
269
in MySQL, a true VARCHAR storage
270
format differs in a row and in a
271
key value: in a key value the length
272
is always stored in 2 bytes! */
273
const byte* mysql_data, /*!< in: MySQL column value, not
274
SQL NULL; NOTE that dfield may also
275
get a pointer to mysql_data,
276
therefore do not discard this as long
277
as dfield is used! */
278
ulint col_len, /*!< in: MySQL column length; NOTE that
279
this is the storage length of the
280
column in the MySQL format row, not
281
necessarily the length of the actual
282
payload data; if the column is a true
283
VARCHAR then this is irrelevant */
284
ulint comp) /*!< in: nonzero=compact format */
286
const byte* ptr = mysql_data;
287
const dtype_t* dtype;
291
dtype = dfield_get_type(dfield);
295
if (type == DATA_INT) {
296
/* Store integer data in Innobase in a big-endian format,
297
sign bit negated if the data is a signed integer. In MySQL,
298
integers are stored in a little-endian format. */
300
byte* p = buf + col_len;
311
if (!(dtype->prtype & DATA_UNSIGNED)) {
318
} else if ((type == DATA_VARCHAR
319
|| type == DATA_VARMYSQL
320
|| type == DATA_BINARY)) {
322
if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
323
/* The length of the actual data is stored to 1 or 2
324
bytes at the start of the field */
326
if (row_format_col) {
327
if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
333
/* In a MySQL key value, lenlen is always 2 */
337
ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
340
/* Remove trailing spaces from old style VARCHAR
343
/* Handle UCS2 strings differently. */
344
ulint mbminlen = dtype_get_mbminlen(dtype);
350
/* Trim "half-chars", just in case. */
353
while (col_len >= 2 && ptr[col_len - 2] == 0x00
354
&& ptr[col_len - 1] == 0x20) {
361
&& ptr[col_len - 1] == 0x20) {
366
} else if (comp && type == DATA_MYSQL
367
&& dtype_get_mbminlen(dtype) == 1
368
&& dtype_get_mbmaxlen(dtype) > 1) {
369
/* In some cases we strip trailing spaces from UTF-8 and other
370
multibyte charsets, from FIXED-length CHAR columns, to save
371
space. UTF-8 would otherwise normally use 3 * the string length
372
bytes to store an ASCII string! */
374
/* We assume that this CHAR field is encoded in a
375
variable-length character set where spaces have
376
1:1 correspondence to 0x20 bytes, such as UTF-8.
378
Consider a CHAR(n) field, a field of n characters.
379
It will contain between n * mbminlen and n * mbmaxlen bytes.
380
We will try to truncate it to n bytes by stripping
381
space padding. If the field contains single-byte
382
characters only, it will be truncated to n characters.
383
Consider a CHAR(5) field containing the string ".a "
384
where "." denotes a 3-byte character represented by
385
the bytes "$%&". After our stripping, the string will
386
be stored as "$%&a " (5 bytes). The string ".abc "
387
will be stored as "$%&abc" (6 bytes).
389
The space padding will be restored in row0sel.c, function
390
row_sel_field_store_in_mysql_format(). */
394
ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
396
n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
398
/* Strip space padding. */
399
while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
402
} else if (type == DATA_BLOB && row_format_col) {
404
ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
407
dfield_set_data(dfield, ptr, col_len);
412
/**************************************************************//**
413
Convert a row in the MySQL format to a row in the Innobase format. Note that
414
the function to convert a MySQL format key value to an InnoDB dtuple is
415
row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
418
row_mysql_convert_row_to_innobase(
419
/*==============================*/
420
dtuple_t* row, /*!< in/out: Innobase row where the
421
field type information is already
423
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct where template
424
must be of type ROW_MYSQL_WHOLE_ROW */
425
byte* mysql_rec) /*!< in: row in the MySQL format;
426
NOTE: do not discard as long as
427
row is used, as row may contain
428
pointers to this record! */
430
mysql_row_templ_t* templ;
434
ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
435
ut_ad(prebuilt->mysql_template);
437
for (i = 0; i < prebuilt->n_template; i++) {
439
templ = prebuilt->mysql_template + i;
440
dfield = dtuple_get_nth_field(row, i);
442
if (templ->mysql_null_bit_mask != 0) {
443
/* Column may be SQL NULL */
445
if (mysql_rec[templ->mysql_null_byte_offset]
446
& (byte) (templ->mysql_null_bit_mask)) {
450
dfield_set_null(dfield);
456
row_mysql_store_col_in_innobase_format(
458
prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
459
TRUE, /* MySQL row format data */
460
mysql_rec + templ->mysql_col_offset,
461
templ->mysql_col_len,
462
dict_table_is_comp(prebuilt->table));
468
/****************************************************************//**
469
Handles user errors and lock waits detected by the database engine.
470
@return TRUE if it was a lock wait and we should continue running the
474
row_mysql_handle_errors(
475
/*====================*/
476
ulint* new_err,/*!< out: possible new error encountered in
477
lock wait, or if no new error, the value
478
of trx->error_state at the entry of this
480
trx_t* trx, /*!< in: transaction */
481
que_thr_t* thr, /*!< in: query thread */
482
trx_savept_t* savept) /*!< in: savepoint or NULL */
487
err = trx->error_state;
489
ut_a(err != DB_SUCCESS);
491
trx->error_state = DB_SUCCESS;
494
case DB_LOCK_WAIT_TIMEOUT:
495
if (row_rollback_on_timeout) {
496
trx_general_rollback_for_mysql(trx, FALSE, NULL);
500
case DB_DUPLICATE_KEY:
501
case DB_FOREIGN_DUPLICATE_KEY:
502
case DB_TOO_BIG_RECORD:
503
case DB_ROW_IS_REFERENCED:
504
case DB_NO_REFERENCED_ROW:
505
case DB_CANNOT_ADD_CONSTRAINT:
506
case DB_TOO_MANY_CONCURRENT_TRXS:
507
case DB_OUT_OF_FILE_SPACE:
509
/* Roll back the latest, possibly incomplete
510
insertion or update */
512
trx_general_rollback_for_mysql(trx, TRUE, savept);
514
/* MySQL will roll back the latest SQL statement */
517
srv_suspend_mysql_thread(thr);
519
if (trx->error_state != DB_SUCCESS) {
520
que_thr_stop_for_mysql(thr);
522
goto handle_new_error;
530
case DB_LOCK_TABLE_FULL:
531
/* Roll back the whole transaction; this resolution was added
532
to version 3.23.43 */
534
trx_general_rollback_for_mysql(trx, FALSE, NULL);
537
case DB_MUST_GET_MORE_FILE_SPACE:
538
fputs("InnoDB: The database cannot continue"
539
" operation because of\n"
540
"InnoDB: lack of space. You must add"
541
" a new data file to\n"
542
"InnoDB: my.cnf and restart the database.\n", stderr);
547
fputs("InnoDB: We detected index corruption"
548
" in an InnoDB type table.\n"
549
"InnoDB: You have to dump + drop + reimport"
550
" the table or, in\n"
551
"InnoDB: a case of widespread corruption,"
553
"InnoDB: tables and recreate the"
554
" whole InnoDB tablespace.\n"
555
"InnoDB: If the mysqld server crashes"
556
" after the startup or when\n"
557
"InnoDB: you dump the tables, look at\n"
558
"InnoDB: " REFMAN "forcing-recovery.html"
559
" for help.\n", stderr);
562
fprintf(stderr, "InnoDB: unknown error code %lu\n",
567
if (trx->error_state != DB_SUCCESS) {
568
*new_err = trx->error_state;
573
trx->error_state = DB_SUCCESS;
578
/********************************************************************//**
579
Create a prebuilt struct for a MySQL table handle.
580
@return own: a prebuilt struct */
585
dict_table_t* table) /*!< in: Innobase table handle */
587
row_prebuilt_t* prebuilt;
589
dict_index_t* clust_index;
593
heap = mem_heap_create(sizeof *prebuilt + 128);
595
prebuilt = mem_heap_zalloc(heap, sizeof *prebuilt);
597
prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
598
prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
600
prebuilt->table = table;
602
prebuilt->sql_stat_start = TRUE;
603
prebuilt->heap = heap;
605
prebuilt->pcur = btr_pcur_create_for_mysql();
606
prebuilt->clust_pcur = btr_pcur_create_for_mysql();
608
prebuilt->select_lock_type = LOCK_NONE;
609
prebuilt->stored_select_lock_type = 99999999;
611
prebuilt->search_tuple = dtuple_create(
612
heap, 2 * dict_table_get_n_cols(table));
614
clust_index = dict_table_get_first_index(table);
616
/* Make sure that search_tuple is long enough for clustered index */
617
ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
619
ref_len = dict_index_get_n_unique(clust_index);
621
ref = dtuple_create(heap, ref_len);
623
dict_index_copy_types(ref, clust_index, ref_len);
625
prebuilt->clust_ref = ref;
627
prebuilt->autoinc_error = 0;
628
prebuilt->autoinc_offset = 0;
630
/* Default to 1, we will set the actual value later in
631
ha_innobase::get_auto_increment(). */
632
prebuilt->autoinc_increment = 1;
634
prebuilt->autoinc_last_value = 0;
639
/********************************************************************//**
640
Free a prebuilt struct for a MySQL table handle. */
645
row_prebuilt_t* prebuilt, /*!< in, own: prebuilt struct */
646
ibool dict_locked) /*!< in: TRUE=data dictionary locked */
651
(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
652
|| prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
655
"InnoDB: Error: trying to free a corrupt\n"
656
"InnoDB: table handle. Magic n %lu,"
657
" magic n2 %lu, table name ",
658
(ulong) prebuilt->magic_n,
659
(ulong) prebuilt->magic_n2);
660
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
663
mem_analyze_corruption(prebuilt);
668
prebuilt->magic_n = ROW_PREBUILT_FREED;
669
prebuilt->magic_n2 = ROW_PREBUILT_FREED;
671
btr_pcur_free_for_mysql(prebuilt->pcur);
672
btr_pcur_free_for_mysql(prebuilt->clust_pcur);
674
if (prebuilt->mysql_template) {
675
mem_free(prebuilt->mysql_template);
678
if (prebuilt->ins_graph) {
679
que_graph_free_recursive(prebuilt->ins_graph);
682
if (prebuilt->sel_graph) {
683
que_graph_free_recursive(prebuilt->sel_graph);
686
if (prebuilt->upd_graph) {
687
que_graph_free_recursive(prebuilt->upd_graph);
690
if (prebuilt->blob_heap) {
691
mem_heap_free(prebuilt->blob_heap);
694
if (prebuilt->old_vers_heap) {
695
mem_heap_free(prebuilt->old_vers_heap);
698
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
699
if (prebuilt->fetch_cache[i] != NULL) {
701
if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
702
(prebuilt->fetch_cache[i]) - 4))
703
|| (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
704
(prebuilt->fetch_cache[i])
705
+ prebuilt->mysql_row_len))) {
706
fputs("InnoDB: Error: trying to free"
707
" a corrupt fetch buffer.\n", stderr);
709
mem_analyze_corruption(
710
prebuilt->fetch_cache[i]);
715
mem_free((prebuilt->fetch_cache[i]) - 4);
719
dict_table_decrement_handle_count(prebuilt->table, dict_locked);
721
mem_heap_free(prebuilt->heap);
724
/*********************************************************************//**
725
Updates the transaction pointers in query graphs stored in the prebuilt
729
row_update_prebuilt_trx(
730
/*====================*/
731
row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct
733
trx_t* trx) /*!< in: transaction handle */
735
if (trx->magic_n != TRX_MAGIC_N) {
737
"InnoDB: Error: trying to use a corrupt\n"
738
"InnoDB: trx handle. Magic n %lu\n",
739
(ulong) trx->magic_n);
741
mem_analyze_corruption(trx);
746
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
748
"InnoDB: Error: trying to use a corrupt\n"
749
"InnoDB: table handle. Magic n %lu, table name ",
750
(ulong) prebuilt->magic_n);
751
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
754
mem_analyze_corruption(prebuilt);
761
if (prebuilt->ins_graph) {
762
prebuilt->ins_graph->trx = trx;
765
if (prebuilt->upd_graph) {
766
prebuilt->upd_graph->trx = trx;
769
if (prebuilt->sel_graph) {
770
prebuilt->sel_graph->trx = trx;
774
/*********************************************************************//**
775
Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
776
has not yet been built in the prebuilt struct, then this function first
778
@return prebuilt dtuple; the column type information is also set in it */
781
row_get_prebuilt_insert_row(
782
/*========================*/
783
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
788
dict_table_t* table = prebuilt->table;
790
ut_ad(prebuilt && table && prebuilt->trx);
792
if (prebuilt->ins_node == NULL) {
794
/* Not called before for this handle: create an insert node
795
and query graph to the prebuilt struct */
797
node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
799
prebuilt->ins_node = node;
801
if (prebuilt->ins_upd_rec_buff == NULL) {
802
prebuilt->ins_upd_rec_buff = mem_heap_alloc(
803
prebuilt->heap, prebuilt->mysql_row_len);
806
row = dtuple_create(prebuilt->heap,
807
dict_table_get_n_cols(table));
809
dict_table_copy_types(row, table);
811
ins_node_set_new_row(node, row);
813
prebuilt->ins_graph = que_node_get_parent(
814
pars_complete_graph_for_exec(node,
817
prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
820
return(prebuilt->ins_node->row);
823
/*********************************************************************//**
824
Updates the table modification counter and calculates new estimates
825
for table and index statistics if necessary. */
828
row_update_statistics_if_needed(
829
/*============================*/
830
dict_table_t* table) /*!< in: table */
834
counter = table->stat_modified_counter;
836
table->stat_modified_counter = counter + 1;
838
/* Calculate new statistics if 1 / 16 of table has been modified
839
since the last time a statistics batch was run, or if
840
stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
841
We calculate statistics at most every 16th round, since we may have
842
a counter table which is very small and updated very often. */
844
if (counter > 2000000000
845
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
847
dict_update_statistics(table);
851
/*********************************************************************//**
852
Unlocks AUTO_INC type locks that were possibly reserved by a trx. */
855
row_unlock_table_autoinc_for_mysql(
856
/*===============================*/
857
trx_t* trx) /*!< in/out: transaction */
859
mutex_enter(&kernel_mutex);
861
lock_release_autoinc_locks(trx);
863
mutex_exit(&kernel_mutex);
866
/*********************************************************************//**
867
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
868
AUTO_INC lock gives exclusive access to the auto-inc counter of the
869
table. The lock is reserved only for the duration of an SQL statement.
870
It is not compatible with another AUTO_INC or exclusive lock on the
872
@return error code or DB_SUCCESS */
875
row_lock_table_autoinc_for_mysql(
876
/*=============================*/
877
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in the MySQL
880
trx_t* trx = prebuilt->trx;
881
ins_node_t* node = prebuilt->ins_node;
882
const dict_table_t* table = prebuilt->table;
888
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
890
/* If we already hold an AUTOINC lock on the table then do nothing.
891
Note: We peek at the value of the current owner without acquiring
892
the kernel mutex. **/
893
if (trx == table->autoinc_trx) {
898
trx->op_info = "setting auto-inc lock";
901
row_get_prebuilt_insert_row(prebuilt);
902
node = prebuilt->ins_node;
905
/* We use the insert query graph as the dummy graph needed
906
in the lock module call */
908
thr = que_fork_get_first_thr(prebuilt->ins_graph);
910
que_thr_move_to_run_state_for_mysql(thr, trx);
913
thr->run_node = node;
914
thr->prev_node = node;
916
/* It may be that the current session has not yet started
917
its transaction, or it has been committed: */
919
trx_start_if_not_started(trx);
921
err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
923
trx->error_state = err;
925
if (err != DB_SUCCESS) {
926
que_thr_stop_for_mysql(thr);
928
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
939
que_thr_stop_for_mysql_no_error(thr, trx);
946
/*********************************************************************//**
947
Sets a table lock on the table mentioned in prebuilt.
948
@return error code or DB_SUCCESS */
951
row_lock_table_for_mysql(
952
/*=====================*/
953
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in the MySQL
955
dict_table_t* table, /*!< in: table to lock, or NULL
956
if prebuilt->table should be
958
prebuilt->select_lock_type */
959
ulint mode) /*!< in: lock mode of table
960
(ignored if table==NULL) */
962
trx_t* trx = prebuilt->trx;
968
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
970
trx->op_info = "setting table lock";
972
if (prebuilt->sel_graph == NULL) {
973
/* Build a dummy select query graph */
974
row_prebuild_sel_graph(prebuilt);
977
/* We use the select query graph as the dummy graph needed
978
in the lock module call */
980
thr = que_fork_get_first_thr(prebuilt->sel_graph);
982
que_thr_move_to_run_state_for_mysql(thr, trx);
986
thr->prev_node = thr->common.parent;
988
/* It may be that the current session has not yet started
989
its transaction, or it has been committed: */
991
trx_start_if_not_started(trx);
994
err = lock_table(0, table, mode, thr);
996
err = lock_table(0, prebuilt->table,
997
prebuilt->select_lock_type, thr);
1000
trx->error_state = err;
1002
if (err != DB_SUCCESS) {
1003
que_thr_stop_for_mysql(thr);
1005
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1007
if (was_lock_wait) {
1016
que_thr_stop_for_mysql_no_error(thr, trx);
1023
/*********************************************************************//**
1024
Does an insert for MySQL.
1025
@return error code or DB_SUCCESS */
1028
row_insert_for_mysql(
1029
/*=================*/
1030
byte* mysql_rec, /*!< in: row in the MySQL format */
1031
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1034
trx_savept_t savept;
1037
ibool was_lock_wait;
1038
trx_t* trx = prebuilt->trx;
1039
ins_node_t* node = prebuilt->ins_node;
1042
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1044
if (prebuilt->table->ibd_file_missing) {
1045
ut_print_timestamp(stderr);
1046
fprintf(stderr, " InnoDB: Error:\n"
1047
"InnoDB: MySQL is trying to use a table handle"
1048
" but the .ibd file for\n"
1049
"InnoDB: table %s does not exist.\n"
1050
"InnoDB: Have you deleted the .ibd file"
1051
" from the database directory under\n"
1052
"InnoDB: the MySQL datadir, or have you"
1053
" used DISCARD TABLESPACE?\n"
1054
"InnoDB: Look from\n"
1055
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1056
"InnoDB: how you can resolve the problem.\n",
1057
prebuilt->table->name);
1061
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1063
"InnoDB: Error: trying to free a corrupt\n"
1064
"InnoDB: table handle. Magic n %lu, table name ",
1065
(ulong) prebuilt->magic_n);
1066
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1069
mem_analyze_corruption(prebuilt);
1074
if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1075
fputs("InnoDB: A new raw disk partition was initialized or\n"
1076
"InnoDB: innodb_force_recovery is on: we do not allow\n"
1077
"InnoDB: database modifications by the user. Shut down\n"
1078
"InnoDB: mysqld and edit my.cnf so that"
1079
" newraw is replaced\n"
1080
"InnoDB: with raw, and innodb_force_... is removed.\n",
1086
trx->op_info = "inserting";
1088
row_mysql_delay_if_needed();
1090
trx_start_if_not_started(trx);
1093
row_get_prebuilt_insert_row(prebuilt);
1094
node = prebuilt->ins_node;
1097
row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1099
savept = trx_savept_take(trx);
1101
thr = que_fork_get_first_thr(prebuilt->ins_graph);
1103
if (prebuilt->sql_stat_start) {
1104
node->state = INS_NODE_SET_IX_LOCK;
1105
prebuilt->sql_stat_start = FALSE;
1107
node->state = INS_NODE_ALLOC_ROW_ID;
1110
que_thr_move_to_run_state_for_mysql(thr, trx);
1113
thr->run_node = node;
1114
thr->prev_node = node;
1118
err = trx->error_state;
1120
if (err != DB_SUCCESS) {
1121
que_thr_stop_for_mysql(thr);
1123
/* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1125
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1127
thr->lock_state= QUE_THR_LOCK_NOLOCK;
1129
if (was_lock_wait) {
1138
que_thr_stop_for_mysql_no_error(thr, trx);
1140
prebuilt->table->stat_n_rows++;
1142
srv_n_rows_inserted++;
1144
if (prebuilt->table->stat_n_rows == 0) {
1145
/* Avoid wrap-over */
1146
prebuilt->table->stat_n_rows--;
1149
row_update_statistics_if_needed(prebuilt->table);
1155
/*********************************************************************//**
1156
Builds a dummy query graph used in selects. */
1159
row_prebuild_sel_graph(
1160
/*===================*/
1161
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1166
ut_ad(prebuilt && prebuilt->trx);
1168
if (prebuilt->sel_graph == NULL) {
1170
node = sel_node_create(prebuilt->heap);
1172
prebuilt->sel_graph = que_node_get_parent(
1173
pars_complete_graph_for_exec(node,
1177
prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1181
/*********************************************************************//**
1182
Creates an query graph node of 'update' type to be used in the MySQL
1184
@return own: update node */
1187
row_create_update_node_for_mysql(
1188
/*=============================*/
1189
dict_table_t* table, /*!< in: table to update */
1190
mem_heap_t* heap) /*!< in: mem heap from which allocated */
1194
node = upd_node_create(heap);
1196
node->in_mysql_interface = TRUE;
1197
node->is_delete = FALSE;
1198
node->searched_update = FALSE;
1199
node->select = NULL;
1200
node->pcur = btr_pcur_create_for_mysql();
1201
node->table = table;
1203
node->update = upd_create(dict_table_get_n_cols(table), heap);
1205
node->update_n_fields = dict_table_get_n_cols(table);
1207
UT_LIST_INIT(node->columns);
1208
node->has_clust_rec_x_lock = TRUE;
1209
node->cmpl_info = 0;
1211
node->table_sym = NULL;
1212
node->col_assign_list = NULL;
1217
/*********************************************************************//**
1218
Gets pointer to a prebuilt update vector used in updates. If the update
1219
graph has not yet been built in the prebuilt struct, then this function
1221
@return prebuilt update vector */
1224
row_get_prebuilt_update_vector(
1225
/*===========================*/
1226
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1229
dict_table_t* table = prebuilt->table;
1232
ut_ad(prebuilt && table && prebuilt->trx);
1234
if (prebuilt->upd_node == NULL) {
1236
/* Not called before for this handle: create an update node
1237
and query graph to the prebuilt struct */
1239
node = row_create_update_node_for_mysql(table, prebuilt->heap);
1241
prebuilt->upd_node = node;
1243
prebuilt->upd_graph = que_node_get_parent(
1244
pars_complete_graph_for_exec(node,
1247
prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1250
return(prebuilt->upd_node->update);
1253
/*********************************************************************//**
1254
Does an update or delete of a row for MySQL.
1255
@return error code or DB_SUCCESS */
1258
row_update_for_mysql(
1259
/*=================*/
1260
byte* mysql_rec, /*!< in: the row to be updated, in
1262
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
1265
trx_savept_t savept;
1268
ibool was_lock_wait;
1269
dict_index_t* clust_index;
1270
/* ulint ref_len; */
1272
dict_table_t* table = prebuilt->table;
1273
trx_t* trx = prebuilt->trx;
1275
ut_ad(prebuilt && trx);
1276
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1277
UT_NOT_USED(mysql_rec);
1279
if (prebuilt->table->ibd_file_missing) {
1280
ut_print_timestamp(stderr);
1281
fprintf(stderr, " InnoDB: Error:\n"
1282
"InnoDB: MySQL is trying to use a table handle"
1283
" but the .ibd file for\n"
1284
"InnoDB: table %s does not exist.\n"
1285
"InnoDB: Have you deleted the .ibd file"
1286
" from the database directory under\n"
1287
"InnoDB: the MySQL datadir, or have you"
1288
" used DISCARD TABLESPACE?\n"
1289
"InnoDB: Look from\n"
1290
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1291
"InnoDB: how you can resolve the problem.\n",
1292
prebuilt->table->name);
1296
if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1298
"InnoDB: Error: trying to free a corrupt\n"
1299
"InnoDB: table handle. Magic n %lu, table name ",
1300
(ulong) prebuilt->magic_n);
1301
ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1304
mem_analyze_corruption(prebuilt);
1309
if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1310
fputs("InnoDB: A new raw disk partition was initialized or\n"
1311
"InnoDB: innodb_force_recovery is on: we do not allow\n"
1312
"InnoDB: database modifications by the user. Shut down\n"
1313
"InnoDB: mysqld and edit my.cnf so that newraw"
1315
"InnoDB: with raw, and innodb_force_... is removed.\n",
1321
trx->op_info = "updating or deleting";
1323
row_mysql_delay_if_needed();
1325
trx_start_if_not_started(trx);
1327
node = prebuilt->upd_node;
1329
clust_index = dict_table_get_first_index(table);
1331
if (prebuilt->pcur->btr_cur.index == clust_index) {
1332
btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1334
btr_pcur_copy_stored_position(node->pcur,
1335
prebuilt->clust_pcur);
1338
ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1340
/* MySQL seems to call rnd_pos before updating each row it
1341
has cached: we can get the correct cursor position from
1342
prebuilt->pcur; NOTE that we cannot build the row reference
1343
from mysql_rec if the clustered index was automatically
1344
generated for the table: MySQL does not know anything about
1345
the row id used as the clustered index key */
1347
savept = trx_savept_take(trx);
1349
thr = que_fork_get_first_thr(prebuilt->upd_graph);
1351
node->state = UPD_NODE_UPDATE_CLUSTERED;
1353
ut_ad(!prebuilt->sql_stat_start);
1355
que_thr_move_to_run_state_for_mysql(thr, trx);
1358
thr->run_node = node;
1359
thr->prev_node = node;
1363
err = trx->error_state;
1365
if (err != DB_SUCCESS) {
1366
que_thr_stop_for_mysql(thr);
1368
if (err == DB_RECORD_NOT_FOUND) {
1369
trx->error_state = DB_SUCCESS;
1375
thr->lock_state= QUE_THR_LOCK_ROW;
1376
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1378
thr->lock_state= QUE_THR_LOCK_NOLOCK;
1380
if (was_lock_wait) {
1389
que_thr_stop_for_mysql_no_error(thr, trx);
1391
if (node->is_delete) {
1392
if (prebuilt->table->stat_n_rows > 0) {
1393
prebuilt->table->stat_n_rows--;
1396
srv_n_rows_deleted++;
1398
srv_n_rows_updated++;
1401
row_update_statistics_if_needed(prebuilt->table);
1408
/*********************************************************************//**
1409
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
1410
this session is using a READ COMMITTED isolation level. Before
1411
calling this function we must use trx_reset_new_rec_lock_info() and
1412
trx_register_new_rec_lock() to store the information which new record locks
1413
really were set. This function removes a newly set lock under prebuilt->pcur,
1414
and also under prebuilt->clust_pcur. Currently, this is only used and tested
1415
in the case of an UPDATE or a DELETE statement, where the row lock is of the
1417
Thus, this implements a 'mini-rollback' that releases the latest record
1419
@return error code or DB_SUCCESS */
1422
row_unlock_for_mysql(
1423
/*=================*/
1424
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL
1426
ibool has_latches_on_recs)/*!< TRUE if called so that we have
1427
the latches on the records under pcur
1428
and clust_pcur, and we do not need to
1429
reposition the cursors. */
1431
btr_pcur_t* pcur = prebuilt->pcur;
1432
btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
1433
trx_t* trx = prebuilt->trx;
1435
ut_ad(prebuilt && trx);
1436
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1439
(!srv_locks_unsafe_for_binlog
1440
&& trx->isolation_level != TRX_ISO_READ_COMMITTED)) {
1443
"InnoDB: Error: calling row_unlock_for_mysql though\n"
1444
"InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
1445
"InnoDB: this session is not using"
1446
" READ COMMITTED isolation level.\n");
1451
trx->op_info = "unlock_row";
1453
if (prebuilt->new_rec_locks >= 1) {
1456
dict_index_t* index;
1457
trx_id_t rec_trx_id;
1462
/* Restore the cursor position and find the record */
1464
if (!has_latches_on_recs) {
1465
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1468
rec = btr_pcur_get_rec(pcur);
1469
index = btr_pcur_get_btr_cur(pcur)->index;
1471
if (prebuilt->new_rec_locks >= 2) {
1472
/* Restore the cursor position and find the record
1473
in the clustered index. */
1475
if (!has_latches_on_recs) {
1476
btr_pcur_restore_position(BTR_SEARCH_LEAF,
1480
rec = btr_pcur_get_rec(clust_pcur);
1481
index = btr_pcur_get_btr_cur(clust_pcur)->index;
1484
if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
1485
/* This is not a clustered index record. We
1486
do not know how to unlock the record. */
1490
/* If the record has been modified by this
1491
transaction, do not unlock it. */
1493
if (index->trx_id_offset) {
1494
rec_trx_id = trx_read_trx_id(rec
1495
+ index->trx_id_offset);
1497
mem_heap_t* heap = NULL;
1498
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1499
ulint* offsets = offsets_;
1501
rec_offs_init(offsets_);
1502
offsets = rec_get_offsets(rec, index, offsets,
1503
ULINT_UNDEFINED, &heap);
1505
rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1507
if (UNIV_LIKELY_NULL(heap)) {
1508
mem_heap_free(heap);
1512
if (ut_dulint_cmp(rec_trx_id, trx->id) != 0) {
1513
/* We did not update the record: unlock it */
1515
rec = btr_pcur_get_rec(pcur);
1516
index = btr_pcur_get_btr_cur(pcur)->index;
1518
lock_rec_unlock(trx, btr_pcur_get_block(pcur),
1519
rec, prebuilt->select_lock_type);
1521
if (prebuilt->new_rec_locks >= 2) {
1522
rec = btr_pcur_get_rec(clust_pcur);
1523
index = btr_pcur_get_btr_cur(clust_pcur)->index;
1525
lock_rec_unlock(trx,
1526
btr_pcur_get_block(clust_pcur),
1528
prebuilt->select_lock_type);
1540
/**********************************************************************//**
1541
Does a cascaded delete or set null in a foreign key operation.
1542
@return error code or DB_SUCCESS */
1545
row_update_cascade_for_mysql(
1546
/*=========================*/
1547
que_thr_t* thr, /*!< in: query thread */
1548
upd_node_t* node, /*!< in: update node used in the cascade
1549
or set null operation */
1550
dict_table_t* table) /*!< in: table where we do the operation */
1555
trx = thr_get_trx(thr);
1557
thr->run_node = node;
1558
thr->prev_node = node;
1562
err = trx->error_state;
1564
/* Note that the cascade node is a subnode of another InnoDB
1565
query graph node. We do a normal lock wait in this node, but
1566
all errors are handled by the parent node. */
1568
if (err == DB_LOCK_WAIT) {
1569
/* Handle lock wait here */
1571
que_thr_stop_for_mysql(thr);
1573
srv_suspend_mysql_thread(thr);
1575
/* Note that a lock wait may also end in a lock wait timeout,
1576
or this transaction is picked as a victim in selective
1577
deadlock resolution */
1579
if (trx->error_state != DB_SUCCESS) {
1581
return(trx->error_state);
1584
/* Retry operation after a normal lock wait */
1589
if (err != DB_SUCCESS) {
1594
if (node->is_delete) {
1595
if (table->stat_n_rows > 0) {
1596
table->stat_n_rows--;
1599
srv_n_rows_deleted++;
1601
srv_n_rows_updated++;
1604
row_update_statistics_if_needed(table);
1609
/*********************************************************************//**
1610
Checks if a table is such that we automatically created a clustered
1611
index on it (on row id).
1612
@return TRUE if the clustered index was generated automatically */
1615
row_table_got_default_clust_index(
1616
/*==============================*/
1617
const dict_table_t* table) /*!< in: table */
1619
const dict_index_t* clust_index;
1621
clust_index = dict_table_get_first_index(table);
1623
return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1626
/*********************************************************************//**
1627
Calculates the key number used inside MySQL for an Innobase index. We have
1628
to take into account if we generated a default clustered index for the table
1629
@return the key number used inside MySQL */
1632
row_get_mysql_key_number_for_index(
1633
/*===============================*/
1634
const dict_index_t* index) /*!< in: index */
1636
const dict_index_t* ind;
1642
ind = dict_table_get_first_index(index->table);
1644
while (index != ind) {
1645
ind = dict_table_get_next_index(ind);
1649
if (row_table_got_default_clust_index(index->table)) {
1657
/*********************************************************************//**
1658
Locks the data dictionary in shared mode from modifications, for performing
1659
foreign key check, rollback, or other operation invisible to MySQL. */
1662
row_mysql_freeze_data_dictionary_func(
1663
/*==================================*/
1664
trx_t* trx, /*!< in/out: transaction */
1665
const char* file, /*!< in: file name */
1666
ulint line) /*!< in: line number */
1668
ut_a(trx->dict_operation_lock_mode == 0);
1670
rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
1672
trx->dict_operation_lock_mode = RW_S_LATCH;
1675
/*********************************************************************//**
1676
Unlocks the data dictionary shared lock. */
1679
row_mysql_unfreeze_data_dictionary(
1680
/*===============================*/
1681
trx_t* trx) /*!< in/out: transaction */
1683
ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
1685
rw_lock_s_unlock(&dict_operation_lock);
1687
trx->dict_operation_lock_mode = 0;
1690
/*********************************************************************//**
1691
Locks the data dictionary exclusively for performing a table create or other
1692
data dictionary modification operation. */
1695
row_mysql_lock_data_dictionary_func(
1696
/*================================*/
1697
trx_t* trx, /*!< in/out: transaction */
1698
const char* file, /*!< in: file name */
1699
ulint line) /*!< in: line number */
1701
ut_a(trx->dict_operation_lock_mode == 0
1702
|| trx->dict_operation_lock_mode == RW_X_LATCH);
1704
/* Serialize data dictionary operations with dictionary mutex:
1705
no deadlocks or lock waits can occur then in these operations */
1707
rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
1708
trx->dict_operation_lock_mode = RW_X_LATCH;
1710
mutex_enter(&(dict_sys->mutex));
1713
/*********************************************************************//**
1714
Unlocks the data dictionary exclusive lock. */
1717
row_mysql_unlock_data_dictionary(
1718
/*=============================*/
1719
trx_t* trx) /*!< in/out: transaction */
1721
ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1723
/* Serialize data dictionary operations with dictionary mutex:
1724
no deadlocks can occur then in these operations */
1726
mutex_exit(&(dict_sys->mutex));
1727
rw_lock_x_unlock(&dict_operation_lock);
1729
trx->dict_operation_lock_mode = 0;
1732
/*********************************************************************//**
1733
Creates a table for MySQL. If the name of the table ends in
1734
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
1735
"innodb_table_monitor", then this will also start the printing of monitor
1736
output by the master thread. If the table name ends in "innodb_mem_validate",
1737
InnoDB will try to invoke mem_validate().
1738
@return error code or DB_SUCCESS */
1741
row_create_table_for_mysql(
1742
/*=======================*/
1743
dict_table_t* table, /*!< in, own: table definition
1745
trx_t* trx) /*!< in: transaction handle */
1750
const char* table_name;
1751
ulint table_name_len;
1755
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1756
#ifdef UNIV_SYNC_DEBUG
1757
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1758
#endif /* UNIV_SYNC_DEBUG */
1759
ut_ad(mutex_own(&(dict_sys->mutex)));
1760
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1762
if (srv_created_new_raw) {
1763
fputs("InnoDB: A new raw disk partition was initialized:\n"
1764
"InnoDB: we do not allow database modifications"
1766
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1767
" is replaced with raw.\n", stderr);
1769
dict_mem_table_free(table);
1770
trx_commit_for_mysql(trx);
1775
trx->op_info = "creating table";
1777
/* Check that no reserved column names are used. */
1778
for (i = 0; i < dict_table_get_n_user_cols(table); i++) {
1779
if (dict_col_name_is_reserved(
1780
dict_table_get_col_name(table, i))) {
1786
trx_start_if_not_started(trx);
1788
/* The table name is prefixed with the database name and a '/'.
1789
Certain table names starting with 'innodb_' have their special
1790
meaning regardless of the database name. Thus, we need to
1791
ignore the database name prefix in the comparisons. */
1792
table_name = strchr(table->name, '/');
1795
table_name_len = strlen(table_name) + 1;
1797
if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
1799
/* Table equals "innodb_monitor":
1800
start monitor prints */
1802
srv_print_innodb_monitor = TRUE;
1804
/* The lock timeout monitor thread also takes care
1805
of InnoDB monitor prints */
1807
os_event_set(srv_lock_timeout_thread_event);
1808
} else if (STR_EQ(table_name, table_name_len,
1809
S_innodb_lock_monitor)) {
1811
srv_print_innodb_monitor = TRUE;
1812
srv_print_innodb_lock_monitor = TRUE;
1813
os_event_set(srv_lock_timeout_thread_event);
1814
} else if (STR_EQ(table_name, table_name_len,
1815
S_innodb_tablespace_monitor)) {
1817
srv_print_innodb_tablespace_monitor = TRUE;
1818
os_event_set(srv_lock_timeout_thread_event);
1819
} else if (STR_EQ(table_name, table_name_len,
1820
S_innodb_table_monitor)) {
1822
srv_print_innodb_table_monitor = TRUE;
1823
os_event_set(srv_lock_timeout_thread_event);
1824
} else if (STR_EQ(table_name, table_name_len,
1825
S_innodb_mem_validate)) {
1826
/* We define here a debugging feature intended for
1829
fputs("Validating InnoDB memory:\n"
1830
"to use this feature you must compile InnoDB with\n"
1831
"UNIV_MEM_DEBUG defined in univ.i and"
1832
" the server must be\n"
1833
"quiet because allocation from a mem heap"
1834
" is not protected\n"
1835
"by any semaphore.\n", stderr);
1836
#ifdef UNIV_MEM_DEBUG
1837
ut_a(mem_validate());
1838
fputs("Memory validated\n", stderr);
1839
#else /* UNIV_MEM_DEBUG */
1840
fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1842
#endif /* UNIV_MEM_DEBUG */
1845
heap = mem_heap_create(512);
1847
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
1849
node = tab_create_graph_create(table, heap);
1851
thr = pars_complete_graph_for_exec(node, trx, heap);
1853
ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1854
que_run_threads(thr);
1856
err = trx->error_state;
1858
if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
1859
trx->error_state = DB_SUCCESS;
1860
trx_general_rollback_for_mysql(trx, FALSE, NULL);
1864
case DB_OUT_OF_FILE_SPACE:
1865
ut_print_timestamp(stderr);
1866
fputs(" InnoDB: Warning: cannot create table ",
1868
ut_print_name(stderr, trx, TRUE, table->name);
1869
fputs(" because tablespace full\n", stderr);
1871
if (dict_table_get_low(table->name)) {
1873
row_drop_table_for_mysql(table->name, trx, FALSE);
1874
trx_commit_for_mysql(trx);
1878
case DB_DUPLICATE_KEY:
1879
ut_print_timestamp(stderr);
1880
fputs(" InnoDB: Error: table ", stderr);
1881
ut_print_name(stderr, trx, TRUE, table->name);
1882
fputs(" already exists in InnoDB internal\n"
1883
"InnoDB: data dictionary. Have you deleted"
1885
"InnoDB: and not used DROP TABLE?"
1886
" Have you used DROP DATABASE\n"
1887
"InnoDB: for InnoDB tables in"
1888
" MySQL version <= 3.23.43?\n"
1889
"InnoDB: See the Restrictions section"
1890
" of the InnoDB manual.\n"
1891
"InnoDB: You can drop the orphaned table"
1892
" inside InnoDB by\n"
1893
"InnoDB: creating an InnoDB table with"
1894
" the same name in another\n"
1895
"InnoDB: database and copying the .frm file"
1896
" to the current database.\n"
1897
"InnoDB: Then MySQL thinks the table exists,"
1898
" and DROP TABLE will\n"
1899
"InnoDB: succeed.\n"
1900
"InnoDB: You can look for further help from\n"
1901
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
1904
/* We may also get err == DB_ERROR if the .ibd file for the
1905
table already exists */
1910
que_graph_free((que_t*) que_node_get_parent(thr));
1917
/*********************************************************************//**
1918
Does an index creation operation for MySQL. TODO: currently failure
1919
to create an index results in dropping the whole table! This is no problem
1920
currently as all indexes must be created at the same time as the table.
1921
@return error number or DB_SUCCESS */
1924
row_create_index_for_mysql(
1925
/*=======================*/
1926
dict_index_t* index, /*!< in, own: index definition
1928
trx_t* trx, /*!< in: transaction handle */
1929
const ulint* field_lengths) /*!< in: if not NULL, must contain
1930
dict_index_get_n_fields(index)
1931
actual field lengths for the
1932
index columns, which are
1933
then checked for not being too
1944
#ifdef UNIV_SYNC_DEBUG
1945
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1946
#endif /* UNIV_SYNC_DEBUG */
1947
ut_ad(mutex_own(&(dict_sys->mutex)));
1948
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1950
trx->op_info = "creating index";
1952
/* Copy the table name because we may want to drop the
1953
table later, after the index object is freed (inside
1954
que_run_threads()) and thus index->table_name is not available. */
1955
table_name = mem_strdup(index->table_name);
1957
trx_start_if_not_started(trx);
1959
/* Check that the same column does not appear twice in the index.
1960
Starting from 4.0.14, InnoDB should be able to cope with that, but
1961
safer not to allow them. */
1963
for (i = 0; i < dict_index_get_n_fields(index); i++) {
1966
for (j = 0; j < i; j++) {
1968
dict_index_get_nth_field(index, j)->name,
1969
dict_index_get_nth_field(index, i)->name)) {
1970
ut_print_timestamp(stderr);
1972
fputs(" InnoDB: Error: column ", stderr);
1973
ut_print_name(stderr, trx, FALSE,
1974
dict_index_get_nth_field(
1976
fputs(" appears twice in ", stderr);
1977
dict_index_name_print(stderr, trx, index);
1979
"InnoDB: This is not allowed"
1980
" in InnoDB.\n", stderr);
1982
err = DB_COL_APPEARS_TWICE_IN_INDEX;
1984
goto error_handling;
1988
/* Check also that prefix_len and actual length
1989
< DICT_MAX_INDEX_COL_LEN */
1991
len = dict_index_get_nth_field(index, i)->prefix_len;
1993
if (field_lengths) {
1994
len = ut_max(len, field_lengths[i]);
1997
if (len >= DICT_MAX_INDEX_COL_LEN) {
1998
err = DB_TOO_BIG_RECORD;
2000
goto error_handling;
2004
heap = mem_heap_create(512);
2006
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2008
/* Note that the space id where we store the index is inherited from
2009
the table in dict_build_index_def_step() in dict0crea.c. */
2011
node = ind_create_graph_create(index, heap);
2013
thr = pars_complete_graph_for_exec(node, trx, heap);
2015
ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2016
que_run_threads(thr);
2018
err = trx->error_state;
2020
que_graph_free((que_t*) que_node_get_parent(thr));
2023
if (err != DB_SUCCESS) {
2024
/* We have special error handling here */
2026
trx->error_state = DB_SUCCESS;
2028
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2030
row_drop_table_for_mysql(table_name, trx, FALSE);
2032
trx_commit_for_mysql(trx);
2034
trx->error_state = DB_SUCCESS;
2039
mem_free(table_name);
2044
/*********************************************************************//**
2045
Scans a table create SQL string and adds to the data dictionary
2046
the foreign key constraints declared in the string. This function
2047
should be called after the indexes for a table have been created.
2048
Each foreign key constraint must be accompanied with indexes in
2049
bot participating tables. The indexes are allowed to contain more
2050
fields than mentioned in the constraint. Check also that foreign key
2051
constraints which reference this table are ok.
2052
@return error code or DB_SUCCESS */
2055
row_table_add_foreign_constraints(
2056
/*==============================*/
2057
trx_t* trx, /*!< in: transaction */
2058
const char* sql_string, /*!< in: table create statement where
2059
foreign keys are declared like:
2060
FOREIGN KEY (a, b) REFERENCES table2(c, d),
2061
table2 can be written also with the
2062
database name before it: test.table2 */
2063
const char* name, /*!< in: table full name in the
2065
database_name/table_name */
2066
ibool reject_fks) /*!< in: if TRUE, fail with error
2067
code DB_CANNOT_ADD_CONSTRAINT if
2068
any foreign keys are found. */
2072
ut_ad(mutex_own(&(dict_sys->mutex)));
2073
#ifdef UNIV_SYNC_DEBUG
2074
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2075
#endif /* UNIV_SYNC_DEBUG */
2078
trx->op_info = "adding foreign keys";
2080
trx_start_if_not_started(trx);
2082
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
2084
err = dict_create_foreign_constraints(trx, sql_string, name,
2086
if (err == DB_SUCCESS) {
2087
/* Check that also referencing constraints are ok */
2088
err = dict_load_foreigns(name, TRUE);
2091
if (err != DB_SUCCESS) {
2092
/* We have special error handling here */
2094
trx->error_state = DB_SUCCESS;
2096
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2098
row_drop_table_for_mysql(name, trx, FALSE);
2100
trx_commit_for_mysql(trx);
2102
trx->error_state = DB_SUCCESS;
2108
/*********************************************************************//**
2109
Drops a table for MySQL as a background operation. MySQL relies on Unix
2110
in ALTER TABLE to the fact that the table handler does not remove the
2111
table before all handles to it has been removed. Furhermore, the MySQL's
2112
call to drop table must be non-blocking. Therefore we do the drop table
2113
as a background operation, which is taken care of by the master thread
2115
@return error code or DB_SUCCESS */
2118
row_drop_table_for_mysql_in_background(
2119
/*===================================*/
2120
const char* name) /*!< in: table name */
2125
trx = trx_allocate_for_background();
2127
/* If the original transaction was dropping a table referenced by
2128
foreign keys, we must set the following to be able to drop the
2131
trx->check_foreigns = FALSE;
2133
/* fputs("InnoDB: Error: Dropping table ", stderr);
2134
ut_print_name(stderr, trx, TRUE, name);
2135
fputs(" in background drop list\n", stderr); */
2137
/* Try to drop the table in InnoDB */
2139
error = row_drop_table_for_mysql(name, trx, FALSE);
2141
/* Flush the log to reduce probability that the .frm files and
2142
the InnoDB data dictionary get out-of-sync if the user runs
2143
with innodb_flush_log_at_trx_commit = 0 */
2145
log_buffer_flush_to_disk();
2147
trx_commit_for_mysql(trx);
2149
trx_free_for_background(trx);
2151
return((int) error);
2154
/*********************************************************************//**
2155
The master thread in srv0srv.c calls this regularly to drop tables which
2156
we must drop in background after queries to them have ended. Such lazy
2157
dropping of tables is needed in ALTER TABLE on Unix.
2158
@return how many tables dropped + remaining tables in list */
2161
row_drop_tables_for_mysql_in_background(void)
2162
/*=========================================*/
2164
row_mysql_drop_t* drop;
2165
dict_table_t* table;
2167
ulint n_tables_dropped = 0;
2169
mutex_enter(&kernel_mutex);
2171
if (!row_mysql_drop_list_inited) {
2173
UT_LIST_INIT(row_mysql_drop_list);
2174
row_mysql_drop_list_inited = TRUE;
2177
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2179
n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2181
mutex_exit(&kernel_mutex);
2184
/* All tables dropped */
2186
return(n_tables + n_tables_dropped);
2189
mutex_enter(&(dict_sys->mutex));
2190
table = dict_table_get_low(drop->table_name);
2191
mutex_exit(&(dict_sys->mutex));
2193
if (table == NULL) {
2194
/* If for some reason the table has already been dropped
2195
through some other mechanism, do not try to drop it */
2197
goto already_dropped;
2200
if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2201
drop->table_name)) {
2202
/* If the DROP fails for some table, we return, and let the
2203
main thread retry later */
2205
return(n_tables + n_tables_dropped);
2211
mutex_enter(&kernel_mutex);
2213
UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2215
ut_print_timestamp(stderr);
2216
fputs(" InnoDB: Dropped table ", stderr);
2217
ut_print_name(stderr, NULL, TRUE, drop->table_name);
2218
fputs(" in background drop queue.\n", stderr);
2220
mem_free(drop->table_name);
2224
mutex_exit(&kernel_mutex);
2229
/*********************************************************************//**
2230
Get the background drop list length. NOTE: the caller must own the kernel
2232
@return how many tables in list */
2235
row_get_background_drop_list_len_low(void)
2236
/*======================================*/
2238
ut_ad(mutex_own(&kernel_mutex));
2240
if (!row_mysql_drop_list_inited) {
2242
UT_LIST_INIT(row_mysql_drop_list);
2243
row_mysql_drop_list_inited = TRUE;
2246
return(UT_LIST_GET_LEN(row_mysql_drop_list));
2249
/*********************************************************************//**
2250
If a table is not yet in the drop list, adds the table to the list of tables
2251
which the master thread drops in background. We need this on Unix because in
2252
ALTER TABLE MySQL may call drop table even if the table has running queries on
2253
it. Also, if there are running foreign key checks on the table, we drop the
2255
@return TRUE if the table was not yet in the drop list, and was added there */
2258
row_add_table_to_background_drop_list(
2259
/*==================================*/
2260
const char* name) /*!< in: table name */
2262
row_mysql_drop_t* drop;
2264
mutex_enter(&kernel_mutex);
2266
if (!row_mysql_drop_list_inited) {
2268
UT_LIST_INIT(row_mysql_drop_list);
2269
row_mysql_drop_list_inited = TRUE;
2272
/* Look if the table already is in the drop list */
2273
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2275
while (drop != NULL) {
2276
if (strcmp(drop->table_name, name) == 0) {
2277
/* Already in the list */
2279
mutex_exit(&kernel_mutex);
2284
drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2287
drop = mem_alloc(sizeof(row_mysql_drop_t));
2289
drop->table_name = mem_strdup(name);
2291
UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2293
/* fputs("InnoDB: Adding table ", stderr);
2294
ut_print_name(stderr, trx, TRUE, drop->table_name);
2295
fputs(" to background drop list\n", stderr); */
2297
mutex_exit(&kernel_mutex);
2302
/*********************************************************************//**
2303
Discards the tablespace of a table which stored in an .ibd file. Discarding
2304
means that this function deletes the .ibd file and assigns a new table id for
2305
the table. Also the flag table->ibd_file_missing is set TRUE.
2306
@return error code or DB_SUCCESS */
2309
row_discard_tablespace_for_mysql(
2310
/*=============================*/
2311
const char* name, /*!< in: table name */
2312
trx_t* trx) /*!< in: transaction handle */
2314
dict_foreign_t* foreign;
2316
dict_table_t* table;
2319
pars_info_t* info = NULL;
2321
/* How do we prevent crashes caused by ongoing operations on
2322
the table? Old operations could try to access non-existent
2325
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2326
MySQL table lock on the table before we can do DISCARD
2327
TABLESPACE. Then there are no running queries on the table.
2329
2) Purge and rollback: we assign a new table id for the
2330
table. Since purge and rollback look for the table based on
2331
the table id, they see the table as 'dropped' and discard
2334
3) Insert buffer: we remove all entries for the tablespace in
2335
the insert buffer tree; as long as the tablespace mem object
2336
does not exist, ongoing insert buffer page merges are
2337
discarded in buf0rea.c. If we recreate the tablespace mem
2338
object with IMPORT TABLESPACE later, then the tablespace will
2339
have the same id, but the tablespace_version field in the mem
2340
object is different, and ongoing old insert buffer page merges
2343
4) Linear readahead and random readahead: we use the same
2344
method as in 3) to discard ongoing operations.
2346
5) FOREIGN KEY operations: if
2347
table->n_foreign_key_checks_running > 0, we do not allow the
2348
discard. We also reserve the data dictionary latch. */
2350
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2352
trx->op_info = "discarding tablespace";
2353
trx_start_if_not_started(trx);
2355
/* Serialize data dictionary operations with dictionary mutex:
2356
no deadlocks can occur then in these operations */
2358
row_mysql_lock_data_dictionary(trx);
2360
table = dict_table_get_low(name);
2363
err = DB_TABLE_NOT_FOUND;
2368
if (table->space == 0) {
2369
ut_print_timestamp(stderr);
2370
fputs(" InnoDB: Error: table ", stderr);
2371
ut_print_name(stderr, trx, TRUE, name);
2373
"InnoDB: is in the system tablespace 0"
2374
" which cannot be discarded\n", stderr);
2380
if (table->n_foreign_key_checks_running > 0) {
2382
ut_print_timestamp(stderr);
2383
fputs(" InnoDB: You are trying to DISCARD table ", stderr);
2384
ut_print_name(stderr, trx, TRUE, table->name);
2386
"InnoDB: though there is a foreign key check"
2388
"InnoDB: Cannot discard the table.\n",
2396
/* Check if the table is referenced by foreign key constraints from
2397
some other table (not the table itself) */
2399
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2401
while (foreign && foreign->foreign_table == table) {
2402
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2405
if (foreign && trx->check_foreigns) {
2407
FILE* ef = dict_foreign_err_file;
2409
/* We only allow discarding a referenced table if
2410
FOREIGN_KEY_CHECKS is set to 0 */
2412
err = DB_CANNOT_DROP_CONSTRAINT;
2414
mutex_enter(&dict_foreign_err_mutex);
2416
ut_print_timestamp(ef);
2418
fputs(" Cannot DISCARD table ", ef);
2419
ut_print_name(stderr, trx, TRUE, name);
2421
"because it is referenced by ", ef);
2422
ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
2424
mutex_exit(&dict_foreign_err_mutex);
2429
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2431
/* Remove all locks except the table-level S and X locks. */
2432
lock_remove_all_on_table(table, FALSE);
2434
info = pars_info_create();
2436
pars_info_add_str_literal(info, "table_name", name);
2437
pars_info_add_dulint_literal(info, "new_id", new_id);
2439
err = que_eval_sql(info,
2440
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2443
"SELECT ID INTO old_id\n"
2445
"WHERE NAME = :table_name\n"
2446
"LOCK IN SHARE MODE;\n"
2447
"IF (SQL % NOTFOUND) THEN\n"
2451
"UPDATE SYS_TABLES SET ID = :new_id\n"
2452
" WHERE ID = old_id;\n"
2453
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2454
" WHERE TABLE_ID = old_id;\n"
2455
"UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2456
" WHERE TABLE_ID = old_id;\n"
2461
if (err != DB_SUCCESS) {
2462
trx->error_state = DB_SUCCESS;
2463
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2464
trx->error_state = DB_SUCCESS;
2466
dict_table_change_id_in_cache(table, new_id);
2468
success = fil_discard_tablespace(table->space);
2471
trx->error_state = DB_SUCCESS;
2472
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2473
trx->error_state = DB_SUCCESS;
2477
/* Set the flag which tells that now it is legal to
2478
IMPORT a tablespace for this table */
2479
table->tablespace_discarded = TRUE;
2480
table->ibd_file_missing = TRUE;
2485
trx_commit_for_mysql(trx);
2487
row_mysql_unlock_data_dictionary(trx);
2494
/*****************************************************************//**
2495
Imports a tablespace. The space id in the .ibd file must match the space id
2496
of the table in the data dictionary.
2497
@return error code or DB_SUCCESS */
2500
row_import_tablespace_for_mysql(
2501
/*============================*/
2502
const char* name, /*!< in: table name */
2503
trx_t* trx) /*!< in: transaction handle */
2505
dict_table_t* table;
2507
ib_uint64_t current_lsn;
2508
ulint err = DB_SUCCESS;
2510
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2512
trx_start_if_not_started(trx);
2514
trx->op_info = "importing tablespace";
2516
current_lsn = log_get_lsn();
2518
/* It is possible, though very improbable, that the lsn's in the
2519
tablespace to be imported have risen above the current system lsn, if
2520
a lengthy purge, ibuf merge, or rollback was performed on a backup
2521
taken with ibbackup. If that is the case, reset page lsn's in the
2522
file. We assume that mysqld was shut down after it performed these
2523
cleanup operations on the .ibd file, so that it stamped the latest lsn
2524
to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2526
TODO: reset also the trx id's in clustered index records and write
2527
a new space id to each data page. That would allow us to import clean
2528
.ibd files from another MySQL installation. */
2530
success = fil_reset_too_high_lsns(name, current_lsn);
2533
ut_print_timestamp(stderr);
2534
fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
2535
ut_print_name(stderr, trx, TRUE, name);
2537
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2542
row_mysql_lock_data_dictionary(trx);
2547
/* Serialize data dictionary operations with dictionary mutex:
2548
no deadlocks can occur then in these operations */
2550
row_mysql_lock_data_dictionary(trx);
2552
table = dict_table_get_low(name);
2555
ut_print_timestamp(stderr);
2556
fputs(" InnoDB: table ", stderr);
2557
ut_print_name(stderr, trx, TRUE, name);
2559
"InnoDB: does not exist in the InnoDB data dictionary\n"
2560
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2563
err = DB_TABLE_NOT_FOUND;
2568
if (table->space == 0) {
2569
ut_print_timestamp(stderr);
2570
fputs(" InnoDB: Error: table ", stderr);
2571
ut_print_name(stderr, trx, TRUE, name);
2573
"InnoDB: is in the system tablespace 0"
2574
" which cannot be imported\n", stderr);
2580
if (!table->tablespace_discarded) {
2581
ut_print_timestamp(stderr);
2582
fputs(" InnoDB: Error: you are trying to"
2583
" IMPORT a tablespace\n"
2584
"InnoDB: ", stderr);
2585
ut_print_name(stderr, trx, TRUE, name);
2586
fputs(", though you have not called DISCARD on it yet\n"
2587
"InnoDB: during the lifetime of the mysqld process!\n",
2595
/* Play safe and remove all insert buffer entries, though we should
2596
have removed them already when DISCARD TABLESPACE was called */
2598
ibuf_delete_for_discarded_space(table->space);
2600
success = fil_open_single_table_tablespace(
2602
table->flags == DICT_TF_COMPACT ? 0 : table->flags,
2605
table->ibd_file_missing = FALSE;
2606
table->tablespace_discarded = FALSE;
2608
if (table->ibd_file_missing) {
2609
ut_print_timestamp(stderr);
2610
fputs(" InnoDB: cannot find or open in the"
2611
" database directory the .ibd file of\n"
2612
"InnoDB: table ", stderr);
2613
ut_print_name(stderr, trx, TRUE, name);
2615
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2623
trx_commit_for_mysql(trx);
2625
row_mysql_unlock_data_dictionary(trx);
2632
/*********************************************************************//**
2633
Truncates a table for MySQL.
2634
@return error code or DB_SUCCESS */
2637
row_truncate_table_for_mysql(
2638
/*=========================*/
2639
dict_table_t* table, /*!< in: table handle */
2640
trx_t* trx) /*!< in: transaction handle */
2642
dict_foreign_t* foreign;
2648
dict_index_t* sys_index;
2652
ulint recreate_space = 0;
2653
pars_info_t* info = NULL;
2655
/* How do we prevent crashes caused by ongoing operations on
2656
the table? Old operations could try to access non-existent
2659
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2660
MySQL table lock on the table before we can do TRUNCATE
2661
TABLE. Then there are no running queries on the table. This is
2662
guaranteed, because in ha_innobase::store_lock(), we do not
2663
weaken the TL_WRITE lock requested by MySQL when executing
2666
2) Purge and rollback: we assign a new table id for the
2667
table. Since purge and rollback look for the table based on
2668
the table id, they see the table as 'dropped' and discard
2671
3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2672
so we do not have to remove insert buffer records, as the
2673
insert buffer works at a low level. If a freed page is later
2674
reallocated, the allocator will remove the ibuf entries for
2677
When we truncate *.ibd files by recreating them (analogous to
2678
DISCARD TABLESPACE), we remove all entries for the table in the
2679
insert buffer tree. This is not strictly necessary, because
2680
in 6) we will assign a new tablespace identifier, but we can
2681
free up some space in the system tablespace.
2683
4) Linear readahead and random readahead: we use the same
2684
method as in 3) to discard ongoing operations. (This is only
2685
relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2687
5) FOREIGN KEY operations: if
2688
table->n_foreign_key_checks_running > 0, we do not allow the
2689
TRUNCATE. We also reserve the data dictionary latch.
2691
6) Crash recovery: To prevent the application of pre-truncation
2692
redo log records on the truncated tablespace, we will assign
2693
a new tablespace identifier to the truncated tablespace. */
2695
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2698
if (srv_created_new_raw) {
2699
fputs("InnoDB: A new raw disk partition was initialized:\n"
2700
"InnoDB: we do not allow database modifications"
2702
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2703
" is replaced with raw.\n", stderr);
2708
trx->op_info = "truncating table";
2710
trx_start_if_not_started(trx);
2712
/* Serialize data dictionary operations with dictionary mutex:
2713
no deadlocks can occur then in these operations */
2715
ut_a(trx->dict_operation_lock_mode == 0);
2716
/* Prevent foreign key checks etc. while we are truncating the
2719
row_mysql_lock_data_dictionary(trx);
2721
ut_ad(mutex_own(&(dict_sys->mutex)));
2722
#ifdef UNIV_SYNC_DEBUG
2723
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2724
#endif /* UNIV_SYNC_DEBUG */
2726
/* Check if the table is referenced by foreign key constraints from
2727
some other table (not the table itself) */
2729
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2731
while (foreign && foreign->foreign_table == table) {
2732
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2735
if (foreign && trx->check_foreigns) {
2736
FILE* ef = dict_foreign_err_file;
2738
/* We only allow truncating a referenced table if
2739
FOREIGN_KEY_CHECKS is set to 0 */
2741
mutex_enter(&dict_foreign_err_mutex);
2743
ut_print_timestamp(ef);
2745
fputs(" Cannot truncate table ", ef);
2746
ut_print_name(ef, trx, TRUE, table->name);
2747
fputs(" by DROP+CREATE\n"
2748
"InnoDB: because it is referenced by ", ef);
2749
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2751
mutex_exit(&dict_foreign_err_mutex);
2757
/* TODO: could we replace the counter n_foreign_key_checks_running
2758
with lock checks on the table? Acquire here an exclusive lock on the
2759
table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2760
they can cope with the table having been truncated here? Foreign key
2761
checks take an IS or IX lock on the table. */
2763
if (table->n_foreign_key_checks_running > 0) {
2764
ut_print_timestamp(stderr);
2765
fputs(" InnoDB: Cannot truncate table ", stderr);
2766
ut_print_name(stderr, trx, TRUE, table->name);
2767
fputs(" by DROP+CREATE\n"
2768
"InnoDB: because there is a foreign key check"
2769
" running on it.\n",
2776
/* Remove all locks except the table-level S and X locks. */
2777
lock_remove_all_on_table(table, FALSE);
2779
trx->table_id = table->id;
2781
if (table->space && !table->dir_path_of_temp_table) {
2782
/* Discard and create the single-table tablespace. */
2783
ulint space = table->space;
2784
ulint flags = fil_space_get_flags(space);
2786
if (flags != ULINT_UNDEFINED
2787
&& fil_discard_tablespace(space)) {
2789
dict_index_t* index;
2793
if (fil_create_new_single_table_tablespace(
2794
&space, table->name, FALSE, flags,
2795
FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
2796
ut_print_timestamp(stderr);
2798
" InnoDB: TRUNCATE TABLE %s failed to"
2799
" create a new tablespace\n",
2801
table->ibd_file_missing = 1;
2806
recreate_space = space;
2808
/* Replace the space_id in the data dictionary cache.
2809
The persisent data dictionary (SYS_TABLES.SPACE
2810
and SYS_INDEXES.SPACE) are updated later in this
2812
table->space = space;
2813
index = dict_table_get_first_index(table);
2815
index->space = space;
2816
index = dict_table_get_next_index(index);
2820
fsp_header_init(space,
2821
FIL_IBD_FILE_INITIAL_SIZE, &mtr);
2826
/* scan SYS_INDEXES for all indexes of the table */
2827
heap = mem_heap_create(800);
2829
tuple = dtuple_create(heap, 1);
2830
dfield = dtuple_get_nth_field(tuple, 0);
2832
buf = mem_heap_alloc(heap, 8);
2833
mach_write_to_8(buf, table->id);
2835
dfield_set_data(dfield, buf, 8);
2836
sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2837
dict_index_copy_types(tuple, sys_index, 1);
2840
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2841
BTR_MODIFY_LEAF, &pcur, &mtr);
2848
if (!btr_pcur_is_on_user_rec(&pcur)) {
2849
/* The end of SYS_INDEXES has been reached. */
2853
rec = btr_pcur_get_rec(&pcur);
2855
field = rec_get_nth_field_old(rec, 0, &len);
2858
if (memcmp(buf, field, len) != 0) {
2859
/* End of indexes for the table (TABLE_ID mismatch). */
2863
if (rec_get_deleted_flag(rec, FALSE)) {
2864
/* The index has been dropped. */
2868
/* This call may commit and restart mtr
2869
and reposition pcur. */
2870
root_page_no = dict_truncate_index_tree(table, recreate_space,
2873
rec = btr_pcur_get_rec(&pcur);
2875
if (root_page_no != FIL_NULL) {
2876
page_rec_write_index_page_no(
2877
rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2878
root_page_no, &mtr);
2879
/* We will need to commit and restart the
2880
mini-transaction in order to avoid deadlocks.
2881
The dict_truncate_index_tree() call has allocated
2882
a page in this mini-transaction, and the rest of
2883
this loop could latch another index page. */
2886
btr_pcur_restore_position(BTR_MODIFY_LEAF,
2891
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2894
btr_pcur_close(&pcur);
2897
mem_heap_free(heap);
2899
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2901
info = pars_info_create();
2903
pars_info_add_int4_literal(info, "space", (lint) table->space);
2904
pars_info_add_dulint_literal(info, "old_id", table->id);
2905
pars_info_add_dulint_literal(info, "new_id", new_id);
2907
err = que_eval_sql(info,
2908
"PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2911
" SET ID = :new_id, SPACE = :space\n"
2912
" WHERE ID = :old_id;\n"
2913
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2914
" WHERE TABLE_ID = :old_id;\n"
2915
"UPDATE SYS_INDEXES"
2916
" SET TABLE_ID = :new_id, SPACE = :space\n"
2917
" WHERE TABLE_ID = :old_id;\n"
2922
if (err != DB_SUCCESS) {
2923
trx->error_state = DB_SUCCESS;
2924
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2925
trx->error_state = DB_SUCCESS;
2926
ut_print_timestamp(stderr);
2927
fputs(" InnoDB: Unable to assign a new identifier to table ",
2929
ut_print_name(stderr, trx, TRUE, table->name);
2931
"InnoDB: after truncating it. Background processes"
2932
" may corrupt the table!\n", stderr);
2935
dict_table_change_id_in_cache(table, new_id);
2939
MySQL calls ha_innobase::reset_auto_increment() which does
2942
dict_table_autoinc_lock(table);
2943
dict_table_autoinc_initialize(table, 1);
2944
dict_table_autoinc_unlock(table);
2945
dict_update_statistics(table);
2947
trx_commit_for_mysql(trx);
2951
row_mysql_unlock_data_dictionary(trx);
2955
srv_wake_master_thread();
2960
/*********************************************************************//**
2961
Drops a table for MySQL. If the name of the dropped table ends in
2962
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
2963
"innodb_table_monitor", then this will also stop the printing of monitor
2964
output by the master thread. If the data dictionary was not already locked
2965
by the transaction, the transaction will be committed. Otherwise, the
2966
data dictionary will remain locked.
2967
@return error code or DB_SUCCESS */
2970
row_drop_table_for_mysql(
2971
/*=====================*/
2972
const char* name, /*!< in: table name */
2973
trx_t* trx, /*!< in: transaction handle */
2974
ibool drop_db)/*!< in: TRUE=dropping whole database */
2976
dict_foreign_t* foreign;
2977
dict_table_t* table;
2980
const char* table_name;
2982
ibool locked_dictionary = FALSE;
2983
pars_info_t* info = NULL;
2987
if (srv_created_new_raw) {
2988
fputs("InnoDB: A new raw disk partition was initialized:\n"
2989
"InnoDB: we do not allow database modifications"
2991
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2992
" is replaced with raw.\n", stderr);
2997
trx->op_info = "dropping table";
2999
trx_start_if_not_started(trx);
3001
/* The table name is prefixed with the database name and a '/'.
3002
Certain table names starting with 'innodb_' have their special
3003
meaning regardless of the database name. Thus, we need to
3004
ignore the database name prefix in the comparisons. */
3005
table_name = strchr(name, '/');
3008
namelen = strlen(table_name) + 1;
3010
if (namelen == sizeof S_innodb_monitor
3011
&& !memcmp(table_name, S_innodb_monitor,
3012
sizeof S_innodb_monitor)) {
3014
/* Table name equals "innodb_monitor":
3015
stop monitor prints */
3017
srv_print_innodb_monitor = FALSE;
3018
srv_print_innodb_lock_monitor = FALSE;
3019
} else if (namelen == sizeof S_innodb_lock_monitor
3020
&& !memcmp(table_name, S_innodb_lock_monitor,
3021
sizeof S_innodb_lock_monitor)) {
3022
srv_print_innodb_monitor = FALSE;
3023
srv_print_innodb_lock_monitor = FALSE;
3024
} else if (namelen == sizeof S_innodb_tablespace_monitor
3025
&& !memcmp(table_name, S_innodb_tablespace_monitor,
3026
sizeof S_innodb_tablespace_monitor)) {
3028
srv_print_innodb_tablespace_monitor = FALSE;
3029
} else if (namelen == sizeof S_innodb_table_monitor
3030
&& !memcmp(table_name, S_innodb_table_monitor,
3031
sizeof S_innodb_table_monitor)) {
3033
srv_print_innodb_table_monitor = FALSE;
3036
/* Serialize data dictionary operations with dictionary mutex:
3037
no deadlocks can occur then in these operations */
3039
if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3040
/* Prevent foreign key checks etc. while we are dropping the
3043
row_mysql_lock_data_dictionary(trx);
3045
locked_dictionary = TRUE;
3048
ut_ad(mutex_own(&(dict_sys->mutex)));
3049
#ifdef UNIV_SYNC_DEBUG
3050
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3051
#endif /* UNIV_SYNC_DEBUG */
3053
table = dict_table_get_low(name);
3056
#if defined(BUILD_DRIZZLE)
3059
err = DB_TABLE_NOT_FOUND;
3060
ut_print_timestamp(stderr);
3062
fputs(" InnoDB: Error: table ", stderr);
3063
ut_print_name(stderr, trx, TRUE, name);
3064
fputs(" does not exist in the InnoDB internal\n"
3065
"InnoDB: data dictionary though MySQL is"
3066
" trying to drop it.\n"
3067
"InnoDB: Have you copied the .frm file"
3068
" of the table to the\n"
3069
"InnoDB: MySQL database directory"
3070
" from another database?\n"
3071
"InnoDB: You can look for further help from\n"
3072
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3074
#endif /* BUILD_DRIZZLE */
3078
/* Check if the table is referenced by foreign key constraints from
3079
some other table (not the table itself) */
3081
foreign = UT_LIST_GET_FIRST(table->referenced_list);
3083
while (foreign && foreign->foreign_table == table) {
3085
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3088
if (foreign && trx->check_foreigns
3089
&& !(drop_db && dict_tables_have_same_db(
3090
name, foreign->foreign_table_name))) {
3091
FILE* ef = dict_foreign_err_file;
3093
/* We only allow dropping a referenced table if
3094
FOREIGN_KEY_CHECKS is set to 0 */
3096
err = DB_CANNOT_DROP_CONSTRAINT;
3098
mutex_enter(&dict_foreign_err_mutex);
3100
ut_print_timestamp(ef);
3102
fputs(" Cannot drop table ", ef);
3103
ut_print_name(ef, trx, TRUE, name);
3105
"because it is referenced by ", ef);
3106
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3108
mutex_exit(&dict_foreign_err_mutex);
3113
if (foreign && trx->check_foreigns) {
3114
goto check_next_foreign;
3117
if (table->n_mysql_handles_opened > 0) {
3120
added = row_add_table_to_background_drop_list(table->name);
3123
ut_print_timestamp(stderr);
3124
fputs(" InnoDB: Warning: MySQL is"
3125
" trying to drop table ", stderr);
3126
ut_print_name(stderr, trx, TRUE, table->name);
3128
"InnoDB: though there are still"
3129
" open handles to it.\n"
3130
"InnoDB: Adding the table to the"
3131
" background drop queue.\n",
3134
/* We return DB_SUCCESS to MySQL though the drop will
3135
happen lazily later */
3138
/* The table is already in the background drop list */
3145
/* TODO: could we replace the counter n_foreign_key_checks_running
3146
with lock checks on the table? Acquire here an exclusive lock on the
3147
table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3148
they can cope with the table having been dropped here? Foreign key
3149
checks take an IS or IX lock on the table. */
3151
if (table->n_foreign_key_checks_running > 0) {
3153
const char* table_name = table->name;
3156
added = row_add_table_to_background_drop_list(table_name);
3159
ut_print_timestamp(stderr);
3160
fputs(" InnoDB: You are trying to drop table ",
3162
ut_print_name(stderr, trx, TRUE, table_name);
3164
"InnoDB: though there is a"
3165
" foreign key check running on it.\n"
3166
"InnoDB: Adding the table to"
3167
" the background drop queue.\n",
3170
/* We return DB_SUCCESS to MySQL though the drop will
3171
happen lazily later */
3175
/* The table is already in the background drop list */
3182
/* Remove all locks there are on the table or its records */
3183
lock_remove_all_on_table(table, TRUE);
3185
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
3186
trx->table_id = table->id;
3188
/* We use the private SQL parser of Innobase to generate the
3189
query graphs needed in deleting the dictionary data from system
3190
tables in Innobase. Deleting a row from SYS_INDEXES table also
3191
frees the file segments of the B-tree associated with the index. */
3193
info = pars_info_create();
3195
pars_info_add_str_literal(info, "table_name", name);
3197
err = que_eval_sql(info,
3198
"PROCEDURE DROP_TABLE_PROC () IS\n"
3199
"sys_foreign_id CHAR;\n"
3202
"foreign_id CHAR;\n"
3205
"SELECT ID INTO table_id\n"
3207
"WHERE NAME = :table_name\n"
3208
"LOCK IN SHARE MODE;\n"
3209
"IF (SQL % NOTFOUND) THEN\n"
3213
"SELECT ID INTO sys_foreign_id\n"
3215
"WHERE NAME = 'SYS_FOREIGN'\n"
3216
"LOCK IN SHARE MODE;\n"
3217
"IF (SQL % NOTFOUND) THEN\n"
3220
"IF (:table_name = 'SYS_FOREIGN') THEN\n"
3223
"IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3226
"WHILE found = 1 LOOP\n"
3227
" SELECT ID INTO foreign_id\n"
3228
" FROM SYS_FOREIGN\n"
3229
" WHERE FOR_NAME = :table_name\n"
3230
" AND TO_BINARY(FOR_NAME)\n"
3231
" = TO_BINARY(:table_name)\n"
3232
" LOCK IN SHARE MODE;\n"
3233
" IF (SQL % NOTFOUND) THEN\n"
3236
" DELETE FROM SYS_FOREIGN_COLS\n"
3237
" WHERE ID = foreign_id;\n"
3238
" DELETE FROM SYS_FOREIGN\n"
3239
" WHERE ID = foreign_id;\n"
3243
"WHILE found = 1 LOOP\n"
3244
" SELECT ID INTO index_id\n"
3245
" FROM SYS_INDEXES\n"
3246
" WHERE TABLE_ID = table_id\n"
3247
" LOCK IN SHARE MODE;\n"
3248
" IF (SQL % NOTFOUND) THEN\n"
3251
" DELETE FROM SYS_FIELDS\n"
3252
" WHERE INDEX_ID = index_id;\n"
3253
" DELETE FROM SYS_INDEXES\n"
3254
" WHERE ID = index_id\n"
3255
" AND TABLE_ID = table_id;\n"
3258
"DELETE FROM SYS_COLUMNS\n"
3259
"WHERE TABLE_ID = table_id;\n"
3260
"DELETE FROM SYS_TABLES\n"
3261
"WHERE ID = table_id;\n"
3265
if (err != DB_SUCCESS) {
3266
ut_a(err == DB_OUT_OF_FILE_SPACE);
3268
err = DB_MUST_GET_MORE_FILE_SPACE;
3270
row_mysql_handle_errors(&err, trx, NULL, NULL);
3275
const char* name_or_path;
3278
heap = mem_heap_create(200);
3280
/* Clone the name, in case it has been allocated
3281
from table->heap, which will be freed by
3282
dict_table_remove_from_cache(table) below. */
3283
name = mem_heap_strdup(heap, name);
3284
space_id = table->space;
3286
if (table->dir_path_of_temp_table != NULL) {
3288
name_or_path = mem_heap_strdup(
3289
heap, table->dir_path_of_temp_table);
3292
name_or_path = name;
3295
dict_table_remove_from_cache(table);
3297
if (dict_load_table(name) != NULL) {
3298
ut_print_timestamp(stderr);
3299
fputs(" InnoDB: Error: not able to remove table ",
3301
ut_print_name(stderr, trx, TRUE, name);
3302
fputs(" from the dictionary cache!\n", stderr);
3306
/* Do not drop possible .ibd tablespace if something went
3307
wrong: we do not want to delete valuable data of the user */
3309
if (err == DB_SUCCESS && space_id > 0) {
3310
if (!fil_space_for_table_exists_in_mem(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");
3322
} else if (!fil_delete_tablespace(space_id)) {
3324
"InnoDB: We removed now the InnoDB"
3325
" internal data dictionary entry\n"
3326
"InnoDB: of table ");
3327
ut_print_name(stderr, trx, TRUE, name);
3328
fprintf(stderr, ".\n");
3330
ut_print_timestamp(stderr);
3332
" InnoDB: Error: not able to"
3333
" delete tablespace %lu of table ",
3335
ut_print_name(stderr, trx, TRUE, name);
3336
fputs("!\n", stderr);
3341
mem_heap_free(heap);
3345
if (locked_dictionary) {
3346
trx_commit_for_mysql(trx);
3348
row_mysql_unlock_data_dictionary(trx);
3353
srv_wake_master_thread();
3358
/*******************************************************************//**
3359
Drop all foreign keys in a database, see Bug#18942.
3360
Called at the end of row_drop_database_for_mysql().
3361
@return error code or DB_SUCCESS */
3364
drop_all_foreign_keys_in_db(
3365
/*========================*/
3366
const char* name, /*!< in: database name which ends to '/' */
3367
trx_t* trx) /*!< in: transaction handle */
3372
ut_a(name[strlen(name) - 1] == '/');
3374
pinfo = pars_info_create();
3376
pars_info_add_str_literal(pinfo, "dbname", name);
3378
/** true if for_name is not prefixed with dbname */
3379
#define TABLE_NOT_IN_THIS_DB \
3380
"SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
3382
err = que_eval_sql(pinfo,
3383
"PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
3384
"foreign_id CHAR;\n"
3387
"DECLARE CURSOR cur IS\n"
3388
"SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
3389
"WHERE FOR_NAME >= :dbname\n"
3390
"LOCK IN SHARE MODE\n"
3391
"ORDER BY FOR_NAME;\n"
3395
"WHILE found = 1 LOOP\n"
3396
" FETCH cur INTO foreign_id, for_name;\n"
3397
" IF (SQL % NOTFOUND) THEN\n"
3399
" ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
3401
" ELSIF (1=1) THEN\n"
3402
" DELETE FROM SYS_FOREIGN_COLS\n"
3403
" WHERE ID = foreign_id;\n"
3404
" DELETE FROM SYS_FOREIGN\n"
3405
" WHERE ID = foreign_id;\n"
3411
FALSE, /* do not reserve dict mutex,
3412
we are already holding it */
3418
/*********************************************************************//**
3419
Drops a database for MySQL.
3420
@return error code or DB_SUCCESS */
3423
row_drop_database_for_mysql(
3424
/*========================*/
3425
const char* name, /*!< in: database name which ends to '/' */
3426
trx_t* trx) /*!< in: transaction handle */
3428
dict_table_t* table;
3430
int err = DB_SUCCESS;
3431
ulint namelen = strlen(name);
3433
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3435
ut_a(name[namelen - 1] == '/');
3437
trx->op_info = "dropping database";
3439
trx_start_if_not_started(trx);
3441
row_mysql_lock_data_dictionary(trx);
3443
while ((table_name = dict_get_first_table_name_in_db(name))) {
3444
ut_a(memcmp(table_name, name, namelen) == 0);
3446
// For the time being I would like to see how often we see
3447
// lost temporary tables. --Brian
3448
fprintf(stderr, "Dropping lost temporary table %s\n", table_name);
3450
table = dict_table_get_low(table_name);
3454
/* Wait until MySQL does not have any queries running on
3457
if (table->n_mysql_handles_opened > 0) {
3458
row_mysql_unlock_data_dictionary(trx);
3460
ut_print_timestamp(stderr);
3461
fputs(" InnoDB: Warning: MySQL is trying to"
3462
" drop database ", stderr);
3463
ut_print_name(stderr, trx, TRUE, name);
3465
"InnoDB: though there are still"
3466
" open handles to table ", stderr);
3467
ut_print_name(stderr, trx, TRUE, table_name);
3468
fputs(".\n", stderr);
3470
os_thread_sleep(1000000);
3472
mem_free(table_name);
3477
err = row_drop_table_for_mysql(table_name, trx, TRUE);
3478
trx_commit_for_mysql(trx);
3480
if (err != DB_SUCCESS) {
3481
fputs("InnoDB: DROP DATABASE ", stderr);
3482
ut_print_name(stderr, trx, TRUE, name);
3483
fprintf(stderr, " failed with error %lu for table ",
3485
ut_print_name(stderr, trx, TRUE, table_name);
3487
mem_free(table_name);
3491
mem_free(table_name);
3494
if (err == DB_SUCCESS) {
3495
/* after dropping all tables try to drop all leftover
3496
foreign keys in case orphaned ones exist */
3497
err = (int) drop_all_foreign_keys_in_db(name, trx);
3499
if (err != DB_SUCCESS) {
3500
fputs("InnoDB: DROP DATABASE ", stderr);
3501
ut_print_name(stderr, trx, TRUE, name);
3502
fprintf(stderr, " failed with error %d while "
3503
"dropping all foreign keys", err);
3507
trx_commit_for_mysql(trx);
3509
row_mysql_unlock_data_dictionary(trx);
3516
/*********************************************************************//**
3517
Checks if a table name contains the string "/#sql" which denotes temporary
3519
@return TRUE if temporary table */
3522
row_is_mysql_tmp_table_name(
3523
/*========================*/
3524
const char* name) /*!< in: table name in the form
3525
'database/tablename' */
3527
return(strstr(name, "/#sql") != NULL);
3528
/* return(strstr(name, "/@0023sql") != NULL); */
3531
/****************************************************************//**
3532
Delete a single constraint.
3533
@return error code or DB_SUCCESS */
3536
row_delete_constraint_low(
3537
/*======================*/
3538
const char* id, /*!< in: constraint id */
3539
trx_t* trx) /*!< in: transaction handle */
3541
pars_info_t* info = pars_info_create();
3543
pars_info_add_str_literal(info, "id", id);
3545
return((int) que_eval_sql(info,
3546
"PROCEDURE DELETE_CONSTRAINT () IS\n"
3548
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3549
"DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3554
/****************************************************************//**
3555
Delete a single constraint.
3556
@return error code or DB_SUCCESS */
3559
row_delete_constraint(
3560
/*==================*/
3561
const char* id, /*!< in: constraint id */
3562
const char* database_name, /*!< in: database name, with the
3564
mem_heap_t* heap, /*!< in: memory heap */
3565
trx_t* trx) /*!< in: transaction handle */
3569
/* New format constraints have ids <databasename>/<constraintname>. */
3570
err = row_delete_constraint_low(
3571
mem_heap_strcat(heap, database_name, id), trx);
3573
if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3574
/* Old format < 4.0.18 constraints have constraint ids
3575
<number>_<number>. We only try deleting them if the
3576
constraint name does not contain a '/' character, otherwise
3577
deleting a new format constraint named 'foo/bar' from
3578
database 'baz' would remove constraint 'bar' from database
3579
'foo', if it existed. */
3581
err = row_delete_constraint_low(id, trx);
3587
/*********************************************************************//**
3588
Renames a table for MySQL.
3589
@return error code or DB_SUCCESS */
3592
row_rename_table_for_mysql(
3593
/*=======================*/
3594
const char* old_name, /*!< in: old table name */
3595
const char* new_name, /*!< in: new table name */
3596
trx_t* trx, /*!< in: transaction handle */
3597
ibool commit) /*!< in: if TRUE then commit trx */
3599
dict_table_t* table;
3600
ulint err = DB_ERROR;
3601
mem_heap_t* heap = NULL;
3602
const char** constraints_to_drop = NULL;
3603
ulint n_constraints_to_drop = 0;
3604
ibool old_is_tmp, new_is_tmp;
3605
pars_info_t* info = NULL;
3607
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3608
ut_a(old_name != NULL);
3609
ut_a(new_name != NULL);
3611
if (srv_created_new_raw || srv_force_recovery) {
3612
fputs("InnoDB: A new raw disk partition was initialized or\n"
3613
"InnoDB: innodb_force_recovery is on: we do not allow\n"
3614
"InnoDB: database modifications by the user. Shut down\n"
3615
"InnoDB: mysqld and edit my.cnf so that newraw"
3617
"InnoDB: with raw, and innodb_force_... is removed.\n",
3623
trx->op_info = "renaming table";
3624
trx_start_if_not_started(trx);
3626
old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3627
new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3629
table = dict_table_get_low(old_name);
3632
#if defined(BUILD_DRIZZLE)
3635
err = DB_TABLE_NOT_FOUND;
3636
ut_print_timestamp(stderr);
3638
fputs(" InnoDB: Error: table ", stderr);
3639
ut_print_name(stderr, trx, TRUE, old_name);
3640
fputs(" does not exist in the InnoDB internal\n"
3641
"InnoDB: data dictionary though MySQL is"
3642
" trying to rename the table.\n"
3643
"InnoDB: Have you copied the .frm file"
3644
" of the table to the\n"
3645
"InnoDB: MySQL database directory"
3646
" from another database?\n"
3647
"InnoDB: You can look for further help from\n"
3648
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3650
#endif /* BUILD_DRIZZLE */
3652
} else if (table->ibd_file_missing) {
3653
err = DB_TABLE_NOT_FOUND;
3654
ut_print_timestamp(stderr);
3656
fputs(" InnoDB: Error: table ", stderr);
3657
ut_print_name(stderr, trx, TRUE, old_name);
3658
fputs(" does not have an .ibd file"
3659
" in the database directory.\n"
3660
"InnoDB: You can look for further help from\n"
3661
"InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3664
} else if (new_is_tmp) {
3665
/* MySQL is doing an ALTER TABLE command and it renames the
3666
original table to a temporary table name. We want to preserve
3667
the original foreign key constraint definitions despite the
3668
name change. An exception is those constraints for which
3669
the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3671
heap = mem_heap_create(100);
3673
err = dict_foreign_parse_drop_constraints(
3674
heap, trx, table, &n_constraints_to_drop,
3675
&constraints_to_drop);
3677
if (err != DB_SUCCESS) {
3683
/* We use the private SQL parser of Innobase to generate the query
3684
graphs needed in updating the dictionary data from system tables. */
3686
info = pars_info_create();
3688
pars_info_add_str_literal(info, "new_table_name", new_name);
3689
pars_info_add_str_literal(info, "old_table_name", old_name);
3691
err = que_eval_sql(info,
3692
"PROCEDURE RENAME_TABLE () IS\n"
3694
"UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3695
" WHERE NAME = :old_table_name;\n"
3699
if (err != DB_SUCCESS) {
3702
} else if (!new_is_tmp) {
3703
/* Rename all constraints. */
3705
info = pars_info_create();
3707
pars_info_add_str_literal(info, "new_table_name", new_name);
3708
pars_info_add_str_literal(info, "old_table_name", old_name);
3712
"PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3713
"gen_constr_prefix CHAR;\n"
3714
"new_db_name CHAR;\n"
3715
"foreign_id CHAR;\n"
3716
"new_foreign_id CHAR;\n"
3717
"old_db_name_len INT;\n"
3718
"old_t_name_len INT;\n"
3719
"new_db_name_len INT;\n"
3724
"old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3725
"new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3726
"new_db_name := SUBSTR(:new_table_name, 0,\n"
3727
" new_db_name_len);\n"
3728
"old_t_name_len := LENGTH(:old_table_name);\n"
3729
"gen_constr_prefix := CONCAT(:old_table_name,\n"
3731
"WHILE found = 1 LOOP\n"
3732
" SELECT ID INTO foreign_id\n"
3733
" FROM SYS_FOREIGN\n"
3734
" WHERE FOR_NAME = :old_table_name\n"
3735
" AND TO_BINARY(FOR_NAME)\n"
3736
" = TO_BINARY(:old_table_name)\n"
3737
" LOCK IN SHARE MODE;\n"
3738
" IF (SQL % NOTFOUND) THEN\n"
3741
" UPDATE SYS_FOREIGN\n"
3742
" SET FOR_NAME = :new_table_name\n"
3743
" WHERE ID = foreign_id;\n"
3744
" id_len := LENGTH(foreign_id);\n"
3745
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
3746
" IF (INSTR(foreign_id,\n"
3747
" gen_constr_prefix) > 0)\n"
3749
" new_foreign_id :=\n"
3750
" CONCAT(:new_table_name,\n"
3751
" SUBSTR(foreign_id, old_t_name_len,\n"
3752
" id_len - old_t_name_len));\n"
3754
" new_foreign_id :=\n"
3755
" CONCAT(new_db_name,\n"
3756
" SUBSTR(foreign_id,\n"
3757
" old_db_name_len,\n"
3758
" id_len - old_db_name_len));\n"
3760
" UPDATE SYS_FOREIGN\n"
3761
" SET ID = new_foreign_id\n"
3762
" WHERE ID = foreign_id;\n"
3763
" UPDATE SYS_FOREIGN_COLS\n"
3764
" SET ID = new_foreign_id\n"
3765
" WHERE ID = foreign_id;\n"
3769
"UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
3770
"WHERE REF_NAME = :old_table_name\n"
3771
" AND TO_BINARY(REF_NAME)\n"
3772
" = TO_BINARY(:old_table_name);\n"
3776
} else if (n_constraints_to_drop > 0) {
3777
/* Drop some constraints of tmp tables. */
3779
ulint db_name_len = dict_get_db_name_len(old_name) + 1;
3780
char* db_name = mem_heap_strdupl(heap, old_name,
3784
for (i = 0; i < n_constraints_to_drop; i++) {
3785
err = row_delete_constraint(constraints_to_drop[i],
3786
db_name, heap, trx);
3788
if (err != DB_SUCCESS) {
3795
if (err != DB_SUCCESS) {
3796
if (err == DB_DUPLICATE_KEY) {
3797
ut_print_timestamp(stderr);
3798
fputs(" InnoDB: Error; possible reasons:\n"
3799
"InnoDB: 1) Table rename would cause"
3800
" two FOREIGN KEY constraints\n"
3801
"InnoDB: to have the same internal name"
3802
" in case-insensitive comparison.\n"
3803
"InnoDB: 2) table ", stderr);
3804
ut_print_name(stderr, trx, TRUE, new_name);
3805
fputs(" exists in the InnoDB internal data\n"
3806
"InnoDB: dictionary though MySQL is"
3807
" trying to rename table ", stderr);
3808
ut_print_name(stderr, trx, TRUE, old_name);
3810
"InnoDB: Have you deleted the .frm file"
3811
" and not used DROP TABLE?\n"
3812
"InnoDB: You can look for further help from\n"
3813
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
3814
"InnoDB: If table ", stderr);
3815
ut_print_name(stderr, trx, TRUE, new_name);
3816
fputs(" is a temporary table #sql..., then"
3818
"InnoDB: there are still queries running"
3819
" on the table, and it will be\n"
3820
"InnoDB: dropped automatically when"
3821
" the queries end.\n"
3822
"InnoDB: You can drop the orphaned table"
3823
" inside InnoDB by\n"
3824
"InnoDB: creating an InnoDB table with"
3825
" the same name in another\n"
3826
"InnoDB: database and copying the .frm file"
3827
" to the current database.\n"
3828
"InnoDB: Then MySQL thinks the table exists,"
3829
" and DROP TABLE will\n"
3830
"InnoDB: succeed.\n", stderr);
3832
trx->error_state = DB_SUCCESS;
3833
trx_general_rollback_for_mysql(trx, FALSE, NULL);
3834
trx->error_state = DB_SUCCESS;
3836
/* The following call will also rename the .ibd data file if
3837
the table is stored in a single-table tablespace */
3839
if (!dict_table_rename_in_cache(table, new_name,
3841
trx->error_state = DB_SUCCESS;
3842
trx_general_rollback_for_mysql(trx, FALSE, NULL);
3843
trx->error_state = DB_SUCCESS;
3847
/* We only want to switch off some of the type checking in
3848
an ALTER, not in a RENAME. */
3850
err = dict_load_foreigns(
3851
new_name, !old_is_tmp || trx->check_foreigns);
3853
if (err != DB_SUCCESS) {
3854
ut_print_timestamp(stderr);
3857
fputs(" InnoDB: Error: in ALTER TABLE ",
3859
ut_print_name(stderr, trx, TRUE, new_name);
3861
"InnoDB: has or is referenced"
3862
" in foreign key constraints\n"
3863
"InnoDB: which are not compatible"
3864
" with the new table definition.\n",
3867
fputs(" InnoDB: Error: in RENAME TABLE"
3870
ut_print_name(stderr, trx, TRUE, new_name);
3872
"InnoDB: is referenced in"
3873
" foreign key constraints\n"
3874
"InnoDB: which are not compatible"
3875
" with the new table definition.\n",
3879
ut_a(dict_table_rename_in_cache(table,
3881
trx->error_state = DB_SUCCESS;
3882
trx_general_rollback_for_mysql(trx, FALSE, NULL);
3883
trx->error_state = DB_SUCCESS;
3890
trx_commit_for_mysql(trx);
3893
if (UNIV_LIKELY_NULL(heap)) {
3894
mem_heap_free(heap);
3902
/*********************************************************************//**
3903
Checks that the index contains entries in an ascending order, unique
3904
constraint is not broken, and calculates the number of index entries
3905
in the read view of the current transaction.
3906
@return TRUE if ok */
3909
row_scan_and_check_index(
3910
/*=====================*/
3911
row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL */
3912
dict_index_t* index, /*!< in: index */
3913
ulint* n_rows) /*!< out: number of entries seen in the
3914
current consistent read */
3916
dtuple_t* prev_entry = NULL;
3917
ulint matched_fields;
3918
ulint matched_bytes;
3924
ibool contains_null;
3927
mem_heap_t* heap = NULL;
3929
ulint offsets_[REC_OFFS_NORMAL_SIZE];
3931
rec_offs_init(offsets_);
3935
if (!row_merge_is_index_usable(prebuilt->trx, index)) {
3936
/* A newly created index may lack some delete-marked
3937
records that may exist in the read view of
3938
prebuilt->trx. Thus, such indexes must not be
3939
accessed by consistent read. */
3943
buf = mem_alloc(UNIV_PAGE_SIZE);
3944
heap = mem_heap_create(100);
3946
/* Make a dummy template in prebuilt, which we will use
3947
in scanning the index entries */
3949
prebuilt->index = index;
3950
/* row_merge_is_index_usable() was already checked above. */
3951
prebuilt->index_usable = TRUE;
3952
prebuilt->sql_stat_start = TRUE;
3953
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
3954
prebuilt->n_template = 0;
3955
prebuilt->need_to_access_clustered = FALSE;
3957
dtuple_set_n_fields(prebuilt->search_tuple, 0);
3959
prebuilt->select_lock_type = LOCK_NONE;
3962
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
3964
/* Check thd->killed every 1,000 scanned rows */
3966
if (trx_is_interrupted(prebuilt->trx)) {
3976
ut_print_timestamp(stderr);
3977
fputs(" InnoDB: Warning: CHECK TABLE on ", stderr);
3978
dict_index_name_print(stderr, prebuilt->trx, index);
3979
fprintf(stderr, " returned %lu\n", ret);
3980
/* fall through (this error is ignored by CHECK TABLE) */
3981
case DB_END_OF_INDEX:
3984
mem_heap_free(heap);
3989
*n_rows = *n_rows + 1;
3991
/* row_search... returns the index record in buf, record origin offset
3992
within buf stored in the first 4 bytes, because we have built a dummy
3995
rec = buf + mach_read_from_4(buf);
3997
offsets = rec_get_offsets(rec, index, offsets_,
3998
ULINT_UNDEFINED, &heap);
4000
if (prev_entry != NULL) {
4004
cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
4007
contains_null = FALSE;
4009
/* In a unique secondary index we allow equal key values if
4010
they contain SQL NULLs */
4013
i < dict_index_get_n_ordering_defined_by_user(index);
4015
if (UNIV_SQL_NULL == dfield_get_len(
4016
dtuple_get_nth_field(prev_entry, i))) {
4018
contains_null = TRUE;
4023
fputs("InnoDB: index records in a wrong order in ",
4026
dict_index_name_print(stderr,
4027
prebuilt->trx, index);
4029
"InnoDB: prev record ", stderr);
4030
dtuple_print(stderr, prev_entry);
4032
"InnoDB: record ", stderr);
4033
rec_print_new(stderr, rec, offsets);
4036
} else if (dict_index_is_unique(index)
4039
>= dict_index_get_n_ordering_defined_by_user(
4042
fputs("InnoDB: duplicate key in ", stderr);
4048
mem_heap_t* tmp_heap = NULL;
4050
/* Empty the heap on each round. But preserve offsets[]
4051
for the row_rec_to_index_entry() call, by copying them
4052
into a separate memory heap when needed. */
4053
if (UNIV_UNLIKELY(offsets != offsets_)) {
4054
ulint size = rec_offs_get_n_alloc(offsets)
4057
tmp_heap = mem_heap_create(size);
4058
offsets = mem_heap_dup(tmp_heap, offsets, size);
4061
mem_heap_empty(heap);
4063
prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
4067
if (UNIV_LIKELY_NULL(tmp_heap)) {
4068
mem_heap_free(tmp_heap);
4072
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
4077
/*********************************************************************//**
4078
Checks a table for corruption.
4079
@return DB_ERROR or DB_SUCCESS */
4082
row_check_table_for_mysql(
4083
/*======================*/
4084
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL
4087
dict_table_t* table = prebuilt->table;
4088
dict_index_t* index;
4090
ulint n_rows_in_table = ULINT_UNDEFINED;
4091
ulint ret = DB_SUCCESS;
4092
ulint old_isolation_level;
4094
if (table->ibd_file_missing) {
4095
ut_print_timestamp(stderr);
4096
fprintf(stderr, " InnoDB: Error:\n"
4097
"InnoDB: MySQL is trying to use a table handle"
4098
" but the .ibd file for\n"
4099
"InnoDB: table %s does not exist.\n"
4100
"InnoDB: Have you deleted the .ibd file"
4101
" from the database directory under\n"
4102
"InnoDB: the MySQL datadir, or have you"
4103
" used DISCARD TABLESPACE?\n"
4104
"InnoDB: Look from\n"
4105
"InnoDB: " REFMAN "innodb-troubleshooting.html\n"
4106
"InnoDB: how you can resolve the problem.\n",
4111
prebuilt->trx->op_info = "checking table";
4113
old_isolation_level = prebuilt->trx->isolation_level;
4115
/* We must run the index record counts at an isolation level
4116
>= READ COMMITTED, because a dirty read can see a wrong number
4117
of records in some index; to play safe, we use always
4118
REPEATABLE READ here */
4120
prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
4122
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
4123
mutex_enter(&kernel_mutex);
4124
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
4125
mutex_exit(&kernel_mutex);
4127
index = dict_table_get_first_index(table);
4129
while (index != NULL) {
4130
/* fputs("Validating index ", stderr);
4131
ut_print_name(stderr, trx, FALSE, index->name);
4132
putc('\n', stderr); */
4134
if (!btr_validate_index(index, prebuilt->trx)) {
4137
if (!row_scan_and_check_index(prebuilt,index, &n_rows)){
4141
if (trx_is_interrupted(prebuilt->trx)) {
4145
/* fprintf(stderr, "%lu entries in index %s\n", n_rows,
4148
if (index == dict_table_get_first_index(table)) {
4149
n_rows_in_table = n_rows;
4150
} else if (n_rows != n_rows_in_table) {
4154
fputs("Error: ", stderr);
4155
dict_index_name_print(stderr,
4156
prebuilt->trx, index);
4158
" contains %lu entries,"
4161
(ulong) n_rows_in_table);
4165
index = dict_table_get_next_index(index);
4168
/* Restore the original isolation level */
4169
prebuilt->trx->isolation_level = old_isolation_level;
4171
/* We validate also the whole adaptive hash index for all tables
4172
at every CHECK TABLE */
4174
if (!btr_search_validate()) {
4179
/* Restore the fatal lock wait timeout after CHECK TABLE. */
4180
mutex_enter(&kernel_mutex);
4181
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
4182
mutex_exit(&kernel_mutex);
4184
prebuilt->trx->op_info = "";
4189
/*********************************************************************//**
4190
Determines if a table is a magic monitor table.
4191
@return TRUE if monitor table */
4194
row_is_magic_monitor_table(
4195
/*=======================*/
4196
const char* table_name) /*!< in: name of the table, in the
4197
form database/table_name */
4199
const char* name; /* table_name without database/ */
4202
name = strchr(table_name, '/');
4205
len = strlen(name) + 1;
4207
if (STR_EQ(name, len, S_innodb_monitor)
4208
|| STR_EQ(name, len, S_innodb_lock_monitor)
4209
|| STR_EQ(name, len, S_innodb_tablespace_monitor)
4210
|| STR_EQ(name, len, S_innodb_table_monitor)
4211
|| STR_EQ(name, len, S_innodb_mem_validate)) {