1
/******************************************************
2
Interface between Innobase row operations and MySQL.
3
Contains also create table and other data dictionary operations.
7
Created 9/17/2000 Heikki Tuuri
8
*******************************************************/
10
#include "row0mysql.h"
13
#include "row0mysql.ic"
21
#include "pars0pars.h"
22
#include "dict0dict.h"
23
#include "dict0crea.h"
24
#include "dict0load.h"
25
#include "dict0boot.h"
27
#include "trx0purge.h"
28
#include "lock0lock.h"
33
#include "ibuf0ibuf.h"
35
/* A dummy variable used to fool the compiler */
36
ibool row_mysql_identically_false = FALSE;
38
/* Provide optional 4.x backwards compatibility for 5.0 and above */
39
ibool row_rollback_on_timeout = FALSE;
41
/* List of tables we should drop in background. ALTER TABLE in MySQL requires
42
that the table handler can drop the table in background when there are no
43
queries to it any more. Protected by the kernel mutex. */
44
typedef struct row_mysql_drop_struct row_mysql_drop_t;
45
struct row_mysql_drop_struct{
47
UT_LIST_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
50
UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
51
ibool row_mysql_drop_list_inited = FALSE;
53
/* Magic table names for invoking various monitor threads */
54
static const char S_innodb_monitor[] = "innodb_monitor";
55
static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
56
static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
57
static const char S_innodb_table_monitor[] = "innodb_table_monitor";
58
static const char S_innodb_mem_validate[] = "innodb_mem_validate";
60
/***********************************************************************
61
Determine if the given name is a name reserved for MySQL system tables. */
64
row_mysql_is_system_table(
65
/*======================*/
66
/* out: TRUE if name is a MySQL
70
if (strncmp(name, "mysql/", 6) != 0) {
75
return(0 == strcmp(name + 6, "host")
76
|| 0 == strcmp(name + 6, "user")
77
|| 0 == strcmp(name + 6, "db"));
80
/***********************************************************************
81
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
84
row_mysql_delay_if_needed(void)
85
/*===========================*/
87
if (srv_dml_needed_delay) {
88
os_thread_sleep(srv_dml_needed_delay);
92
/***********************************************************************
93
Frees the blob heap in prebuilt when no longer needed. */
96
row_mysql_prebuilt_free_blob_heap(
97
/*==============================*/
98
row_prebuilt_t* prebuilt) /* in: prebuilt struct of a
99
ha_innobase:: table handle */
101
mem_heap_free(prebuilt->blob_heap);
102
prebuilt->blob_heap = NULL;
105
/***********************************************************************
106
Stores a >= 5.0.3 format true VARCHAR length to dest, in the MySQL row
110
row_mysql_store_true_var_len(
111
/*=========================*/
112
/* out: pointer to the data, we skip the 1 or 2 bytes
113
at the start that are used to store the len */
114
byte* dest, /* in: where to store */
115
ulint len, /* in: length, must fit in two bytes */
116
ulint lenlen) /* in: storage length of len: either 1 or 2 bytes */
119
ut_a(len < 256 * 256);
121
mach_write_to_2_little_endian(dest, len);
129
mach_write_to_1(dest, len);
134
/***********************************************************************
135
Reads a >= 5.0.3 format true VARCHAR length, in the MySQL row format, and
136
returns a pointer to the data. */
139
row_mysql_read_true_varchar(
140
/*========================*/
141
/* out: pointer to the data, we skip the 1 or 2 bytes
142
at the start that are used to store the len */
143
ulint* len, /* out: variable-length field length */
144
byte* field, /* in: field in the MySQL format */
145
ulint lenlen) /* in: storage length of len: either 1 or 2 bytes */
148
*len = mach_read_from_2_little_endian(field);
155
*len = mach_read_from_1(field);
160
/***********************************************************************
161
Stores a reference to a BLOB in the MySQL format. */
164
row_mysql_store_blob_ref(
165
/*=====================*/
166
byte* dest, /* in: where to store */
167
ulint col_len, /* in: dest buffer size: determines into
168
how many bytes the BLOB length is stored,
169
the space for the length may vary from 1
171
byte* data, /* in: BLOB data; if the value to store
172
is SQL NULL this should be NULL pointer */
173
ulint len) /* in: BLOB length; if the value to store
174
is SQL NULL this should be 0; remember
175
also to set the NULL bit in the MySQL record
178
/* MySQL might assume the field is set to zero except the length and
179
the pointer fields */
181
memset(dest, '\0', col_len);
183
/* In dest there are 1 - 4 bytes reserved for the BLOB length,
184
and after that 8 bytes reserved for the pointer to the data.
185
In 32-bit architectures we only use the first 4 bytes of the pointer
188
ut_a(col_len - 8 > 1 || len < 256);
189
ut_a(col_len - 8 > 2 || len < 256 * 256);
190
ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
192
mach_write_to_n_little_endian(dest, col_len - 8, len);
194
ut_memcpy(dest + col_len - 8, &data, sizeof(byte*));
197
/***********************************************************************
198
Reads a reference to a BLOB in the MySQL format. */
201
row_mysql_read_blob_ref(
202
/*====================*/
203
/* out: pointer to BLOB data */
204
ulint* len, /* out: BLOB length */
205
byte* ref, /* in: BLOB reference in the MySQL format */
206
ulint col_len) /* in: BLOB reference length (not BLOB
211
*len = mach_read_from_n_little_endian(ref, col_len - 8);
213
ut_memcpy(&data, ref + col_len - 8, sizeof(byte*));
218
/******************************************************************
219
Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format.
220
The counterpart of this function is row_sel_field_store_in_mysql_format() in
224
row_mysql_store_col_in_innobase_format(
225
/*===================================*/
226
/* out: up to which byte we used
227
buf in the conversion */
228
dfield_t* dfield, /* in/out: dfield where dtype
229
information must be already set when
230
this function is called! */
231
byte* buf, /* in/out: buffer for a converted
232
integer value; this must be at least
233
col_len long then! */
234
ibool row_format_col, /* TRUE if the mysql_data is from
235
a MySQL row, FALSE if from a MySQL
237
in MySQL, a true VARCHAR storage
238
format differs in a row and in a
239
key value: in a key value the length
240
is always stored in 2 bytes! */
241
byte* mysql_data, /* in: MySQL column value, not
242
SQL NULL; NOTE that dfield may also
243
get a pointer to mysql_data,
244
therefore do not discard this as long
245
as dfield is used! */
246
ulint col_len, /* in: MySQL column length; NOTE that
247
this is the storage length of the
248
column in the MySQL format row, not
249
necessarily the length of the actual
250
payload data; if the column is a true
251
VARCHAR then this is irrelevant */
252
ulint comp) /* in: nonzero=compact format */
254
byte* ptr = mysql_data;
259
dtype = dfield_get_type(dfield);
263
if (type == DATA_INT) {
264
/* Store integer data in Innobase in a big-endian format,
265
sign bit negated if the data is a signed integer. In MySQL,
266
integers are stored in a little-endian format. */
279
if (!(dtype->prtype & DATA_UNSIGNED)) {
281
*ptr = (byte) (*ptr ^ 128);
285
} else if ((type == DATA_VARCHAR
286
|| type == DATA_VARMYSQL
287
|| type == DATA_BINARY)) {
289
if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
290
/* The length of the actual data is stored to 1 or 2
291
bytes at the start of the field */
293
if (row_format_col) {
294
if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
300
/* In a MySQL key value, lenlen is always 2 */
304
ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
307
/* Remove trailing spaces from old style VARCHAR
310
/* Handle UCS2 strings differently. */
311
ulint mbminlen = dtype_get_mbminlen(dtype);
317
/* Trim "half-chars", just in case. */
320
while (col_len >= 2 && ptr[col_len - 2] == 0x00
321
&& ptr[col_len - 1] == 0x20) {
328
&& ptr[col_len - 1] == 0x20) {
333
} else if (comp && type == DATA_MYSQL
334
&& dtype_get_mbminlen(dtype) == 1
335
&& dtype_get_mbmaxlen(dtype) > 1) {
336
/* In some cases we strip trailing spaces from UTF-8 and other
337
multibyte charsets, from FIXED-length CHAR columns, to save
338
space. UTF-8 would otherwise normally use 3 * the string length
339
bytes to store a latin1 string! */
341
/* We assume that this CHAR field is encoded in a
342
variable-length character set where spaces have
343
1:1 correspondence to 0x20 bytes, such as UTF-8.
345
Consider a CHAR(n) field, a field of n characters.
346
It will contain between n * mbminlen and n * mbmaxlen bytes.
347
We will try to truncate it to n bytes by stripping
348
space padding. If the field contains single-byte
349
characters only, it will be truncated to n characters.
350
Consider a CHAR(5) field containing the string ".a "
351
where "." denotes a 3-byte character represented by
352
the bytes "$%&". After our stripping, the string will
353
be stored as "$%&a " (5 bytes). The string ".abc "
354
will be stored as "$%&abc" (6 bytes).
356
The space padding will be restored in row0sel.c, function
357
row_sel_field_store_in_mysql_format(). */
361
ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
363
n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
365
/* Strip space padding. */
366
while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
369
} else if (type == DATA_BLOB && row_format_col) {
371
ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
374
dfield_set_data(dfield, ptr, col_len);
379
/******************************************************************
380
Convert a row in the MySQL format to a row in the Innobase format. Note that
381
the function to convert a MySQL format key value to an InnoDB dtuple is
382
row_sel_convert_mysql_key_to_innobase() in row0sel.c. */
385
row_mysql_convert_row_to_innobase(
386
/*==============================*/
387
dtuple_t* row, /* in/out: Innobase row where the
388
field type information is already
390
row_prebuilt_t* prebuilt, /* in: prebuilt struct where template
391
must be of type ROW_MYSQL_WHOLE_ROW */
392
byte* mysql_rec) /* in: row in the MySQL format;
393
NOTE: do not discard as long as
394
row is used, as row may contain
395
pointers to this record! */
397
mysql_row_templ_t* templ;
401
ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
402
ut_ad(prebuilt->mysql_template);
404
for (i = 0; i < prebuilt->n_template; i++) {
406
templ = prebuilt->mysql_template + i;
407
dfield = dtuple_get_nth_field(row, i);
409
if (templ->mysql_null_bit_mask != 0) {
410
/* Column may be SQL NULL */
412
if (mysql_rec[templ->mysql_null_byte_offset]
413
& (byte) (templ->mysql_null_bit_mask)) {
417
dfield_set_data(dfield, NULL, UNIV_SQL_NULL);
423
row_mysql_store_col_in_innobase_format(
425
prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
426
TRUE, /* MySQL row format data */
427
mysql_rec + templ->mysql_col_offset,
428
templ->mysql_col_len,
429
dict_table_is_comp(prebuilt->table));
435
/********************************************************************
436
Handles user errors and lock waits detected by the database engine. */
439
row_mysql_handle_errors(
440
/*====================*/
441
/* out: TRUE if it was a lock wait and
442
we should continue running the query thread */
443
ulint* new_err,/* out: possible new error encountered in
444
lock wait, or if no new error, the value
445
of trx->error_state at the entry of this
447
trx_t* trx, /* in: transaction */
448
que_thr_t* thr, /* in: query thread */
449
trx_savept_t* savept) /* in: savepoint or NULL */
451
#ifndef UNIV_HOTBACKUP
455
err = trx->error_state;
457
ut_a(err != DB_SUCCESS);
459
trx->error_state = DB_SUCCESS;
461
if ((err == DB_DUPLICATE_KEY)
462
|| (err == DB_FOREIGN_DUPLICATE_KEY)) {
464
/* Roll back the latest, possibly incomplete
465
insertion or update */
467
trx_general_rollback_for_mysql(trx, TRUE, savept);
469
} else if (err == DB_TOO_BIG_RECORD) {
471
/* Roll back the latest, possibly incomplete
472
insertion or update */
474
trx_general_rollback_for_mysql(trx, TRUE, savept);
476
/* MySQL will roll back the latest SQL statement */
477
} else if (err == DB_ROW_IS_REFERENCED
478
|| err == DB_NO_REFERENCED_ROW
479
|| err == DB_CANNOT_ADD_CONSTRAINT
480
|| err == DB_TOO_MANY_CONCURRENT_TRXS) {
482
/* Roll back the latest, possibly incomplete
483
insertion or update */
485
trx_general_rollback_for_mysql(trx, TRUE, savept);
487
/* MySQL will roll back the latest SQL statement */
488
} else if (err == DB_LOCK_WAIT) {
490
srv_suspend_mysql_thread(thr);
492
if (trx->error_state != DB_SUCCESS) {
493
que_thr_stop_for_mysql(thr);
495
goto handle_new_error;
502
} else if (err == DB_DEADLOCK
503
|| err == DB_LOCK_TABLE_FULL
504
|| (err == DB_LOCK_WAIT_TIMEOUT
505
&& row_rollback_on_timeout)) {
506
/* Roll back the whole transaction; this resolution was added
507
to version 3.23.43 */
509
trx_general_rollback_for_mysql(trx, FALSE, NULL);
511
} else if (err == DB_OUT_OF_FILE_SPACE
512
|| err == DB_LOCK_WAIT_TIMEOUT) {
514
ut_ad(!(err == DB_LOCK_WAIT_TIMEOUT
515
&& row_rollback_on_timeout));
518
/* Roll back the latest, possibly incomplete
519
insertion or update */
521
trx_general_rollback_for_mysql(trx, TRUE, savept);
523
/* MySQL will roll back the latest SQL statement */
525
} else if (err == DB_MUST_GET_MORE_FILE_SPACE) {
527
fputs("InnoDB: The database cannot continue"
528
" operation because of\n"
529
"InnoDB: lack of space. You must add"
530
" a new data file to\n"
531
"InnoDB: my.cnf and restart the database.\n", stderr);
534
} else if (err == DB_CORRUPTION) {
536
fputs("InnoDB: We detected index corruption"
537
" in an InnoDB type table.\n"
538
"InnoDB: You have to dump + drop + reimport"
539
" the table or, in\n"
540
"InnoDB: a case of widespread corruption,"
542
"InnoDB: tables and recreate the"
543
" whole InnoDB tablespace.\n"
544
"InnoDB: If the mysqld server crashes"
545
" after the startup or when\n"
546
"InnoDB: you dump the tables, look at\n"
547
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
548
"forcing-recovery.html"
549
" for help.\n", stderr);
552
fprintf(stderr, "InnoDB: unknown error code %lu\n",
557
if (trx->error_state != DB_SUCCESS) {
558
*new_err = trx->error_state;
563
trx->error_state = DB_SUCCESS;
566
#else /* UNIV_HOTBACKUP */
567
/* This function depends on MySQL code that is not included in
568
InnoDB Hot Backup builds. Besides, this function should never
569
be called in InnoDB Hot Backup. */
572
#endif /* UNIV_HOTBACKUP */
575
/************************************************************************
576
Create a prebuilt struct for a MySQL table handle. */
581
/* out, own: a prebuilt struct */
582
dict_table_t* table) /* in: Innobase table handle */
584
row_prebuilt_t* prebuilt;
586
dict_index_t* clust_index;
591
heap = mem_heap_create(128);
593
prebuilt = mem_heap_alloc(heap, sizeof(row_prebuilt_t));
595
prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
596
prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
598
prebuilt->table = table;
600
prebuilt->trx = NULL;
602
prebuilt->sql_stat_start = TRUE;
604
prebuilt->mysql_has_locked = FALSE;
606
prebuilt->index = NULL;
608
prebuilt->used_in_HANDLER = FALSE;
610
prebuilt->n_template = 0;
611
prebuilt->mysql_template = NULL;
613
prebuilt->heap = heap;
614
prebuilt->ins_node = NULL;
616
prebuilt->ins_upd_rec_buff = NULL;
618
prebuilt->upd_node = NULL;
619
prebuilt->ins_graph = NULL;
620
prebuilt->upd_graph = NULL;
622
prebuilt->pcur = btr_pcur_create_for_mysql();
623
prebuilt->clust_pcur = btr_pcur_create_for_mysql();
625
prebuilt->select_lock_type = LOCK_NONE;
626
prebuilt->stored_select_lock_type = 99999999;
628
prebuilt->row_read_type = ROW_READ_WITH_LOCKS;
630
prebuilt->sel_graph = NULL;
632
prebuilt->search_tuple = dtuple_create(
633
heap, 2 * dict_table_get_n_cols(table));
635
clust_index = dict_table_get_first_index(table);
637
/* Make sure that search_tuple is long enough for clustered index */
638
ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
640
ref_len = dict_index_get_n_unique(clust_index);
642
ref = dtuple_create(heap, ref_len);
644
dict_index_copy_types(ref, clust_index, ref_len);
646
prebuilt->clust_ref = ref;
648
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
649
prebuilt->fetch_cache[i] = NULL;
652
prebuilt->n_fetch_cached = 0;
654
prebuilt->blob_heap = NULL;
656
prebuilt->old_vers_heap = NULL;
658
prebuilt->last_value = 0;
663
/************************************************************************
664
Free a prebuilt struct for a MySQL table handle. */
669
row_prebuilt_t* prebuilt) /* in, own: prebuilt struct */
673
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
674
|| prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED) {
676
"InnoDB: Error: trying to free a corrupt\n"
677
"InnoDB: table handle. Magic n %lu,"
678
" magic n2 %lu, table name",
679
(ulong) prebuilt->magic_n,
680
(ulong) prebuilt->magic_n2);
681
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
684
mem_analyze_corruption(prebuilt);
689
prebuilt->magic_n = ROW_PREBUILT_FREED;
690
prebuilt->magic_n2 = ROW_PREBUILT_FREED;
692
btr_pcur_free_for_mysql(prebuilt->pcur);
693
btr_pcur_free_for_mysql(prebuilt->clust_pcur);
695
if (prebuilt->mysql_template) {
696
mem_free(prebuilt->mysql_template);
699
if (prebuilt->ins_graph) {
700
que_graph_free_recursive(prebuilt->ins_graph);
703
if (prebuilt->sel_graph) {
704
que_graph_free_recursive(prebuilt->sel_graph);
707
if (prebuilt->upd_graph) {
708
que_graph_free_recursive(prebuilt->upd_graph);
711
if (prebuilt->blob_heap) {
712
mem_heap_free(prebuilt->blob_heap);
715
if (prebuilt->old_vers_heap) {
716
mem_heap_free(prebuilt->old_vers_heap);
719
for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
720
if (prebuilt->fetch_cache[i] != NULL) {
722
if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
723
(prebuilt->fetch_cache[i]) - 4))
724
|| (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
725
(prebuilt->fetch_cache[i])
726
+ prebuilt->mysql_row_len))) {
727
fputs("InnoDB: Error: trying to free"
728
" a corrupt fetch buffer.\n", stderr);
730
mem_analyze_corruption(
731
prebuilt->fetch_cache[i]);
736
mem_free((prebuilt->fetch_cache[i]) - 4);
740
dict_table_decrement_handle_count(prebuilt->table);
742
mem_heap_free(prebuilt->heap);
745
/*************************************************************************
746
Updates the transaction pointers in query graphs stored in the prebuilt
750
row_update_prebuilt_trx(
751
/*====================*/
752
/* out: prebuilt dtuple */
753
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
755
trx_t* trx) /* in: transaction handle */
757
if (trx->magic_n != TRX_MAGIC_N) {
759
"InnoDB: Error: trying to use a corrupt\n"
760
"InnoDB: trx handle. Magic n %lu\n",
761
(ulong) trx->magic_n);
763
mem_analyze_corruption(trx);
768
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
770
"InnoDB: Error: trying to use a corrupt\n"
771
"InnoDB: table handle. Magic n %lu, table name",
772
(ulong) prebuilt->magic_n);
773
ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
776
mem_analyze_corruption(prebuilt);
783
if (prebuilt->ins_graph) {
784
prebuilt->ins_graph->trx = trx;
787
if (prebuilt->upd_graph) {
788
prebuilt->upd_graph->trx = trx;
791
if (prebuilt->sel_graph) {
792
prebuilt->sel_graph->trx = trx;
796
/*************************************************************************
797
Gets pointer to a prebuilt dtuple used in insertions. If the insert graph
798
has not yet been built in the prebuilt struct, then this function first
802
row_get_prebuilt_insert_row(
803
/*========================*/
804
/* out: prebuilt dtuple; the column
805
type information is also set in it */
806
row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
811
dict_table_t* table = prebuilt->table;
814
ut_ad(prebuilt && table && prebuilt->trx);
816
if (prebuilt->ins_node == NULL) {
818
/* Not called before for this handle: create an insert node
819
and query graph to the prebuilt struct */
821
node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
823
prebuilt->ins_node = node;
825
if (prebuilt->ins_upd_rec_buff == NULL) {
826
prebuilt->ins_upd_rec_buff = mem_heap_alloc(
827
prebuilt->heap, prebuilt->mysql_row_len);
830
row = dtuple_create(prebuilt->heap,
831
dict_table_get_n_cols(table));
833
dict_table_copy_types(row, table);
835
/* We init the value of every field to the SQL NULL to avoid
836
a debug assertion from failing */
838
for (i = 0; i < dtuple_get_n_fields(row); i++) {
840
dtuple_get_nth_field(row, i)->len = UNIV_SQL_NULL;
843
ins_node_set_new_row(node, row);
845
prebuilt->ins_graph = que_node_get_parent(
846
pars_complete_graph_for_exec(node,
849
prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
852
return(prebuilt->ins_node->row);
855
/*************************************************************************
856
Updates the table modification counter and calculates new estimates
857
for table and index statistics if necessary. */
860
row_update_statistics_if_needed(
861
/*============================*/
862
dict_table_t* table) /* in: table */
866
counter = table->stat_modified_counter;
868
table->stat_modified_counter = counter + 1;
870
/* Calculate new statistics if 1 / 16 of table has been modified
871
since the last time a statistics batch was run, or if
872
stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
873
We calculate statistics at most every 16th round, since we may have
874
a counter table which is very small and updated very often. */
876
if (counter > 2000000000
877
|| ((ib_longlong)counter > 16 + table->stat_n_rows / 16)) {
879
dict_update_statistics(table);
883
/*************************************************************************
884
Unlocks an AUTO_INC type lock possibly reserved by trx. */
887
row_unlock_table_autoinc_for_mysql(
888
/*===============================*/
889
trx_t* trx) /* in: transaction */
891
if (!trx->auto_inc_lock) {
896
lock_table_unlock_auto_inc(trx);
899
/*************************************************************************
900
Sets an AUTO_INC type lock on the table mentioned in prebuilt. The
901
AUTO_INC lock gives exclusive access to the auto-inc counter of the
902
table. The lock is reserved only for the duration of an SQL statement.
903
It is not compatible with another AUTO_INC or exclusive lock on the
907
row_lock_table_autoinc_for_mysql(
908
/*=============================*/
909
/* out: error code or DB_SUCCESS */
910
row_prebuilt_t* prebuilt) /* in: prebuilt struct in the MySQL
913
trx_t* trx = prebuilt->trx;
914
ins_node_t* node = prebuilt->ins_node;
920
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
922
if (trx->auto_inc_lock) {
927
trx->op_info = "setting auto-inc lock";
930
row_get_prebuilt_insert_row(prebuilt);
931
node = prebuilt->ins_node;
934
/* We use the insert query graph as the dummy graph needed
935
in the lock module call */
937
thr = que_fork_get_first_thr(prebuilt->ins_graph);
939
que_thr_move_to_run_state_for_mysql(thr, trx);
942
thr->run_node = node;
943
thr->prev_node = node;
945
/* It may be that the current session has not yet started
946
its transaction, or it has been committed: */
948
trx_start_if_not_started(trx);
950
err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
952
trx->error_state = err;
954
if (err != DB_SUCCESS) {
955
que_thr_stop_for_mysql(thr);
957
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
968
que_thr_stop_for_mysql_no_error(thr, trx);
975
/*************************************************************************
976
Sets a table lock on the table mentioned in prebuilt. */
979
row_lock_table_for_mysql(
980
/*=====================*/
981
/* out: error code or DB_SUCCESS */
982
row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL
984
dict_table_t* table, /* in: table to lock, or NULL
985
if prebuilt->table should be
987
prebuilt->select_lock_type */
988
ulint mode) /* in: lock mode of table
989
(ignored if table==NULL) */
991
trx_t* trx = prebuilt->trx;
997
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
999
trx->op_info = "setting table lock";
1001
if (prebuilt->sel_graph == NULL) {
1002
/* Build a dummy select query graph */
1003
row_prebuild_sel_graph(prebuilt);
1006
/* We use the select query graph as the dummy graph needed
1007
in the lock module call */
1009
thr = que_fork_get_first_thr(prebuilt->sel_graph);
1011
que_thr_move_to_run_state_for_mysql(thr, trx);
1014
thr->run_node = thr;
1015
thr->prev_node = thr->common.parent;
1017
/* It may be that the current session has not yet started
1018
its transaction, or it has been committed: */
1020
trx_start_if_not_started(trx);
1023
err = lock_table(0, table, mode, thr);
1025
err = lock_table(0, prebuilt->table,
1026
prebuilt->select_lock_type, thr);
1029
trx->error_state = err;
1031
if (err != DB_SUCCESS) {
1032
que_thr_stop_for_mysql(thr);
1034
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1036
if (was_lock_wait) {
1045
que_thr_stop_for_mysql_no_error(thr, trx);
1052
/*************************************************************************
1053
Does an insert for MySQL. */
1056
row_insert_for_mysql(
1057
/*=================*/
1058
/* out: error code or DB_SUCCESS */
1059
byte* mysql_rec, /* in: row in the MySQL format */
1060
row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1063
trx_savept_t savept;
1066
ibool was_lock_wait;
1067
trx_t* trx = prebuilt->trx;
1068
ins_node_t* node = prebuilt->ins_node;
1071
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1073
if (prebuilt->table->ibd_file_missing) {
1074
ut_print_timestamp(stderr);
1075
fprintf(stderr, " InnoDB: Error:\n"
1076
"InnoDB: MySQL is trying to use a table handle"
1077
" but the .ibd file for\n"
1078
"InnoDB: table %s does not exist.\n"
1079
"InnoDB: Have you deleted the .ibd file"
1080
" from the database directory under\n"
1081
"InnoDB: the MySQL datadir, or have you"
1082
" used DISCARD TABLESPACE?\n"
1083
"InnoDB: Look from\n"
1084
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
1085
"innodb-troubleshooting.html\n"
1086
"InnoDB: how you can resolve the problem.\n",
1087
prebuilt->table->name);
1091
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
1093
"InnoDB: Error: trying to free a corrupt\n"
1094
"InnoDB: table handle. Magic n %lu, table name",
1095
(ulong) prebuilt->magic_n);
1096
ut_print_name(stderr, prebuilt->trx, TRUE,
1097
prebuilt->table->name);
1100
mem_analyze_corruption(prebuilt);
1105
if (srv_created_new_raw || srv_force_recovery) {
1106
fputs("InnoDB: A new raw disk partition was initialized or\n"
1107
"InnoDB: innodb_force_recovery is on: we do not allow\n"
1108
"InnoDB: database modifications by the user. Shut down\n"
1109
"InnoDB: mysqld and edit my.cnf so that"
1110
" newraw is replaced\n"
1111
"InnoDB: with raw, and innodb_force_... is removed.\n",
1117
trx->op_info = "inserting";
1119
row_mysql_delay_if_needed();
1121
trx_start_if_not_started(trx);
1124
row_get_prebuilt_insert_row(prebuilt);
1125
node = prebuilt->ins_node;
1128
row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1130
savept = trx_savept_take(trx);
1132
thr = que_fork_get_first_thr(prebuilt->ins_graph);
1134
if (prebuilt->sql_stat_start) {
1135
node->state = INS_NODE_SET_IX_LOCK;
1136
prebuilt->sql_stat_start = FALSE;
1138
node->state = INS_NODE_ALLOC_ROW_ID;
1141
que_thr_move_to_run_state_for_mysql(thr, trx);
1144
thr->run_node = node;
1145
thr->prev_node = node;
1149
err = trx->error_state;
1151
if (err != DB_SUCCESS) {
1152
que_thr_stop_for_mysql(thr);
1154
/* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1156
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1158
thr->lock_state= QUE_THR_LOCK_NOLOCK;
1160
if (was_lock_wait) {
1169
que_thr_stop_for_mysql_no_error(thr, trx);
1171
prebuilt->table->stat_n_rows++;
1173
srv_n_rows_inserted++;
1175
if (prebuilt->table->stat_n_rows == 0) {
1176
/* Avoid wrap-over */
1177
prebuilt->table->stat_n_rows--;
1180
row_update_statistics_if_needed(prebuilt->table);
1186
/*************************************************************************
1187
Builds a dummy query graph used in selects. */
1190
row_prebuild_sel_graph(
1191
/*===================*/
1192
row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1197
ut_ad(prebuilt && prebuilt->trx);
1199
if (prebuilt->sel_graph == NULL) {
1201
node = sel_node_create(prebuilt->heap);
1203
prebuilt->sel_graph = que_node_get_parent(
1204
pars_complete_graph_for_exec(node,
1208
prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1212
/*************************************************************************
1213
Creates an query graph node of 'update' type to be used in the MySQL
1217
row_create_update_node_for_mysql(
1218
/*=============================*/
1219
/* out, own: update node */
1220
dict_table_t* table, /* in: table to update */
1221
mem_heap_t* heap) /* in: mem heap from which allocated */
1225
node = upd_node_create(heap);
1227
node->in_mysql_interface = TRUE;
1228
node->is_delete = FALSE;
1229
node->searched_update = FALSE;
1230
node->select_will_do_update = FALSE;
1231
node->select = NULL;
1232
node->pcur = btr_pcur_create_for_mysql();
1233
node->table = table;
1235
node->update = upd_create(dict_table_get_n_cols(table), heap);
1237
node->update_n_fields = dict_table_get_n_cols(table);
1239
UT_LIST_INIT(node->columns);
1240
node->has_clust_rec_x_lock = TRUE;
1241
node->cmpl_info = 0;
1243
node->table_sym = NULL;
1244
node->col_assign_list = NULL;
1249
/*************************************************************************
1250
Gets pointer to a prebuilt update vector used in updates. If the update
1251
graph has not yet been built in the prebuilt struct, then this function
1255
row_get_prebuilt_update_vector(
1256
/*===========================*/
1257
/* out: prebuilt update vector */
1258
row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1261
dict_table_t* table = prebuilt->table;
1264
ut_ad(prebuilt && table && prebuilt->trx);
1266
if (prebuilt->upd_node == NULL) {
1268
/* Not called before for this handle: create an update node
1269
and query graph to the prebuilt struct */
1271
node = row_create_update_node_for_mysql(table, prebuilt->heap);
1273
prebuilt->upd_node = node;
1275
prebuilt->upd_graph = que_node_get_parent(
1276
pars_complete_graph_for_exec(node,
1279
prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1282
return(prebuilt->upd_node->update);
1285
/*************************************************************************
1286
Does an update or delete of a row for MySQL. */
1289
row_update_for_mysql(
1290
/*=================*/
1291
/* out: error code or DB_SUCCESS */
1292
byte* mysql_rec, /* in: the row to be updated, in
1294
row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1297
trx_savept_t savept;
1300
ibool was_lock_wait;
1301
dict_index_t* clust_index;
1302
/* ulint ref_len; */
1304
dict_table_t* table = prebuilt->table;
1305
trx_t* trx = prebuilt->trx;
1307
ut_ad(prebuilt && trx);
1308
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1309
UT_NOT_USED(mysql_rec);
1311
if (prebuilt->table->ibd_file_missing) {
1312
ut_print_timestamp(stderr);
1313
fprintf(stderr, " InnoDB: Error:\n"
1314
"InnoDB: MySQL is trying to use a table handle"
1315
" but the .ibd file for\n"
1316
"InnoDB: table %s does not exist.\n"
1317
"InnoDB: Have you deleted the .ibd file"
1318
" from the database directory under\n"
1319
"InnoDB: the MySQL datadir, or have you"
1320
" used DISCARD TABLESPACE?\n"
1321
"InnoDB: Look from\n"
1322
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
1323
"innodb-troubleshooting.html\n"
1324
"InnoDB: how you can resolve the problem.\n",
1325
prebuilt->table->name);
1329
if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
1331
"InnoDB: Error: trying to free a corrupt\n"
1332
"InnoDB: table handle. Magic n %lu, table name",
1333
(ulong) prebuilt->magic_n);
1334
ut_print_name(stderr, prebuilt->trx, TRUE,
1335
prebuilt->table->name);
1338
mem_analyze_corruption(prebuilt);
1343
if (srv_created_new_raw || srv_force_recovery) {
1344
fputs("InnoDB: A new raw disk partition was initialized or\n"
1345
"InnoDB: innodb_force_recovery is on: we do not allow\n"
1346
"InnoDB: database modifications by the user. Shut down\n"
1347
"InnoDB: mysqld and edit my.cnf so that newraw"
1349
"InnoDB: with raw, and innodb_force_... is removed.\n",
1355
trx->op_info = "updating or deleting";
1357
row_mysql_delay_if_needed();
1359
trx_start_if_not_started(trx);
1361
node = prebuilt->upd_node;
1363
clust_index = dict_table_get_first_index(table);
1365
if (prebuilt->pcur->btr_cur.index == clust_index) {
1366
btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1368
btr_pcur_copy_stored_position(node->pcur,
1369
prebuilt->clust_pcur);
1372
ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1374
/* MySQL seems to call rnd_pos before updating each row it
1375
has cached: we can get the correct cursor position from
1376
prebuilt->pcur; NOTE that we cannot build the row reference
1377
from mysql_rec if the clustered index was automatically
1378
generated for the table: MySQL does not know anything about
1379
the row id used as the clustered index key */
1381
savept = trx_savept_take(trx);
1383
thr = que_fork_get_first_thr(prebuilt->upd_graph);
1385
node->state = UPD_NODE_UPDATE_CLUSTERED;
1387
ut_ad(!prebuilt->sql_stat_start);
1389
que_thr_move_to_run_state_for_mysql(thr, trx);
1392
thr->run_node = node;
1393
thr->prev_node = node;
1397
err = trx->error_state;
1399
if (err != DB_SUCCESS) {
1400
que_thr_stop_for_mysql(thr);
1402
if (err == DB_RECORD_NOT_FOUND) {
1403
trx->error_state = DB_SUCCESS;
1409
thr->lock_state= QUE_THR_LOCK_ROW;
1410
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1412
thr->lock_state= QUE_THR_LOCK_NOLOCK;
1414
if (was_lock_wait) {
1423
que_thr_stop_for_mysql_no_error(thr, trx);
1425
if (node->is_delete) {
1426
if (prebuilt->table->stat_n_rows > 0) {
1427
prebuilt->table->stat_n_rows--;
1430
srv_n_rows_deleted++;
1432
srv_n_rows_updated++;
1435
row_update_statistics_if_needed(prebuilt->table);
1442
/*************************************************************************
1443
This can only be used when srv_locks_unsafe_for_binlog is TRUE or
1444
this session is using a READ COMMITTED isolation level. Before
1445
calling this function we must use trx_reset_new_rec_lock_info() and
1446
trx_register_new_rec_lock() to store the information which new record locks
1447
really were set. This function removes a newly set lock under prebuilt->pcur,
1448
and also under prebuilt->clust_pcur. Currently, this is only used and tested
1449
in the case of an UPDATE or a DELETE statement, where the row lock is of the
1451
Thus, this implements a 'mini-rollback' that releases the latest record
1455
row_unlock_for_mysql(
1456
/*=================*/
1457
/* out: error code or DB_SUCCESS */
1458
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL
1460
ibool has_latches_on_recs)/* TRUE if called so that we have
1461
the latches on the records under pcur
1462
and clust_pcur, and we do not need to
1463
reposition the cursors. */
1465
dict_index_t* index;
1466
btr_pcur_t* pcur = prebuilt->pcur;
1467
btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
1468
trx_t* trx = prebuilt->trx;
1472
ut_ad(prebuilt && trx);
1473
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1475
if (!(srv_locks_unsafe_for_binlog
1476
|| trx->isolation_level == TRX_ISO_READ_COMMITTED)) {
1479
"InnoDB: Error: calling row_unlock_for_mysql though\n"
1480
"InnoDB: srv_locks_unsafe_for_binlog is FALSE and\n"
1481
"InnoDB: this session is not using"
1482
" READ COMMITTED isolation level.\n");
1487
trx->op_info = "unlock_row";
1489
index = btr_pcur_get_btr_cur(pcur)->index;
1491
if (index != NULL && trx_new_rec_locks_contain(trx, index)) {
1495
/* Restore the cursor position and find the record */
1497
if (!has_latches_on_recs) {
1498
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1501
rec = btr_pcur_get_rec(pcur);
1503
lock_rec_unlock(trx, rec, prebuilt->select_lock_type);
1507
/* If the search was done through the clustered index, then
1508
we have not used clust_pcur at all, and we must NOT try to
1509
reset locks on clust_pcur. The values in clust_pcur may be
1512
if (index->type & DICT_CLUSTERED) {
1518
index = btr_pcur_get_btr_cur(clust_pcur)->index;
1520
if (index != NULL && trx_new_rec_locks_contain(trx, index)) {
1524
/* Restore the cursor position and find the record */
1526
if (!has_latches_on_recs) {
1527
btr_pcur_restore_position(BTR_SEARCH_LEAF, clust_pcur,
1531
rec = btr_pcur_get_rec(clust_pcur);
1533
lock_rec_unlock(trx, rec, prebuilt->select_lock_type);
1544
/**************************************************************************
1545
Does a cascaded delete or set null in a foreign key operation. */
1548
row_update_cascade_for_mysql(
1549
/*=========================*/
1550
/* out: error code or DB_SUCCESS */
1551
que_thr_t* thr, /* in: query thread */
1552
upd_node_t* node, /* in: update node used in the cascade
1553
or set null operation */
1554
dict_table_t* table) /* in: table where we do the operation */
1559
trx = thr_get_trx(thr);
1561
thr->run_node = node;
1562
thr->prev_node = node;
1566
err = trx->error_state;
1568
/* Note that the cascade node is a subnode of another InnoDB
1569
query graph node. We do a normal lock wait in this node, but
1570
all errors are handled by the parent node. */
1572
if (err == DB_LOCK_WAIT) {
1573
/* Handle lock wait here */
1575
que_thr_stop_for_mysql(thr);
1577
srv_suspend_mysql_thread(thr);
1579
/* Note that a lock wait may also end in a lock wait timeout,
1580
or this transaction is picked as a victim in selective
1581
deadlock resolution */
1583
if (trx->error_state != DB_SUCCESS) {
1585
return(trx->error_state);
1588
/* Retry operation after a normal lock wait */
1593
if (err != DB_SUCCESS) {
1598
if (node->is_delete) {
1599
if (table->stat_n_rows > 0) {
1600
table->stat_n_rows--;
1603
srv_n_rows_deleted++;
1605
srv_n_rows_updated++;
1608
row_update_statistics_if_needed(table);
1613
/*************************************************************************
1614
Checks if a table is such that we automatically created a clustered
1615
index on it (on row id). */
1618
row_table_got_default_clust_index(
1619
/*==============================*/
1620
dict_table_t* table)
1622
const dict_index_t* clust_index;
1624
clust_index = dict_table_get_first_index(table);
1626
return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1629
/*************************************************************************
1630
Calculates the key number used inside MySQL for an Innobase index. We have
1631
to take into account if we generated a default clustered index for the table */
1634
row_get_mysql_key_number_for_index(
1635
/*===============================*/
1636
dict_index_t* index)
1644
ind = dict_table_get_first_index(index->table);
1646
while (index != ind) {
1647
ind = dict_table_get_next_index(ind);
1651
if (row_table_got_default_clust_index(index->table)) {
1659
/*************************************************************************
1660
Locks the data dictionary in shared mode from modifications, for performing
1661
foreign key check, rollback, or other operation invisible to MySQL. */
1664
row_mysql_freeze_data_dictionary(
1665
/*=============================*/
1666
trx_t* trx) /* in: transaction */
1668
ut_a(trx->dict_operation_lock_mode == 0);
1670
rw_lock_s_lock(&dict_operation_lock);
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: 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(
1696
/*===========================*/
1697
trx_t* trx) /* in: transaction */
1699
ut_a(trx->dict_operation_lock_mode == 0
1700
|| trx->dict_operation_lock_mode == RW_X_LATCH);
1702
/* Serialize data dictionary operations with dictionary mutex:
1703
no deadlocks or lock waits can occur then in these operations */
1705
rw_lock_x_lock(&dict_operation_lock);
1706
trx->dict_operation_lock_mode = RW_X_LATCH;
1708
mutex_enter(&(dict_sys->mutex));
1711
/*************************************************************************
1712
Unlocks the data dictionary exclusive lock. */
1715
row_mysql_unlock_data_dictionary(
1716
/*=============================*/
1717
trx_t* trx) /* in: transaction */
1719
ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1721
/* Serialize data dictionary operations with dictionary mutex:
1722
no deadlocks can occur then in these operations */
1724
mutex_exit(&(dict_sys->mutex));
1725
rw_lock_x_unlock(&dict_operation_lock);
1727
trx->dict_operation_lock_mode = 0;
1730
/*************************************************************************
1731
Drops a table for MySQL. If the name of the table ends in
1732
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
1733
"innodb_table_monitor", then this will also start the printing of monitor
1734
output by the master thread. If the table name ends in "innodb_mem_validate",
1735
InnoDB will try to invoke mem_validate(). */
1738
row_create_table_for_mysql(
1739
/*=======================*/
1740
/* out: error code or DB_SUCCESS */
1741
dict_table_t* table, /* in: table definition */
1742
trx_t* trx) /* in: transaction handle */
1747
const char* table_name;
1748
ulint table_name_len;
1752
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1753
#ifdef UNIV_SYNC_DEBUG
1754
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1755
#endif /* UNIV_SYNC_DEBUG */
1756
ut_ad(mutex_own(&(dict_sys->mutex)));
1757
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1759
if (srv_created_new_raw) {
1760
fputs("InnoDB: A new raw disk partition was initialized:\n"
1761
"InnoDB: we do not allow database modifications"
1763
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1764
" is replaced with raw.\n", stderr);
1766
dict_mem_table_free(table);
1767
trx_commit_for_mysql(trx);
1772
trx->op_info = "creating table";
1774
if (row_mysql_is_system_table(table->name)) {
1777
"InnoDB: Error: trying to create a MySQL system"
1778
" table %s of type InnoDB.\n"
1779
"InnoDB: MySQL system tables must be"
1780
" of the MyISAM type!\n",
1783
dict_mem_table_free(table);
1784
trx_commit_for_mysql(trx);
1789
/* Check that no reserved column names are used. */
1790
for (i = 0; i < dict_table_get_n_user_cols(table); i++) {
1791
if (dict_col_name_is_reserved(
1792
dict_table_get_col_name(table, i))) {
1794
dict_mem_table_free(table);
1795
trx_commit_for_mysql(trx);
1801
trx_start_if_not_started(trx);
1803
/* The table name is prefixed with the database name and a '/'.
1804
Certain table names starting with 'innodb_' have their special
1805
meaning regardless of the database name. Thus, we need to
1806
ignore the database name prefix in the comparisons. */
1807
table_name = strchr(table->name, '/');
1810
table_name_len = strlen(table_name) + 1;
1812
if (table_name_len == sizeof S_innodb_monitor
1813
&& !memcmp(table_name, S_innodb_monitor,
1814
sizeof S_innodb_monitor)) {
1816
/* Table equals "innodb_monitor":
1817
start monitor prints */
1819
srv_print_innodb_monitor = TRUE;
1821
/* The lock timeout monitor thread also takes care
1822
of InnoDB monitor prints */
1824
os_event_set(srv_lock_timeout_thread_event);
1825
} else if (table_name_len == sizeof S_innodb_lock_monitor
1826
&& !memcmp(table_name, S_innodb_lock_monitor,
1827
sizeof S_innodb_lock_monitor)) {
1829
srv_print_innodb_monitor = TRUE;
1830
srv_print_innodb_lock_monitor = TRUE;
1831
os_event_set(srv_lock_timeout_thread_event);
1832
} else if (table_name_len == sizeof S_innodb_tablespace_monitor
1833
&& !memcmp(table_name, S_innodb_tablespace_monitor,
1834
sizeof S_innodb_tablespace_monitor)) {
1836
srv_print_innodb_tablespace_monitor = TRUE;
1837
os_event_set(srv_lock_timeout_thread_event);
1838
} else if (table_name_len == sizeof S_innodb_table_monitor
1839
&& !memcmp(table_name, S_innodb_table_monitor,
1840
sizeof S_innodb_table_monitor)) {
1842
srv_print_innodb_table_monitor = TRUE;
1843
os_event_set(srv_lock_timeout_thread_event);
1844
} else if (table_name_len == sizeof S_innodb_mem_validate
1845
&& !memcmp(table_name, S_innodb_mem_validate,
1846
sizeof S_innodb_mem_validate)) {
1847
/* We define here a debugging feature intended for
1850
fputs("Validating InnoDB memory:\n"
1851
"to use this feature you must compile InnoDB with\n"
1852
"UNIV_MEM_DEBUG defined in univ.i and"
1853
" the server must be\n"
1854
"quiet because allocation from a mem heap"
1855
" is not protected\n"
1856
"by any semaphore.\n", stderr);
1857
#ifdef UNIV_MEM_DEBUG
1858
ut_a(mem_validate());
1859
fputs("Memory validated\n", stderr);
1860
#else /* UNIV_MEM_DEBUG */
1861
fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1863
#endif /* UNIV_MEM_DEBUG */
1866
heap = mem_heap_create(512);
1868
trx->dict_operation = TRUE;
1870
node = tab_create_graph_create(table, heap);
1872
thr = pars_complete_graph_for_exec(node, trx, heap);
1874
ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
1875
que_run_threads(thr);
1877
err = trx->error_state;
1879
if (err != DB_SUCCESS) {
1880
/* We have special error handling here */
1882
trx->error_state = DB_SUCCESS;
1884
trx_general_rollback_for_mysql(trx, FALSE, NULL);
1886
if (err == DB_OUT_OF_FILE_SPACE) {
1887
ut_print_timestamp(stderr);
1889
fputs(" InnoDB: Warning: cannot create table ",
1891
ut_print_name(stderr, trx, TRUE, table->name);
1892
fputs(" because tablespace full\n", stderr);
1894
if (dict_table_get_low(table->name)) {
1896
row_drop_table_for_mysql(table->name, trx,
1900
} else if (err == DB_DUPLICATE_KEY) {
1901
ut_print_timestamp(stderr);
1903
fputs(" InnoDB: Error: table ", stderr);
1904
ut_print_name(stderr, trx, TRUE, table->name);
1905
fputs(" already exists in InnoDB internal\n"
1906
"InnoDB: data dictionary. Have you deleted"
1908
"InnoDB: and not used DROP TABLE?"
1909
" Have you used DROP DATABASE\n"
1910
"InnoDB: for InnoDB tables in"
1911
" MySQL version <= 3.23.43?\n"
1912
"InnoDB: See the Restrictions section"
1913
" of the InnoDB manual.\n"
1914
"InnoDB: You can drop the orphaned table"
1915
" inside InnoDB by\n"
1916
"InnoDB: creating an InnoDB table with"
1917
" the same name in another\n"
1918
"InnoDB: database and copying the .frm file"
1919
" to the current database.\n"
1920
"InnoDB: Then MySQL thinks the table exists,"
1921
" and DROP TABLE will\n"
1922
"InnoDB: succeed.\n"
1923
"InnoDB: You can look for further help from\n"
1924
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
1925
"innodb-troubleshooting.html\n",
1929
/* We may also get err == DB_ERROR if the .ibd file for the
1930
table already exists */
1932
trx->error_state = DB_SUCCESS;
1935
que_graph_free((que_t*) que_node_get_parent(thr));
1942
/*************************************************************************
1943
Does an index creation operation for MySQL. TODO: currently failure
1944
to create an index results in dropping the whole table! This is no problem
1945
currently as all indexes must be created at the same time as the table. */
1948
row_create_index_for_mysql(
1949
/*=======================*/
1950
/* out: error number or DB_SUCCESS */
1951
dict_index_t* index, /* in: index definition */
1952
trx_t* trx, /* in: transaction handle */
1953
const ulint* field_lengths) /* in: if not NULL, must contain
1954
dict_index_get_n_fields(index)
1955
actual field lengths for the
1956
index columns, which are
1957
then checked for not being too
1967
#ifdef UNIV_SYNC_DEBUG
1968
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1969
#endif /* UNIV_SYNC_DEBUG */
1970
ut_ad(mutex_own(&(dict_sys->mutex)));
1971
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1973
trx->op_info = "creating index";
1975
trx_start_if_not_started(trx);
1977
/* Check that the same column does not appear twice in the index.
1978
Starting from 4.0.14, InnoDB should be able to cope with that, but
1979
safer not to allow them. */
1981
for (i = 0; i < dict_index_get_n_fields(index); i++) {
1982
for (j = 0; j < i; j++) {
1984
dict_index_get_nth_field(index, j)->name,
1985
dict_index_get_nth_field(index, i)->name)) {
1987
ut_print_timestamp(stderr);
1989
fputs(" InnoDB: Error: column ", stderr);
1990
ut_print_name(stderr, trx, FALSE,
1991
dict_index_get_nth_field(
1993
fputs(" appears twice in ", stderr);
1994
dict_index_name_print(stderr, trx, index);
1996
"InnoDB: This is not allowed"
1997
" in InnoDB.\n", stderr);
1999
err = DB_COL_APPEARS_TWICE_IN_INDEX;
2001
goto error_handling;
2005
/* Check also that prefix_len and actual length
2006
< DICT_MAX_INDEX_COL_LEN */
2008
len = dict_index_get_nth_field(index, i)->prefix_len;
2010
if (field_lengths) {
2011
len = ut_max(len, field_lengths[i]);
2014
if (len >= DICT_MAX_INDEX_COL_LEN) {
2015
err = DB_TOO_BIG_RECORD;
2017
goto error_handling;
2021
heap = mem_heap_create(512);
2023
trx->dict_operation = TRUE;
2025
/* Note that the space id where we store the index is inherited from
2026
the table in dict_build_index_def_step() in dict0crea.c. */
2028
node = ind_create_graph_create(index, heap);
2030
thr = pars_complete_graph_for_exec(node, trx, heap);
2032
ut_a(thr == que_fork_start_command(que_node_get_parent(thr)));
2033
que_run_threads(thr);
2035
err = trx->error_state;
2037
que_graph_free((que_t*) que_node_get_parent(thr));
2040
if (err != DB_SUCCESS) {
2041
/* We have special error handling here */
2043
trx->error_state = DB_SUCCESS;
2045
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2047
row_drop_table_for_mysql(index->table_name, trx, FALSE);
2049
trx->error_state = DB_SUCCESS;
2057
/*************************************************************************
2058
Scans a table create SQL string and adds to the data dictionary
2059
the foreign key constraints declared in the string. This function
2060
should be called after the indexes for a table have been created.
2061
Each foreign key constraint must be accompanied with indexes in
2062
bot participating tables. The indexes are allowed to contain more
2063
fields than mentioned in the constraint. Check also that foreign key
2064
constraints which reference this table are ok. */
2067
row_table_add_foreign_constraints(
2068
/*==============================*/
2069
/* out: error code or DB_SUCCESS */
2070
trx_t* trx, /* in: transaction */
2071
const char* sql_string, /* in: table create statement where
2072
foreign keys are declared like:
2073
FOREIGN KEY (a, b) REFERENCES table2(c, d),
2074
table2 can be written also with the
2075
database name before it: test.table2 */
2076
const char* name, /* in: table full name in the
2078
database_name/table_name */
2079
ibool reject_fks) /* in: if TRUE, fail with error
2080
code DB_CANNOT_ADD_CONSTRAINT if
2081
any foreign keys are found. */
2085
ut_ad(mutex_own(&(dict_sys->mutex)));
2086
#ifdef UNIV_SYNC_DEBUG
2087
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2088
#endif /* UNIV_SYNC_DEBUG */
2091
trx->op_info = "adding foreign keys";
2093
trx_start_if_not_started(trx);
2095
trx->dict_operation = TRUE;
2097
err = dict_create_foreign_constraints(trx, sql_string, name,
2100
if (err == DB_SUCCESS) {
2101
/* Check that also referencing constraints are ok */
2102
err = dict_load_foreigns(name, TRUE);
2105
if (err != DB_SUCCESS) {
2106
/* We have special error handling here */
2108
trx->error_state = DB_SUCCESS;
2110
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2112
row_drop_table_for_mysql(name, trx, FALSE);
2114
trx->error_state = DB_SUCCESS;
2120
/*************************************************************************
2121
Drops a table for MySQL as a background operation. MySQL relies on Unix
2122
in ALTER TABLE to the fact that the table handler does not remove the
2123
table before all handles to it has been removed. Furhermore, the MySQL's
2124
call to drop table must be non-blocking. Therefore we do the drop table
2125
as a background operation, which is taken care of by the master thread
2129
row_drop_table_for_mysql_in_background(
2130
/*===================================*/
2131
/* out: error code or DB_SUCCESS */
2132
const char* name) /* in: table name */
2137
trx = trx_allocate_for_background();
2139
/* If the original transaction was dropping a table referenced by
2140
foreign keys, we must set the following to be able to drop the
2143
trx->check_foreigns = FALSE;
2145
/* fputs("InnoDB: Error: Dropping table ", stderr);
2146
ut_print_name(stderr, trx, TRUE, name);
2147
fputs(" in background drop list\n", stderr); */
2149
/* Try to drop the table in InnoDB */
2151
error = row_drop_table_for_mysql(name, trx, FALSE);
2153
/* Flush the log to reduce probability that the .frm files and
2154
the InnoDB data dictionary get out-of-sync if the user runs
2155
with innodb_flush_log_at_trx_commit = 0 */
2157
log_buffer_flush_to_disk();
2159
trx_commit_for_mysql(trx);
2161
trx_free_for_background(trx);
2163
return((int) error);
2166
/*************************************************************************
2167
The master thread in srv0srv.c calls this regularly to drop tables which
2168
we must drop in background after queries to them have ended. Such lazy
2169
dropping of tables is needed in ALTER TABLE on Unix. */
2172
row_drop_tables_for_mysql_in_background(void)
2173
/*=========================================*/
2174
/* out: how many tables dropped
2175
+ remaining tables in list */
2177
row_mysql_drop_t* drop;
2178
dict_table_t* table;
2180
ulint n_tables_dropped = 0;
2182
mutex_enter(&kernel_mutex);
2184
if (!row_mysql_drop_list_inited) {
2186
UT_LIST_INIT(row_mysql_drop_list);
2187
row_mysql_drop_list_inited = TRUE;
2190
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2192
n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2194
mutex_exit(&kernel_mutex);
2197
/* All tables dropped */
2199
return(n_tables + n_tables_dropped);
2202
mutex_enter(&(dict_sys->mutex));
2203
table = dict_table_get_low(drop->table_name);
2204
mutex_exit(&(dict_sys->mutex));
2206
if (table == NULL) {
2207
/* If for some reason the table has already been dropped
2208
through some other mechanism, do not try to drop it */
2210
goto already_dropped;
2213
if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2214
drop->table_name)) {
2215
/* If the DROP fails for some table, we return, and let the
2216
main thread retry later */
2218
return(n_tables + n_tables_dropped);
2224
mutex_enter(&kernel_mutex);
2226
UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2228
ut_print_timestamp(stderr);
2230
" InnoDB: Dropped table %s in background drop queue.\n",
2233
mem_free(drop->table_name);
2237
mutex_exit(&kernel_mutex);
2242
/*************************************************************************
2243
Get the background drop list length. NOTE: the caller must own the kernel
2247
row_get_background_drop_list_len_low(void)
2248
/*======================================*/
2249
/* out: how many tables in list */
2251
ut_ad(mutex_own(&kernel_mutex));
2253
if (!row_mysql_drop_list_inited) {
2255
UT_LIST_INIT(row_mysql_drop_list);
2256
row_mysql_drop_list_inited = TRUE;
2259
return(UT_LIST_GET_LEN(row_mysql_drop_list));
2262
/*************************************************************************
2263
If a table is not yet in the drop list, adds the table to the list of tables
2264
which the master thread drops in background. We need this on Unix because in
2265
ALTER TABLE MySQL may call drop table even if the table has running queries on
2266
it. Also, if there are running foreign key checks on the table, we drop the
2270
row_add_table_to_background_drop_list(
2271
/*==================================*/
2272
/* out: TRUE if the table was not yet in the
2273
drop list, and was added there */
2274
dict_table_t* table) /* in: table */
2276
row_mysql_drop_t* drop;
2278
mutex_enter(&kernel_mutex);
2280
if (!row_mysql_drop_list_inited) {
2282
UT_LIST_INIT(row_mysql_drop_list);
2283
row_mysql_drop_list_inited = TRUE;
2286
/* Look if the table already is in the drop list */
2287
drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2289
while (drop != NULL) {
2290
if (strcmp(drop->table_name, table->name) == 0) {
2291
/* Already in the list */
2293
mutex_exit(&kernel_mutex);
2298
drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2301
drop = mem_alloc(sizeof(row_mysql_drop_t));
2303
drop->table_name = mem_strdup(table->name);
2305
UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2307
/* fputs("InnoDB: Adding table ", stderr);
2308
ut_print_name(stderr, trx, TRUE, drop->table_name);
2309
fputs(" to background drop list\n", stderr); */
2311
mutex_exit(&kernel_mutex);
2316
#ifndef UNIV_HOTBACKUP
2317
/*************************************************************************
2318
Discards the tablespace of a table which stored in an .ibd file. Discarding
2319
means that this function deletes the .ibd file and assigns a new table id for
2320
the table. Also the flag table->ibd_file_missing is set TRUE. */
2323
row_discard_tablespace_for_mysql(
2324
/*=============================*/
2325
/* out: error code or DB_SUCCESS */
2326
const char* name, /* in: table name */
2327
trx_t* trx) /* in: transaction handle */
2329
dict_foreign_t* foreign;
2331
dict_table_t* table;
2334
pars_info_t* info = NULL;
2336
/* How do we prevent crashes caused by ongoing operations on
2337
the table? Old operations could try to access non-existent
2340
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2341
MySQL table lock on the table before we can do DISCARD
2342
TABLESPACE. Then there are no running queries on the table.
2344
2) Purge and rollback: we assign a new table id for the
2345
table. Since purge and rollback look for the table based on
2346
the table id, they see the table as 'dropped' and discard
2349
3) Insert buffer: we remove all entries for the tablespace in
2350
the insert buffer tree; as long as the tablespace mem object
2351
does not exist, ongoing insert buffer page merges are
2352
discarded in buf0rea.c. If we recreate the tablespace mem
2353
object with IMPORT TABLESPACE later, then the tablespace will
2354
have the same id, but the tablespace_version field in the mem
2355
object is different, and ongoing old insert buffer page merges
2358
4) Linear readahead and random readahead: we use the same
2359
method as in 3) to discard ongoing operations.
2361
5) FOREIGN KEY operations: if
2362
table->n_foreign_key_checks_running > 0, we do not allow the
2363
discard. We also reserve the data dictionary latch. */
2365
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2367
trx->op_info = "discarding tablespace";
2368
trx_start_if_not_started(trx);
2370
/* Serialize data dictionary operations with dictionary mutex:
2371
no deadlocks can occur then in these operations */
2373
row_mysql_lock_data_dictionary(trx);
2375
table = dict_table_get_low(name);
2378
err = DB_TABLE_NOT_FOUND;
2383
if (table->space == 0) {
2384
ut_print_timestamp(stderr);
2385
fputs(" InnoDB: Error: table ", stderr);
2386
ut_print_name(stderr, trx, TRUE, name);
2388
"InnoDB: is in the system tablespace 0"
2389
" which cannot be discarded\n", stderr);
2395
if (table->n_foreign_key_checks_running > 0) {
2397
ut_print_timestamp(stderr);
2398
fputs(" InnoDB: You are trying to DISCARD table ", stderr);
2399
ut_print_name(stderr, trx, TRUE, table->name);
2401
"InnoDB: though there is a foreign key check"
2403
"InnoDB: Cannot discard the table.\n",
2411
/* Check if the table is referenced by foreign key constraints from
2412
some other table (not the table itself) */
2414
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2416
while (foreign && foreign->foreign_table == table) {
2417
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2420
if (foreign && trx->check_foreigns) {
2422
FILE* ef = dict_foreign_err_file;
2424
/* We only allow discarding a referenced table if
2425
FOREIGN_KEY_CHECKS is set to 0 */
2427
err = DB_CANNOT_DROP_CONSTRAINT;
2429
mutex_enter(&dict_foreign_err_mutex);
2431
ut_print_timestamp(ef);
2433
fputs(" Cannot DISCARD table ", ef);
2434
ut_print_name(ef, trx, TRUE, name);
2436
"because it is referenced by ", ef);
2437
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2439
mutex_exit(&dict_foreign_err_mutex);
2444
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2446
/* Remove any locks there are on the table or its records */
2447
lock_reset_all_on_table(table);
2449
info = pars_info_create();
2451
pars_info_add_str_literal(info, "table_name", name);
2452
pars_info_add_dulint_literal(info, "new_id", new_id);
2454
err = que_eval_sql(info,
2455
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2458
"SELECT ID INTO old_id\n"
2460
"WHERE NAME = :table_name\n"
2461
"LOCK IN SHARE MODE;\n"
2462
"IF (SQL % NOTFOUND) THEN\n"
2466
"UPDATE SYS_TABLES SET ID = :new_id\n"
2467
" WHERE ID = old_id;\n"
2468
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2469
" WHERE TABLE_ID = old_id;\n"
2470
"UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2471
" WHERE TABLE_ID = old_id;\n"
2476
if (err != DB_SUCCESS) {
2477
trx->error_state = DB_SUCCESS;
2478
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2479
trx->error_state = DB_SUCCESS;
2481
dict_table_change_id_in_cache(table, new_id);
2483
success = fil_discard_tablespace(table->space);
2486
trx->error_state = DB_SUCCESS;
2487
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2488
trx->error_state = DB_SUCCESS;
2492
/* Set the flag which tells that now it is legal to
2493
IMPORT a tablespace for this table */
2494
table->tablespace_discarded = TRUE;
2495
table->ibd_file_missing = TRUE;
2500
trx_commit_for_mysql(trx);
2502
row_mysql_unlock_data_dictionary(trx);
2509
/*********************************************************************
2510
Imports a tablespace. The space id in the .ibd file must match the space id
2511
of the table in the data dictionary. */
2514
row_import_tablespace_for_mysql(
2515
/*============================*/
2516
/* out: error code or DB_SUCCESS */
2517
const char* name, /* in: table name */
2518
trx_t* trx) /* in: transaction handle */
2520
dict_table_t* table;
2523
ulint err = DB_SUCCESS;
2525
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2527
trx_start_if_not_started(trx);
2529
trx->op_info = "importing tablespace";
2531
current_lsn = log_get_lsn();
2533
/* It is possible, though very improbable, that the lsn's in the
2534
tablespace to be imported have risen above the current system lsn, if
2535
a lengthy purge, ibuf merge, or rollback was performed on a backup
2536
taken with ibbackup. If that is the case, reset page lsn's in the
2537
file. We assume that mysqld was shut down after it performed these
2538
cleanup operations on the .ibd file, so that it stamped the latest lsn
2539
to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2541
TODO: reset also the trx id's in clustered index records and write
2542
a new space id to each data page. That would allow us to import clean
2543
.ibd files from another MySQL installation. */
2545
success = fil_reset_too_high_lsns(name, current_lsn);
2548
ut_print_timestamp(stderr);
2549
fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
2550
ut_print_name(stderr, trx, TRUE, name);
2552
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2557
row_mysql_lock_data_dictionary(trx);
2562
/* Serialize data dictionary operations with dictionary mutex:
2563
no deadlocks can occur then in these operations */
2565
row_mysql_lock_data_dictionary(trx);
2567
table = dict_table_get_low(name);
2570
ut_print_timestamp(stderr);
2571
fputs(" InnoDB: table ", stderr);
2572
ut_print_name(stderr, trx, TRUE, name);
2574
"InnoDB: does not exist in the InnoDB data dictionary\n"
2575
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2578
err = DB_TABLE_NOT_FOUND;
2583
if (table->space == 0) {
2584
ut_print_timestamp(stderr);
2585
fputs(" InnoDB: Error: table ", stderr);
2586
ut_print_name(stderr, trx, TRUE, name);
2588
"InnoDB: is in the system tablespace 0"
2589
" which cannot be imported\n", stderr);
2595
if (!table->tablespace_discarded) {
2596
ut_print_timestamp(stderr);
2597
fputs(" InnoDB: Error: you are trying to"
2598
" IMPORT a tablespace\n"
2599
"InnoDB: ", stderr);
2600
ut_print_name(stderr, trx, TRUE, name);
2601
fputs(", though you have not called DISCARD on it yet\n"
2602
"InnoDB: during the lifetime of the mysqld process!\n",
2610
/* Play safe and remove all insert buffer entries, though we should
2611
have removed them already when DISCARD TABLESPACE was called */
2613
ibuf_delete_for_discarded_space(table->space);
2615
success = fil_open_single_table_tablespace(TRUE, table->space,
2618
table->ibd_file_missing = FALSE;
2619
table->tablespace_discarded = FALSE;
2621
if (table->ibd_file_missing) {
2622
ut_print_timestamp(stderr);
2623
fputs(" InnoDB: cannot find or open in the"
2624
" database directory the .ibd file of\n"
2625
"InnoDB: table ", stderr);
2626
ut_print_name(stderr, trx, TRUE, name);
2628
"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2636
trx_commit_for_mysql(trx);
2638
row_mysql_unlock_data_dictionary(trx);
2645
/*************************************************************************
2646
Truncates a table for MySQL. */
2649
row_truncate_table_for_mysql(
2650
/*=========================*/
2651
/* out: error code or DB_SUCCESS */
2652
dict_table_t* table, /* in: table handle */
2653
trx_t* trx) /* in: transaction handle */
2655
dict_foreign_t* foreign;
2661
dict_index_t* sys_index;
2665
pars_info_t* info = NULL;
2667
/* How do we prevent crashes caused by ongoing operations on
2668
the table? Old operations could try to access non-existent
2671
1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2672
MySQL table lock on the table before we can do TRUNCATE
2673
TABLE. Then there are no running queries on the table. This is
2674
guaranteed, because in ha_innobase::store_lock(), we do not
2675
weaken the TL_WRITE lock requested by MySQL when executing
2678
2) Purge and rollback: we assign a new table id for the
2679
table. Since purge and rollback look for the table based on
2680
the table id, they see the table as 'dropped' and discard
2683
3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2684
so we do not have to remove insert buffer records, as the
2685
insert buffer works at a low level. If a freed page is later
2686
reallocated, the allocator will remove the ibuf entries for
2689
TODO: when we truncate *.ibd files (analogous to DISCARD
2690
TABLESPACE), we will have to remove we remove all entries for
2691
the table in the insert buffer tree!
2693
4) Linear readahead and random readahead: we use the same
2694
method as in 3) to discard ongoing operations. (This will only
2695
be relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2697
5) FOREIGN KEY operations: if
2698
table->n_foreign_key_checks_running > 0, we do not allow the
2699
TRUNCATE. We also reserve the data dictionary latch. */
2701
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2704
if (srv_created_new_raw) {
2705
fputs("InnoDB: A new raw disk partition was initialized:\n"
2706
"InnoDB: we do not allow database modifications"
2708
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2709
" is replaced with raw.\n", stderr);
2714
trx->op_info = "truncating table";
2716
trx_start_if_not_started(trx);
2718
/* Serialize data dictionary operations with dictionary mutex:
2719
no deadlocks can occur then in these operations */
2721
ut_a(trx->dict_operation_lock_mode == 0);
2722
/* Prevent foreign key checks etc. while we are truncating the
2725
row_mysql_lock_data_dictionary(trx);
2727
ut_ad(mutex_own(&(dict_sys->mutex)));
2728
#ifdef UNIV_SYNC_DEBUG
2729
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2730
#endif /* UNIV_SYNC_DEBUG */
2732
/* Check if the table is referenced by foreign key constraints from
2733
some other table (not the table itself) */
2735
foreign = UT_LIST_GET_FIRST(table->referenced_list);
2737
while (foreign && foreign->foreign_table == table) {
2738
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2741
if (foreign && trx->check_foreigns) {
2742
FILE* ef = dict_foreign_err_file;
2744
/* We only allow truncating a referenced table if
2745
FOREIGN_KEY_CHECKS is set to 0 */
2747
mutex_enter(&dict_foreign_err_mutex);
2749
ut_print_timestamp(ef);
2751
fputs(" Cannot truncate table ", ef);
2752
ut_print_name(ef, trx, TRUE, table->name);
2753
fputs(" by DROP+CREATE\n"
2754
"InnoDB: because it is referenced by ", ef);
2755
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2757
mutex_exit(&dict_foreign_err_mutex);
2763
/* TODO: could we replace the counter n_foreign_key_checks_running
2764
with lock checks on the table? Acquire here an exclusive lock on the
2765
table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2766
they can cope with the table having been truncated here? Foreign key
2767
checks take an IS or IX lock on the table. */
2769
if (table->n_foreign_key_checks_running > 0) {
2770
ut_print_timestamp(stderr);
2771
fputs(" InnoDB: Cannot truncate table ", stderr);
2772
ut_print_name(stderr, trx, TRUE, table->name);
2773
fputs(" by DROP+CREATE\n"
2774
"InnoDB: because there is a foreign key check"
2775
" running on it.\n",
2782
/* Remove any locks there are on the table or its records */
2784
lock_reset_all_on_table(table);
2786
trx->table_id = table->id;
2788
/* scan SYS_INDEXES for all indexes of the table */
2789
heap = mem_heap_create(800);
2791
tuple = dtuple_create(heap, 1);
2792
dfield = dtuple_get_nth_field(tuple, 0);
2794
buf = mem_heap_alloc(heap, 8);
2795
mach_write_to_8(buf, table->id);
2797
dfield_set_data(dfield, buf, 8);
2798
sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2799
dict_index_copy_types(tuple, sys_index, 1);
2802
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2803
BTR_MODIFY_LEAF, &pcur, &mtr);
2810
if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
2811
/* The end of SYS_INDEXES has been reached. */
2815
rec = btr_pcur_get_rec(&pcur);
2817
field = rec_get_nth_field_old(rec, 0, &len);
2820
if (memcmp(buf, field, len) != 0) {
2821
/* End of indexes for the table (TABLE_ID mismatch). */
2825
if (rec_get_deleted_flag(rec, FALSE)) {
2826
/* The index has been dropped. */
2830
/* This call may commit and restart mtr
2831
and reposition pcur. */
2832
root_page_no = dict_truncate_index_tree(table, &pcur, &mtr);
2834
rec = btr_pcur_get_rec(&pcur);
2836
if (root_page_no != FIL_NULL) {
2837
page_rec_write_index_page_no(
2838
rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2839
root_page_no, &mtr);
2840
/* We will need to commit and restart the
2841
mini-transaction in order to avoid deadlocks.
2842
The dict_truncate_index_tree() call has allocated
2843
a page in this mini-transaction, and the rest of
2844
this loop could latch another index page. */
2847
btr_pcur_restore_position(BTR_MODIFY_LEAF,
2852
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2855
btr_pcur_close(&pcur);
2858
mem_heap_free(heap);
2860
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
2862
info = pars_info_create();
2864
pars_info_add_dulint_literal(info, "old_id", table->id);
2865
pars_info_add_dulint_literal(info, "new_id", new_id);
2867
err = que_eval_sql(info,
2868
"PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2870
"UPDATE SYS_TABLES SET ID = :new_id\n"
2871
" WHERE ID = :old_id;\n"
2872
"UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2873
" WHERE TABLE_ID = :old_id;\n"
2874
"UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2875
" WHERE TABLE_ID = :old_id;\n"
2880
if (err != DB_SUCCESS) {
2881
trx->error_state = DB_SUCCESS;
2882
trx_general_rollback_for_mysql(trx, FALSE, NULL);
2883
trx->error_state = DB_SUCCESS;
2884
ut_print_timestamp(stderr);
2885
fputs(" InnoDB: Unable to assign a new identifier to table ",
2887
ut_print_name(stderr, trx, TRUE, table->name);
2889
"InnoDB: after truncating it. Background processes"
2890
" may corrupt the table!\n", stderr);
2893
dict_table_change_id_in_cache(table, new_id);
2896
/* MySQL calls ha_innobase::reset_auto_increment() which does
2898
dict_table_autoinc_lock(table);
2899
dict_table_autoinc_initialize(table, 0);
2900
dict_table_autoinc_unlock(table);
2901
dict_update_statistics(table);
2903
trx_commit_for_mysql(trx);
2907
row_mysql_unlock_data_dictionary(trx);
2911
srv_wake_master_thread();
2915
#endif /* !UNIV_HOTBACKUP */
2917
/*************************************************************************
2918
Drops a table for MySQL. If the name of the dropped table ends in
2919
one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
2920
"innodb_table_monitor", then this will also stop the printing of monitor
2921
output by the master thread. */
2924
row_drop_table_for_mysql(
2925
/*=====================*/
2926
/* out: error code or DB_SUCCESS */
2927
const char* name, /* in: table name */
2928
trx_t* trx, /* in: transaction handle */
2929
ibool drop_db)/* in: TRUE=dropping whole database */
2931
dict_foreign_t* foreign;
2932
dict_table_t* table;
2935
const char* table_name;
2937
ibool locked_dictionary = FALSE;
2938
pars_info_t* info = NULL;
2942
if (srv_created_new_raw) {
2943
fputs("InnoDB: A new raw disk partition was initialized:\n"
2944
"InnoDB: we do not allow database modifications"
2946
"InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2947
" is replaced with raw.\n", stderr);
2952
trx->op_info = "dropping table";
2954
trx_start_if_not_started(trx);
2956
/* The table name is prefixed with the database name and a '/'.
2957
Certain table names starting with 'innodb_' have their special
2958
meaning regardless of the database name. Thus, we need to
2959
ignore the database name prefix in the comparisons. */
2960
table_name = strchr(name, '/');
2963
namelen = strlen(table_name) + 1;
2965
if (namelen == sizeof S_innodb_monitor
2966
&& !memcmp(table_name, S_innodb_monitor,
2967
sizeof S_innodb_monitor)) {
2969
/* Table name equals "innodb_monitor":
2970
stop monitor prints */
2972
srv_print_innodb_monitor = FALSE;
2973
srv_print_innodb_lock_monitor = FALSE;
2974
} else if (namelen == sizeof S_innodb_lock_monitor
2975
&& !memcmp(table_name, S_innodb_lock_monitor,
2976
sizeof S_innodb_lock_monitor)) {
2977
srv_print_innodb_monitor = FALSE;
2978
srv_print_innodb_lock_monitor = FALSE;
2979
} else if (namelen == sizeof S_innodb_tablespace_monitor
2980
&& !memcmp(table_name, S_innodb_tablespace_monitor,
2981
sizeof S_innodb_tablespace_monitor)) {
2983
srv_print_innodb_tablespace_monitor = FALSE;
2984
} else if (namelen == sizeof S_innodb_table_monitor
2985
&& !memcmp(table_name, S_innodb_table_monitor,
2986
sizeof S_innodb_table_monitor)) {
2988
srv_print_innodb_table_monitor = FALSE;
2991
/* Serialize data dictionary operations with dictionary mutex:
2992
no deadlocks can occur then in these operations */
2994
if (trx->dict_operation_lock_mode != RW_X_LATCH) {
2995
/* Prevent foreign key checks etc. while we are dropping the
2998
row_mysql_lock_data_dictionary(trx);
3000
locked_dictionary = TRUE;
3003
ut_ad(mutex_own(&(dict_sys->mutex)));
3004
#ifdef UNIV_SYNC_DEBUG
3005
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3006
#endif /* UNIV_SYNC_DEBUG */
3008
table = dict_table_get_low(name);
3011
err = DB_TABLE_NOT_FOUND;
3012
ut_print_timestamp(stderr);
3014
fputs(" InnoDB: Error: table ", stderr);
3015
ut_print_name(stderr, trx, TRUE, name);
3016
fputs(" does not exist in the InnoDB internal\n"
3017
"InnoDB: data dictionary though MySQL is"
3018
" trying to drop it.\n"
3019
"InnoDB: Have you copied the .frm file"
3020
" of the table to the\n"
3021
"InnoDB: MySQL database directory"
3022
" from another database?\n"
3023
"InnoDB: You can look for further help from\n"
3024
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3025
"innodb-troubleshooting.html\n",
3030
/* Check if the table is referenced by foreign key constraints from
3031
some other table (not the table itself) */
3033
foreign = UT_LIST_GET_FIRST(table->referenced_list);
3035
while (foreign && foreign->foreign_table == table) {
3037
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3040
if (foreign && trx->check_foreigns
3041
&& !(drop_db && dict_tables_have_same_db(
3042
name, foreign->foreign_table_name))) {
3043
FILE* ef = dict_foreign_err_file;
3045
/* We only allow dropping a referenced table if
3046
FOREIGN_KEY_CHECKS is set to 0 */
3048
err = DB_CANNOT_DROP_CONSTRAINT;
3050
mutex_enter(&dict_foreign_err_mutex);
3052
ut_print_timestamp(ef);
3054
fputs(" Cannot drop table ", ef);
3055
ut_print_name(ef, trx, TRUE, name);
3057
"because it is referenced by ", ef);
3058
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3060
mutex_exit(&dict_foreign_err_mutex);
3065
if (foreign && trx->check_foreigns) {
3066
goto check_next_foreign;
3069
if (table->n_mysql_handles_opened > 0) {
3072
added = row_add_table_to_background_drop_list(table);
3075
ut_print_timestamp(stderr);
3076
fputs(" InnoDB: Warning: MySQL is"
3077
" trying to drop table ", stderr);
3078
ut_print_name(stderr, trx, TRUE, table->name);
3080
"InnoDB: though there are still"
3081
" open handles to it.\n"
3082
"InnoDB: Adding the table to the"
3083
" background drop queue.\n",
3086
/* We return DB_SUCCESS to MySQL though the drop will
3087
happen lazily later */
3091
/* The table is already in the background drop list */
3098
/* TODO: could we replace the counter n_foreign_key_checks_running
3099
with lock checks on the table? Acquire here an exclusive lock on the
3100
table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3101
they can cope with the table having been dropped here? Foreign key
3102
checks take an IS or IX lock on the table. */
3104
if (table->n_foreign_key_checks_running > 0) {
3108
added = row_add_table_to_background_drop_list(table);
3111
ut_print_timestamp(stderr);
3112
fputs(" InnoDB: You are trying to drop table ",
3114
ut_print_name(stderr, trx, TRUE, table->name);
3116
"InnoDB: though there is a"
3117
" foreign key check running on it.\n"
3118
"InnoDB: Adding the table to"
3119
" the background drop queue.\n",
3122
/* We return DB_SUCCESS to MySQL though the drop will
3123
happen lazily later */
3127
/* The table is already in the background drop list */
3134
/* Remove any locks there are on the table or its records */
3136
lock_reset_all_on_table(table);
3138
trx->dict_operation = TRUE;
3139
trx->table_id = table->id;
3141
/* We use the private SQL parser of Innobase to generate the
3142
query graphs needed in deleting the dictionary data from system
3143
tables in Innobase. Deleting a row from SYS_INDEXES table also
3144
frees the file segments of the B-tree associated with the index. */
3146
info = pars_info_create();
3148
pars_info_add_str_literal(info, "table_name", name);
3150
err = que_eval_sql(info,
3151
"PROCEDURE DROP_TABLE_PROC () IS\n"
3152
"sys_foreign_id CHAR;\n"
3155
"foreign_id CHAR;\n"
3158
"SELECT ID INTO table_id\n"
3160
"WHERE NAME = :table_name\n"
3161
"LOCK IN SHARE MODE;\n"
3162
"IF (SQL % NOTFOUND) THEN\n"
3167
"SELECT ID INTO sys_foreign_id\n"
3169
"WHERE NAME = 'SYS_FOREIGN'\n"
3170
"LOCK IN SHARE MODE;\n"
3171
"IF (SQL % NOTFOUND) THEN\n"
3174
"IF (:table_name = 'SYS_FOREIGN') THEN\n"
3177
"IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3180
"WHILE found = 1 LOOP\n"
3181
" SELECT ID INTO foreign_id\n"
3182
" FROM SYS_FOREIGN\n"
3183
" WHERE FOR_NAME = :table_name\n"
3184
" AND TO_BINARY(FOR_NAME)\n"
3185
" = TO_BINARY(:table_name)\n"
3186
" LOCK IN SHARE MODE;\n"
3187
" IF (SQL % NOTFOUND) THEN\n"
3190
" DELETE FROM SYS_FOREIGN_COLS\n"
3191
" WHERE ID = foreign_id;\n"
3192
" DELETE FROM SYS_FOREIGN\n"
3193
" WHERE ID = foreign_id;\n"
3197
"WHILE found = 1 LOOP\n"
3198
" SELECT ID INTO index_id\n"
3199
" FROM SYS_INDEXES\n"
3200
" WHERE TABLE_ID = table_id\n"
3201
" LOCK IN SHARE MODE;\n"
3202
" IF (SQL % NOTFOUND) THEN\n"
3205
" DELETE FROM SYS_FIELDS\n"
3206
" WHERE INDEX_ID = index_id;\n"
3207
" DELETE FROM SYS_INDEXES\n"
3208
" WHERE ID = index_id\n"
3209
" AND TABLE_ID = table_id;\n"
3212
"DELETE FROM SYS_COLUMNS\n"
3213
"WHERE TABLE_ID = table_id;\n"
3214
"DELETE FROM SYS_TABLES\n"
3215
"WHERE ID = table_id;\n"
3220
if (err != DB_SUCCESS) {
3221
ut_a(err == DB_OUT_OF_FILE_SPACE);
3223
err = DB_MUST_GET_MORE_FILE_SPACE;
3225
row_mysql_handle_errors(&err, trx, NULL, NULL);
3230
const char* name_or_path;
3233
heap = mem_heap_create(200);
3235
/* Clone the name, in case it has been allocated
3236
from table->heap, which will be freed by
3237
dict_table_remove_from_cache(table) below. */
3238
name = mem_heap_strdup(heap, name);
3239
space_id = table->space;
3241
if (table->dir_path_of_temp_table != NULL) {
3243
name_or_path = mem_heap_strdup(
3244
heap, table->dir_path_of_temp_table);
3247
name_or_path = name;
3250
dict_table_remove_from_cache(table);
3252
if (dict_load_table(name) != NULL) {
3253
ut_print_timestamp(stderr);
3254
fputs(" InnoDB: Error: not able to remove table ",
3256
ut_print_name(stderr, trx, TRUE, name);
3257
fputs(" from the dictionary cache!\n", stderr);
3261
/* Do not drop possible .ibd tablespace if something went
3262
wrong: we do not want to delete valuable data of the user */
3264
if (err == DB_SUCCESS && space_id > 0) {
3265
if (!fil_space_for_table_exists_in_mem(space_id,
3272
"InnoDB: We removed now the InnoDB"
3273
" internal data dictionary entry\n"
3274
"InnoDB: of table ");
3275
ut_print_name(stderr, trx, TRUE, name);
3276
fprintf(stderr, ".\n");
3277
} else if (!fil_delete_tablespace(space_id)) {
3279
"InnoDB: We removed now the InnoDB"
3280
" internal data dictionary entry\n"
3281
"InnoDB: of table ");
3282
ut_print_name(stderr, trx, TRUE, name);
3283
fprintf(stderr, ".\n");
3285
ut_print_timestamp(stderr);
3287
" InnoDB: Error: not able to"
3288
" delete tablespace %lu of table ",
3290
ut_print_name(stderr, trx, TRUE, name);
3291
fputs("!\n", stderr);
3296
mem_heap_free(heap);
3300
trx_commit_for_mysql(trx);
3302
if (locked_dictionary) {
3303
row_mysql_unlock_data_dictionary(trx);
3308
#ifndef UNIV_HOTBACKUP
3309
srv_wake_master_thread();
3310
#endif /* !UNIV_HOTBACKUP */
3315
/*************************************************************************
3316
Drops a database for MySQL. */
3319
row_drop_database_for_mysql(
3320
/*========================*/
3321
/* out: error code or DB_SUCCESS */
3322
const char* name, /* in: database name which ends to '/' */
3323
trx_t* trx) /* in: transaction handle */
3325
dict_table_t* table;
3327
int err = DB_SUCCESS;
3328
ulint namelen = strlen(name);
3330
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3332
ut_a(name[namelen - 1] == '/');
3334
trx->op_info = "dropping database";
3336
trx_start_if_not_started(trx);
3338
row_mysql_lock_data_dictionary(trx);
3340
while ((table_name = dict_get_first_table_name_in_db(name))) {
3341
ut_a(memcmp(table_name, name, namelen) == 0);
3343
table = dict_table_get_low(table_name);
3347
/* Wait until MySQL does not have any queries running on
3350
if (table->n_mysql_handles_opened > 0) {
3351
row_mysql_unlock_data_dictionary(trx);
3353
ut_print_timestamp(stderr);
3354
fputs(" InnoDB: Warning: MySQL is trying to"
3355
" drop database ", stderr);
3356
ut_print_name(stderr, trx, TRUE, name);
3358
"InnoDB: though there are still"
3359
" open handles to table ", stderr);
3360
ut_print_name(stderr, trx, TRUE, table_name);
3361
fputs(".\n", stderr);
3363
os_thread_sleep(1000000);
3365
mem_free(table_name);
3370
err = row_drop_table_for_mysql(table_name, trx, TRUE);
3372
mem_free(table_name);
3374
if (err != DB_SUCCESS) {
3375
fputs("InnoDB: DROP DATABASE ", stderr);
3376
ut_print_name(stderr, trx, TRUE, name);
3377
fprintf(stderr, " failed with error %lu for table ",
3379
ut_print_name(stderr, trx, TRUE, table_name);
3385
trx_commit_for_mysql(trx);
3387
row_mysql_unlock_data_dictionary(trx);
3394
/*************************************************************************
3395
Checks if a table name contains the string "/#sql" which denotes temporary
3399
row_is_mysql_tmp_table_name(
3400
/*========================*/
3401
/* out: TRUE if temporary table */
3402
const char* name) /* in: table name in the form
3403
'database/tablename' */
3405
return(strstr(name, "/#sql") != NULL);
3406
/* return(strstr(name, "/@0023sql") != NULL); */
3409
/********************************************************************
3410
Delete a single constraint. */
3413
row_delete_constraint_low(
3414
/*======================*/
3415
/* out: error code or DB_SUCCESS */
3416
const char* id, /* in: constraint id */
3417
trx_t* trx) /* in: transaction handle */
3419
pars_info_t* info = pars_info_create();
3421
pars_info_add_str_literal(info, "id", id);
3423
return((int) que_eval_sql(info,
3424
"PROCEDURE DELETE_CONSTRAINT () IS\n"
3426
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3427
"DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3432
/********************************************************************
3433
Delete a single constraint. */
3436
row_delete_constraint(
3437
/*==================*/
3438
/* out: error code or DB_SUCCESS */
3439
const char* id, /* in: constraint id */
3440
const char* database_name, /* in: database name, with the
3442
mem_heap_t* heap, /* in: memory heap */
3443
trx_t* trx) /* in: transaction handle */
3447
/* New format constraints have ids <databasename>/<constraintname>. */
3448
err = row_delete_constraint_low(
3449
mem_heap_strcat(heap, database_name, id), trx);
3451
if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3452
/* Old format < 4.0.18 constraints have constraint ids
3453
<number>_<number>. We only try deleting them if the
3454
constraint name does not contain a '/' character, otherwise
3455
deleting a new format constraint named 'foo/bar' from
3456
database 'baz' would remove constraint 'bar' from database
3457
'foo', if it existed. */
3459
err = row_delete_constraint_low(id, trx);
3465
/*************************************************************************
3466
Renames a table for MySQL. */
3469
row_rename_table_for_mysql(
3470
/*=======================*/
3471
/* out: error code or DB_SUCCESS */
3472
const char* old_name, /* in: old table name */
3473
const char* new_name, /* in: new table name */
3474
trx_t* trx) /* in: transaction handle */
3476
dict_table_t* table;
3478
mem_heap_t* heap = NULL;
3479
const char** constraints_to_drop = NULL;
3480
ulint n_constraints_to_drop = 0;
3481
ibool old_is_tmp, new_is_tmp;
3482
pars_info_t* info = NULL;
3484
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3485
ut_a(old_name != NULL);
3486
ut_a(new_name != NULL);
3488
if (srv_created_new_raw || srv_force_recovery) {
3489
fputs("InnoDB: A new raw disk partition was initialized or\n"
3490
"InnoDB: innodb_force_recovery is on: we do not allow\n"
3491
"InnoDB: database modifications by the user. Shut down\n"
3492
"InnoDB: mysqld and edit my.cnf so that newraw"
3494
"InnoDB: with raw, and innodb_force_... is removed.\n",
3497
trx_commit_for_mysql(trx);
3501
if (row_mysql_is_system_table(new_name)) {
3504
"InnoDB: Error: trying to create a MySQL"
3505
" system table %s of type InnoDB.\n"
3506
"InnoDB: MySQL system tables must be"
3507
" of the MyISAM type!\n",
3510
trx_commit_for_mysql(trx);
3514
trx->op_info = "renaming table";
3515
trx_start_if_not_started(trx);
3517
old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3518
new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3520
/* Serialize data dictionary operations with dictionary mutex:
3521
no deadlocks can occur then in these operations */
3523
row_mysql_lock_data_dictionary(trx);
3525
table = dict_table_get_low(old_name);
3528
err = DB_TABLE_NOT_FOUND;
3529
ut_print_timestamp(stderr);
3531
fputs(" InnoDB: Error: table ", stderr);
3532
ut_print_name(stderr, trx, TRUE, old_name);
3533
fputs(" does not exist in the InnoDB internal\n"
3534
"InnoDB: data dictionary though MySQL is"
3535
" trying to rename the table.\n"
3536
"InnoDB: Have you copied the .frm file"
3537
" of the table to the\n"
3538
"InnoDB: MySQL database directory"
3539
" from another database?\n"
3540
"InnoDB: You can look for further help from\n"
3541
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3542
"innodb-troubleshooting.html\n",
3547
if (table->ibd_file_missing) {
3548
err = DB_TABLE_NOT_FOUND;
3549
ut_print_timestamp(stderr);
3551
fputs(" InnoDB: Error: table ", stderr);
3552
ut_print_name(stderr, trx, TRUE, old_name);
3553
fputs(" does not have an .ibd file"
3554
" in the database directory.\n"
3555
"InnoDB: You can look for further help from\n"
3556
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3557
"innodb-troubleshooting.html\n",
3563
/* MySQL is doing an ALTER TABLE command and it renames the
3564
original table to a temporary table name. We want to preserve
3565
the original foreign key constraint definitions despite the
3566
name change. An exception is those constraints for which
3567
the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3569
heap = mem_heap_create(100);
3571
err = dict_foreign_parse_drop_constraints(
3572
heap, trx, table, &n_constraints_to_drop,
3573
&constraints_to_drop);
3575
if (err != DB_SUCCESS) {
3581
/* We use the private SQL parser of Innobase to generate the query
3582
graphs needed in deleting the dictionary data from system tables in
3583
Innobase. Deleting a row from SYS_INDEXES table also frees the file
3584
segments of the B-tree associated with the index. */
3586
info = pars_info_create();
3588
pars_info_add_str_literal(info, "new_table_name", new_name);
3589
pars_info_add_str_literal(info, "old_table_name", old_name);
3591
err = que_eval_sql(info,
3592
"PROCEDURE RENAME_TABLE () IS\n"
3594
"UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3595
" WHERE NAME = :old_table_name;\n"
3599
if (err != DB_SUCCESS) {
3605
/* Rename all constraints. */
3607
info = pars_info_create();
3609
pars_info_add_str_literal(info, "new_table_name", new_name);
3610
pars_info_add_str_literal(info, "old_table_name", old_name);
3614
"PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3615
"gen_constr_prefix CHAR;\n"
3616
"new_db_name CHAR;\n"
3617
"foreign_id CHAR;\n"
3618
"new_foreign_id CHAR;\n"
3619
"old_db_name_len INT;\n"
3620
"old_t_name_len INT;\n"
3621
"new_db_name_len INT;\n"
3626
"old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3627
"new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3628
"new_db_name := SUBSTR(:new_table_name, 0,\n"
3629
" new_db_name_len);\n"
3630
"old_t_name_len := LENGTH(:old_table_name);\n"
3631
"gen_constr_prefix := CONCAT(:old_table_name,\n"
3633
"WHILE found = 1 LOOP\n"
3634
" SELECT ID INTO foreign_id\n"
3635
" FROM SYS_FOREIGN\n"
3636
" WHERE FOR_NAME = :old_table_name\n"
3637
" AND TO_BINARY(FOR_NAME)\n"
3638
" = TO_BINARY(:old_table_name)\n"
3639
" LOCK IN SHARE MODE;\n"
3640
" IF (SQL % NOTFOUND) THEN\n"
3643
" UPDATE SYS_FOREIGN\n"
3644
" SET FOR_NAME = :new_table_name\n"
3645
" WHERE ID = foreign_id;\n"
3646
" id_len := LENGTH(foreign_id);\n"
3647
" IF (INSTR(foreign_id, '/') > 0) THEN\n"
3648
" IF (INSTR(foreign_id,\n"
3649
" gen_constr_prefix) > 0)\n"
3651
" new_foreign_id :=\n"
3652
" CONCAT(:new_table_name,\n"
3653
" SUBSTR(foreign_id, old_t_name_len,\n"
3654
" id_len - old_t_name_len));\n"
3656
" new_foreign_id :=\n"
3657
" CONCAT(new_db_name,\n"
3658
" SUBSTR(foreign_id,\n"
3659
" old_db_name_len,\n"
3660
" id_len - old_db_name_len));\n"
3662
" UPDATE SYS_FOREIGN\n"
3663
" SET ID = new_foreign_id\n"
3664
" WHERE ID = foreign_id;\n"
3665
" UPDATE SYS_FOREIGN_COLS\n"
3666
" SET ID = new_foreign_id\n"
3667
" WHERE ID = foreign_id;\n"
3671
"UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
3672
"WHERE REF_NAME = :old_table_name\n"
3673
" AND TO_BINARY(REF_NAME)\n"
3674
" = TO_BINARY(:old_table_name);\n"
3678
} else if (n_constraints_to_drop > 0) {
3679
/* Drop some constraints of tmp tables. */
3681
ulint db_name_len = dict_get_db_name_len(old_name) + 1;
3682
char* db_name = mem_heap_strdupl(heap, old_name,
3686
for (i = 0; i < n_constraints_to_drop; i++) {
3687
err = row_delete_constraint(constraints_to_drop[i],
3688
db_name, heap, trx);
3690
if (err != DB_SUCCESS) {
3697
if (err != DB_SUCCESS) {
3698
if (err == DB_DUPLICATE_KEY) {
3699
ut_print_timestamp(stderr);
3700
fputs(" InnoDB: Error; possible reasons:\n"
3701
"InnoDB: 1) Table rename would cause"
3702
" two FOREIGN KEY constraints\n"
3703
"InnoDB: to have the same internal name"
3704
" in case-insensitive comparison.\n"
3705
"InnoDB: 2) table ", stderr);
3706
ut_print_name(stderr, trx, TRUE, new_name);
3707
fputs(" exists in the InnoDB internal data\n"
3708
"InnoDB: dictionary though MySQL is"
3709
" trying to rename table ", stderr);
3710
ut_print_name(stderr, trx, TRUE, old_name);
3712
"InnoDB: Have you deleted the .frm file"
3713
" and not used DROP TABLE?\n"
3714
"InnoDB: You can look for further help from\n"
3715
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3716
"innodb-troubleshooting.html\n"
3717
"InnoDB: If table ", stderr);
3718
ut_print_name(stderr, trx, TRUE, new_name);
3719
fputs(" is a temporary table #sql..., then"
3721
"InnoDB: there are still queries running"
3722
" on the table, and it will be\n"
3723
"InnoDB: dropped automatically when"
3724
" the queries end.\n"
3725
"InnoDB: You can drop the orphaned table"
3726
" inside InnoDB by\n"
3727
"InnoDB: creating an InnoDB table with"
3728
" the same name in another\n"
3729
"InnoDB: database and copying the .frm file"
3730
" to the current database.\n"
3731
"InnoDB: Then MySQL thinks the table exists,"
3732
" and DROP TABLE will\n"
3733
"InnoDB: succeed.\n", stderr);
3735
trx->error_state = DB_SUCCESS;
3736
trx_general_rollback_for_mysql(trx, FALSE, NULL);
3737
trx->error_state = DB_SUCCESS;
3739
/* The following call will also rename the .ibd data file if
3740
the table is stored in a single-table tablespace */
3742
ibool success = dict_table_rename_in_cache(table, new_name,
3746
trx->error_state = DB_SUCCESS;
3747
trx_general_rollback_for_mysql(trx, FALSE, NULL);
3748
trx->error_state = DB_SUCCESS;
3749
ut_print_timestamp(stderr);
3750
fputs(" InnoDB: Error in table rename,"
3751
" cannot rename ", stderr);
3752
ut_print_name(stderr, trx, TRUE, old_name);
3753
fputs(" to ", stderr);
3754
ut_print_name(stderr, trx, TRUE, new_name);
3761
/* We only want to switch off some of the type checking in
3762
an ALTER, not in a RENAME. */
3764
err = dict_load_foreigns(
3765
new_name, old_is_tmp ? trx->check_foreigns : TRUE);
3767
if (err != DB_SUCCESS) {
3768
ut_print_timestamp(stderr);
3771
fputs(" InnoDB: Error: in ALTER TABLE ",
3773
ut_print_name(stderr, trx, TRUE, new_name);
3775
"InnoDB: has or is referenced"
3776
" in foreign key constraints\n"
3777
"InnoDB: which are not compatible"
3778
" with the new table definition.\n",
3781
fputs(" InnoDB: Error: in RENAME TABLE"
3784
ut_print_name(stderr, trx, TRUE, new_name);
3786
"InnoDB: is referenced in"
3787
" foreign key constraints\n"
3788
"InnoDB: which are not compatible"
3789
" with the new table definition.\n",
3793
ut_a(dict_table_rename_in_cache(table,
3795
trx->error_state = DB_SUCCESS;
3796
trx_general_rollback_for_mysql(trx, FALSE, NULL);
3797
trx->error_state = DB_SUCCESS;
3802
trx_commit_for_mysql(trx);
3803
row_mysql_unlock_data_dictionary(trx);
3805
if (UNIV_LIKELY_NULL(heap)) {
3806
mem_heap_free(heap);
3814
/*************************************************************************
3815
Checks that the index contains entries in an ascending order, unique
3816
constraint is not broken, and calculates the number of index entries
3817
in the read view of the current transaction. */
3820
row_scan_and_check_index(
3821
/*=====================*/
3822
/* out: TRUE if ok */
3823
row_prebuilt_t* prebuilt, /* in: prebuilt struct in MySQL */
3824
dict_index_t* index, /* in: index */
3825
ulint* n_rows) /* out: number of entries seen in the
3826
current consistent read */
3828
dtuple_t* prev_entry = NULL;
3829
ulint matched_fields;
3830
ulint matched_bytes;
3836
ibool contains_null;
3839
mem_heap_t* heap = NULL;
3840
ulint offsets_[REC_OFFS_NORMAL_SIZE];
3841
ulint* offsets = offsets_;
3842
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
3846
buf = mem_alloc(UNIV_PAGE_SIZE);
3847
heap = mem_heap_create(100);
3849
/* Make a dummy template in prebuilt, which we will use
3850
in scanning the index entries */
3852
prebuilt->index = index;
3853
prebuilt->sql_stat_start = TRUE;
3854
prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE;
3855
prebuilt->n_template = 0;
3856
prebuilt->need_to_access_clustered = FALSE;
3858
dtuple_set_n_fields(prebuilt->search_tuple, 0);
3860
prebuilt->select_lock_type = LOCK_NONE;
3863
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
3865
/* Check thd->killed every 1,000 scanned rows */
3867
if (trx_is_interrupted(prebuilt->trx)) {
3872
if (ret != DB_SUCCESS) {
3875
mem_heap_free(heap);
3880
*n_rows = *n_rows + 1;
3882
/* row_search... returns the index record in buf, record origin offset
3883
within buf stored in the first 4 bytes, because we have built a dummy
3886
rec = buf + mach_read_from_4(buf);
3888
if (prev_entry != NULL) {
3892
offsets = rec_get_offsets(rec, index, offsets,
3893
ULINT_UNDEFINED, &heap);
3894
cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
3897
contains_null = FALSE;
3899
/* In a unique secondary index we allow equal key values if
3900
they contain SQL NULLs */
3903
i < dict_index_get_n_ordering_defined_by_user(index);
3905
if (UNIV_SQL_NULL == dfield_get_len(
3906
dtuple_get_nth_field(prev_entry, i))) {
3908
contains_null = TRUE;
3913
fputs("InnoDB: index records in a wrong order in ",
3916
dict_index_name_print(stderr,
3917
prebuilt->trx, index);
3919
"InnoDB: prev record ", stderr);
3920
dtuple_print(stderr, prev_entry);
3922
"InnoDB: record ", stderr);
3923
rec_print_new(stderr, rec, offsets);
3926
} else if ((index->type & DICT_UNIQUE)
3929
>= dict_index_get_n_ordering_defined_by_user(
3932
fputs("InnoDB: duplicate key in ", stderr);
3937
mem_heap_empty(heap);
3940
prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
3942
ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
3947
/*************************************************************************
3948
Checks a table for corruption. */
3951
row_check_table_for_mysql(
3952
/*======================*/
3953
/* out: DB_ERROR or DB_SUCCESS */
3954
row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
3957
dict_table_t* table = prebuilt->table;
3958
dict_index_t* index;
3960
ulint n_rows_in_table = ULINT_UNDEFINED;
3961
ulint ret = DB_SUCCESS;
3962
ulint old_isolation_level;
3964
if (prebuilt->table->ibd_file_missing) {
3965
ut_print_timestamp(stderr);
3966
fprintf(stderr, " InnoDB: Error:\n"
3967
"InnoDB: MySQL is trying to use a table handle"
3968
" but the .ibd file for\n"
3969
"InnoDB: table %s does not exist.\n"
3970
"InnoDB: Have you deleted the .ibd file"
3971
" from the database directory under\n"
3972
"InnoDB: the MySQL datadir, or have you"
3973
" used DISCARD TABLESPACE?\n"
3974
"InnoDB: Look from\n"
3975
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3976
"innodb-troubleshooting.html\n"
3977
"InnoDB: how you can resolve the problem.\n",
3978
prebuilt->table->name);
3982
prebuilt->trx->op_info = "checking table";
3984
old_isolation_level = prebuilt->trx->isolation_level;
3986
/* We must run the index record counts at an isolation level
3987
>= READ COMMITTED, because a dirty read can see a wrong number
3988
of records in some index; to play safe, we use always
3989
REPEATABLE READ here */
3991
prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ;
3993
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
3994
mutex_enter(&kernel_mutex);
3995
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
3996
mutex_exit(&kernel_mutex);
3998
index = dict_table_get_first_index(table);
4000
while (index != NULL) {
4001
/* fputs("Validating index ", stderr);
4002
ut_print_name(stderr, trx, FALSE, index->name);
4003
putc('\n', stderr); */
4005
if (!btr_validate_index(index, prebuilt->trx)) {
4008
if (!row_scan_and_check_index(prebuilt,
4013
if (trx_is_interrupted(prebuilt->trx)) {
4017
/* fprintf(stderr, "%lu entries in index %s\n", n_rows,
4020
if (index == dict_table_get_first_index(table)) {
4021
n_rows_in_table = n_rows;
4022
} else if (n_rows != n_rows_in_table) {
4026
fputs("Error: ", stderr);
4027
dict_index_name_print(stderr,
4028
prebuilt->trx, index);
4030
" contains %lu entries,"
4033
(ulong) n_rows_in_table);
4037
index = dict_table_get_next_index(index);
4040
/* Restore the original isolation level */
4041
prebuilt->trx->isolation_level = old_isolation_level;
4043
/* We validate also the whole adaptive hash index for all tables
4044
at every CHECK TABLE */
4046
if (!btr_search_validate()) {
4051
/* Restore the fatal lock wait timeout after CHECK TABLE. */
4052
mutex_enter(&kernel_mutex);
4053
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
4054
mutex_exit(&kernel_mutex);
4056
prebuilt->trx->op_info = "";