diff --git a/sql/sp_head.h b/sql/sp_head.h index 34dd09fd88f..601d41ab04a 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -1041,7 +1041,7 @@ public: Query_arena(thd->lex->sphead->get_main_mem_root(), STMT_INITIALIZED_FOR_SP) { } ~sp_lex_cursor() { free_items(); } - void cleanup_stmt() { } + void cleanup_stmt(bool /*restore_set_statement_vars*/) { } Query_arena *query_arena() { return this; } bool validate() { @@ -1831,7 +1831,8 @@ public: cursor is closed. For now stored procedures always use materialized cursors and the call is not used. */ - virtual void cleanup_stmt() { /* no op */ } + virtual void cleanup_stmt(bool /*restore_set_statement_vars*/) + { /* no op */ } private: sp_lex_keeper m_lex_keeper; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 6317e578156..9b6f1b1ef68 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3835,7 +3835,7 @@ void Query_arena::set_query_arena(Query_arena *set) } -void Query_arena::cleanup_stmt() +void Query_arena::cleanup_stmt(bool /*restore_set_statement_vars*/) { DBUG_ASSERT(! "Query_arena::cleanup_stmt() not implemented"); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 0f85da68c8e..004b92712c8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1212,7 +1212,7 @@ public: void free_items(); /* Close the active state associated with execution of this statement */ - virtual void cleanup_stmt(); + virtual void cleanup_stmt(bool /*restore_set_statement_vars*/); }; diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index b995a841a74..0324e9691e8 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -197,7 +197,7 @@ int mysql_open_cursor(THD *thd, select_result *result, } *pcursor= materialized_cursor; - thd->stmt_arena->cleanup_stmt(); + thd->stmt_arena->cleanup_stmt(true); } end: diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b1e7a12adac..8307cd0ed4d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2419,7 +2419,18 @@ resume: thd->update_all_stats(); - log_slow_statement(thd); + /* + Write to slow query log only those statements that received via the text + protocol except the EXECUTE statement. The reason we do that way is + that for statements received via binary protocol and for the EXECUTE + statement, the slow statements have been already written to slow query log + inside the method Prepared_statement::execute(). + */ + if(command == COM_QUERY && + thd->lex->sql_command != SQLCOM_EXECUTE) + log_slow_statement(thd); + else + delete_explain_query(thd->lex); THD_STAGE_INFO(thd, stage_cleaning_up); thd->reset_query(); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index b09dd4dc381..2f5470db123 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -201,7 +201,7 @@ public: virtual ~Prepared_statement(); void setup_set_params(); virtual Query_arena::Type type() const; - virtual void cleanup_stmt(); + virtual void cleanup_stmt(bool restore_set_statement_vars); bool set_name(const LEX_CSTRING *name); inline void close_cursor() { delete cursor; cursor= 0; } inline bool is_in_use() { return flags & (uint) IS_IN_USE; } @@ -4193,11 +4193,14 @@ Query_arena::Type Prepared_statement::type() const } -void Prepared_statement::cleanup_stmt() +void Prepared_statement::cleanup_stmt(bool restore_set_statement_vars) { DBUG_ENTER("Prepared_statement::cleanup_stmt"); DBUG_PRINT("enter",("stmt: %p", this)); - lex->restore_set_statement_var(); + + if (restore_set_statement_vars) + lex->restore_set_statement_var(); + thd->rollback_item_tree_changes(); cleanup_items(free_list); thd->cleanup_after_query(); @@ -4406,12 +4409,6 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE; } - /* - Restore original values of variables modified on handling - SET STATEMENT clause. - */ - thd->lex->restore_set_statement_var(); - /* The order is important */ lex->unit.cleanup(); @@ -4440,7 +4437,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) if (lex->sql_command != SQLCOM_SET_OPTION) lex_unlock_plugins(lex); - cleanup_stmt(); + /* + Pass the value true to restore original values of variables modified + on handling SET STATEMENT clause. + */ + cleanup_stmt(true); + thd->restore_backup_statement(this, &stmt_backup); thd->stmt_arena= old_stmt_arena; thd->cur_stmt= save_cur_stmt; @@ -5159,6 +5161,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) (char *) thd->security_ctx->host_or_ip, 1); error= mysql_execute_command(thd, true); MYSQL_QUERY_EXEC_DONE(error); + thd->update_server_status(); } else { @@ -5184,8 +5187,47 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) DBUG_ASSERT(! (error && cursor)); if (! cursor) - cleanup_stmt(); - + /* + Pass the value false to don't restore set statement variables. + See the next comment block for more details. + */ + cleanup_stmt(false); + + /* + Log the statement to slow query log if it passes filtering. + We do it here for prepared statements despite of the fact that the function + log_slow_statement() is also called upper the stack from the function + dispatch_command(). The reason for logging slow queries here is that + the function log_slow_statement() must be called before restoring system + variables that could be set on execution of SET STATEMENT clause. Since + for prepared statement restoring of system variables set on execution of + SET STATEMENT clause is performed on return from the method + Prepared_statement::execute(), by the time the function log_slow_statement() + be invoked from the function dispatch_command() all variables set by + the SET STATEMEN clause would be already reset to their original values + that break semantic of the SET STATEMENT clause. + + E.g., lets consider the following statements + SET slow_query_log= 1; + SET @@long_query_time=0.01; + PREPARE stmt FROM 'set statement slow_query_log=0 for select sleep(0.1)'; + EXECUTE stmt; + + It's expected that the above statements don't write any record + to slow query log since the system variable slow_query_log is set to 0 + during execution of the whole statement + 'set statement slow_query_log=0 for select sleep(0.1)' + + However, if the function log_slow_statement wasn't called here the record + for the statement would be written to slow query log since the variable + slow_query_log is restored to its original value by the time the function + log_slow_statement is called from disptach_command() to write a record + into slow query log. + */ + log_slow_statement(thd); + + lex->restore_set_statement_var(); + /* EXECUTE command has its own dummy "explain data". We don't need it, instead, we want to keep the query plan of the statement that was