1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-28201: Server crashes upon SHOW ANALYZE/EXPLAIN FORMAT=JSON

- Describe the lifetime of EXPLAIN data structures in
  sql_explain.h:ExplainDataStructureLifetime.

- Make Item_field::set_field() call set_refers_to_temp_table()
  when it refers to a temp. table.
- Introduce QT_DONT_ACCESS_TMP_TABLES flag for Item::print.
  It directs Item_field::print to not try access its the
  temp table.
- Introduce Explain_query::notify_tables_are_closed()
  and call it right before the query closes its tables.
- Make Explain data stuctures' print_explain_json() methods
  accept "no_tmp_tbl" parameter which means pass
  QT_DONT_ACCESS_TMP_TABLES when printing items.
- Make Show_explain_request::call_in_target_thread() not call
  set_current_thd(). This wasn't needed as the code inside
  lex->print_explain() uses output->thd anyway. output->thd
  refers to the SHOW command's THD object.
This commit is contained in:
Sergei Petrunia
2022-04-04 12:32:22 +03:00
parent 02c3babdec
commit 3f68c2169e
22 changed files with 319 additions and 163 deletions

View File

@ -27,9 +27,8 @@ Query optimization produces two data structures:
produce output of SHOW EXPLAIN, EXPLAIN [FORMAT=JSON], or
ANALYZE [FORMAT=JSON], without accessing the execution data structures.
(the only exception is that Explain data structures keep Item* pointers,
and we require that one might call item->print(QT_EXPLAIN) when printing
FORMAT=JSON output)
The exception is that Explain data structures have Item* pointers. See
ExplainDataStructureLifetime below for details.
=== ANALYZE data ===
EXPLAIN data structures have embedded ANALYZE data structures. These are
@ -135,12 +134,13 @@ public:
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze)=0;
virtual void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze)= 0;
bool is_analyze, bool no_tmp_tbl)= 0;
int print_explain_for_children(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json_for_children(Explain_query *query,
Json_writer *writer, bool is_analyze);
Json_writer *writer, bool is_analyze,
bool no_tmp_tbl);
bool print_explain_json_cache(Json_writer *writer, bool is_analyze);
virtual ~Explain_node(){}
};
@ -174,10 +174,10 @@ public:
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
bool is_analyze, bool no_tmp_tbl);
void print_explain_json_interns(Explain_query *query, Json_writer *writer,
bool is_analyze);
bool is_analyze, bool no_tmp_tbl);
/* A flat array of Explain structs for tables. */
Explain_table_access** join_tabs;
@ -261,7 +261,7 @@ public:
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
bool is_analyze, bool no_tmp_tbl);
Table_access_tracker *get_using_temporary_read_tracker()
{
@ -304,7 +304,8 @@ public:
Explain_aggr_filesort(MEM_ROOT *mem_root, bool is_analyze,
Filesort *filesort);
void print_json_members(Json_writer *writer, bool is_analyze);
void print_json_members(Json_writer *writer, bool is_analyze,
bool no_tmp_tbl);
};
class Explain_aggr_tmp_table : public Explain_aggr_node
@ -325,7 +326,8 @@ class Explain_aggr_window_funcs : public Explain_aggr_node
public:
enum_explain_aggr_node_type get_type() { return AGGR_OP_WINDOW_FUNCS; }
void print_json_members(Json_writer *writer, bool is_analyze);
void print_json_members(Json_writer *writer, bool is_analyze,
bool no_tmp_tbl);
friend class Window_funcs_computation;
};
@ -378,7 +380,7 @@ public:
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
bool is_analyze, bool no_tmp_tbl);
const char *fake_select_type;
bool using_filesort;
@ -417,36 +419,54 @@ class Explain_insert;
/*
Explain structure for a query (i.e. a statement).
This should be able to survive when the query plan was deleted. Currently,
we do not intend for it survive until after query's MEM_ROOT is freed. It
does surivive freeing of query's items.
For reference, the process of post-query cleanup is as follows:
This should be able to survive when the query plan was deleted. Currently,
we do not intend for it survive until after query's MEM_ROOT is freed.
== ExplainDataStructureLifetime ==
>dispatch_command
| >mysql_parse
| | ...
| | lex_end()
| | ...
| | >THD::cleanup_after_query
| | | ...
| | | free_items()
| | | ...
| | <THD::cleanup_after_query
| | ...
| |
| | explain->query_plan_ready(); // (1)
| |
| | some_join->cleanup(); // (2)
| |
| | explain->notify_tables_are_closed(); // (3)
| | close_thread_tables(); // (4)
| | ...
| | free_items(); // (5)
| | ...
| |
| <mysql_parse
|
| log_slow_statement()
|
| log_slow_statement() // (6)
|
| free_root()
|
|
>dispatch_command
That is, the order of actions is:
- free query's Items
- write to slow query log
- free query's MEM_ROOT
(1) - Query plan construction is finished and it is available for reading.
(2) - Temporary tables are freed. After this point,
we need to pass QT_DONT_ACCESS_TMP_TABLES to item->print(). Since
we don't track when #2 happens for each temp.table, we pass this
flag whenever we're printing the query plan for a SHOW command.
Also, we pass it when printing ANALYZE (?)
(3) - Notification about (4).
(4) - Tables used by the query are closed. One known consequence of this is
that the values of the const tables' fields are not available anymore.
We could use the same approach as in QT_DONT_ACCESS_TMP_TABLES to work
around that, but instead we disallow producing FORMAT=JSON output at
step #3. We also processing of SHOW command. The rationale is that
query is close to finish anyway.
(5) - Item objects are freed. After this, it's certainly not possible to
print them into FORMAT=JSON output.
(6) - We may decide to log tabular EXPLAIN output to the slow query log.
*/
class Explain_query : public Sql_alloc
@ -479,14 +499,14 @@ public:
bool print_explain_str(THD *thd, String *out_str, bool is_analyze);
int print_explain_json(select_result_sink *output, bool is_analyze,
bool is_show_cmd,
ulonglong query_time_in_progress_ms= 0);
/* If true, at least part of EXPLAIN can be printed */
bool have_query_plan() { return insert_plan || upd_del_plan|| get_node(1) != NULL; }
void query_plan_ready();
void notify_item_objects_about_to_be_freed();
void notify_tables_are_closed();
MEM_ROOT *mem_root;
@ -501,7 +521,7 @@ private:
Dynamic_array<Explain_union*> unions;
Dynamic_array<Explain_select*> selects;
THD *thd; // for APC start/stop
THD *stmt_thd; // for APC start/stop
bool apc_enabled;
/*
Debugging aid: count how many times add_node() was called. Ideally, it
@ -510,6 +530,9 @@ private:
is unacceptable.
*/
longlong operations;
#ifndef DBUG_OFF
bool can_print_json= false;
#endif
};
@ -853,14 +876,15 @@ public:
uint select_id, const char *select_type,
bool using_temporary, bool using_filesort);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
bool is_analyze, bool no_tmp_tbl);
private:
void append_tag_name(String *str, enum explain_extra_tag tag);
void fill_key_str(String *key_str, bool is_json) const;
void fill_key_len_str(String *key_len_str, bool is_json) const;
double get_r_filtered();
void tag_to_json(Json_writer *writer, enum explain_extra_tag tag);
void tag_to_json(Json_writer *writer, enum explain_extra_tag tag,
bool no_tmp_tbl);
};
@ -943,7 +967,7 @@ public:
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
virtual void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
bool is_analyze, bool no_tmp_tbl);
};
@ -969,7 +993,7 @@ public:
int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
bool is_analyze, bool no_tmp_tbl);
};
@ -996,7 +1020,7 @@ public:
virtual int print_explain(Explain_query *query, select_result_sink *output,
uint8 explain_flags, bool is_analyze);
virtual void print_explain_json(Explain_query *query, Json_writer *writer,
bool is_analyze);
bool is_analyze, bool no_tmp_tbl);
};