MySQL 8.0.39
Source Code Documentation
opt_explain.cc File Reference

"EXPLAIN <command>" implementation. More...

#include "sql/opt_explain.h"
#include <sys/types.h>
#include <algorithm>
#include <atomic>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <functional>
#include <string>
#include <vector>
#include "ft_global.h"
#include "lex_string.h"
#include "m_ctype.h"
#include "m_string.h"
#include "mem_root_deque.h"
#include "my_alloc.h"
#include "my_base.h"
#include "my_bitmap.h"
#include "my_dbug.h"
#include "my_double2ulonglong.h"
#include "my_inttypes.h"
#include "my_sqlcommand.h"
#include "my_sys.h"
#include "my_thread_local.h"
#include "mysql_com.h"
#include "mysqld_error.h"
#include "sql/auth/auth_acls.h"
#include "sql/auth/sql_security_ctx.h"
#include "sql/current_thd.h"
#include "sql/debug_sync.h"
#include "sql/derror.h"
#include "sql/enum_query_type.h"
#include "sql/field.h"
#include "sql/handler.h"
#include "sql/item.h"
#include "sql/item_func.h"
#include "sql/item_subselect.h"
#include "sql/join_optimizer/access_path.h"
#include "sql/join_optimizer/bit_utils.h"
#include "sql/join_optimizer/explain_access_path.h"
#include "sql/key.h"
#include "sql/mysqld.h"
#include "sql/mysqld_thd_manager.h"
#include "sql/opt_costmodel.h"
#include "sql/opt_explain_format.h"
#include "sql/opt_trace.h"
#include "sql/parse_tree_node_base.h"
#include "sql/protocol.h"
#include "sql/query_term.h"
#include "sql/range_optimizer/group_index_skip_scan_plan.h"
#include "sql/range_optimizer/path_helpers.h"
#include "sql/sql_bitmap.h"
#include "sql/sql_class.h"
#include "sql/sql_cmd.h"
#include "sql/sql_const.h"
#include "sql/sql_error.h"
#include "sql/sql_executor.h"
#include "sql/sql_lex.h"
#include "sql/sql_list.h"
#include "sql/sql_opt_exec_shared.h"
#include "sql/sql_optimizer.h"
#include "sql/sql_parse.h"
#include "sql/sql_partition.h"
#include "sql/sql_select.h"
#include "sql/table.h"
#include "sql/table_function.h"
#include "sql/visible_fields.h"
#include "sql_string.h"
#include "template_utils.h"

Classes

class  anonymous_namespace{opt_explain.cc}::Explain
 A base for all Explain_* classes. More...
 
class  anonymous_namespace{opt_explain.cc}::Explain::Lazy_condition
 
class  anonymous_namespace{opt_explain.cc}::Explain_no_table
 Explain_no_table class outputs a trivial EXPLAIN row with "extra" column. More...
 
class  anonymous_namespace{opt_explain.cc}::Explain_setop_result
 Explain_union_result class outputs EXPLAIN row for UNION. More...
 
class  anonymous_namespace{opt_explain.cc}::Explain_table_base
 Common base class for Explain_join and Explain_table. More...
 
class  anonymous_namespace{opt_explain.cc}::Explain_join
 Explain_join class produces EXPLAIN output for JOINs. More...
 
class  anonymous_namespace{opt_explain.cc}::Explain_table
 Explain_table class produce EXPLAIN output for queries without top-level JOIN. More...
 
class  anonymous_namespace{opt_explain.cc}::Explain_secondary_engine
 This class outputs an empty plan for queries that use a secondary engine. More...
 
class  Query_result_null
 A query result handler that outputs nothing. More...
 
class  Find_thd_query_lock
 Callback function used by Sql_cmd_explain_other_thread::execute() to find thd based on the thread id. More...
 

Namespaces

namespace  anonymous_namespace{opt_explain.cc}
 

Typedefs

typedef qep_row::extra extra
 

Functions

static bool mysql_explain_query_expression (THD *explain_thd, const THD *query_thd, Query_expression *unit)
 Explain UNION or subqueries of the unit. More...
 
static bool ExplainIterator (THD *ethd, const THD *query_thd, Query_expression *unit)
 
static bool explain_ref_key (Explain_format *fmt, uint key_parts, store_key *key_copy[])
 
static bool store_table_name (Table_ref *tr, Explain_format *fmt, std::function< bool(const char *name, size_t len)> func)
 Generates either usual table name or <derived::N>, and passes it to any given function for showing to the user. More...
 
static bool explain_no_table (THD *explain_thd, const THD *query_thd, Query_block *query_block, const char *message, enum_parsing_context ctx)
 Send a message as an "extra" column value. More...
 
static bool check_acl_for_explain (const Table_ref *table_list)
 Check that we are allowed to explain all views in list. More...
 
bool explain_single_table_modification (THD *explain_thd, const THD *query_thd, const Modification_plan *plan, Query_block *select)
 EXPLAIN handling for single-table INSERT VALUES, UPDATE, and DELETE queries. More...
 
bool explain_query_specification (THD *explain_thd, const THD *query_thd, Query_term *query_term, enum_parsing_context ctx)
 Explain query_block's join. More...
 
void print_query_for_explain (const THD *query_thd, Query_expression *unit, String *str)
 This code which prints the extended description is not robust against malformed queries, so skip calling this function if we have an error or if explaining other thread (see Explain::can_print_clauses()). More...
 
bool explain_query (THD *explain_thd, const THD *query_thd, Query_expression *unit)
 EXPLAIN handling for SELECT, INSERT/REPLACE SELECT, and multi-table UPDATE/DELETE queries. More...
 

Variables

const char * join_type_str []
 
static const enum_query_type cond_print_flags
 
static const char * plan_not_ready []
 First string: for regular EXPLAIN; second: for EXPLAIN CONNECTION. More...
 

Detailed Description

"EXPLAIN <command>" implementation.

Typedef Documentation

◆ extra

Function Documentation

◆ check_acl_for_explain()

static bool check_acl_for_explain ( const Table_ref table_list)
static

Check that we are allowed to explain all views in list.

Because this function is called only when we have a complete plan, we know that:

  • views contained in merge-able views have been merged and brought up in the top list of tables, so we only need to scan this list
  • table_list is not changing while we are reading it. If we don't have a complete plan, EXPLAIN output does not contain table names, so we don't need to check views.
Parameters
table_listtable to start with, usually lex->query_tables
Returns
true Caller can't EXPLAIN query due to lack of rights on a view in the query false Caller can EXPLAIN query

◆ explain_no_table()

static bool explain_no_table ( THD explain_thd,
const THD query_thd,
Query_block query_block,
const char *  message,
enum_parsing_context  ctx 
)
static

Send a message as an "extra" column value.

This function forms the 1st row of the QEP output with a simple text message. This is useful to explain such trivial cases as "No tables used" etc.

Note
Also this function explains the rest of QEP (subqueries or joined tables if any).
Parameters
explain_thdthread handle for the connection doing explain
query_thdthread handle for the connection being explained
query_blockquery_block to explain
messagetext message for the "extra" column.
ctxcurrent query context, CTX_JOIN in most cases.
Returns
false if success, true if error

◆ explain_query()

bool explain_query ( THD explain_thd,
const THD query_thd,
Query_expression unit 
)

EXPLAIN handling for SELECT, INSERT/REPLACE SELECT, and multi-table UPDATE/DELETE queries.

Send to the client a QEP data set for any DML statement that has a QEP represented completely by JOIN object(s).

This function uses a specific Query_result object for sending explain output to the client.

When explaining own query, the existing Query_result object (found in outermost Query_expression or Query_block) is used. However, if the Query_result is unsuitable for explanation (need_explain_interceptor() returns true), wrap the Query_result inside an Query_result_explain object.

When explaining other query, create a Query_result_send object and prepare it as if it was a regular SELECT query.

Note
see explain_single_table_modification() for single-table UPDATE/DELETE EXPLAIN handling.
explain_query() calls abort_result_set() itself in the case of failure (OOM etc.) since it may use an internally created Query_result object that has to be deleted before exiting the function.
Parameters
explain_thdthread handle for the connection doing explain
query_thdthread handle for the connection being explained
unitquery tree to explain
Returns
false if success, true if error

◆ explain_query_specification()

bool explain_query_specification ( THD explain_thd,
const THD query_thd,
Query_term query_term,
enum_parsing_context  ctx 
)

Explain query_block's join.

Parameters
explain_thdthread handle for the connection doing explain
query_thdthread handle for the connection being explained
query_termexplain join attached to given term's query_block
ctxcurrent explain context

◆ explain_ref_key()

static bool explain_ref_key ( Explain_format fmt,
uint  key_parts,
store_key key_copy[] 
)
static

◆ explain_single_table_modification()

bool explain_single_table_modification ( THD explain_thd,
const THD query_thd,
const Modification_plan plan,
Query_block select 
)

EXPLAIN handling for single-table INSERT VALUES, UPDATE, and DELETE queries.

Send to the client a QEP data set for single-table EXPLAIN INSERT VALUES/UPDATE/DELETE queries. As far as single-table INSERT VALUES/UPDATE/DELETE are implemented without the regular JOIN tree, we can't reuse explain_query_expression() directly, thus we deal with this single table in a special way and then call explain_query_expression() for subqueries (if any).

Parameters
explain_thdthread handle for the connection doing explain
query_thdthread handle for the connection being explained
plantable modification plan
selectQuery's select lex
Returns
false if success, true if error

Prepare the self-allocated result object

For queries with top-level JOIN the caller provides pre-allocated Query_result_send object. Then that JOIN object prepares the Query_result_send object calling result->prepare() in Query_block::prepare(), result->optimize() in JOIN::optimize() and result->start_execution() in JOIN::exec(). However without the presence of the top-level JOIN we have to prepare/initialize Query_result_send object manually.

◆ ExplainIterator()

static bool ExplainIterator ( THD ethd,
const THD query_thd,
Query_expression unit 
)
static

◆ mysql_explain_query_expression()

bool mysql_explain_query_expression ( THD explain_thd,
const THD query_thd,
Query_expression unit 
)
static

Explain UNION or subqueries of the unit.

If the unit is a UNION, explain it as a UNION. Otherwise explain nested subselects.

Parameters
explain_thdthread handle for the connection doing explain
query_thdthread handle for the connection being explained
unitunit object, might not belong to ethd
Returns
false if success, true if error

◆ print_query_for_explain()

void print_query_for_explain ( const THD query_thd,
Query_expression unit,
String str 
)

This code which prints the extended description is not robust against malformed queries, so skip calling this function if we have an error or if explaining other thread (see Explain::can_print_clauses()).

For DML statements use QT_NO_DATA_EXPANSION to avoid over-simplification.

◆ store_table_name()

static bool store_table_name ( Table_ref tr,
Explain_format fmt,
std::function< bool(const char *name, size_t len)>  func 
)
static

Generates either usual table name or <derived::N>, and passes it to any given function for showing to the user.

Parameters
trTable reference
fmtEXPLAIN's format
funcFunction receiving the name
Returns
true if error.

Variable Documentation

◆ cond_print_flags

const enum_query_type cond_print_flags
static
Initial value:
=
enum_query_type
Query type constants (usable as bitmap flags).
Definition: enum_query_type.h:31
@ QT_ORDINARY
Nothing specific, ordinary SQL query.
Definition: enum_query_type.h:33
@ QT_SHOW_SELECT_NUMBER
When printing a SELECT, add its number (query_block->number).
Definition: enum_query_type.h:48

◆ join_type_str

const char* join_type_str[]
Initial value:
= {
"UNKNOWN", "system", "const", "eq_ref", "ref", "ALL",
"range", "index", "fulltext", "ref_or_null", "index_merge"}

◆ plan_not_ready

const char* plan_not_ready[]
static
Initial value:
= {"Not optimized, outer query is empty",
"Plan isn't ready yet"}

First string: for regular EXPLAIN; second: for EXPLAIN CONNECTION.