summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--innobase/btr/btr0sea.c3
-rw-r--r--innobase/include/buf0buf.h14
-rw-r--r--innobase/include/os0file.h2
-rw-r--r--innobase/include/srv0srv.h12
-rw-r--r--innobase/row/row0ins.c27
-rw-r--r--innobase/srv/srv0srv.c12
-rw-r--r--innobase/srv/srv0start.c27
-rw-r--r--mysql-test/r/innodb.result29
-rw-r--r--mysql-test/t/innodb.test34
-rw-r--r--sql/ha_innodb.cc109
10 files changed, 191 insertions, 78 deletions
diff --git a/innobase/btr/btr0sea.c b/innobase/btr/btr0sea.c
index 9b1e93fe700..81f23cfa99c 100644
--- a/innobase/btr/btr0sea.c
+++ b/innobase/btr/btr0sea.c
@@ -889,7 +889,8 @@ Drops a page hash index. */
void
btr_search_drop_page_hash_index(
/*============================*/
- page_t* page) /* in: index page, s- or x-latched */
+ page_t* page) /* in: index page, s- or x-latched, or an index page
+ for which we know that block->buf_fix_count == 0 */
{
hash_table_t* table;
buf_block_t* block;
diff --git a/innobase/include/buf0buf.h b/innobase/include/buf0buf.h
index 24e7a71c02d..fc1d9a64c7f 100644
--- a/innobase/include/buf0buf.h
+++ b/innobase/include/buf0buf.h
@@ -831,7 +831,13 @@ struct buf_block_struct{
records with the same prefix should be
indexed in the hash index */
- /* The following 6 fields are protected by btr_search_latch: */
+ /* These 6 fields may only be modified when we have
+ an x-latch on btr_search_latch AND
+ a) we are holding an s-latch or x-latch on block->lock or
+ b) we know that block->buf_fix_count == 0.
+
+ An exception to this is when we init or create a page
+ in the buffer pool in buf0buf.c. */
ibool is_hashed; /* TRUE if hash index has already been
built on this page; note that it does
@@ -849,11 +855,7 @@ struct buf_block_struct{
BTR_SEARCH_RIGHT_SIDE in hash
indexing */
dict_index_t* index; /* Index for which the adaptive
- hash index has been created.
- This field may only be modified
- while holding an s-latch or x-latch
- on block->lock and an x-latch on
- btr_search_latch. */
+ hash index has been created. */
/* 6. Debug fields */
#ifdef UNIV_SYNC_DEBUG
rw_lock_t debug_latch; /* in the debug version, each thread
diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h
index 224fd59a76b..02a38dd49ef 100644
--- a/innobase/include/os0file.h
+++ b/innobase/include/os0file.h
@@ -187,7 +187,7 @@ Creates a temporary file. */
FILE*
os_file_create_tmpfile(void);
/*========================*/
- /* out: temporary file handle (never NULL) */
+ /* out: temporary file handle, or NULL on error */
/***************************************************************************
The os_file_opendir() function opens a directory stream corresponding to the
directory named by the dirname argument. The directory stream is positioned
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 11347f430d4..99ea4f2de27 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -34,6 +34,18 @@ extern ibool srv_lower_case_table_names;
extern mutex_t srv_monitor_file_mutex;
/* Temporary file for innodb monitor output */
extern FILE* srv_monitor_file;
+/* Mutex for locking srv_dict_tmpfile.
+This mutex has a very high rank; threads reserving it should not
+be holding any InnoDB latches. */
+extern mutex_t srv_dict_tmpfile_mutex;
+/* Temporary file for output from the data dictionary */
+extern FILE* srv_dict_tmpfile;
+/* Mutex for locking srv_misc_tmpfile.
+This mutex has a very low rank; threads reserving it should not
+acquire any further latches or sleep before releasing this one. */
+extern mutex_t srv_misc_tmpfile_mutex;
+/* Temporary file for miscellanous diagnostic output */
+extern FILE* srv_misc_tmpfile;
/* Server parameters which are read from the initfile */
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 5e833372299..32aa0385596 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -588,20 +588,21 @@ row_ins_set_detailed(
trx_t* trx, /* in: transaction */
dict_foreign_t* foreign) /* in: foreign key constraint */
{
-
- FILE* tf = os_file_create_tmpfile();
-
- if (tf) {
- ut_print_name(tf, trx, foreign->foreign_table_name);
- dict_print_info_on_foreign_key_in_create_format(tf, trx,
- foreign, FALSE);
-
- trx_set_detailed_error_from_file(trx, tf);
-
- fclose(tf);
+ mutex_enter(&srv_misc_tmpfile_mutex);
+ rewind(srv_misc_tmpfile);
+
+ if (os_file_set_eof(srv_misc_tmpfile)) {
+ ut_print_name(srv_misc_tmpfile, trx,
+ foreign->foreign_table_name);
+ dict_print_info_on_foreign_key_in_create_format(
+ srv_misc_tmpfile,
+ trx, foreign, FALSE);
+ trx_set_detailed_error_from_file(trx, srv_misc_tmpfile);
} else {
- trx_set_detailed_error(trx, "temp file creation failed");
+ trx_set_detailed_error(trx, "temp file operation failed");
}
+
+ mutex_exit(&srv_misc_tmpfile_mutex);
}
/*************************************************************************
@@ -709,7 +710,7 @@ row_ins_foreign_report_add_err(
}
if (rec) {
- rec_print(ef, rec, foreign->foreign_index);
+ rec_print(ef, rec, foreign->referenced_index);
}
putc('\n', ef);
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index c585536baee..6e0b9b23266 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -397,6 +397,18 @@ mutex_t srv_innodb_monitor_mutex;
mutex_t srv_monitor_file_mutex;
/* Temporary file for innodb monitor output */
FILE* srv_monitor_file;
+/* Mutex for locking srv_dict_tmpfile.
+This mutex has a very high rank; threads reserving it should not
+be holding any InnoDB latches. */
+mutex_t srv_dict_tmpfile_mutex;
+/* Temporary file for output from the data dictionary */
+FILE* srv_dict_tmpfile;
+/* Mutex for locking srv_misc_tmpfile.
+This mutex has a very low rank; threads reserving it should not
+acquire any further latches or sleep before releasing this one. */
+mutex_t srv_misc_tmpfile_mutex;
+/* Temporary file for miscellanous diagnostic output */
+FILE* srv_misc_tmpfile;
ulint srv_main_thread_process_no = 0;
ulint srv_main_thread_id = 0;
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index e5151ebf631..4f99f340e1c 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -1180,6 +1180,20 @@ NetWare. */
}
}
+ mutex_create(&srv_dict_tmpfile_mutex);
+ mutex_set_level(&srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION);
+ srv_dict_tmpfile = os_file_create_tmpfile();
+ if (!srv_dict_tmpfile) {
+ return(DB_ERROR);
+ }
+
+ mutex_create(&srv_misc_tmpfile_mutex);
+ mutex_set_level(&srv_misc_tmpfile_mutex, SYNC_ANY_LATCH);
+ srv_misc_tmpfile = os_file_create_tmpfile();
+ if (!srv_misc_tmpfile) {
+ return(DB_ERROR);
+ }
+
/* Restrict the maximum number of file i/o threads */
if (srv_n_file_io_threads > SRV_MAX_N_IO_THREADS) {
@@ -1822,8 +1836,19 @@ innobase_shutdown_for_mysql(void)
mem_free(srv_monitor_file_name);
}
}
-
+ if (srv_dict_tmpfile) {
+ fclose(srv_dict_tmpfile);
+ srv_dict_tmpfile = 0;
+ }
+
+ if (srv_misc_tmpfile) {
+ fclose(srv_misc_tmpfile);
+ srv_misc_tmpfile = 0;
+ }
+
mutex_free(&srv_monitor_file_mutex);
+ mutex_free(&srv_dict_tmpfile_mutex);
+ mutex_free(&srv_misc_tmpfile_mutex);
/* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside
them */
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 0e0e6a20770..dcff72ba7c0 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -2846,4 +2846,33 @@ d varchar(255) character set utf8,
e varchar(255) character set utf8,
key (a,b,c,d,e)) engine=innodb;
ERROR 42000: Specified key was too long; max key length is 3072 bytes
+create table t1(a int primary key) row_format=redundant engine=innodb;
+create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb;
+create table t3(a int primary key) row_format=compact engine=innodb;
+create table t4(a int primary key,constraint foreign key(a)references t3(a)) row_format=redundant engine=innodb;
+insert into t1 values(1);
+insert into t3 values(1);
+insert into t2 values(2);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+insert into t4 values(2);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+insert into t2 values(1);
+insert into t4 values(1);
+update t1 set a=2;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+update t2 set a=2;
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+update t3 set a=2;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+update t4 set a=2;
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+truncate t1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+truncate t3;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test/t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`))
+truncate t2;
+truncate t4;
+truncate t1;
+truncate t3;
+drop table t4,t3,t2,t1;
End of 5.0 tests
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 735deba2b05..887d8193157 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -1833,4 +1833,38 @@ create table t1 (a varchar(255) character set utf8,
e varchar(255) character set utf8,
key (a,b,c,d,e)) engine=innodb;
+# test that foreign key errors are reported correctly (Bug #15550)
+
+create table t1(a int primary key) row_format=redundant engine=innodb;
+create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb;
+create table t3(a int primary key) row_format=compact engine=innodb;
+create table t4(a int primary key,constraint foreign key(a)references t3(a)) row_format=redundant engine=innodb;
+
+insert into t1 values(1);
+insert into t3 values(1);
+-- error 1452
+insert into t2 values(2);
+-- error 1452
+insert into t4 values(2);
+insert into t2 values(1);
+insert into t4 values(1);
+-- error 1451
+update t1 set a=2;
+-- error 1452
+update t2 set a=2;
+-- error 1451
+update t3 set a=2;
+-- error 1452
+update t4 set a=2;
+-- error 1451
+truncate t1;
+-- error 1451
+truncate t3;
+truncate t2;
+truncate t4;
+truncate t1;
+truncate t3;
+
+drop table t4,t3,t2,t1;
+
--echo End of 5.0 tests
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 6c8dc9f81f6..afeb1238aa7 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -5742,6 +5742,7 @@ ha_innobase::update_table_comment(
uint length = (uint) strlen(comment);
char* str;
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
+ long flen;
/* We do not know if MySQL can call this function before calling
external_lock(). To be safe, update the thd of the current table
@@ -5761,43 +5762,43 @@ ha_innobase::update_table_comment(
trx_search_latch_release_if_reserved(prebuilt->trx);
str = NULL;
- if (FILE* file = os_file_create_tmpfile()) {
- long flen;
+ /* output the data to a temporary file */
- /* output the data to a temporary file */
- fprintf(file, "InnoDB free: %lu kB",
+ mutex_enter_noninline(&srv_dict_tmpfile_mutex);
+ rewind(srv_dict_tmpfile);
+
+ fprintf(srv_dict_tmpfile, "InnoDB free: %lu kB",
(ulong) fsp_get_available_space_in_free_extents(
prebuilt->table->space));
- dict_print_info_on_foreign_keys(FALSE, file,
+ dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
prebuilt->trx, prebuilt->table);
- flen = ftell(file);
- if (flen < 0) {
- flen = 0;
- } else if (length + flen + 3 > 64000) {
- flen = 64000 - 3 - length;
- }
+ flen = ftell(srv_dict_tmpfile);
+ if (flen < 0) {
+ flen = 0;
+ } else if (length + flen + 3 > 64000) {
+ flen = 64000 - 3 - length;
+ }
- /* allocate buffer for the full string, and
- read the contents of the temporary file */
+ /* allocate buffer for the full string, and
+ read the contents of the temporary file */
- str = my_malloc(length + flen + 3, MYF(0));
+ str = my_malloc(length + flen + 3, MYF(0));
- if (str) {
- char* pos = str + length;
- if (length) {
- memcpy(str, comment, length);
- *pos++ = ';';
- *pos++ = ' ';
- }
- rewind(file);
- flen = (uint) fread(pos, 1, flen, file);
- pos[flen] = 0;
+ if (str) {
+ char* pos = str + length;
+ if (length) {
+ memcpy(str, comment, length);
+ *pos++ = ';';
+ *pos++ = ' ';
}
-
- fclose(file);
+ rewind(srv_dict_tmpfile);
+ flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile);
+ pos[flen] = 0;
}
+ mutex_exit_noninline(&srv_dict_tmpfile_mutex);
+
prebuilt->trx->op_info = (char*)"";
return(str ? str : (char*) comment);
@@ -5815,6 +5816,7 @@ ha_innobase::get_foreign_key_create_info(void)
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt;
char* str = 0;
+ long flen;
ut_a(prebuilt != NULL);
@@ -5824,47 +5826,42 @@ ha_innobase::get_foreign_key_create_info(void)
update_thd(current_thd);
- if (FILE* file = os_file_create_tmpfile()) {
- long flen;
+ prebuilt->trx->op_info = (char*)"getting info on foreign keys";
- prebuilt->trx->op_info = (char*)"getting info on foreign keys";
+ /* In case MySQL calls this in the middle of a SELECT query,
+ release possible adaptive hash latch to avoid
+ deadlocks of threads */
- /* In case MySQL calls this in the middle of a SELECT query,
- release possible adaptive hash latch to avoid
- deadlocks of threads */
+ trx_search_latch_release_if_reserved(prebuilt->trx);
- trx_search_latch_release_if_reserved(prebuilt->trx);
+ mutex_enter_noninline(&srv_dict_tmpfile_mutex);
+ rewind(srv_dict_tmpfile);
- /* output the data to a temporary file */
- dict_print_info_on_foreign_keys(TRUE, file,
+ /* output the data to a temporary file */
+ dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile,
prebuilt->trx, prebuilt->table);
- prebuilt->trx->op_info = (char*)"";
-
- flen = ftell(file);
- if (flen < 0) {
- flen = 0;
- } else if (flen > 64000 - 1) {
- flen = 64000 - 1;
- }
+ prebuilt->trx->op_info = (char*)"";
- /* allocate buffer for the string, and
- read the contents of the temporary file */
+ flen = ftell(srv_dict_tmpfile);
+ if (flen < 0) {
+ flen = 0;
+ } else if (flen > 64000 - 1) {
+ flen = 64000 - 1;
+ }
- str = my_malloc(flen + 1, MYF(0));
+ /* allocate buffer for the string, and
+ read the contents of the temporary file */
- if (str) {
- rewind(file);
- flen = (uint) fread(str, 1, flen, file);
- str[flen] = 0;
- }
+ str = my_malloc(flen + 1, MYF(0));
- fclose(file);
- } else {
- /* unable to create temporary file */
- str = my_strdup(
-"/* Error: cannot display foreign key constraints */", MYF(0));
+ if (str) {
+ rewind(srv_dict_tmpfile);
+ flen = (uint) fread(str, 1, flen, srv_dict_tmpfile);
+ str[flen] = 0;
}
+ mutex_exit_noninline(&srv_dict_tmpfile_mutex);
+
return(str);
}