diff --git a/mysql-test/r/heap_btree.result b/mysql-test/r/heap_btree.result index 9db03855c01fb15761c17c00f18831166c14fc7e..7ad0f212d99367c28aa7fbec107bf77b5bad07d3 100644 --- a/mysql-test/r/heap_btree.result +++ b/mysql-test/r/heap_btree.result @@ -336,4 +336,11 @@ a b NULL NULL NULL 1 drop table t1; +# +# bug#39918 - memory (heap) engine crashing while executing self join with delete +# +CREATE TABLE t1(a INT, KEY USING BTREE (a)) ENGINE=MEMORY; +INSERT INTO t1 VALUES(1),(1); +DELETE a1 FROM t1 AS a1, t1 AS a2 WHERE a1.a=a2.a; +DROP TABLE t1; End of 5.0 tests diff --git a/mysql-test/t/heap_btree.test b/mysql-test/t/heap_btree.test index b51eeb27331aa4dc89095abf89bfce240aab9da4..637c6ba1c81b471ef5e91f14afb4958fb983fbd2 100644 --- a/mysql-test/t/heap_btree.test +++ b/mysql-test/t/heap_btree.test @@ -253,5 +253,13 @@ insert into t1 values (1, 1), (3, 3), (2, 2), (NULL, 1), (NULL, NULL), (0, 0); select * from t1 where a is null; drop table t1; +-- echo # +-- echo # bug#39918 - memory (heap) engine crashing while executing self join with delete +-- echo # + +CREATE TABLE t1(a INT, KEY USING BTREE (a)) ENGINE=MEMORY; +INSERT INTO t1 VALUES(1),(1); +DELETE a1 FROM t1 AS a1, t1 AS a2 WHERE a1.a=a2.a; +DROP TABLE t1; --echo End of 5.0 tests diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 1b42e5224914782780e7c372c4bc709f57cc8db1..7b967206305b7e753ed3c78f816695cc15983792 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -582,6 +582,11 @@ int mysql_multi_delete_prepare(THD *thd) } } } + /* + Reset the exclude flag to false so it doesn't interfare + with further calls to unique_table + */ + lex->select_lex.exclude_from_table_unique_test= FALSE; DBUG_RETURN(FALSE); } @@ -617,11 +622,24 @@ multi_delete::initialize_tables(JOIN *join) DBUG_RETURN(1); table_map tables_to_delete_from=0; + delete_while_scanning= 1; for (walk= delete_tables; walk; walk= walk->next_local) + { tables_to_delete_from|= walk->table->map; + if (delete_while_scanning && + unique_table(thd, walk, join->tables_list, false)) + { + /* + If the table we are going to delete from appears + in join, we need to defer delete. So the delete + doesn't interfers with the scaning of results. + */ + delete_while_scanning= 0; + } + } + walk= delete_tables; - delete_while_scanning= 1; for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables; tab < end; tab++)