diff options
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r-- | sql/sp_head.cc | 163 |
1 files changed, 130 insertions, 33 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1dfea47a108..48bd8ac8221 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -29,6 +29,8 @@ #include "sql_derived.h" // mysql_handle_derived #include "sql_cte.h" #include "sql_select.h" // Virtual_tmp_table +#include "opt_trace.h" +#include "my_json_writer.h" #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation @@ -44,6 +46,9 @@ #include "transaction.h" // trans_commit_stmt #include "sql_audit.h" #include "debug_sync.h" +#ifdef WITH_WSREP +#include "wsrep_trans_observer.h" +#endif /* WITH_WSREP */ /* Sufficient max length of printed destinations and frame offsets (all uints). @@ -71,33 +76,6 @@ static void reset_start_time_for_sp(THD *thd) } -Item::Type -sp_map_item_type(const Type_handler *handler) -{ - if (handler == &type_handler_row) - return Item::ROW_ITEM; - enum_field_types type= real_type_to_type(handler->real_field_type()); - - switch (type) { - case MYSQL_TYPE_BIT: - case MYSQL_TYPE_TINY: - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_LONGLONG: - case MYSQL_TYPE_INT24: - return Item::INT_ITEM; - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - return Item::DECIMAL_ITEM; - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - return Item::REAL_ITEM; - default: - return Item::STRING_ITEM; - } -} - - bool Item_splocal::append_for_log(THD *thd, String *str) { if (fix_fields_if_needed(thd, NULL)) @@ -319,7 +297,7 @@ sp_get_flags_for_command(LEX *lex) - EXPLAIN DELETE ... - ANALYZE DELETE ... */ - if (lex->select_lex.item_list.is_empty() && + if (lex->first_select_lex()->item_list.is_empty() && !lex->describe && !lex->analyze_stmt) flags= 0; else @@ -512,7 +490,8 @@ sp_head::operator delete(void *ptr, size_t size) throw() } -sp_head::sp_head(sp_package *parent, const Sp_handler *sph) +sp_head::sp_head(sp_package *parent, const Sp_handler *sph, + enum_sp_aggregate_type agg_type) :Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP), Database_qualified_name(&null_clex_str, &null_clex_str), m_parent(parent), @@ -545,6 +524,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph) m_pcont(new (&main_mem_root) sp_pcontext()), m_cont_level(0) { + set_chistics_agg_type(agg_type); m_first_instance= this; m_first_free_instance= this; m_last_cached_sp= this; @@ -562,6 +542,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph) my_hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); my_hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); + m_security_ctx.init(); DBUG_VOID_RETURN; } @@ -570,7 +551,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph) sp_package::sp_package(LEX *top_level_lex, const sp_name *name, const Sp_handler *sph) - :sp_head(NULL, sph), + :sp_head(NULL, sph, DEFAULT_AGGREGATE), m_current_routine(NULL), m_top_level_lex(top_level_lex), m_rcontext(NULL), @@ -1172,6 +1153,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success) if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet)) DBUG_RETURN(TRUE); + opt_trace_disable_if_no_security_context_access(thd); + /* init per-instruction memroot */ init_sql_alloc(&execute_mem_root, "per_instruction_memroot", MEM_ROOT_BLOCK_SIZE, 0, MYF(0)); @@ -1353,6 +1336,13 @@ sp_head::execute(THD *thd, bool merge_da_on_success) sql_digest_state *parent_digest= thd->m_digest; thd->m_digest= NULL; +#ifdef WITH_WSREP + if (WSREP(thd) && thd->wsrep_next_trx_id() == WSREP_UNDEFINED_TRX_ID) + { + thd->set_wsrep_next_trx_id(thd->query_id); + WSREP_DEBUG("assigned new next trx ID for SP, trx id: %" PRIu64, thd->wsrep_next_trx_id()); + } +#endif /* WITH_WSREP */ err_status= i->execute(thd, &ip); thd->m_digest= parent_digest; @@ -1924,7 +1914,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, for (arg_no= 0; arg_no < argcount; arg_no++) { /* Arguments must be fixed in Item_func_sp::fix_fields */ - DBUG_ASSERT(argp[arg_no]->fixed); + DBUG_ASSERT(argp[arg_no]->is_fixed()); if ((err_status= (*func_ctx)->set_parameter(thd, arg_no, &(argp[arg_no])))) goto err_with_cleanup; @@ -2001,6 +1991,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, thd->variables.option_bits&= ~OPTION_BIN_LOG; } + opt_trace_disable_if_no_stored_proc_func_access(thd, this); /* Switch to call arena/mem_root so objects like sp_cursor or Item_cache holders for case expressions can be allocated on it. @@ -2291,9 +2282,11 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) err_status= set_routine_security_ctx(thd, this, &save_security_ctx); #endif + opt_trace_disable_if_no_stored_proc_func_access(thd, this); if (!err_status) { err_status= execute(thd, TRUE); + DBUG_PRINT("info", ("execute returned %d", (int) err_status)); } if (save_log_general) @@ -2692,6 +2685,17 @@ sp_head::set_chistics(const st_sp_chistics &chistics) m_chistics.comment.length); } + +void +sp_head::set_c_chistics(const st_sp_chistics &chistics) +{ + // Set all chistics but preserve agg_type. + enum_sp_aggregate_type save_agg_type= agg_type(); + set_chistics(chistics); + set_chistics_agg_type(save_agg_type); +} + + void sp_head::set_info(longlong created, longlong modified, const st_sp_chistics &chistics, sql_mode_t sql_mode) @@ -3315,6 +3319,13 @@ 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); + + Json_writer_object trace_command(thd); + Json_writer_array trace_command_steps(thd, "steps"); if (open_tables) res= check_dependencies_in_with_clauses(m_lex->with_clauses_list) || instr->exec_open_and_lock_tables(thd, m_lex->query_tables); @@ -3594,6 +3605,49 @@ sp_instr_stmt::exec_core(THD *thd, uint *nextp) (char *)thd->security_ctx->host_or_ip, 3); int res= mysql_execute_command(thd); +#ifdef WITH_WSREP + if (WSREP(thd)) + { + if ((thd->is_fatal_error || thd->killed_errno()) && + (thd->wsrep_trx().state() == wsrep::transaction::s_executing)) + { + /* + SP was killed, and it is not due to a wsrep conflict. + We skip after_statement hook at this point because + otherwise it clears the error, and cleans up the + whole transaction. For now we just return and finish + our handling once we are back to mysql_parse. + */ + WSREP_DEBUG("Skipping after_command hook for killed SP"); + } + else + { + const bool must_replay= wsrep_must_replay(thd); + (void) wsrep_after_statement(thd); + /* + Reset the return code to zero if the transaction was + replayed succesfully. + */ + if (res && must_replay && !wsrep_current_error(thd)) + res= 0; + /* + Final wsrep error status for statement is known only after + wsrep_after_statement() call. If the error is set, override + error in thd diagnostics area and reset wsrep client_state error + so that the error does not get propagated via client-server protocol. + */ + if (wsrep_current_error(thd)) + { + wsrep_override_error(thd, wsrep_current_error(thd), + wsrep_current_error_status(thd)); + thd->wsrep_cs().reset_error(); + /* Reset also thd->killed if it has been set during BF abort. */ + if (thd->killed == KILL_QUERY) + thd->reset_killed(); + } + } + } +#endif /* WITH_WSREP */ MYSQL_QUERY_EXEC_DONE(res); *nextp= m_ip+1; return res; @@ -4531,8 +4585,8 @@ int sp_instr_error::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_error::execute"); - my_message(m_errcode, ER_THD(thd, m_errcode), MYF(0)); + WSREP_DEBUG("sp_instr_error: %s %d", ER_THD(thd, m_errcode), thd->is_error()); *nextp= m_ip+1; DBUG_RETURN(-1); } @@ -4580,7 +4634,7 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item)) { /* If this also failed, we have to abort. */ - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); } } else @@ -5120,6 +5174,36 @@ bool sp_head::spvar_fill_table_rowtype_reference(THD *thd, } +bool sp_head::check_group_aggregate_instructions_forbid() const +{ + if (unlikely(m_flags & sp_head::HAS_AGGREGATE_INSTR)) + { + my_error(ER_NOT_AGGREGATE_FUNCTION, MYF(0)); + return true; + } + return false; +} + + +bool sp_head::check_group_aggregate_instructions_require() const +{ + if (unlikely(!(m_flags & HAS_AGGREGATE_INSTR))) + { + my_error(ER_INVALID_AGGREGATE_FUNCTION, MYF(0)); + return true; + } + return false; +} + + +bool sp_head::check_group_aggregate_instructions_function() const +{ + return agg_type() == GROUP_AGGREGATE ? + check_group_aggregate_instructions_require() : + check_group_aggregate_instructions_forbid(); +} + + /* In Oracle mode stored routines have an optional name at the end of a declaration: @@ -5154,6 +5238,19 @@ err: } +bool +sp_head::check_standalone_routine_end_name(const sp_name *end_name) const +{ + if (end_name && !end_name->eq(this)) + { + my_error(ER_END_IDENTIFIER_DOES_NOT_MATCH, MYF(0), + ErrConvDQName(end_name).ptr(), ErrConvDQName(this).ptr()); + return true; + } + return false; +} + + ulong sp_head::sp_cache_version() const { return m_parent ? m_parent->sp_cache_version() : m_sp_cache_version; |