diff --git a/mysql-test/main/delete.result b/mysql-test/main/delete.result index c4bf335091a..21a3bedcaed 100644 --- a/mysql-test/main/delete.result +++ b/mysql-test/main/delete.result @@ -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 diff --git a/mysql-test/main/delete.test b/mysql-test/main/delete.test index 583d8223168..54d0ed7f014 100644 --- a/mysql-test/main/delete.test +++ b/mysql-test/main/delete.test @@ -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 diff --git a/sql/filesort.h b/sql/filesort.h index ebb521e2adc..8c7931e75e9 100644 --- a/sql/filesort.h +++ b/sql/filesort.h @@ -56,8 +56,11 @@ public: 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; /* diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d0d0d47641e..781980bb8de 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -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)) {