mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
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.
This commit is contained in:
parent
2be07c7094
commit
6b8ec684c7
3 changed files with 125 additions and 11 deletions
32
mysql-test/r/bug39022.result
Normal file
32
mysql-test/r/bug39022.result
Normal file
|
@ -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;
|
58
mysql-test/t/bug39022.test
Normal file
58
mysql-test/t/bug39022.test
Normal file
|
@ -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;
|
|
@ -11521,21 +11521,45 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last)
|
|||
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())
|
||||
{
|
||||
read_cached_record(join_tab);
|
||||
if (!select || !select->skip_record())
|
||||
reset_cache_write(&join_tab->cache);
|
||||
return NESTED_LOOP_ERROR;
|
||||
}
|
||||
|
||||
if (consider_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue