From 6bc2e9338127cf9e97fa76cc97ab23f9c929991b Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Fri, 21 Oct 2022 12:04:00 +0300 Subject: 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). --- sql/sql_explain.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'sql/sql_explain.cc') diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index 8690a4a38bb..1ac17de2663 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -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; -- cgit v1.2.1