From c6a9fd79047b1ce5b0938a609978e63d9aa04b3a Mon Sep 17 00:00:00 2001 From: Rex Date: Thu, 30 Nov 2023 11:47:44 +1200 Subject: [PATCH] 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) Pushed into 10.5 at Monty's request. Applicable to 10.6, 10.11, 11.0. OK'd by Monty in slack:#askmonty 2023-12-01 --- sql/filesort.h | 7 +++++-- sql/sql_delete.cc | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sql/filesort.h b/sql/filesort.h index 9f71da02c96..7f54de266e6 100644 --- a/sql/filesort.h +++ b/sql/filesort.h @@ -54,8 +54,11 @@ public: /* 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 81c3141c252..ab0d5d35927 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1234,6 +1234,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)) {