diff options
Diffstat (limited to 'sql/sql_lex.cc')
-rw-r--r-- | sql/sql_lex.cc | 130 |
1 files changed, 126 insertions, 4 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 5f18d9861a9..3c183d95b42 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -503,6 +503,7 @@ void lex_start(THD *thd) lex->expr_allows_subselect= TRUE; lex->use_only_table_context= FALSE; lex->parse_vcol_expr= FALSE; + lex->verbose= 0; lex->name.str= 0; lex->name.length= 0; @@ -1889,6 +1890,7 @@ void st_select_lex::init_query() nest_level= 0; link_next= 0; is_prep_leaf_list_saved= FALSE; + have_merged_subqueries= FALSE; bzero((char*) expr_cache_may_be_used, sizeof(expr_cache_may_be_used)); m_non_agg_field_used= false; m_agg_func_used= false; @@ -3480,7 +3482,7 @@ bool st_select_lex::optimize_unflattened_subqueries(bool const_only) if (options & SELECT_DESCRIBE) { /* Optimize the subquery in the context of EXPLAIN. */ - sl->set_explain_type(); + sl->set_explain_type(FALSE); sl->options|= SELECT_DESCRIBE; inner_join->select_options|= SELECT_DESCRIBE; } @@ -3930,9 +3932,12 @@ void st_select_lex::update_correlated_cache() /** Set the EXPLAIN type for this subquery. + + @param on_the_fly TRUE<=> We're running a SHOW EXPLAIN command, so we must + not change any variables */ -void st_select_lex::set_explain_type() +void st_select_lex::set_explain_type(bool on_the_fly) { bool is_primary= FALSE; if (next_select()) @@ -3954,6 +3959,9 @@ void st_select_lex::set_explain_type() } } + if (on_the_fly && !is_primary && have_merged_subqueries) + is_primary= TRUE; + SELECT_LEX *first= master_unit()->first_select(); /* drop UNCACHEABLE_EXPLAIN, because it is for internal usage only */ uint8 is_uncacheable= (uncacheable & ~UNCACHEABLE_EXPLAIN); @@ -4006,10 +4014,15 @@ void st_select_lex::set_explain_type() else { type= is_uncacheable ? "UNCACHEABLE UNION": "UNION"; + if (this == master_unit()->fake_select_lex) + type= "UNION RESULT"; + } } } - options|= SELECT_DESCRIBE; + + if (!on_the_fly) + options|= SELECT_DESCRIBE; } @@ -4156,6 +4169,116 @@ bool st_select_lex::is_merged_child_of(st_select_lex *ancestor) } +int print_explain_message_line(select_result_sink *result, + SELECT_LEX *select_lex, + bool on_the_fly, + uint8 options, + const char *message); + + +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"; + } + res= print_explain_message_line(output, this, TRUE /* on_the_fly */, + 0, msg); + } +err: + return res; +} + + +int st_select_lex_unit::print_explain(select_result_sink *output, + uint8 explain_flags, bool *printed_anything) +{ + 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"; + 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, printed_anything))) + break; + } + + /* 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; +} + + /** A routine used by the parser to decide whether we are specifying a full partitioning or if only partitions to add or to split. @@ -4174,7 +4297,6 @@ bool LEX::is_partition_management() const alter_info.flags == ALTER_REORGANIZE_PARTITION)); } - #ifdef MYSQL_SERVER uint binlog_unsafe_map[256]; |