revision-id: 32692140e1a4f9aa87359f3ef6efe4a615119e71 (mariadb-10.6.5-39-g32692140e1a) parent(s): 946dafb260fc5683e1ec1410a801f2235ba2313a author: Sergei Petrunia committer: Sergei Petrunia timestamp: 2021-12-19 17:19:02 +0300 message: MDEV-27306: SET STATEMENT optimizer_trace=1 Doesn't save the trace In mysql_execute_command(), move optimizer trace initialization to be after run_set_statement_if_requested() call. Unfortunately, mysql_execute_command() code uses "goto error" a lot, and this means optimizer trace code cannot use RAII objects. Work this around by: - Make Opt_trace_start a non-RAII object, add init() method. - Move the code that writes the top-level object and array into Opt_trace_start::init(). --- mysql-test/main/opt_trace.result | 17 +++++++++++++++++ mysql-test/main/opt_trace.test | 8 ++++++++ sql/opt_trace.cc | 20 ++++++++++++++------ sql/opt_trace.h | 18 +++++++++++------- sql/sp_head.cc | 7 +++---- sql/sql_parse.cc | 11 +++++------ sql/sql_prepare.cc | 6 +++--- 7 files changed, 61 insertions(+), 26 deletions(-) diff --git a/mysql-test/main/opt_trace.result b/mysql-test/main/opt_trace.result index b0c2a9ca4d9..477c1f31095 100644 --- a/mysql-test/main/opt_trace.result +++ b/mysql-test/main/opt_trace.result @@ -9248,5 +9248,22 @@ json_detailed(json_extract(trace, '$**.best_join_order')) ] ] DROP TABLE t1; +# +# MDEV-27306: SET STATEMENT optimizer_trace=1 Doesn't save the trace +# +set optimizer_trace=0; +set statement optimizer_trace=1 for select * from seq_1_to_10 where seq<2; +seq +1 +# The trace must not be empty: +select left(trace, 100) from information_schema.optimizer_trace; +left(trace, 100) +{ + "steps": [ + { + "join_preparation": { + "select_id": 1, + "steps": [ + # End of 10.6 tests set optimizer_trace='enabled=off'; diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test index 402caf2a165..9a7aa017cd4 100644 --- a/mysql-test/main/opt_trace.test +++ b/mysql-test/main/opt_trace.test @@ -865,5 +865,13 @@ select json_detailed(json_extract(trace, '$**.best_join_order')) from information_schema.OPTIMIZER_TRACE; DROP TABLE t1; +--echo # +--echo # MDEV-27306: SET STATEMENT optimizer_trace=1 Doesn't save the trace +--echo # +set optimizer_trace=0; +set statement optimizer_trace=1 for select * from seq_1_to_10 where seq<2; +--echo # The trace must not be empty: +select left(trace, 100) from information_schema.optimizer_trace; + --echo # End of 10.6 tests set optimizer_trace='enabled=off'; diff --git a/sql/opt_trace.cc b/sql/opt_trace.cc index ba9220cac44..4bc493940fb 100644 --- a/sql/opt_trace.cc +++ b/sql/opt_trace.cc @@ -471,12 +471,14 @@ void Opt_trace_context::end() current_trace= NULL; } -Opt_trace_start::Opt_trace_start(THD *thd, TABLE_LIST *tbl, - enum enum_sql_command sql_command, - List<set_var_base> *set_vars, - const char *query, - size_t query_length, - const CHARSET_INFO *query_charset):ctx(&thd->opt_trace) + +void Opt_trace_start::init(THD *thd, + TABLE_LIST *tbl, + enum enum_sql_command sql_command, + List<set_var_base> *set_vars, + const char *query, + size_t query_length, + const CHARSET_INFO *query_charset) { /* if optimizer trace is enabled and the statment we have is traceable, @@ -496,6 +498,9 @@ Opt_trace_start::Opt_trace_start(THD *thd, TABLE_LIST *tbl, ctx->set_query(query, query_length, query_charset); traceable= TRUE; opt_trace_disable_if_no_tables_access(thd, tbl); + Json_writer *w= ctx->get_current_json(); + w->start_object(); + w->add_member("steps").start_array(); } } @@ -503,6 +508,9 @@ Opt_trace_start::~Opt_trace_start() { if (traceable) { + Json_writer *w= ctx->get_current_json(); + w->end_array(); + w->end_object(); ctx->end(); traceable= FALSE; } diff --git a/sql/opt_trace.h b/sql/opt_trace.h index 101fb5f707e..1ee23a33591 100644 --- a/sql/opt_trace.h +++ b/sql/opt_trace.h @@ -72,14 +72,18 @@ struct Opt_trace_info */ -class Opt_trace_start { +class Opt_trace_start +{ public: - Opt_trace_start(THD *thd_arg, TABLE_LIST *tbl, - enum enum_sql_command sql_command, - List<set_var_base> *set_vars, - const char *query, - size_t query_length, - const CHARSET_INFO *query_charset); + Opt_trace_start(THD *thd_arg): ctx(&thd_arg->opt_trace), traceable(false) {} + + void init(THD *thd, TABLE_LIST *tbl, + enum enum_sql_command sql_command, + List<set_var_base> *set_vars, + const char *query, + size_t query_length, + const CHARSET_INFO *query_charset); + ~Opt_trace_start(); private: diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 641c88de826..97905f6a5b4 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3489,10 +3489,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, thd->lex->safe_to_cache_query= 0; #endif - Opt_trace_start ots(thd, m_lex->query_tables, - SQLCOM_SELECT, &m_lex->var_list, - NULL, 0, - thd->variables.character_set_client); + Opt_trace_start ots(thd); + ots.init(thd, m_lex->query_tables, SQLCOM_SELECT, &m_lex->var_list, + NULL, 0, thd->variables.character_set_client); Json_writer_object trace_command(thd); Json_writer_array trace_command_steps(thd, "steps"); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2a48c8fb1ce..0886fc85151 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3644,12 +3644,7 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) #ifdef HAVE_REPLICATION } /* endif unlikely slave */ #endif - Opt_trace_start ots(thd, all_tables, lex->sql_command, &lex->var_list, - thd->query(), thd->query_length(), - thd->variables.character_set_client); - - Json_writer_object trace_command(thd); - Json_writer_array trace_command_steps(thd, "steps"); + Opt_trace_start ots(thd); /* store old value of binlog format */ enum_binlog_format orig_binlog_format,orig_current_stmt_binlog_format; @@ -3715,6 +3710,10 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) if (run_set_statement_if_requested(thd, lex)) goto error; + /* After SET STATEMENT is done, we can initialize the Optimizer Trace: */ + ots.init(thd, all_tables, lex->sql_command, &lex->var_list, thd->query(), + thd->query_length(), thd->variables.character_set_client); + if (thd->lex->mi.connection_name.str == NULL) thd->lex->mi.connection_name= thd->variables.default_master_connection; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 4ead77c225f..67032142591 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2437,9 +2437,9 @@ static bool check_prepared_statement(Prepared_statement *stmt) For the optimizer trace, this is the symmetric, for statement preparation, of what is done at statement execution (in mysql_execute_command()). */ - Opt_trace_start ots(thd, tables, lex->sql_command, &lex->var_list, - thd->query(), thd->query_length(), - thd->variables.character_set_client); + Opt_trace_start ots(thd); + ots.init(thd, tables, lex->sql_command, &lex->var_list, thd->query(), + thd->query_length(), thd->variables.character_set_client); Json_writer_object trace_command(thd); Json_writer_array trace_command_steps(thd, "steps");