From 18fec5128b6fd9712f63e306f03f16833f2599b2 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 12 Feb 2013 08:20:14 +0400 Subject: EXPLAIN DELETE for MariaDB - Backported the code to 10.0-base - Removed incorrect assert --- sql/sql_lex.cc | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b8ce3b6720e..74e4b3e1162 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -448,6 +448,7 @@ void lex_start(THD *thd) lex->thd= lex->unit.thd= thd; + lex->delete_plan= NULL; lex->context_stack.empty(); lex->unit.init_query(); lex->unit.init_select(); @@ -2557,6 +2558,7 @@ LEX::LEX() INITIAL_LEX_PLUGIN_LIST_SIZE, 0); reset_query_tables_list(TRUE); mi.init(); + delete_plan= NULL; } @@ -4166,12 +4168,17 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) return all_merged; } - -int print_explain_message_line(select_result_sink *result, - SELECT_LEX *select_lex, - bool on_the_fly, - uint8 options, - const char *message); +int LEX::print_explain(select_result_sink *output, uint8 explain_flags, + bool *printed_anything) +{ + if (delete_plan) + { + delete_plan->print_explain(output, explain_flags, printed_anything); + return 0; + } + int res= unit.print_explain(output, explain_flags, printed_anything); + return res; +} int st_select_lex::print_explain(select_result_sink *output, @@ -4235,8 +4242,9 @@ int st_select_lex::print_explain(select_result_sink *output, DBUG_ASSERT(join->have_query_plan == JOIN::QEP_DELETED); msg= "Query plan already deleted"; } - res= print_explain_message_line(output, this, TRUE /* on_the_fly */, - 0, msg); + set_explain_type(TRUE/* on_the_fly */); + res= print_explain_message_line(output, 0/*options*/, select_number, type, + msg); } err: return res; @@ -4256,9 +4264,10 @@ int st_select_lex_unit::print_explain(select_result_sink *output, EXPLAIN state" error. */ const char *msg="Query plan already deleted"; - res= print_explain_message_line(output, first, TRUE /* on_the_fly */, - 0, msg); - return 0; + first->set_explain_type(TRUE/* on_the_fly */); + res= print_explain_message_line(output, 0/*options*/, first->select_number, + first->type, msg); + return res; } for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) -- cgit v1.2.1 From d2995031d9214206689660069024525808c8a683 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 12 Feb 2013 14:37:08 +0400 Subject: SHOW EXPLAIN for MariaDB - Support [SHOW] EXPLAIN UPDATE (needs code cleanup). --- sql/sql_lex.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 74e4b3e1162..714ab373b17 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -448,7 +448,7 @@ void lex_start(THD *thd) lex->thd= lex->unit.thd= thd; - lex->delete_plan= NULL; + lex->upd_del_plan= NULL; lex->context_stack.empty(); lex->unit.init_query(); lex->unit.init_select(); @@ -2558,7 +2558,7 @@ LEX::LEX() INITIAL_LEX_PLUGIN_LIST_SIZE, 0); reset_query_tables_list(TRUE); mi.init(); - delete_plan= NULL; + upd_del_plan= NULL; } @@ -4171,9 +4171,9 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) int LEX::print_explain(select_result_sink *output, uint8 explain_flags, bool *printed_anything) { - if (delete_plan) + if (upd_del_plan) { - delete_plan->print_explain(output, explain_flags, printed_anything); + upd_del_plan->print_explain(output, explain_flags, printed_anything); return 0; } int res= unit.print_explain(output, explain_flags, printed_anything); -- cgit v1.2.1 From 03691a77718c781469b5675c6b03d6064255debb Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Mon, 17 Jun 2013 11:59:38 +0400 Subject: SHOW EXPLAIN UPDATE/DELETE - Introduce "Query Plan Footprints" (abbrev. QPFs) QPF is a part of query plan that is 1. sufficient to produce EXPLAIN output, 2. can be used to produce EXPLAIN output even after its subquery/union was executed and deleted 3. is cheap to save so that we can always save query plans - This patch doesn't fully address #2, we make/save strings for a number of EXPLAIN's columns. This will be fixed. --- sql/sql_lex.cc | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 3 deletions(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 1d2490666ea..b2d4ca13823 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4172,6 +4172,7 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) return all_merged; } + int LEX::print_explain(select_result_sink *output, uint8 explain_flags, bool *printed_anything) { @@ -4180,11 +4181,87 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags, upd_del_plan->print_explain(output, explain_flags, printed_anything); return 0; } - int res= unit.print_explain(output, explain_flags, printed_anything); - return res; + //int res= unit.print_explain(output, explain_flags, printed_anything); + + //psergey-todo: here, we should make Query Plan Footprint, and then produce + // an EXPLAIN output from it. + /* + The new, QueryPlanFootprint way: + */ + QPF_query qpf; + unit.save_qpf(&qpf); + //return res; + return 0; } +void st_select_lex::save_qpf(QPF_query *output) +{ + int res; + if (join && join->have_query_plan == JOIN::QEP_AVAILABLE) + { + /* + There is a number of reasons join can be marked as degenerate, so all + three conditions below can happen simultaneously, or individually: + */ + if (!join->table_count || !join->tables_list || join->zero_result_cause) + { + /* It's a degenerate join */ + const char *cause= join->zero_result_cause ? join-> zero_result_cause : + "No tables used"; + res= join->save_qpf(output, FALSE, FALSE, FALSE, cause); + } + else + { + join->save_qpf(output, join->need_tmp, // need_tmp_table + !join->skip_sort_order && !join->no_order && + (join->order || join->group_list), // bool need_order + join->select_distinct, // bool distinct + NULL); //const char *message + } + if (res) + goto err; + + for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); + unit; + unit= unit->next_unit()) + { + /* + Display subqueries only if they are not parts of eliminated WHERE/ON + clauses. + */ + if (!(unit->item && unit->item->eliminated)) + { + unit->save_qpf(output); + } + } + } + else + { + const char *msg; + if (!join) + 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 + { + DBUG_ASSERT(join->have_query_plan == JOIN::QEP_DELETED); + msg= "Query plan already deleted"; + } + set_explain_type(TRUE/* on_the_fly */); + QPF_select *qp_sel= new QPF_select; + qp_sel->select_id= select_number; + qp_sel->select_type= type; + qp_sel->message= msg; + output->add_node(qp_sel); + } +err: + return ;//res; +} + +#if 0 int st_select_lex::print_explain(select_result_sink *output, uint8 explain_flags, bool *printed_anything) @@ -4253,8 +4330,60 @@ int st_select_lex::print_explain(select_result_sink *output, err: return res; } +#endif + + +int st_select_lex_unit::save_qpf(QPF_query *output) +{ + //int res= 0; + SELECT_LEX *first= first_select(); + + QPF_union *qpfu= new QPF_union; + /* + TODO: The following code should be eliminated. If we have a capability to + save Query Plan Footprints, we should just save them, and never need to + print "query plan already deleted". + */ + if (first && !first->next_select() && !first->join) + { + /* + If there is only one child, 'first', and it has join==NULL, emit "not in + EXPLAIN state" error. + */ + const char *msg="Query plan already deleted"; + first->set_explain_type(TRUE/* on_the_fly */); + + QPF_select *qp_sel= new QPF_select; + qp_sel->select_id= first->select_number; + qp_sel->select_type= first->type; + qp_sel->message= msg; + output->add_node(qp_sel); + qpfu->add_select(qp_sel->select_id); + return 0; + } + + for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) + { + sl->save_qpf(output); + qpfu->add_select(sl->select_number); + } + // Save the UNION node + output->add_node(qpfu); +#if 0 + /* Note: fake_select_lex->join may be NULL or non-NULL at this point */ + if (fake_select_lex) + { + res= print_fake_select_lex_join(output, TRUE /* on the fly */, + fake_select_lex, explain_flags); + } + return res; +#endif + return 0; +} + +#if 0 int st_select_lex_unit::print_explain(select_result_sink *output, uint8 explain_flags, bool *printed_anything) { @@ -4288,7 +4417,7 @@ int st_select_lex_unit::print_explain(select_result_sink *output, } return res; } - +#endif /** A routine used by the parser to decide whether we are specifying a full -- cgit v1.2.1 From 1951d40a88e3b3fc0d2fac2ba3358d887e738485 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Tue, 18 Jun 2013 21:08:34 +0400 Subject: [SHOW] EXPLAIN UPDATE/DELETE, code re-structuring - Make EXPLAIN UPDATE/DELETE use "Query Plan Footprints", too. --- sql/sql_lex.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b2d4ca13823..bc16f61b77e 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -448,7 +448,6 @@ void lex_start(THD *thd) lex->thd= lex->unit.thd= thd; - lex->upd_del_plan= NULL; lex->context_stack.empty(); lex->unit.init_query(); lex->unit.init_select(); @@ -2561,7 +2560,6 @@ LEX::LEX() INITIAL_LEX_PLUGIN_LIST_SIZE, 0); reset_query_tables_list(TRUE); mi.init(); - upd_del_plan= NULL; } @@ -4176,11 +4174,11 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) int LEX::print_explain(select_result_sink *output, uint8 explain_flags, bool *printed_anything) { - if (upd_del_plan) + /* if (upd_del_plan) { upd_del_plan->print_explain(output, explain_flags, printed_anything); return 0; - } + }*/ //int res= unit.print_explain(output, explain_flags, printed_anything); //psergey-todo: here, we should make Query Plan Footprint, and then produce -- cgit v1.2.1 From 0a560289aaa8c17e3f1930871088f43efce641e8 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 20 Jun 2013 15:15:24 +0400 Subject: [SHOW] EXPLAIN UPDATE/DELETE, code re-structuring - Introduce back QueryPlan/QueryPlanFootprint separation for single-table UPDATEs/DELETEs - Create an empty QueryPlanFootprint for all kinds of queries --- sql/sql_lex.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index bc16f61b77e..6ad7b288a4b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -447,6 +447,8 @@ void lex_start(THD *thd) DBUG_ENTER("lex_start"); lex->thd= lex->unit.thd= thd; + + lex->query_plan_footprint= NULL; lex->context_stack.empty(); lex->unit.init_query(); -- cgit v1.2.1 From 52cfa54c1d211a17a9df7c38a4568ddc4d09e6d9 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 20 Jun 2013 20:58:26 +0400 Subject: [SHOW] EXPLAIN UPDATE/DELETE, code re-structuring Single table UPDATE/DELETE - Correctly print type=SIMPLE vs type=PRIMARY - Handle UPDATE/DELETE of mergeable VIEWs: we get the VIEW's select as the first subquery. (MySQL 5.6 doesn't print it because it finds that the subquery is not attached to any select) --- sql/sql_lex.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6ad7b288a4b..455ef55944d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4337,6 +4337,13 @@ int st_select_lex_unit::save_qpf(QPF_query *output) { //int res= 0; SELECT_LEX *first= first_select(); + + if (!first->next_select()) + { + /* This is a 1-way UNION, i.e. not really a UNION */ + first->save_qpf(output); + return 0; + } QPF_union *qpfu= new QPF_union; /* -- cgit v1.2.1 From ab4a13b2b91e260d8c75a3c41b7ff5c24747cee0 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 20 Jun 2013 22:30:30 +0400 Subject: Switching [EXPLAIN] UPDATE/DELETE to rely on query plan footprints. This requires that subselect's footprints are saved before it is deleted. Attempt to save select's QPF exposes one to a variety of edge cases: - the select may be a UNION's "fake select" which has no valid id - optimization may fail in the middle (but subsequent JOIN::optimize() calls will succeed, despite the fact that there never was a query plan) --- sql/sql_lex.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 455ef55944d..3161dc85fb9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4341,7 +4341,8 @@ int st_select_lex_unit::save_qpf(QPF_query *output) if (!first->next_select()) { /* This is a 1-way UNION, i.e. not really a UNION */ - first->save_qpf(output); + if (!output->get_select(first->select_number)) + first->save_qpf(output); return 0; } @@ -4371,7 +4372,8 @@ int st_select_lex_unit::save_qpf(QPF_query *output) for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) { - sl->save_qpf(output); + if (!output->get_select(sl->select_number)) + sl->save_qpf(output); qpfu->add_select(sl->select_number); } -- cgit v1.2.1 From af5e128e50cac8881f7bfca44cc473600abdce86 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Fri, 21 Jun 2013 13:26:53 +0400 Subject: [SHOW] EXPLAIN UPDATE/DELETE, code re-structuring - Handle statements inside SPs: = regular statements = SET command, which does not have its own statement. - Handle execution of subquery from range optimizer: allocate subquery QPFs on the same MEM_ROOT as the whole query plan was allocated. --- sql/sql_lex.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3161dc85fb9..df38d9fcdb0 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4251,7 +4251,7 @@ void st_select_lex::save_qpf(QPF_query *output) msg= "Query plan already deleted"; } set_explain_type(TRUE/* on_the_fly */); - QPF_select *qp_sel= new QPF_select; + QPF_select *qp_sel= new (output->mem_root) QPF_select; qp_sel->select_id= select_number; qp_sel->select_type= type; qp_sel->message= msg; @@ -4346,7 +4346,7 @@ int st_select_lex_unit::save_qpf(QPF_query *output) return 0; } - QPF_union *qpfu= new QPF_union; + QPF_union *qpfu= new (output->mem_root) QPF_union; /* TODO: The following code should be eliminated. If we have a capability to save Query Plan Footprints, we should just save them, and never need to @@ -4361,7 +4361,7 @@ int st_select_lex_unit::save_qpf(QPF_query *output) const char *msg="Query plan already deleted"; first->set_explain_type(TRUE/* on_the_fly */); - QPF_select *qp_sel= new QPF_select; + QPF_select *qp_sel= new (output->mem_root)QPF_select; qp_sel->select_id= first->select_number; qp_sel->select_type= first->type; qp_sel->message= msg; -- cgit v1.2.1 From 99a8bfe68cdd6411ed24b3fa465d5dd4b70be6dc Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 27 Jun 2013 01:00:22 +0400 Subject: [SHOW] EXPLAIN UPDATE/DELETE, code re-structuring - Update view.result (old EXPLAIN didn't match the execution) - Put in a stub code to work around the SELECT ... UNION SELECT ... ORDER BY (subuqery) problem --- sql/sql_lex.cc | 182 ++++++++++++++++----------------------------------------- 1 file changed, 50 insertions(+), 132 deletions(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index df38d9fcdb0..c453a599dce 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4172,29 +4172,32 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) return all_merged; } +/* + This is used by SHOW EXPLAIN. It assuses query plan has been already + collected into QPF structures and we only need to print it out. +*/ int LEX::print_explain(select_result_sink *output, uint8 explain_flags, - bool *printed_anything) + bool *printed_anything) //TODO: remove printed_anything { - /* if (upd_del_plan) + int res; + if (query_plan_footprint) { - upd_del_plan->print_explain(output, explain_flags, printed_anything); - return 0; - }*/ - //int res= unit.print_explain(output, explain_flags, printed_anything); - - //psergey-todo: here, we should make Query Plan Footprint, and then produce - // an EXPLAIN output from it. - /* - The new, QueryPlanFootprint way: - */ - QPF_query qpf; - unit.save_qpf(&qpf); - //return res; - return 0; + res= query_plan_footprint->print_explain(output, explain_flags); + *printed_anything= true; + } + else + { + res= 0; + *printed_anything= false; + } + return res; } +/* + +*/ void st_select_lex::save_qpf(QPF_query *output) { int res; @@ -4261,92 +4264,12 @@ err: return ;//res; } -#if 0 -int st_select_lex::print_explain(select_result_sink *output, - uint8 explain_flags, - bool *printed_anything) -{ - int res; - if (join && join->have_query_plan == JOIN::QEP_AVAILABLE) - { - /* - 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 */ - const char *cause= join->zero_result_cause ? join-> zero_result_cause : - "No tables used"; - res= join->print_explain(output, explain_flags, TRUE, FALSE, FALSE, - FALSE, cause); - } - else - { - res= join->print_explain(output, explain_flags, TRUE, - join->need_tmp, // need_tmp_table - !join->skip_sort_order && !join->no_order && - (join->order || join->group_list), // bool need_order - join->select_distinct, // bool distinct - NULL); //const char *message - } - if (res) - goto err; - - for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); - unit; - unit= unit->next_unit()) - { - /* - Display subqueries only if they are not parts of eliminated WHERE/ON - clauses. - */ - if (!(unit->item && unit->item->eliminated)) - { - if ((res= unit->print_explain(output, explain_flags, printed_anything))) - goto err; - } - } - } - else - { - const char *msg; - if (!join) - 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 - { - DBUG_ASSERT(join->have_query_plan == JOIN::QEP_DELETED); - msg= "Query plan already deleted"; - } - set_explain_type(TRUE/* on_the_fly */); - res= print_explain_message_line(output, 0/*options*/, select_number, type, - msg); - } -err: - return res; -} -#endif - -int st_select_lex_unit::save_qpf(QPF_query *output) +int st_select_lex_unit::save_union_qpf(QPF_query *output) { - //int res= 0; SELECT_LEX *first= first_select(); - - if (!first->next_select()) - { - /* This is a 1-way UNION, i.e. not really a UNION */ - if (!output->get_select(first->select_number)) - first->save_qpf(output); - return 0; - } - QPF_union *qpfu= new (output->mem_root) QPF_union; + /* TODO: The following code should be eliminated. If we have a capability to save Query Plan Footprints, we should just save them, and never need to @@ -4380,53 +4303,48 @@ int st_select_lex_unit::save_qpf(QPF_query *output) // Save the UNION node output->add_node(qpfu); -#if 0 - /* Note: fake_select_lex->join may be NULL or non-NULL at this point */ + qpfu->fake_select_type= "UNION RESULT"; + qpfu->using_filesort= test(global_parameters->order_list.first); + return 0; +} + + +int st_select_lex_unit::save_union_qpf_part2(QPF_query *output) +{ + QPF_union *qpfu= output->get_union(first_select()->select_number); if (fake_select_lex) { - res= print_fake_select_lex_join(output, TRUE /* on the fly */, - fake_select_lex, explain_flags); + for (SELECT_LEX_UNIT *unit= fake_select_lex->first_inner_unit(); + unit; unit= unit->next_unit()) + { + if (!(unit->item && unit->item->eliminated)) + { + qpfu->add_child(unit->first_select()->select_number); + } + } } - return res; -#endif return 0; } -#if 0 -int st_select_lex_unit::print_explain(select_result_sink *output, - uint8 explain_flags, bool *printed_anything) + +int st_select_lex_unit::save_qpf(QPF_query *output) { - int res= 0; + //int res= 0; SELECT_LEX *first= first_select(); - - if (first && !first->next_select() && !first->join) - { - /* - If there is only one child, 'first', and it has join==NULL, emit "not in - EXPLAIN state" error. - */ - const char *msg="Query plan already deleted"; - first->set_explain_type(TRUE/* on_the_fly */); - res= print_explain_message_line(output, 0/*options*/, first->select_number, - first->type, msg); - return res; - } - for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) + if (!first->next_select()) { - if ((res= sl->print_explain(output, explain_flags, printed_anything))) - break; + /* This is a 1-way UNION, i.e. not really a UNION */ + if (!output->get_select(first->select_number)) + first->save_qpf(output); + return 0; } - /* Note: fake_select_lex->join may be NULL or non-NULL at this point */ - if (fake_select_lex) - { - res= print_fake_select_lex_join(output, TRUE /* on the fly */, - fake_select_lex, explain_flags); - } - return res; + save_union_qpf(output); + + return 0; } -#endif + /** A routine used by the parser to decide whether we are specifying a full -- cgit v1.2.1 From 8b7bbcf4dca77690091360e5ae7d011fb74554d6 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 27 Jun 2013 16:41:12 +0400 Subject: [SHOW] EXPLAIN UPDATE/DELETE, code re-structuring - Make query plan be re-saved after the first join execution (saving it after JOIN::cleanup is too late because EXPLAIN output is currently produced before that) - Handle QPF allocation/deallocation for edge cases, like unsuccessful BINLOG command. - Work around the problem with UNION's direct subselects not being visible. - Update test results ("Using temporary; Using filesort" are now always printed last in the Extra column) - This cset gets rid of memory leaks/crashes. Some result mismatches still remain. --- sql/sql_lex.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index c453a599dce..2e4eaf5b721 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2552,7 +2552,8 @@ void Query_tables_list::destroy_query_tables_list() */ LEX::LEX() - :result(0), option_type(OPT_DEFAULT), is_lex_started(0), + : query_plan_footprint(NULL), + result(0), option_type(OPT_DEFAULT), is_lex_started(0), limit_rows_examined_cnt(ULONGLONG_MAX) { -- cgit v1.2.1 From d634638c5613683dd0690c1ed40db1bb75877e1c Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 27 Jun 2013 18:52:47 +0400 Subject: [SHOW] EXPLAIN UPDATE/DELETE, code re-structuring - If a subquery is correlated wrt a const table, it will change from being a "DEPENDENT SUBQUERY" into "SUBQUERY", at the end of its parent's JOIN::optimize() call. Handle this, update the subquery's QPF. - Make show_explain.test to work = "Query plan already deleted" does not happen anymore. = Handle special case of queries that don't have top-level selects, like SET x = (SELECT ...) --- sql/sql_lex.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2e4eaf5b721..f5aa84b6f41 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3495,6 +3495,18 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only) is_correlated_unit|= sl->is_correlated; inner_join->select_options= save_options; un->thd->lex->current_select= save_select; + /// psergey: + QPF_query *qpf; + if ((qpf= inner_join->thd->lex->query_plan_footprint)) + { + QPF_select *qp_sel; + if ((qp_sel= qpf->get_select(inner_join->select_lex->select_number))) + { + sl->set_explain_type(TRUE); + qp_sel->select_type= sl->type; + } + } + /// if (empty_union_result) { /* @@ -4182,7 +4194,7 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags, bool *printed_anything) //TODO: remove printed_anything { int res; - if (query_plan_footprint) + if (query_plan_footprint && query_plan_footprint->have_query_plan()) { res= query_plan_footprint->print_explain(output, explain_flags); *printed_anything= true; -- cgit v1.2.1 From c0f7efb1aeeabebe502a786cc461a9d76bf18487 Mon Sep 17 00:00:00 2001 From: Sergey Petrunya Date: Thu, 27 Jun 2013 16:28:57 +0400 Subject: Code cleanup --- sql/sql_lex.cc | 101 +++++++-------------------------------------------------- 1 file changed, 12 insertions(+), 89 deletions(-) (limited to 'sql/sql_lex.cc') diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f5aa84b6f41..9337ed5c356 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -4191,7 +4191,7 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) */ int LEX::print_explain(select_result_sink *output, uint8 explain_flags, - bool *printed_anything) //TODO: remove printed_anything + bool *printed_anything) { int res; if (query_plan_footprint && query_plan_footprint->have_query_plan()) @@ -4209,74 +4209,20 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags, /* - -*/ -void st_select_lex::save_qpf(QPF_query *output) -{ - int res; - if (join && join->have_query_plan == JOIN::QEP_AVAILABLE) - { - /* - There is a number of reasons join can be marked as degenerate, so all - three conditions below can happen simultaneously, or individually: - */ - if (!join->table_count || !join->tables_list || join->zero_result_cause) - { - /* It's a degenerate join */ - const char *cause= join->zero_result_cause ? join-> zero_result_cause : - "No tables used"; - res= join->save_qpf(output, FALSE, FALSE, FALSE, cause); - } - else - { - join->save_qpf(output, join->need_tmp, // need_tmp_table - !join->skip_sort_order && !join->no_order && - (join->order || join->group_list), // bool need_order - join->select_distinct, // bool distinct - NULL); //const char *message - } - if (res) - goto err; + Save query plan of a UNION. The only variable member is whether the union has + "Using filesort". - for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); - unit; - unit= unit->next_unit()) - { - /* - Display subqueries only if they are not parts of eliminated WHERE/ON - clauses. - */ - if (!(unit->item && unit->item->eliminated)) - { - unit->save_qpf(output); - } - } - } - else - { - const char *msg; - if (!join) - DBUG_ASSERT(0); /* Seems not to be possible */ + There is also save_union_qpf_part2() function, which is called before we read + UNION's output. - /* 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 - { - DBUG_ASSERT(join->have_query_plan == JOIN::QEP_DELETED); - msg= "Query plan already deleted"; - } - set_explain_type(TRUE/* on_the_fly */); - QPF_select *qp_sel= new (output->mem_root) QPF_select; - qp_sel->select_id= select_number; - qp_sel->select_type= type; - qp_sel->message= msg; - output->add_node(qp_sel); - } -err: - return ;//res; -} + The reason for it is examples like this: + SELECT col1 FROM t1 UNION SELECT col2 FROM t2 ORDER BY (select ... from t3 ...) + + Here, the (select ... from t3 ...) subquery must be a child of UNION's + st_select_lex. However, it is not connected as child until a very late + stage in execution. +*/ int st_select_lex_unit::save_union_qpf(QPF_query *output) { @@ -4307,11 +4253,7 @@ int st_select_lex_unit::save_union_qpf(QPF_query *output) } for (SELECT_LEX *sl= first; sl; sl= sl->next_select()) - { - if (!output->get_select(sl->select_number)) - sl->save_qpf(output); qpfu->add_select(sl->select_number); - } // Save the UNION node output->add_node(qpfu); @@ -4340,25 +4282,6 @@ int st_select_lex_unit::save_union_qpf_part2(QPF_query *output) } -int st_select_lex_unit::save_qpf(QPF_query *output) -{ - //int res= 0; - SELECT_LEX *first= first_select(); - - if (!first->next_select()) - { - /* This is a 1-way UNION, i.e. not really a UNION */ - if (!output->get_select(first->select_number)) - first->save_qpf(output); - return 0; - } - - save_union_qpf(output); - - return 0; -} - - /** A routine used by the parser to decide whether we are specifying a full partitioning or if only partitions to add or to split. -- cgit v1.2.1