diff --git a/mysql-test/r/show_explain.result b/mysql-test/r/show_explain.result index d6c46c81c79..aa473eafd9b 100644 --- a/mysql-test/r/show_explain.result +++ b/mysql-test/r/show_explain.result @@ -153,10 +153,7 @@ set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_end'; select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1 +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a (select max(a) from t0 b where b.a+a.a<10) 0 9 # Try to do SHOW EXPLAIN for a query that runs a SET command: @@ -308,12 +305,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using join buffer (flat, BNL join) set debug_dbug='d,show_explain_in_find_all_keys'; SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; -# NOTE: current code will not show "Using join buffer": +# FIXED by "conservative assumptions about when QEP is available" fix: +# NOTE: current code will not show "Using join buffer": show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a 1 2 @@ -366,10 +361,7 @@ set @show_explain_probe_select_id=2; set debug_dbug='d,show_explain_probe_join_exec_end'; SELECT * FROM v1, t2; show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Not yet optimized -Warnings: -Note 1003 SELECT * FROM v1, t2 +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a b 8 4 8 5 @@ -401,10 +393,7 @@ set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_end'; select * from t0 where 1>10; show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 select * from t0 where 1>10 +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a set debug_dbug=''; # @@ -416,10 +405,7 @@ set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_end'; select * from t0,t3 where t3.a=112233; show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 select * from t0,t3 where t3.a=112233 +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command a a set debug_dbug=''; drop table t3; @@ -524,10 +510,7 @@ set @show_explain_probe_select_id=1; set debug_dbug='d,show_explain_probe_join_exec_end'; SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`); show explain for $thr2; -id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Query plan already deleted -Warnings: -Note 1003 SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`) +ERROR HY000: Error when executing command SHOW EXPLAIN: Target is not running EXPLAINable command pk a1 set debug_dbug=''; DROP TABLE t2; @@ -616,4 +599,30 @@ t1 1 b 1 b A NULL NULL NULL YES BTREE t1 1 c 1 c A NULL NULL NULL YES BTREE set debug_dbug=''; DROP TABLE t1; +# +# MDEV-324: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN for a query with TEMPTABLE view +# loses 'DERIVED' line on the way without saying that the plan was already deleted +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +EXPLAIN SELECT a + 1 FROM v1; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 2 +2 DERIVED t1 ALL NULL NULL NULL NULL 2 +set debug_dbug='d,show_explain_probe_join_tab_preread'; +set @show_explain_probe_select_id=1; +SELECT a + 1 FROM v1; +show explain for $thr2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL NULL NULL NULL NULL 2 +2 DERIVED NULL NULL NULL NULL NULL NULL NULL Query plan already deleted +Warnings: +Note 1003 SELECT a + 1 FROM v1 +a + 1 +2 +3 +set debug_dbug=''; +DROP VIEW v1; +DROP TABLE t1; drop table t0; diff --git a/mysql-test/t/show_explain.test b/mysql-test/t/show_explain.test index 5605e304bcc..8f6b6301671 100644 --- a/mysql-test/t/show_explain.test +++ b/mysql-test/t/show_explain.test @@ -191,6 +191,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; send select a, (select max(a) from t0 b where b.a+a.a<10) from t0 a where a<1; connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -325,7 +326,9 @@ send SELECT alias.a FROM t2, ( SELECT * FROM t2 ) AS alias GROUP BY alias.a; connection default; --source include/wait_condition.inc ---echo # NOTE: current code will not show "Using join buffer": +--echo # FIXED by "conservative assumptions about when QEP is available" fix: +--echo # NOTE: current code will not show "Using join buffer": +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -374,6 +377,7 @@ send SELECT * FROM v1, t2; connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -403,6 +407,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; send select * from t0 where 1>10; connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -418,6 +423,7 @@ set debug_dbug='d,show_explain_probe_join_exec_end'; send select * from t0,t3 where t3.a=112233; connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -513,6 +519,7 @@ send SELECT * FROM t2 WHERE (5, 78) IN (SELECT `a1`, MAX(`a1`) FROM t2 GROUP BY `a1`); connection default; --source include/wait_condition.inc +--error ER_ERROR_WHEN_EXECUTING_COMMAND evalp show explain for $thr2; connection con1; reap; @@ -601,6 +608,32 @@ set debug_dbug=''; DROP TABLE t1; +--echo # +--echo # MDEV-324: SHOW EXPLAIN: Plan produced by SHOW EXPLAIN for a query with TEMPTABLE view +--echo # loses 'DERIVED' line on the way without saying that the plan was already deleted +--echo # +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; + +EXPLAIN SELECT a + 1 FROM v1; + +set debug_dbug='d,show_explain_probe_join_tab_preread'; +set @show_explain_probe_select_id=1; + +send + SELECT a + 1 FROM v1; +connection default; +--source include/wait_condition.inc +evalp show explain for $thr2; +connection con1; +reap; +set debug_dbug=''; + +DROP VIEW v1; +DROP TABLE t1; + + ## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a ## thread and served together. diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f477c0fe0ec..65ead744ddb 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2356,13 +2356,14 @@ int select_result_explain_buffer::send_data(List &items) } +/* Write all strings out to the output, and free them. */ + void select_result_explain_buffer::flush_data() { List_iterator it(data_rows); String *str; while ((str= it++)) { - /* TODO: write out the lines. */ protocol->set_packet(str->ptr(), str->length()); protocol->write(); delete str; @@ -2370,6 +2371,20 @@ void select_result_explain_buffer::flush_data() data_rows.empty(); } + +/* Just free all of the accumulated strings */ + +void select_result_explain_buffer::discard_data() +{ + List_iterator it(data_rows); + String *str; + while ((str= it++)) + { + delete str; + } + data_rows.empty(); +} + ////////////////////////////////////////////////////////////////////////////// @@ -3288,6 +3303,7 @@ void Show_explain_request::get_explain_data(void *arg) // Actually, change the ARENA, because we're going to allocate items! Query_arena backup_arena; THD *target_thd= req->target_thd; + bool printed_anything= FALSE; target_thd->set_n_backup_active_arena((Query_arena*)req->request_thd, &backup_arena); @@ -3296,7 +3312,11 @@ void Show_explain_request::get_explain_data(void *arg) target_thd->query_length(), &my_charset_bin); - if (target_thd->lex->unit.print_explain(req->explain_buf, 0 /* explain flags */)) + if (target_thd->lex->unit.print_explain(req->explain_buf, 0 /* explain flags*/, + &printed_anything)) + req->failed_to_produce= TRUE; + + if (!printed_anything) req->failed_to_produce= TRUE; target_thd->restore_active_arena((Query_arena*)req->request_thd, diff --git a/sql/sql_class.h b/sql/sql_class.h index 6be477605f1..0d58bb413f0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3328,6 +3328,8 @@ public: /* this will be called in the parent thread: */ void flush_data(); + void discard_data(); + List data_rows; }; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index df0fcd24249..99320d88702 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4074,7 +4074,8 @@ int print_explain_message_line(select_result_sink *result, int st_select_lex::print_explain(select_result_sink *output, - uint8 explain_flags) + uint8 explain_flags, + bool *printed_anything) { int res; if (join && join->have_query_plan == JOIN::QEP_AVAILABLE) @@ -4083,6 +4084,7 @@ int st_select_lex::print_explain(select_result_sink *output, There is a number of reasons join can be marked as degenerate, so all three conditions below can happen simultaneously, or individually: */ + *printed_anything= TRUE; if (!join->table_count || !join->tables_list || join->zero_result_cause) { /* It's a degenerate join */ @@ -4112,7 +4114,8 @@ int st_select_lex::print_explain(select_result_sink *output, */ if (!(unit->item && unit->item->eliminated)) { - unit->print_explain(output, explain_flags); + if ((res= unit->print_explain(output, explain_flags, printed_anything))) + goto err; } } } @@ -4120,7 +4123,9 @@ int st_select_lex::print_explain(select_result_sink *output, { const char *msg; if (!join) - DBUG_ASSERT(0); // psergey: TODO: can this happen or not? + DBUG_ASSERT(0); /* Seems not to be possible */ + + /* Not printing anything useful, don't touch *printed_anything here */ if (join->have_query_plan == JOIN::QEP_NOT_PRESENT_YET) msg= "Not yet optimized"; else @@ -4132,12 +4137,12 @@ int st_select_lex::print_explain(select_result_sink *output, 0, msg); } err: - return 0; + return res; } int st_select_lex_unit::print_explain(select_result_sink *output, - uint8 explain_flags) + uint8 explain_flags, bool *printed_anything) { int res= 0; SELECT_LEX *first= first_select(); @@ -4148,12 +4153,15 @@ int st_select_lex_unit::print_explain(select_result_sink *output, If there is only one child, 'first', and it has join==NULL, emit "not in EXPLAIN state" error. */ - return 1; + const char *msg="Query plan already deleted"; + res= print_explain_message_line(output, first, TRUE /* on_the_fly */, + 0, msg); + return 0; } for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) { - if ((res= sl->print_explain(output, explain_flags))) + if ((res= sl->print_explain(output, explain_flags, printed_anything))) break; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 911a6b766f6..eb908089479 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -718,7 +718,8 @@ public: friend int subselect_union_engine::exec(); List *get_unit_column_types(); - int print_explain(select_result_sink *output, uint8 explain_flags); + int print_explain(select_result_sink *output, uint8 explain_flags, + bool *printed_anything); }; typedef class st_select_lex_unit SELECT_LEX_UNIT; @@ -1039,7 +1040,8 @@ public: bool save_prep_leaf_tables(THD *thd); bool is_merged_child_of(st_select_lex *ancestor); - int print_explain(select_result_sink *output, uint8 explain_flags); + int print_explain(select_result_sink *output, uint8 explain_flags, + bool *printed_anything); /* For MODE_ONLY_FULL_GROUP_BY we need to maintain two flags: - Non-aggregated fields are used in this select. diff --git a/sql/sql_select.cc b/sql/sql_select.cc index aba5c0761c8..5aa69f54fa3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10365,9 +10365,18 @@ bool JOIN_TAB::preread_init() mysql_handle_single_derived(join->thd->lex, derived, DT_CREATE | DT_FILL)) return TRUE; + preread_init_done= TRUE; if (select && select->quick) select->quick->replace_handler(table->file); + + DBUG_EXECUTE_IF("show_explain_probe_join_tab_preread", + if (dbug_user_var_equals_int(join->thd, + "show_explain_probe_select_id", + join->select_lex->select_number)) + dbug_serve_apcs(join->thd, 1); + ); + return FALSE; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5079e82fa40..9f0adf4a608 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2085,6 +2085,7 @@ void mysqld_show_explain(THD *thd, ulong thread_id) "Target is not running EXPLAINable command"); } bres= TRUE; + explain_buf->discard_data(); } else {