Skip to content

Commit

Permalink
MDEV-32212 DELETE with ORDER BY and semijoin optimization causing crash
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mariadb-RexJohnston committed Nov 30, 2023
1 parent 89a5a8d commit c6a9fd7
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 2 deletions.
7 changes: 5 additions & 2 deletions sql/filesort.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ class Filesort: public Sql_alloc

/*
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;

Expand Down
7 changes: 7 additions & 0 deletions sql/sql_delete.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down

0 comments on commit c6a9fd7

Please sign in to comment.