diff options
author | Dmitry Shulga <dmitry.shulga@mariadb.com> | 2021-03-02 19:09:44 +0700 |
---|---|---|
committer | Dmitry Shulga <dmitry.shulga@mariadb.com> | 2021-03-02 19:09:44 +0700 |
commit | fc77431624b8d4dc966cd3855c16bee856b05645 (patch) | |
tree | e04790cec7e0d1bb4ccb2bf1457d4f368b8efcb2 | |
parent | dd9e5827a68c7864d61af44a4dea6932f963c55c (diff) | |
download | mariadb-git-fc77431624b8d4dc966cd3855c16bee856b05645.tar.gz |
MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement
Attempt to execute EXPLAIN statement on multi-table DELETE statement
leads to firing firing of the assertion
DBUG_ASSERT(! is_set());
in the method Diagnostics_area::set_eof_status.
For example, above mentioned assertion failure happens
in case any of the following statements
EXPLAIN DELETE FROM t1.* USING t1
EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b
are executed in prepared statement mode provided the table t1
does exist.
This assertion is hit by the reason that a status of
Diagnostics_area is set twice. The first time it is set from
the function do_select() when the method multi_delete::send_eof()
called. The second time it is set when the method
Explain_query::send_explain() calls the method select_send::send_eof
(this method invokes the method Diagnostics_area::set_eof_status that
finally hits assertion)
The second invocation for a setter method of the class Diagnostics_area
is correct and run to send a response containing explain data.
But first invocation of a setter method of the class Diagnostics_area
is wrong since the function do_select() shouldn't be called at all
for handling of the EXPLAIN statement.
The reason by that the function do_select() is called during handling of
the EXPLAIN statement is that the flag SELECT_DESCRIBE not set in the
data member JOIN::select_options. The flag SELECT_DESCRIBE
if is copied from values select_lex->options.
During parsing of EXPLAIN statement this flag is set but latter reset
from the function reinit_stmt_before_use() that is called on
execution of prepared statement.
void reinit_stmt_before_use(THD *thd, LEX *lex)
{
...
for (; sl; sl= sl->next_select_in_list())
{
if (sl->changed_elements & TOUCHED_SEL_COND)
{
/* remove option which was put by mysql_explain_union() */
sl->options&= ~SELECT_DESCRIBE;
...
}
...
}
So, to fix the issue the flag SELECT_DESCRIBE is set forcibly at the
mysql_select() function in case thd->lex->describe set,
that is in case EXPLAIN being executed.
-rw-r--r-- | mysql-test/r/ps.result | 17 | ||||
-rw-r--r-- | mysql-test/t/ps.test | 14 | ||||
-rw-r--r-- | sql/sql_select.cc | 3 |
3 files changed, 34 insertions, 0 deletions
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 076c7d9abda..17284a3cad8 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -5402,5 +5402,22 @@ EXISTS(SELECT 1 FROM t1 GROUP BY a IN (select a from t1)) 0 DROP TABLE t1; # +# MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement +# +CREATE TABLE t1(c1 CHAR(255) PRIMARY KEY); +PREPARE stmt FROM 'EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b'; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE a system NULL NULL NULL NULL 0 const row not found +1 SIMPLE b system NULL NULL NULL NULL 0 const row not found +DROP TABLE t1; +CREATE TABLE t1(a INT); +PREPARE stmt FROM 'EXPLAIN DELETE FROM t1.* USING t1'; +EXECUTE stmt; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 system NULL NULL NULL NULL 0 const row not found +DEALLOCATE PREPARE stmt; +DROP TABLE t1; +# # End of 10.2 tests # diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 1b1f88094ff..a267c8b0e42 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -4913,5 +4913,19 @@ EXECUTE stmt; DROP TABLE t1; --echo # +--echo # MDEV-25006: Failed assertion on executing EXPLAIN DELETE statement as a prepared statement +--echo # + +CREATE TABLE t1(c1 CHAR(255) PRIMARY KEY); +PREPARE stmt FROM 'EXPLAIN DELETE b FROM t1 AS a JOIN t1 AS b'; +EXECUTE stmt; +DROP TABLE t1; +CREATE TABLE t1(a INT); +PREPARE stmt FROM 'EXPLAIN DELETE FROM t1.* USING t1'; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +DROP TABLE t1; + +--echo # --echo # End of 10.2 tests --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index aa3474dff5f..f30ce088bc4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3801,6 +3801,9 @@ mysql_select(THD *thd, } else { + if (thd->lex->describe) + select_options|= SELECT_DESCRIBE; + /* When in EXPLAIN, delay deleting the joins so that they are still available when we're producing EXPLAIN EXTENDED warning text. |