Commit 5a5ba7f1 authored by Rex's avatar Rex Committed by Rex Johnston

MDEV-32212 DELETE with ORDER BY and semijoin optimization causing crash

Statements affected by this bug are delete statements that have all
these conditions

1) single table delete syntax
2) and in (sub-query) predicate
3) semi-join optimization enabled
4) an order by clause.

Semijoin optimization on an innocent looking query, such as

DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1;

turns it from a single table delete to a multi-table delete.

During multi_delete::initialize_tables for the top level join object, a
table is initialized missing a keep_current_rowid flag, needed to
position a handler for removal of the correct row after the filesort
structure has been built.

Fix provided by Monty (monty@mariadb.com)
OK'd in slack:#askmonty 2023-12-01
applicable to 11.1 on
parent 2b40f8d2
......@@ -610,4 +610,49 @@ c1 c2 c3
2 1 4
2 2 5
drop table t1;
#
# MDEV-32212 DELETE with ORDER BY and semijoin optimization causing crash
#
CREATE TABLE t1 (c1 INT) ENGINE=InnoDB;
CREATE TABLE t2 (c2 INT) ENGINE=InnoDB;
INSERT INTO t1 values (1),(2),(3),(4),(5),(6);
INSERT INTO t2 values (2);
DELETE FROM t1 WHERE c1 IN (select c2 from t2);
select * from t1;
c1
1
3
4
5
6
truncate t1;
truncate t2;
INSERT INTO t1 values (1),(2),(3),(4),(5),(6);
INSERT INTO t2 values (2);
check sj optimization with order-by
analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using filesort
1 PRIMARY t2 ALL NULL NULL NULL NULL 1 1.00 100.00 16.67 Using where; FirstMatch(t1)
select * from t1;
c1
1
3
4
5
6
truncate t2;
INSERT INTO t2 values (3);
disallows sj optimization
analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1 limit 1;
id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 5 1.00 100.00 100.00 Using where; Using filesort
2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 1 1.00 100.00 20.00 Using where
select * from t1;
c1
1
4
5
6
DROP TABLE t1, t2;
End of 11.1 tests
......@@ -667,4 +667,31 @@ select *from t1;
drop table t1;
--echo #
--echo # MDEV-32212 DELETE with ORDER BY and semijoin optimization causing crash
--echo #
--source include/have_innodb.inc
CREATE TABLE t1 (c1 INT) ENGINE=InnoDB;
CREATE TABLE t2 (c2 INT) ENGINE=InnoDB;
INSERT INTO t1 values (1),(2),(3),(4),(5),(6);
INSERT INTO t2 values (2);
DELETE FROM t1 WHERE c1 IN (select c2 from t2);
select * from t1;
truncate t1;
truncate t2;
INSERT INTO t1 values (1),(2),(3),(4),(5),(6);
INSERT INTO t2 values (2);
--echo check sj optimization with order-by
analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1;
select * from t1;
truncate t2;
INSERT INTO t2 values (3);
--echo disallows sj optimization
analyze DELETE FROM t1 WHERE c1 IN (select c2 from t2) ORDER BY c1 limit 1;
select * from t1;
DROP TABLE t1, t2;
--echo End of 11.1 tests
......@@ -56,8 +56,11 @@ class Filesort: public Sql_alloc
bool using_pq;
/*
TRUE means sort operation must produce table rowids.
FALSE means that it halso has an option of producing {sort_key,
addon_fields} pairs.
FALSE means that it also has an option of producing {sort_key, addon_fields}
pairs.
Usually initialized with value of join_tab->keep_current_rowid to allow for
a call to table->file->position() using these table rowids.
*/
bool sort_positions;
/*
......
......@@ -1054,6 +1054,13 @@ multi_delete::initialize_tables(JOIN *join)
{
TABLE_LIST *tbl= walk->correspondent_table->find_table_for_update();
tables_to_delete_from|= tbl->table->map;
/*
Ensure that filesort re-reads the row from the engine before
delete is called.
*/
join->map2table[tbl->table->tablenr]->keep_current_rowid= true;
if (delete_while_scanning &&
unique_table(thd, tbl, join->tables_list, 0))
{
......
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