Commit 0c1bdcbd authored by unknown's avatar unknown

A fix for Bug#32030 "DELETE does not return an error and deletes rows if

error evaluating WHERE"

DELETE with a subquery in WHERE clause would sometimes ignore subquery
evaluation error and proceed with deletion.

The fix is to check for an error after evaluation of the WHERE clause
in DELETE.

Addressed review comments.


mysql-test/r/group_min_max.result:
  Update the test results to reflect the fix for Bug#32030.
mysql-test/r/ps.result:
  Update test results (Bug#32030)
mysql-test/t/group_min_max.test:
  Update the test case to reflect the fix for Bug#32030
mysql-test/t/ps.test:
  Add a test case for Bug#32030
sql/sql_delete.cc:
  Check for an error before calling send_ok(). Two different places are
  covered because the subquery code has slightly different execution
  paths depending on ps-protocol/old-protocol
parent ecef8379
...@@ -2299,8 +2299,7 @@ Handler_read_next 0 ...@@ -2299,8 +2299,7 @@ Handler_read_next 0
FLUSH STATUS; FLUSH STATUS;
DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x
FROM t1) > 10000; FROM t1) > 10000;
Warnings: ERROR 21000: Subquery returns more than 1 row
Error 1242 Subquery returns more than 1 row
SHOW STATUS LIKE 'handler_read__e%'; SHOW STATUS LIKE 'handler_read__e%';
Variable_name Value Variable_name Value
Handler_read_key 8 Handler_read_key 8
......
...@@ -2680,4 +2680,24 @@ t1 CREATE TABLE `t1` ( ...@@ -2680,4 +2680,24 @@ t1 CREATE TABLE `t1` (
KEY `c` (`c`(10)) KEY `c` (`c`(10))
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
drop table if exists t1, t2;
Warnings:
Note 1051 Unknown table 't1'
Note 1051 Unknown table 't2'
create table t1 (a int, b int);
create table t2 like t1;
insert into t1 (a, b) values (1,1), (1,2), (1,3), (1,4), (1,5),
(2,2), (2,3), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4), (4,5), (4,6);
insert into t2 select a, max(b) from t1 group by a;
prepare stmt from "delete from t2 where (select (select max(b) from t1 group
by a having a < 2) x from t1) > 10000";
delete from t2 where (select (select max(b) from t1 group
by a having a < 2) x from t1) > 10000;
ERROR 21000: Subquery returns more than 1 row
execute stmt;
ERROR 21000: Subquery returns more than 1 row
execute stmt;
ERROR 21000: Subquery returns more than 1 row
deallocate prepare stmt;
drop table t1, t2;
End of 5.1 tests. End of 5.1 tests.
...@@ -890,6 +890,7 @@ FLUSH STATUS; ...@@ -890,6 +890,7 @@ FLUSH STATUS;
DELETE FROM t3 WHERE (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) > 10000; DELETE FROM t3 WHERE (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) > 10000;
SHOW STATUS LIKE 'handler_read__e%'; SHOW STATUS LIKE 'handler_read__e%';
FLUSH STATUS; FLUSH STATUS;
--error ER_SUBQUERY_NO_1_ROW
DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x DELETE FROM t3 WHERE (SELECT (SELECT MAX(b) FROM t1 GROUP BY a HAVING a < 2) x
FROM t1) > 10000; FROM t1) > 10000;
SHOW STATUS LIKE 'handler_read__e%'; SHOW STATUS LIKE 'handler_read__e%';
......
...@@ -2778,4 +2778,37 @@ execute stmt; ...@@ -2778,4 +2778,37 @@ execute stmt;
show create table t1; show create table t1;
drop table t1; drop table t1;
#
# Bug #32030 DELETE does not return an error and deletes rows if error
# evaluating WHERE
#
# Test that there is an error for prepared delete just like for the normal
# one.
#
drop table if exists t1, t2;
create table t1 (a int, b int);
create table t2 like t1;
insert into t1 (a, b) values (1,1), (1,2), (1,3), (1,4), (1,5),
(2,2), (2,3), (2,1), (3,1), (4,1), (4,2), (4,3), (4,4), (4,5), (4,6);
insert into t2 select a, max(b) from t1 group by a;
prepare stmt from "delete from t2 where (select (select max(b) from t1 group
by a having a < 2) x from t1) > 10000";
--error ER_SUBQUERY_NO_1_ROW
delete from t2 where (select (select max(b) from t1 group
by a having a < 2) x from t1) > 10000;
--error ER_SUBQUERY_NO_1_ROW
execute stmt;
--error ER_SUBQUERY_NO_1_ROW
execute stmt;
deallocate prepare stmt;
drop table t1, t2;
--echo End of 5.1 tests. --echo End of 5.1 tests.
...@@ -35,6 +35,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -35,6 +35,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
READ_RECORD info; READ_RECORD info;
bool using_limit=limit != HA_POS_ERROR; bool using_limit=limit != HA_POS_ERROR;
bool transactional_table, safe_update, const_cond; bool transactional_table, safe_update, const_cond;
bool const_cond_result;
ha_rows deleted= 0; ha_rows deleted= 0;
uint usable_index= MAX_KEY; uint usable_index= MAX_KEY;
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
...@@ -86,6 +87,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -86,6 +87,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
select_lex->no_error= thd->lex->ignore; select_lex->no_error= thd->lex->ignore;
const_cond_result= const_cond && (!conds || conds->val_int());
if (thd->is_error())
{
/* Error evaluating val_int(). */
DBUG_RETURN(TRUE);
}
/* /*
Test if the user wants to delete all rows and deletion doesn't have Test if the user wants to delete all rows and deletion doesn't have
any side-effects (because of triggers), so we can use optimized any side-effects (because of triggers), so we can use optimized
...@@ -105,7 +112,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -105,7 +112,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
- We should not be binlogging this statement row-based, and - We should not be binlogging this statement row-based, and
- there should be no delete triggers associated with the table. - there should be no delete triggers associated with the table.
*/ */
if (!using_limit && const_cond && (!conds || conds->val_int()) && if (!using_limit && const_cond_result &&
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
(thd->lex->sql_command == SQLCOM_TRUNCATE || (thd->lex->sql_command == SQLCOM_TRUNCATE ||
(!thd->current_stmt_binlog_row_based && (!thd->current_stmt_binlog_row_based &&
...@@ -300,7 +307,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -300,7 +307,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
else else
table->file->unlock_row(); // Row failed selection, release lock on it table->file->unlock_row(); // Row failed selection, release lock on it
} }
if (thd->killed && !error) if (thd->killed || thd->is_error())
error= 1; // Aborted error= 1; // Aborted
if (will_batch && (loc_error= table->file->end_bulk_delete())) if (will_batch && (loc_error= table->file->end_bulk_delete()))
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment