Skip to content

Commit

Permalink
MDEV-22993: Crash on EXPLAIN with PUSHED DOWN SELECT and subquery
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
spetrunia committed Jun 24, 2020
1 parent b80b523 commit b4abe7c
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 38 deletions.
93 changes: 73 additions & 20 deletions mysql-test/suite/federated/federatedx_create_handlers.result
Original file line number Diff line number Diff line change
Expand Up @@ -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 <derived2> ref key0 key0 18 federated.t3.name 2
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
SELECT *
FROM federated.t3, (SELECT t1.name FROM federated.t1
Expand Down Expand Up @@ -251,25 +250,7 @@ ANALYZE
"select_id": 2,
"table": {
"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
}
}
}
}
]
}
}
}
}
Expand Down Expand Up @@ -319,6 +300,78 @@ select @var;
@var
xxx
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;
connection slave;
DROP TABLE federated.t1, federated.t2;
Expand Down
34 changes: 34 additions & 0 deletions mysql-test/suite/federated/federatedx_create_handlers.test
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,40 @@ select name into outfile 'tmp.txt' from federated.t1;
let $path=`select concat(@@datadir, 'test/tmp.txt')`;
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;

connection slave;
Expand Down
54 changes: 36 additions & 18 deletions sql/sql_select.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26840,24 +26840,33 @@ int JOIN::save_explain_data_intern(Explain_query *output,
output->add_node(xpl_sel);
}

for (SELECT_LEX_UNIT *tmp_unit= join->select_lex->first_inner_unit();
tmp_unit;
tmp_unit= tmp_unit->next_unit())
/*
Don't try to add query plans for child selects if this select was pushed
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)
{
/*
Display subqueries only if
(1) they are not parts of ON clauses that were eliminated by table
elimination.
(2) they are not merged derived tables
(3) they are not hanging CTEs (they are needed for execution)
*/
if (!(tmp_unit->item && tmp_unit->item->eliminated) && // (1)
(!tmp_unit->derived ||
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);
for (SELECT_LEX_UNIT *tmp_unit= join->select_lex->first_inner_unit();
tmp_unit;
tmp_unit= tmp_unit->next_unit())
{
/*
Display subqueries only if
(1) they are not parts of ON clauses that were eliminated by table
elimination.
(2) they are not merged derived tables
(3) they are not hanging CTEs (they are needed for execution)
*/
if (!(tmp_unit->item && tmp_unit->item->eliminated) && // (1)
(!tmp_unit->derived ||
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);
}
}
}

Expand Down Expand Up @@ -26890,7 +26899,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
THD *thd=join->thd;
select_result *result=join->result;
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 */
for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit();
unit;
Expand Down

0 comments on commit b4abe7c

Please sign in to comment.