Commit b4abe7c9 authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-22993: Crash on EXPLAIN with PUSHED DOWN SELECT and subquery

- select_describe() should not attempt to produce query plans
  for subqueries if the query is handled by a Select Handler.

- JOIN::save_explain_data_intern should not add links to Explain_select
  for children selects if:
  1. The whole query is handled by the Select Handler, or
  2. this select (and so its children) is handled by Derived Handler.
parent b80b5239
...@@ -209,7 +209,6 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -209,7 +209,6 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t3 ALL NULL NULL NULL NULL 7 1 PRIMARY t3 ALL NULL NULL NULL NULL 7
1 PRIMARY <derived2> ref key0 key0 18 federated.t3.name 2 1 PRIMARY <derived2> ref key0 key0 18 federated.t3.name 2
2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL 2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL
3 MATERIALIZED t2 ALL NULL NULL NULL NULL 7 Using temporary
ANALYZE FORMAT=JSON ANALYZE FORMAT=JSON
SELECT * SELECT *
FROM federated.t3, (SELECT t1.name FROM federated.t1 FROM federated.t3, (SELECT t1.name FROM federated.t1
...@@ -251,25 +250,7 @@ ANALYZE ...@@ -251,25 +250,7 @@ ANALYZE
"select_id": 2, "select_id": 2,
"table": { "table": {
"message": "Pushed derived" "message": "Pushed derived"
}, }
"subqueries": [
{
"query_block": {
"select_id": 3,
"temporary_table": {
"table": {
"table_name": "t2",
"access_type": "ALL",
"r_loops": 0,
"rows": 7,
"r_rows": null,
"filtered": 100,
"r_filtered": null
}
}
}
}
]
} }
} }
} }
...@@ -319,6 +300,78 @@ select @var; ...@@ -319,6 +300,78 @@ select @var;
@var @var
xxx xxx
select name into outfile 'tmp.txt' from federated.t1; select name into outfile 'tmp.txt' from federated.t1;
#
# MDEV-22993: Crash on EXPLAIN with PUSHED DOWN SELECT and subquery
#
explain
select * from federated.t1
where name in (select name from federated.t2);
id select_type table type possible_keys key key_len ref rows Extra
1 PUSHED SELECT NULL NULL NULL NULL NULL NULL NULL NULL
explain format=json
select * from federated.t1
where name in (select name from federated.t2);
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"message": "Pushed select"
}
}
}
#
# MDEV-22993, testcase #2: EXPLAIN output doesn't make sense when
# derived table pushdown is used.
#
create table t5 (a int) engine=myisam;
insert into t5 values (1),(2);
# Must not show lines with id=3
explain
select * from t5,
(select id from federated.t1
where name in (select name from federated.t2) or name like 'foo%') as TQ;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t5 ALL NULL NULL NULL NULL 2
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join)
2 PUSHED DERIVED NULL NULL NULL NULL NULL NULL NULL NULL
# Must not show elements with select_id=3
explain format=json
select * from t5,
(select id from federated.t1
where name in (select name from federated.t2) or name like 'foo%') as TQ;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "t5",
"access_type": "ALL",
"rows": 2,
"filtered": 100
},
"block-nl-join": {
"table": {
"table_name": "<derived2>",
"access_type": "ALL",
"rows": 5,
"filtered": 100
},
"buffer_type": "flat",
"buffer_size": "65",
"join_type": "BNL",
"materialized": {
"query_block": {
"select_id": 2,
"table": {
"message": "Pushed derived"
}
}
}
}
}
}
drop table t5;
DROP TABLE federated.t1, federated.t2, federated.t3, federated.t4; DROP TABLE federated.t1, federated.t2, federated.t3, federated.t4;
connection slave; connection slave;
DROP TABLE federated.t1, federated.t2; DROP TABLE federated.t1, federated.t2;
......
...@@ -167,6 +167,40 @@ select name into outfile 'tmp.txt' from federated.t1; ...@@ -167,6 +167,40 @@ select name into outfile 'tmp.txt' from federated.t1;
let $path=`select concat(@@datadir, 'test/tmp.txt')`; let $path=`select concat(@@datadir, 'test/tmp.txt')`;
remove_file $path; remove_file $path;
--echo #
--echo # MDEV-22993: Crash on EXPLAIN with PUSHED DOWN SELECT and subquery
--echo #
explain
select * from federated.t1
where name in (select name from federated.t2);
explain format=json
select * from federated.t1
where name in (select name from federated.t2);
--echo #
--echo # MDEV-22993, testcase #2: EXPLAIN output doesn't make sense when
--echo # derived table pushdown is used.
--echo #
create table t5 (a int) engine=myisam;
insert into t5 values (1),(2);
--echo # Must not show lines with id=3
explain
select * from t5,
(select id from federated.t1
where name in (select name from federated.t2) or name like 'foo%') as TQ;
--echo # Must not show elements with select_id=3
explain format=json
select * from t5,
(select id from federated.t1
where name in (select name from federated.t2) or name like 'foo%') as TQ;
drop table t5;
DROP TABLE federated.t1, federated.t2, federated.t3, federated.t4; DROP TABLE federated.t1, federated.t2, federated.t3, federated.t4;
connection slave; connection slave;
......
...@@ -26840,24 +26840,33 @@ int JOIN::save_explain_data_intern(Explain_query *output, ...@@ -26840,24 +26840,33 @@ int JOIN::save_explain_data_intern(Explain_query *output,
output->add_node(xpl_sel); output->add_node(xpl_sel);
} }
for (SELECT_LEX_UNIT *tmp_unit= join->select_lex->first_inner_unit(); /*
tmp_unit; Don't try to add query plans for child selects if this select was pushed
tmp_unit= tmp_unit->next_unit()) down into a Smart Storage Engine:
- the entire statement was pushed down ("PUSHED SELECT"), or
- this derived table was pushed down ("PUSHED DERIVED")
*/
if (!select_lex->pushdown_select && select_lex->type != pushed_derived_text)
{ {
/* for (SELECT_LEX_UNIT *tmp_unit= join->select_lex->first_inner_unit();
Display subqueries only if tmp_unit;
(1) they are not parts of ON clauses that were eliminated by table tmp_unit= tmp_unit->next_unit())
elimination. {
(2) they are not merged derived tables /*
(3) they are not hanging CTEs (they are needed for execution) Display subqueries only if
*/ (1) they are not parts of ON clauses that were eliminated by table
if (!(tmp_unit->item && tmp_unit->item->eliminated) && // (1) elimination.
(!tmp_unit->derived || (2) they are not merged derived tables
tmp_unit->derived->is_materialized_derived()) && // (2) (3) they are not hanging CTEs (they are needed for execution)
!(tmp_unit->with_element && */
(!tmp_unit->derived || !tmp_unit->derived->derived_result))) // (3) if (!(tmp_unit->item && tmp_unit->item->eliminated) && // (1)
{ (!tmp_unit->derived ||
explain->add_child(tmp_unit->first_select()->select_number); tmp_unit->derived->is_materialized_derived()) && // (2)
!(tmp_unit->with_element &&
(!tmp_unit->derived || !tmp_unit->derived->derived_result))) // (3)
{
explain->add_child(tmp_unit->first_select()->select_number);
}
} }
} }
...@@ -26890,7 +26899,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, ...@@ -26890,7 +26899,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
THD *thd=join->thd; THD *thd=join->thd;
select_result *result=join->result; select_result *result=join->result;
DBUG_ENTER("select_describe"); DBUG_ENTER("select_describe");
if (join->select_lex->pushdown_select)
{
/*
The whole statement was pushed down to a Smart Storage Engine. Do not
attempt to produce a query plan locally.
*/
DBUG_VOID_RETURN;
}
/* Update the QPF with latest values of using_temporary, using_filesort */ /* Update the QPF with latest values of using_temporary, using_filesort */
for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit();
unit; unit;
......
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