Commit fc774316 authored by Dmitry Shulga's avatar Dmitry Shulga

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.
parent dd9e5827
......@@ -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
#
......@@ -4912,6 +4912,20 @@ EXECUTE stmt;
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 #
......@@ -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.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment