#At file:///home/kgeorge/mysql/work/B39022-5.1-bugteam/ based on revid:satya.bn@stripped
3294 Georgi Kodinov 2009-12-23
Bug #39022: Mysql randomly crashing in lock_sec_rec_cons_read_sees
flush_cached_records() was not correctly checking for errors after calling
Item::val_xxx() methods. The expressions may contain subqueries
or stored procedures that cause errors that should stop the statement.
Fixed by correctly checking for errors and propagating them up the call stack.
added:
mysql-test/r/bug39022.result
mysql-test/t/bug39022.test
modified:
sql/sql_select.cc
=== added file 'mysql-test/r/bug39022.result'
--- a/mysql-test/r/bug39022.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/bug39022.result 2009-12-23 10:45:18 +0000
@@ -0,0 +1,32 @@
+#
+# Bug #39022: Mysql randomly crashing in lock_sec_rec_cons_read_sees
+#
+CREATE TABLE t1(a TINYINT NOT NULL,b TINYINT,PRIMARY KEY(b)) ENGINE=innodb;
+CREATE TABLE t2(d TINYINT NOT NULL,UNIQUE KEY(d)) ENGINE=innodb;
+INSERT INTO t1 VALUES (13,0),(8,1),(9,2),(6,3),
+(11,5),(11,6),(7,7),(7,8),(4,9),(6,10),(3,11),(11,12),
+(12,13),(7,14);
+INSERT INTO t2 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),
+(11),(12),(13),(14);
+# in thread1
+START TRANSACTION;
+# in thread2
+REPLACE INTO t2 VALUES (-17);
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d);
+d
+# in thread1
+REPLACE INTO t1(a,b) VALUES (67,20);
+# in thread2
+COMMIT;
+START TRANSACTION;
+REPLACE INTO t1(a,b) VALUES (65,-50);
+REPLACE INTO t2 VALUES (-91);
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d);
+# in thread1
+# should not crash
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d);
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+# in thread2
+d
+# in default
+DROP TABLE t1,t2;
=== added file 'mysql-test/t/bug39022.test'
--- a/mysql-test/t/bug39022.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/bug39022.test 2009-12-23 10:45:18 +0000
@@ -0,0 +1,58 @@
+-- source include/have_log_bin.inc
+-- source include/have_innodb.inc
+
+--echo #
+--echo # Bug #39022: Mysql randomly crashing in lock_sec_rec_cons_read_sees
+--echo #
+
+CREATE TABLE t1(a TINYINT NOT NULL,b TINYINT,PRIMARY KEY(b)) ENGINE=innodb;
+CREATE TABLE t2(d TINYINT NOT NULL,UNIQUE KEY(d)) ENGINE=innodb;
+INSERT INTO t1 VALUES (13,0),(8,1),(9,2),(6,3),
+(11,5),(11,6),(7,7),(7,8),(4,9),(6,10),(3,11),(11,12),
+(12,13),(7,14);
+INSERT INTO t2 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),
+(11),(12),(13),(14);
+
+connect (thread1, localhost, root,,);
+connect (thread2, localhost, root,,);
+
+connection thread1;
+--echo # in thread1
+START TRANSACTION;
+
+connection thread2;
+--echo # in thread2
+REPLACE INTO t2 VALUES (-17);
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d);
+
+connection thread1;
+--echo # in thread1
+REPLACE INTO t1(a,b) VALUES (67,20);
+
+connection thread2;
+--echo # in thread2
+COMMIT;
+START TRANSACTION;
+REPLACE INTO t1(a,b) VALUES (65,-50);
+REPLACE INTO t2 VALUES (-91);
+send;
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); #waits
+
+connection thread1;
+--echo # in thread1
+
+--echo # should not crash
+--error ER_LOCK_DEADLOCK
+SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); #crashes
+
+connection thread2;
+--echo # in thread2
+REAP;
+
+connection default;
+--echo # in default
+
+disconnect thread1;
+disconnect thread2;
+
+DROP TABLE t1,t2;
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2009-12-17 09:55:18 +0000
+++ b/sql/sql_select.cc 2009-12-23 10:45:18 +0000
@@ -11494,21 +11494,45 @@ flush_cached_records(JOIN *join,JOIN_TAB
return NESTED_LOOP_KILLED; // Aborted by user /* purecov: inspected */
}
SQL_SELECT *select=join_tab->select;
- if (rc == NESTED_LOOP_OK &&
- (!join_tab->cache.select || !join_tab->cache.select->skip_record()))
+ if (rc == NESTED_LOOP_OK)
{
- uint i;
- reset_cache_read(&join_tab->cache);
- for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;)
+ bool consider_record= !join_tab->cache.select ||
+ !join_tab->cache.select->skip_record();
+
+ /*
+ Check for error: skip_record() can execute code by calling
+ Item_subselect::val_*. We need to check for errors (if any)
+ after such call.
+ */
+ if (join->thd->is_error())
+ {
+ reset_cache_write(&join_tab->cache);
+ return NESTED_LOOP_ERROR;
+ }
+
+ if (consider_record)
{
- read_cached_record(join_tab);
- if (!select || !select->skip_record())
+ uint i;
+ reset_cache_read(&join_tab->cache);
+ for (i=(join_tab->cache.records- (skip_last ? 1 : 0)) ; i-- > 0 ;)
{
- rc= (join_tab->next_select)(join,join_tab+1,0);
- if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
+ read_cached_record(join_tab);
+ if (!select || !select->skip_record())
{
- reset_cache_write(&join_tab->cache);
- return rc;
+ /*
+ Check for error: skip_record() can execute code by calling
+ Item_subselect::val_*. We need to check for errors (if any)
+ after such call.
+ */
+ if (join->thd->is_error())
+ rc= NESTED_LOOP_ERROR;
+ else
+ rc= (join_tab->next_select)(join,join_tab+1,0);
+ if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
+ {
+ reset_cache_write(&join_tab->cache);
+ return rc;
+ }
}
}
}
Attachment: [text/bzr-bundle] bzr/joro@sun.com-20091223104518-n6w04zv3kr708rzd.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-bugteam branch (joro:3294) Bug#39022 | Georgi Kodinov | 23 Dec |