diff options
author | Konstantin Osipov <kostja@sun.com> | 2010-08-09 18:33:17 +0400 |
---|---|---|
committer | Konstantin Osipov <kostja@sun.com> | 2010-08-09 18:33:17 +0400 |
commit | b1207bf1b83270e7440755d75fa549b480b56f82 (patch) | |
tree | 2e81c30f897a3775a6b130101a9c1ea96e97afbe /sql | |
parent | 8d0dc9b58bcb5f1cf13618eebe3fc6f60b8f2926 (diff) | |
parent | 7b7efa1261720e6c6ad76cbe9a5d922ba2dd7fc2 (diff) | |
download | mariadb-git-b1207bf1b83270e7440755d75fa549b480b56f82.tar.gz |
Merge 5.5-bugfixing -> 5.5-runtime.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/CMakeLists.txt | 11 | ||||
-rw-r--r-- | sql/item.cc | 4 | ||||
-rw-r--r-- | sql/sp_head.cc | 193 | ||||
-rw-r--r-- | sql/sp_pcontext.h | 7 | ||||
-rw-r--r-- | sql/sp_rcontext.cc | 239 | ||||
-rw-r--r-- | sql/sp_rcontext.h | 69 | ||||
-rw-r--r-- | sql/sql_class.cc | 34 | ||||
-rw-r--r-- | sql/sql_class.h | 29 | ||||
-rw-r--r-- | sql/sql_delete.cc | 4 | ||||
-rw-r--r-- | sql/sql_error.cc | 8 | ||||
-rw-r--r-- | sql/sql_error.h | 16 | ||||
-rw-r--r-- | sql/sql_insert.cc | 10 | ||||
-rw-r--r-- | sql/sql_parse.cc | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 2 | ||||
-rw-r--r-- | sql/sql_signal.cc | 12 | ||||
-rw-r--r-- | sql/sql_update.cc | 4 |
16 files changed, 305 insertions, 341 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index e8a594c4d8b..879e1bbed90 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -42,7 +42,6 @@ SET (SQL_SOURCE ../sql-common/client.c derror.cc des_key_file.cc discover.cc ../libmysql/errmsg.c field.cc field_conv.cc filesort.cc gstream.cc sha2.cc - ha_partition.cc handler.cc hash_filo.h sql_plugin_services.h hostname.cc init.cc item.cc item_buff.cc item_cmpfunc.cc item_create.cc item_func.cc item_geofunc.cc item_row.cc @@ -266,18 +265,20 @@ IF(WIN32 AND MYSQLD_EXECUTABLE) ENDIF() MAKE_DIRECTORY(${CMAKE_CURRENT_BINARY_DIR}/data) ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/data/mysql/user.frm + OUTPUT initdb.dep COMMAND ${CMAKE_COMMAND} ${CONFIG_PARAM} -P ${CMAKE_CURRENT_BINARY_DIR}/create_initial_db.cmake WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data + COMMAND ${CMAKE_COMMAND} -E touch initdb.dep + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS mysqld ) ADD_CUSTOM_TARGET(initial_database ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/data/mysql/user.frm + DEPENDS initdb.dep ) - INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data DESTINATION . COMPONENT DataFiles - PATTERN "bootstrap.sql" EXCLUDE) + INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data DESTINATION . + COMPONENT DataFiles PATTERN "initdb.dep" EXCLUDE PATTERN "bootstrap.sql" EXCLUDE) ELSE() # Not windows or cross compiling, just install an empty directory INSTALL(FILES ${DUMMY_FILE} DESTINATION data/mysql) diff --git a/sql/item.cc b/sql/item.cc index 8210f4e6caf..1decb5ec426 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -7510,13 +7510,13 @@ String *Item_cache_datetime::val_str(String *str) if (cached_field_type == MYSQL_TYPE_TIME) { ulonglong time= int_value; - DBUG_ASSERT(time < TIME_MAX_VALUE); + DBUG_ASSERT(time <= TIME_MAX_VALUE); set_zero_time(<ime, MYSQL_TIMESTAMP_TIME); ltime.second= time % 100; time/= 100; ltime.minute= time % 100; time/= 100; - ltime.hour= time % 100; + ltime.hour= time; } else { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 11f138e67be..2d3a32c7f7f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1076,6 +1076,104 @@ void sp_head::recursion_level_error(THD *thd) /** + Find an SQL handler for any condition (warning or error) after execution + of a stored routine instruction. Basically, this function looks for an + appropriate SQL handler in RT-contexts. If an SQL handler is found, it is + remembered in the RT-context for future activation (the context can be + inactive at the moment). + + If there is no pending condition, the function just returns. + + If there was an error during the execution, an SQL handler for it will be + searched within the current and outer scopes. + + There might be several errors in the Warning Info (that's possible by using + SIGNAL/RESIGNAL in nested scopes) -- the function is looking for an SQL + handler for the latest (current) error only. + + If there was a warning during the execution, an SQL handler for it will be + searched within the current scope only. + + If several warnings were thrown during the execution and there are different + SQL handlers for them, it is not determined which SQL handler will be chosen. + Only one SQL handler will be executed. + + If warnings and errors were thrown during the execution, the error takes + precedence. I.e. error handler will be executed. If there is no handler + for that error, condition will remain unhandled. + + Once a warning or an error has been handled it is not removed from + Warning Info. + + According to The Standard (quoting PeterG): + + An SQL procedure statement works like this ... + SQL/Foundation 13.5 <SQL procedure statement> + (General Rules) (greatly summarized) says: + (1) Empty diagnostics area, thus clearing the condition. + (2) Execute statement. + During execution, if Exception Condition occurs, + set Condition Area = Exception Condition and stop + statement. + During execution, if No Data occurs, + set Condition Area = No Data Condition and continue + statement. + During execution, if Warning occurs, + and Condition Area is not already full due to + an earlier No Data condition, set Condition Area + = Warning and continue statement. + (3) Finish statement. + At end of execution, if Condition Area is not + already full due to an earlier No Data or Warning, + set Condition Area = Successful Completion. + In effect, this system means there is a precedence: + Exception trumps No Data, No Data trumps Warning, + Warning trumps Successful Completion. + + NB: "Procedure statements" include any DDL or DML or + control statements. So CREATE and DELETE and WHILE + and CALL and RETURN are procedure statements. But + DECLARE and END are not procedure statements. + + @param thd thread handle + @param ctx runtime context of the stored routine +*/ + +static void +find_handler_after_execution(THD *thd, sp_rcontext *ctx) +{ + if (thd->is_error()) + { + ctx->find_handler(thd, + thd->stmt_da->sql_errno(), + thd->stmt_da->get_sqlstate(), + MYSQL_ERROR::WARN_LEVEL_ERROR, + thd->stmt_da->message()); + } + else if (thd->warning_info->statement_warn_count()) + { + List_iterator<MYSQL_ERROR> it(thd->warning_info->warn_list()); + MYSQL_ERROR *err; + while ((err= it++)) + { + if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_WARN && + err->get_level() != MYSQL_ERROR::WARN_LEVEL_NOTE) + continue; + + if (ctx->find_handler(thd, + err->get_sql_errno(), + err->get_sqlstate(), + err->get_level(), + err->get_message_text())) + { + break; + } + } + } +} + + +/** Execute the routine. The main instruction jump loop is there. Assume the parameters already set. @todo @@ -1096,7 +1194,7 @@ sp_head::execute(THD *thd) LEX_STRING saved_cur_db_name= { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) }; bool cur_db_changed= FALSE; - sp_rcontext *ctx; + sp_rcontext *ctx= thd->spcont; bool err_status= FALSE; uint ip= 0; ulong save_sql_mode; @@ -1157,8 +1255,6 @@ sp_head::execute(THD *thd) goto done; } - if ((ctx= thd->spcont)) - ctx->clear_handler(); thd->is_slave_error= 0; old_arena= thd->stmt_arena; @@ -1243,7 +1339,6 @@ sp_head::execute(THD *thd) do { sp_instr *i; - uint hip; #if defined(ENABLED_PROFILING) /* @@ -1265,6 +1360,9 @@ sp_head::execute(THD *thd) break; } + /* Reset number of warnings for this query. */ + thd->warning_info->reset_for_next_command(); + DBUG_PRINT("execute", ("Instruction %u", ip)); /* @@ -1309,40 +1407,28 @@ sp_head::execute(THD *thd) free_root(&execute_mem_root, MYF(0)); /* - Check if an exception has occurred and a handler has been found - Note: We have to check even if err_status == FALSE, since warnings (and - some errors) don't return a non-zero value. We also have to check even - if thd->killed != 0, since some errors return with this even when a - handler has been found (e.g. "bad data"). + Find and process SQL handlers unless it is a fatal error (fatal + errors are not catchable by SQL handlers) or the connection has been + killed during execution. */ - if (ctx) + if (!thd->is_fatal_error && !thd->killed_errno()) { - uint handler_index; + /* + Find SQL handler in the appropriate RT-contexts: + - warnings can be handled by SQL handlers within + the current scope only; + - errors can be handled by any SQL handler from outer scope. + */ + find_handler_after_execution(thd, ctx); - switch (ctx->found_handler(& hip, & handler_index)) { - case SP_HANDLER_NONE: - break; - case SP_HANDLER_CONTINUE: - thd->restore_active_arena(&execute_arena, &backup_arena); - thd->set_n_backup_active_arena(&execute_arena, &backup_arena); - ctx->push_hstack(i->get_cont_dest()); - /* Fall through */ - default: - if (ctx->end_partial_result_set) - thd->protocol->end_partial_result_set(thd); - ip= hip; + /* If found, activate handler for the current scope. */ + if (ctx->activate_handler(thd, &ip, i, &execute_arena, &backup_arena)) err_status= FALSE; - ctx->clear_handler(); - ctx->enter_handler(hip, handler_index); - thd->clear_error(); - thd->is_fatal_error= 0; - thd->killed= THD::NOT_KILLED; - thd->mysys_var->abort= 0; - continue; - } - - ctx->end_partial_result_set= FALSE; } + + /* Reset sp_rcontext::end_partial_result_set flag. */ + ctx->end_partial_result_set= FALSE; + } while (!err_status && !thd->killed && !thd->is_fatal_error); #if defined(ENABLED_PROFILING) @@ -3037,23 +3123,14 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) { int res= thd->spcont->set_variable(thd, m_offset, &m_value); - if (res && thd->spcont->found_handler_here()) + if (res) { - /* - Failed to evaluate the value, and a handler has been found. Reset the - variable to NULL. - */ + /* Failed to evaluate the value. Reset the variable to NULL. */ if (thd->spcont->set_variable(thd, m_offset, 0)) { /* If this also failed, let's abort. */ - - sp_rcontext *spcont= thd->spcont; - - thd->spcont= NULL; /* Avoid handlers */ - my_error(ER_OUT_OF_RESOURCES, MYF(0)); - spcont->clear_handler(); - thd->spcont= spcont; + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); } } @@ -3586,18 +3663,6 @@ sp_instr_copen::execute(THD *thd, uint *nextp) if (thd->stmt_arena->free_list) cleanup_items(thd->stmt_arena->free_list); thd->stmt_arena= old_arena; - /* - Work around the fact that errors in selects are not returned properly - (but instead converted into a warning), so if a condition handler - caught, we have lost the result code. - */ - if (!res) - { - uint dummy1, dummy2; - - if (thd->spcont->found_handler(&dummy1, &dummy2)) - res= -1; - } /* TODO: Assert here that we either have an error or a cursor */ } DBUG_RETURN(res); @@ -3773,13 +3838,11 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) { int res= thd->spcont->set_case_expr(thd, m_case_expr_id, &m_case_expr); - if (res && - !thd->spcont->get_case_expr(m_case_expr_id) && - thd->spcont->found_handler_here()) + if (res && !thd->spcont->get_case_expr(m_case_expr_id)) { /* Failed to evaluate the value, the case expression is still not - initialized, and a handler has been found. Set to NULL so we can continue. + initialized. Set to NULL so we can continue. */ Item *null_item= new Item_null(); @@ -3788,13 +3851,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. */ - - sp_rcontext *spcont= thd->spcont; - - thd->spcont= NULL; /* Avoid handlers */ - my_error(ER_OUT_OF_RESOURCES, MYF(0)); - spcont->clear_handler(); - thd->spcont= spcont; + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); } } else diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index b12d5362c6b..c27c7d22da2 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -332,13 +332,6 @@ public: int push_cond(LEX_STRING *name, sp_cond_type_t *val); - inline void - pop_cond(uint num) - { - while (num--) - pop_dynamic(&m_conds); - } - sp_cond_type_t * find_cond(LEX_STRING *name, my_bool scoped=0); diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index b08f8008b59..e76a5e9ebde 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -171,48 +171,50 @@ sp_rcontext::set_return_value(THD *thd, Item **return_value_item) #define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2') #define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2') -/* - Find a handler for the given errno. - This is called from all error message functions (e.g. push_warning, - net_send_error, et al) when a sp_rcontext is in effect. If a handler - is found, no error is sent, and the the SP execution loop will instead - invoke the found handler. - This might be called several times before we get back to the execution - loop, so m_hfound can be >= 0 if a handler has already been found. - (In which case we don't search again - the first found handler will - be used.) - Handlers are pushed on the stack m_handler, with the latest/innermost +/** + Find an SQL handler for the given error. + + SQL handlers are pushed on the stack m_handler, with the latest/innermost one on the top; we then search for matching handlers from the top and down. + We search through all the handlers, looking for the most specific one (sql_errno more specific than sqlstate more specific than the rest). Note that mysql error code handlers is a MySQL extension, not part of the standard. - SYNOPSIS - sql_errno The error code - level Warning level + SQL handlers for warnings are searched in the current scope only. - RETURN - 1 if a handler was found, m_hfound is set to its index (>= 0) - 0 if not found, m_hfound is -1 + SQL handlers for errors are searched in the current and in outer scopes. + That's why finding and activation of handler must be separated: an errror + handler might be located in the outer scope, which is not active at the + moment. Before such handler can be activated, execution flow should + unwind to that scope. + + Found SQL handler is remembered in m_hfound for future activation. + If no handler is found, m_hfound is -1. + + @param thd Thread handle + @param sql_errno The error code + @param sqlstate The error SQL state + @param level The error level + @param msg The error message + + @retval TRUE if an SQL handler was found + @retval FALSE otherwise */ bool sp_rcontext::find_handler(THD *thd, uint sql_errno, - const char* sqlstate, + const char *sqlstate, MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl) + const char *msg) { - if (m_hfound >= 0) - { - *cond_hdl= NULL; - return TRUE; // Already got one - } + int i= m_hcount; - int i= m_hcount, found= -1; + /* Reset previously found handler. */ + m_hfound= -1; /* If this is a fatal sub-statement error, and this runtime @@ -240,105 +242,56 @@ sp_rcontext::find_handler(THD *thd, { case sp_cond_type_t::number: if (sql_errno == cond->mysqlerr && - (found < 0 || m_handler[found].cond->type > sp_cond_type_t::number)) - found= i; // Always the most specific + (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_cond_type_t::number)) + m_hfound= i; // Always the most specific break; case sp_cond_type_t::state: if (strcmp(sqlstate, cond->sqlstate) == 0 && - (found < 0 || m_handler[found].cond->type > sp_cond_type_t::state)) - found= i; + (m_hfound < 0 || m_handler[m_hfound].cond->type > sp_cond_type_t::state)) + m_hfound= i; break; case sp_cond_type_t::warning: if ((IS_WARNING_CONDITION(sqlstate) || level == MYSQL_ERROR::WARN_LEVEL_WARN) && - found < 0) - found= i; + m_hfound < 0) + m_hfound= i; break; case sp_cond_type_t::notfound: - if (IS_NOT_FOUND_CONDITION(sqlstate) && found < 0) - found= i; + if (IS_NOT_FOUND_CONDITION(sqlstate) && m_hfound < 0) + m_hfound= i; break; case sp_cond_type_t::exception: if (IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR && - found < 0) - found= i; + m_hfound < 0) + m_hfound= i; break; } } - if (found < 0) - { - /* - Only "exception conditions" are propagated to handlers in calling - contexts. If no handler is found locally for a "completion condition" - (warning or "not found") we will simply resume execution. - */ - if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && - level == MYSQL_ERROR::WARN_LEVEL_ERROR) - return m_prev_runtime_ctx->find_handler(thd, - sql_errno, - sqlstate, - level, - msg, - cond_hdl); - *cond_hdl= NULL; - return FALSE; - } - - m_hfound= found; - MYSQL_ERROR *raised= NULL; - DBUG_ASSERT(m_hfound >= 0); - DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index()); - raised= & m_raised_conditions[m_hfound]; - raised->clear(); - raised->set(sql_errno, sqlstate, level, msg); - - *cond_hdl= raised; - return TRUE; -} - -/* - Handle the error for a given errno. - The severity of the error is adjusted depending of the current sql_mode. - If an handler is present for the error (see find_handler()), - this function will return true. - If a handler is found and if the severity of the error indicate - that the current instruction executed should abort, - the flag thd->net.report_error is also set. - This will cause the execution of the current instruction in a - sp_instr* to fail, and give control to the handler code itself - in the sp_head::execute() loop. - - SYNOPSIS - sql_errno The error code - level Warning level - thd The current thread + if (m_hfound >= 0) + { + DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index()); - RETURN - TRUE if a handler was found. - FALSE if no handler was found. -*/ -bool -sp_rcontext::handle_condition(THD *thd, - uint sql_errno, - const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl) -{ - MYSQL_ERROR::enum_warning_level elevated_level= level; + m_raised_conditions[m_hfound].clear(); + m_raised_conditions[m_hfound].set(sql_errno, sqlstate, level, msg); + return TRUE; + } - /* Depending on the sql_mode of execution, - warnings may be considered errors */ - if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) && - thd->really_abort_on_warning()) + /* + Only "exception conditions" are propagated to handlers in calling + contexts. If no handler is found locally for a "completion condition" + (warning or "not found") we will simply resume execution. + */ + if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && + level == MYSQL_ERROR::WARN_LEVEL_ERROR) { - elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR; + return m_prev_runtime_ctx->find_handler(thd, sql_errno, sqlstate, + level, msg); } - return find_handler(thd, sql_errno, sqlstate, elevated_level, msg, cond_hdl); + return FALSE; } void @@ -384,7 +337,9 @@ sp_rcontext::pop_handlers(uint count) { DBUG_ENTER("sp_rcontext::pop_handlers"); DBUG_ASSERT(m_hcount >= count); + m_hcount-= count; + DBUG_PRINT("info", ("m_hcount: %d", m_hcount)); DBUG_VOID_RETURN; } @@ -394,7 +349,9 @@ sp_rcontext::push_hstack(uint h) { DBUG_ENTER("sp_rcontext::push_hstack"); DBUG_ASSERT(m_hsp < m_root_parsing_ctx->max_handler_index()); + m_hstack[m_hsp++]= h; + DBUG_PRINT("info", ("m_hsp: %d", m_hsp)); DBUG_VOID_RETURN; } @@ -405,21 +362,74 @@ sp_rcontext::pop_hstack() uint handler; DBUG_ENTER("sp_rcontext::pop_hstack"); DBUG_ASSERT(m_hsp); + handler= m_hstack[--m_hsp]; + DBUG_PRINT("info", ("m_hsp: %d", m_hsp)); DBUG_RETURN(handler); } -void -sp_rcontext::enter_handler(uint hip, uint hindex) +/** + Prepare found handler to be executed. + + @retval TRUE if an SQL handler is activated (was found) and IP of the + first handler instruction. + @retval FALSE if there is no active handler +*/ + +bool +sp_rcontext::activate_handler(THD *thd, + uint *ip, + sp_instr *instr, + Query_arena *execute_arena, + Query_arena *backup_arena) { - DBUG_ENTER("sp_rcontext::enter_handler"); - DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index()); - m_in_handler[m_ihsp].ip= hip; - m_in_handler[m_ihsp].index= hindex; - m_ihsp++; - DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp)); - DBUG_VOID_RETURN; + if (m_hfound < 0) + return FALSE; + + switch (m_handler[m_hfound].type) { + case SP_HANDLER_NONE: + break; + + case SP_HANDLER_CONTINUE: + thd->restore_active_arena(execute_arena, backup_arena); + thd->set_n_backup_active_arena(execute_arena, backup_arena); + push_hstack(instr->get_cont_dest()); + + /* Fall through */ + + default: + /* End aborted result set. */ + + if (end_partial_result_set) + thd->protocol->end_partial_result_set(thd); + + /* Enter handler. */ + + DBUG_ASSERT(m_ihsp < m_root_parsing_ctx->max_handler_index()); + DBUG_ASSERT(m_hfound >= 0); + + m_in_handler[m_ihsp].ip= m_handler[m_hfound].handler; + m_in_handler[m_ihsp].index= m_hfound; + m_ihsp++; + + DBUG_PRINT("info", ("Entering handler...")); + DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp)); + + /* Reset error state. */ + + thd->clear_error(); + thd->killed= THD::NOT_KILLED; // Some errors set thd->killed + // (e.g. "bad data"). + + /* Return IP of the activated SQL handler. */ + *ip= m_handler[m_hfound].handler; + + /* Reset found handler. */ + m_hfound= -1; + } + + return TRUE; } void @@ -427,9 +437,11 @@ sp_rcontext::exit_handler() { DBUG_ENTER("sp_rcontext::exit_handler"); DBUG_ASSERT(m_ihsp); + uint hindex= m_in_handler[m_ihsp-1].index; m_raised_conditions[hindex].clear(); m_ihsp-= 1; + DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp)); DBUG_VOID_RETURN; } @@ -567,6 +579,11 @@ sp_cursor::fetch(THD *thd, List<struct sp_variable> *vars) return -1; } + DBUG_EXECUTE_IF("bug23032_emit_warning", + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_UNKNOWN_ERROR, + ER(ER_UNKNOWN_ERROR));); + result.set_spvar_list(vars); /* Attempt to fetch one row */ diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index fad253706cb..1af758ed0af 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -131,67 +131,40 @@ class sp_rcontext : public Sql_alloc return m_return_value_set; } + /* + SQL handlers support. + */ + void push_handler(struct sp_cond_type *cond, uint h, int type); void pop_handlers(uint count); - // Returns 1 if a handler was found, 0 otherwise. bool find_handler(THD *thd, uint sql_errno, - const char* sqlstate, + const char *sqlstate, MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl); + const char *msg); - // If there is an error handler for this error, handle it and return TRUE. - bool - handle_condition(THD *thd, - uint sql_errno, - const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl); - - // Returns handler type and sets *ip to location if one was found - inline int - found_handler(uint *ip, uint *index) - { - if (m_hfound < 0) - return SP_HANDLER_NONE; - *ip= m_handler[m_hfound].handler; - *index= m_hfound; - return m_handler[m_hfound].type; - } - - MYSQL_ERROR* raised_condition() const; - - // Returns true if we found a handler in this context - inline bool - found_handler_here() - { - return (m_hfound >= 0); - } + MYSQL_ERROR * + raised_condition() const; - // Clears the handler find state - inline void - clear_handler() - { - m_hfound= -1; - } + void + push_hstack(uint h); - void push_hstack(uint h); + uint + pop_hstack(); - uint pop_hstack(); + bool + activate_handler(THD *thd, + uint *ip, + sp_instr *instr, + Query_arena *execute_arena, + Query_arena *backup_arena); - /** - Enter a SQL exception handler. - @param hip the handler instruction pointer - @param index the handler index - */ - void enter_handler(uint hip, uint index); - void exit_handler(); + void + exit_handler(); void push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i); @@ -199,7 +172,7 @@ class sp_rcontext : public Sql_alloc void pop_cursors(uint count); - void + inline void pop_all_cursors() { pop_cursors(m_ccount); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1ff2ba59093..60a871e9e88 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -845,35 +845,6 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno, } } - /* - If a continue handler is found, the error message will be cleared - by the stored procedures code. - */ - if (!is_fatal_error && spcont && - spcont->handle_condition(this, sql_errno, sqlstate, level, msg, &cond)) - { - /* - Do not push any warnings, a handled error must be completely - silenced. - */ - DBUG_RETURN(cond); - } - - /* Un-handled conditions */ - - cond= raise_condition_no_handler(sql_errno, sqlstate, level, msg); - DBUG_RETURN(cond); -} - -MYSQL_ERROR* -THD::raise_condition_no_handler(uint sql_errno, - const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, - const char* msg) -{ - MYSQL_ERROR *cond= NULL; - DBUG_ENTER("THD::raise_condition_no_handler"); - query_cache_abort(&query_cache_tls); /* FIXME: broken special case */ @@ -886,6 +857,7 @@ THD::raise_condition_no_handler(uint sql_errno, cond= warning_info->push_warning(this, sql_errno, sqlstate, level, msg); DBUG_RETURN(cond); } + extern "C" void *thd_alloc(MYSQL_THD thd, unsigned int size) { @@ -1737,9 +1709,9 @@ bool select_send::send_result_set_metadata(List<Item> &list, uint flags) return res; } -void select_send::abort() +void select_send::abort_result_set() { - DBUG_ENTER("select_send::abort"); + DBUG_ENTER("select_send::abort_result_set"); if (is_result_set_started && thd->spcont) { diff --git a/sql/sql_class.h b/sql/sql_class.h index 8a54e7069b1..b23b65dae2f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2800,23 +2800,6 @@ private: MYSQL_ERROR::enum_warning_level level, const char* msg); - /** - Raise a generic SQL condition, without activation any SQL condition - handlers. - This method is necessary to support the RESIGNAL statement, - which is allowed to bypass SQL exception handlers. - @param sql_errno the condition error number - @param sqlstate the condition SQLSTATE - @param level the condition level - @param msg the condition message text - @return The condition raised, or NULL - */ - MYSQL_ERROR* - raise_condition_no_handler(uint sql_errno, - const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, - const char* msg); - public: /** Overloaded to guard query/query_length fields */ virtual void set_statement(Statement *stmt); @@ -2987,7 +2970,7 @@ public: @retval TRUE error, an error message is set */ virtual bool check_simple_select() const; - virtual void abort() {} + virtual void abort_result_set() {} /* Cleanup instance of this class for next execution of a prepared statement/stored procedure. @@ -3030,7 +3013,7 @@ public: bool send_data(List<Item> &items); bool send_eof(); virtual bool check_simple_select() const { return FALSE; } - void abort(); + void abort_result_set(); virtual void cleanup(); }; @@ -3122,7 +3105,7 @@ class select_insert :public select_result_interceptor { virtual bool can_rollback_data() { return 0; } void send_error(uint errcode,const char *err); bool send_eof(); - void abort(); + virtual void abort_result_set(); /* not implemented: select_insert is never re-used in prepared statements */ void cleanup(); }; @@ -3158,7 +3141,7 @@ public: void store_values(List<Item> &values); void send_error(uint errcode,const char *err); bool send_eof(); - void abort(); + virtual void abort_result_set(); virtual bool can_rollback_data() { return 1; } // Needed for access from local class MY_HOOKS in prepare(), since thd is proteted. @@ -3492,7 +3475,7 @@ public: { return deleted; } - virtual void abort(); + virtual void abort_result_set(); }; @@ -3543,7 +3526,7 @@ public: { return updated; } - virtual void abort(); + virtual void abort_result_set(); }; class my_var : public Sql_alloc { diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 00666bc85b4..2f69bac917e 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -770,9 +770,9 @@ void multi_delete::send_error(uint errcode,const char *err) } -void multi_delete::abort() +void multi_delete::abort_result_set() { - DBUG_ENTER("multi_delete::abort"); + DBUG_ENTER("multi_delete::abort_result_set"); /* the error was handled or nothing deleted and no side effects return */ if (error_handled || diff --git a/sql/sql_error.cc b/sql/sql_error.cc index e5d0f79b2d7..8c038e10a1f 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -494,14 +494,6 @@ void Warning_info::clear_warning_info(ulonglong warn_id_arg) m_current_row_for_warning= 1; /* Start counting from the first row */ } -void Warning_info::reserve_space(THD *thd, uint count) -{ - /* Make room for count conditions */ - while ((m_warn_list.elements > 0) && - ((m_warn_list.elements + count) > thd->variables.max_error_count)) - m_warn_list.pop(); -} - /** Append warnings only if the original contents of the routine warning info was replaced. diff --git a/sql/sql_error.h b/sql/sql_error.h index 9e649a004df..87e98e27673 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -153,8 +153,8 @@ private: Representation of a SQL condition. A SQL condition can be a completion condition (note, warning), or an exception condition (error, not found). - @note This class is named MYSQL_ERROR instead of SQL_condition for historical reasons, - to facilitate merging code with previous releases. + @note This class is named MYSQL_ERROR instead of SQL_condition for + historical reasons, to facilitate merging code with previous releases. */ class MYSQL_ERROR : public Sql_alloc { @@ -471,18 +471,6 @@ public: ulong statement_warn_count() const { return m_statement_warn_count; } - /** - Reserve some space in the condition area. - This is a privileged operation, reserved for the RESIGNAL implementation, - as only the RESIGNAL statement is allowed to remove conditions from - the condition area. - For other statements, new conditions are not added to the condition - area once the condition area is full. - @param thd The current thread - @param count The number of slots to reserve - */ - void reserve_space(THD *thd, uint count); - /** Add a new condition to the current list. */ MYSQL_ERROR *push_warning(THD *thd, uint sql_errno, const char* sqlstate, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index cc0b6ba3a2d..a0d347f48de 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3399,9 +3399,9 @@ bool select_insert::send_eof() DBUG_RETURN(0); } -void select_insert::abort() { +void select_insert::abort_result_set() { - DBUG_ENTER("select_insert::abort"); + DBUG_ENTER("select_insert::abort_result_set"); /* If the creation of the table failed (due to a syntax error, for example), no table will have been opened and therefore 'table' @@ -3938,9 +3938,9 @@ bool select_create::send_eof() } -void select_create::abort() +void select_create::abort_result_set() { - DBUG_ENTER("select_create::abort"); + DBUG_ENTER("select_create::abort_result_set"); /* In select_insert::abort() we roll back the statement, including @@ -3958,7 +3958,7 @@ void select_create::abort() log state. */ tmp_disable_binlog(thd); - select_insert::abort(); + select_insert::abort_result_set(); thd->transaction.stmt.modified_non_trans_table= FALSE; reenable_binlog(thd); /* possible error of writing binary log is ignored deliberately */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4c6a822d4c3..2ef8e9761b1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3391,7 +3391,7 @@ end_with_restore_list: res|= thd->is_error(); MYSQL_MULTI_DELETE_DONE(res, del_result->num_deleted()); if (res) - del_result->abort(); + del_result->abort_result_set(); delete del_result; } else @@ -4861,7 +4861,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) ER_YES, str.ptr()); } if (res) - result->abort(); + result->abort_result_set(); else result->send_eof(); delete result; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 93c3e76c047..ccfd93a1bc8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -299,7 +299,7 @@ bool handle_select(THD *thd, LEX *lex, select_result *result, thd->is_error())); res|= thd->is_error(); if (unlikely(res)) - result->abort(); + result->abort_result_set(); MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows); DBUG_RETURN(res); diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc index f340da373e8..09e9a828fa1 100644 --- a/sql/sql_signal.cc +++ b/sql/sql_signal.cc @@ -499,18 +499,6 @@ bool Resignal_statement::execute(THD *thd) } /* RESIGNAL with signal_value */ - - /* Make room for 2 conditions */ - thd->warning_info->reserve_space(thd, 2); - - MYSQL_ERROR *raised= NULL; - raised= thd->raise_condition_no_handler(signaled->get_sql_errno(), - signaled->get_sqlstate(), - signaled->get_level(), - signaled->get_message_text()); - if (raised) - raised->copy_opt_attributes(signaled); - result= raise_condition(thd, signaled); DBUG_RETURN(result); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c52467531a9..35478e28520 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1261,7 +1261,7 @@ bool mysql_multi_update(THD *thd, { /* If we had a another error reported earlier then this will be ignored */ (*result)->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR)); - (*result)->abort(); + (*result)->abort_result_set(); } thd->abort_on_warning= 0; DBUG_RETURN(res); @@ -1861,7 +1861,7 @@ void multi_update::send_error(uint errcode,const char *err) } -void multi_update::abort() +void multi_update::abort_result_set() { /* the error was handled or nothing deleted and no side effects return */ if (error_handled || |