summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorgi Kodinov <joro@sun.com>2009-07-13 18:11:16 +0300
committerGeorgi Kodinov <joro@sun.com>2009-07-13 18:11:16 +0300
commit410e1a72b957b72e0fb2a50930e7e82847c4486c (patch)
tree8915bb86227f4747f69f6afbe8076c9d43a2181f
parent544147417a567c2a40e8cf01e25c7785e26887a1 (diff)
downloadmariadb-git-410e1a72b957b72e0fb2a50930e7e82847c4486c.tar.gz
Bug #40113: Embedded SELECT inside UPDATE or DELETE can timeout
without error When using quick access methods for searching rows in UPDATE or DELETE there was no check if a fatal error was not already sent to the client while evaluating the quick condition. As a result a false OK (following the error) was sent to the client and the error was thus transformed into a warning. Fixed by checking for errors sent to the client during SQL_SELECT::check_quick() and treating them as real errors. Fixed a wrong test case in group_min_max.test Fixed a wrong return code in mysql_update() and mysql_delete() mysql-test/r/bug40113.result: Bug #40013: test case mysql-test/r/group_min_max.result: Bug #40013: fixed a wrong test case mysql-test/t/bug40113-master.opt: Bug #40013: test case mysql-test/t/bug40113.test: Bug #40013: test case mysql-test/t/group_min_max.test: Bug #40013: fixed a wrong test case sql/sql_delete.cc: Bug #40113: check for errors evaluating the quick select sql/sql_update.cc: Bug #40113: check for errors evaluating the quick select
-rw-r--r--mysql-test/r/bug40113.result29
-rw-r--r--mysql-test/r/group_min_max.result6
-rw-r--r--mysql-test/t/bug40113-master.opt1
-rw-r--r--mysql-test/t/bug40113.test46
-rw-r--r--mysql-test/t/group_min_max.test2
-rw-r--r--sql/sql_delete.cc10
-rw-r--r--sql/sql_update.cc11
7 files changed, 97 insertions, 8 deletions
diff --git a/mysql-test/r/bug40113.result b/mysql-test/r/bug40113.result
new file mode 100644
index 00000000000..289037a3f35
--- /dev/null
+++ b/mysql-test/r/bug40113.result
@@ -0,0 +1,29 @@
+#
+# Bug #40113: Embedded SELECT inside UPDATE or DELETE can timeout
+# without error
+#
+CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b)) ENGINE=InnoDB;
+INSERT INTO t1 (a,b) VALUES (1070109,99);
+CREATE TABLE t2 (b int, a int, PRIMARY KEY (b)) ENGINE=InnoDB;
+INSERT INTO t2 (b,a) VALUES (7,1070109);
+SELECT * FROM t1;
+a b
+1070109 99
+BEGIN;
+SELECT b FROM t2 WHERE b=7 FOR UPDATE;
+b
+7
+BEGIN;
+SELECT b FROM t2 WHERE b=7 FOR UPDATE;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+INSERT INTO t1 (a) VALUES ((SELECT a FROM t2 WHERE b=7));
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+UPDATE t1 SET a='7000000' WHERE a=(SELECT a FROM t2 WHERE b=7);
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+DELETE FROM t1 WHERE a=(SELECT a FROM t2 WHERE b=7);
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+SELECT * FROM t1;
+a b
+1070109 99
+DROP TABLE t2, t1;
+End of 5.0 tests
diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result
index 1138a5e1d88..9acbbaac499 100644
--- a/mysql-test/r/group_min_max.result
+++ b/mysql-test/r/group_min_max.result
@@ -2278,12 +2278,10 @@ Handler_read_key 8
Handler_read_next 0
FLUSH STATUS;
DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x
-FROM t1) > 10000;
-Warnings:
-Error 1242 Subquery returns more than 1 row
+FROM t1 WHERE a = 1 AND b = 1) > 10000;
SHOW STATUS LIKE 'handler_read__e%';
Variable_name Value
-Handler_read_key 8
+Handler_read_key 9
Handler_read_next 1
DROP TABLE t1,t2,t3;
CREATE TABLE t1 (a int, INDEX idx(a));
diff --git a/mysql-test/t/bug40113-master.opt b/mysql-test/t/bug40113-master.opt
new file mode 100644
index 00000000000..462f8fbe828
--- /dev/null
+++ b/mysql-test/t/bug40113-master.opt
@@ -0,0 +1 @@
+--innodb_lock_wait_timeout=1
diff --git a/mysql-test/t/bug40113.test b/mysql-test/t/bug40113.test
new file mode 100644
index 00000000000..6d35d0b73d3
--- /dev/null
+++ b/mysql-test/t/bug40113.test
@@ -0,0 +1,46 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # Bug #40113: Embedded SELECT inside UPDATE or DELETE can timeout
+--echo # without error
+--echo #
+
+CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b)) ENGINE=InnoDB;
+
+INSERT INTO t1 (a,b) VALUES (1070109,99);
+
+CREATE TABLE t2 (b int, a int, PRIMARY KEY (b)) ENGINE=InnoDB;
+
+INSERT INTO t2 (b,a) VALUES (7,1070109);
+
+SELECT * FROM t1;
+
+BEGIN;
+
+SELECT b FROM t2 WHERE b=7 FOR UPDATE;
+
+CONNECT (addconroot, localhost, root,,);
+CONNECTION addconroot;
+
+BEGIN;
+
+--error ER_LOCK_WAIT_TIMEOUT
+SELECT b FROM t2 WHERE b=7 FOR UPDATE;
+
+--error ER_LOCK_WAIT_TIMEOUT
+INSERT INTO t1 (a) VALUES ((SELECT a FROM t2 WHERE b=7));
+
+--error ER_LOCK_WAIT_TIMEOUT
+UPDATE t1 SET a='7000000' WHERE a=(SELECT a FROM t2 WHERE b=7);
+
+--error ER_LOCK_WAIT_TIMEOUT
+DELETE FROM t1 WHERE a=(SELECT a FROM t2 WHERE b=7);
+
+SELECT * FROM t1;
+
+CONNECTION default;
+DISCONNECT addconroot;
+
+DROP TABLE t2, t1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test
index 163c170eaa0..c81babb42e6 100644
--- a/mysql-test/t/group_min_max.test
+++ b/mysql-test/t/group_min_max.test
@@ -866,7 +866,7 @@ DELETE FROM t3 WHERE (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) > 10000;
SHOW STATUS LIKE 'handler_read__e%';
FLUSH STATUS;
DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x
- FROM t1) > 10000;
+ FROM t1 WHERE a = 1 AND b = 1) > 10000;
SHOW STATUS LIKE 'handler_read__e%';
DROP TABLE t1,t2,t3;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 30b14209a7c..3bf088609cd 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -144,6 +144,14 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
delete select;
free_underlaid_joins(thd, select_lex);
thd->row_count_func= 0;
+ /*
+ Error was already created by quick select evaluation (check_quick()).
+ TODO: Add error code output parameter to Item::val_xxx() methods.
+ Currently they rely on the user checking DA for
+ errors when unwinding the stack after calling Item::val_xxx().
+ */
+ if (thd->net.report_error)
+ DBUG_RETURN(TRUE);
send_ok(thd,0L);
/*
@@ -407,7 +415,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
if (select_lex->inner_refs_list.elements &&
fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
- DBUG_RETURN(-1);
+ DBUG_RETURN(TRUE);
select_lex->fix_prepare_information(thd, conds, &fake_conds);
DBUG_RETURN(FALSE);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 481fe30c6e7..f95f0a22a71 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -230,7 +230,7 @@ int mysql_update(THD *thd,
if (select_lex->inner_refs_list.elements &&
fix_inner_refs(thd, all_fields, select_lex, select_lex->ref_pointer_array))
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
if (conds)
{
@@ -247,7 +247,14 @@ int mysql_update(THD *thd,
{
delete select;
free_underlaid_joins(thd, select_lex);
- if (error)
+ /*
+ There was an error or the error was already sent by
+ the quick select evaluation.
+ TODO: Add error code output parameter to Item::val_xxx() methods.
+ Currently they rely on the user checking DA for
+ errors when unwinding the stack after calling Item::val_xxx().
+ */
+ if (error || thd->net.report_error)
{
DBUG_RETURN(1); // Error in where
}