1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-23160: SIGSEGV in Explain_node::print_explain_for_children on UNION SELECT

and also MDEV-25564, MDEV-18157.

Attempt to produce EXPLAIN output caused a crash in
Explain_node::print_explain_for_children. The cause of this was that an
Explain_node (actually a derived) had a link to child select#N, but
there was no query plan present for select#N.

The query plan wasn't present because the subquery was eliminated.
- Either it was a degenerate subquery like "(SELECT 1)" in MDEV-25564.
- Or it was a subquery in a UNION subquery's ORDER BY clause:
   col IN (SELECT ... UNION
           SELECT ... ORDER BY (SELECT FROM t1))

In such cases, legacy code structure in subquery/union processing code(*)
makes it hard to detect that the subquery was eliminated, so we end up
with EXPLAIN data structures (Explain_node::children) having dangling
links to child subqueries.
Do make the checks and don't follow the dangling links.

(In ideal world, we should not have these dangling links. But fixing
the code (*) would have high risk for the stable versions).
This commit is contained in:
Sergei Petrunia
2022-10-21 12:04:00 +03:00
parent 0c06320ae9
commit 6bc2e93381
3 changed files with 90 additions and 2 deletions

View File

@ -639,7 +639,11 @@ int Explain_node::print_explain_for_children(Explain_query *query,
for (int i= 0; i < (int) children.elements(); i++)
{
Explain_node *node= query->get_node(children.at(i));
if (node->print_explain(query, output, explain_flags, is_analyze))
/*
Note: node may not be present because for certain kinds of subqueries,
the optimizer is not able to see that they were eliminated.
*/
if (node && node->print_explain(query, output, explain_flags, is_analyze))
return 1;
}
return 0;
@ -683,8 +687,15 @@ void Explain_node::print_explain_json_for_children(Explain_query *query,
for (int i= 0; i < (int) children.elements(); i++)
{
Explain_node *node= query->get_node(children.at(i));
/* Derived tables are printed inside Explain_table_access objects */
/*
Note: node may not be present because for certain kinds of subqueries,
the optimizer is not able to see that they were eliminated.
*/
if (!node)
continue;
/* Derived tables are printed inside Explain_table_access objects */
if (!is_connection_printable_in_json(node->connection_type))
continue;