From: Marc Alff Date: October 3 2008 9:35pm Subject: bzr commit into mysql-6.0-wl2110-review branch (marc.alff:2704) Bug#11661 WL#2110 WL#2265 List-Archive: http://lists.mysql.com/commits/55293 X-Bug: 11661 Message-Id: <20081003213529.F03152D868@lambda.WEBLAB> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit #At file:///home/malff/BZR-TREE/mysql-6.0-wl2110-review/ 2704 Marc Alff 2008-10-03 WL#2110 (Stored Procedures: Implement SIGNAL) WL#2265 (Stored Procedures: Implement RESIGNAL) Bug#11661 (Raising Exceptions from within stored procedures: Support for SIGNAL statement) Fixed review comments related to memory management. - Changed all the handle_condition() methods to return a SQL_condition as *output*, instead of *input*. The logic now find first where the condition should be written to, and then the caller writes the extra attributes in place. This change removes the need for SQL_condition::deep_copy(). Also, when a condition is dropped (Internal handlers, warn_list full), this saves some CPU cycle. - Removed SQL_condition::deep_copy() - Removed sp_rcontext::m_cond_root, and reverted related changes. - Adjusted the code that raises a condition according to the new paradigm. modified: sql/handler.cc sql/log.cc sql/sp.cc sql/sp_head.cc sql/sp_rcontext.cc sql/sp_rcontext.h sql/sql_acl.cc sql/sql_base.cc sql/sql_class.cc sql/sql_class.h sql/sql_fixstring.cc sql/sql_fixstring.h sql/sql_signal.cc sql/unireg.cc === modified file 'sql/handler.cc' --- a/sql/handler.cc 2008-09-29 15:14:27 +0000 +++ b/sql/handler.cc 2008-10-03 21:35:16 +0000 @@ -1819,17 +1819,28 @@ const char *get_canonical_filename(handl struct Ha_delete_table_error_handler: public Internal_error_handler { public: - virtual bool handle_condition(THD *thd, const SQL_condition *cond); + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); char buff[MYSQL_ERRMSG_SIZE]; }; bool Ha_delete_table_error_handler:: -handle_condition(THD *, const SQL_condition *cond) +handle_condition(THD *, + uint, + const char*, + MYSQL_ERROR::enum_warning_level, + const char* msg, + SQL_condition ** cond_hdl) { + *cond_hdl= NULL; /* Grab the error message */ - strmake(buff, cond->get_message_text(), sizeof(buff)-1); + strmake(buff, msg, sizeof(buff)-1); return TRUE; } === modified file 'sql/log.cc' --- a/sql/log.cc 2008-09-29 15:14:27 +0000 +++ b/sql/log.cc 2008-10-03 21:35:16 +0000 @@ -82,14 +82,25 @@ public: virtual ~Silence_log_table_errors() {} - virtual bool handle_condition(THD *thd, const SQL_condition *cond); + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sql_state, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); const char *message() const { return m_message; } }; bool -Silence_log_table_errors::handle_condition(THD *, const SQL_condition *cond) +Silence_log_table_errors::handle_condition(THD *, + uint, + const char*, + MYSQL_ERROR::enum_warning_level, + const char* msg, + SQL_condition ** cond_hdl) { - strmake(m_message, cond->get_message_text(), sizeof(m_message)-1); + *cond_hdl= NULL; + strmake(m_message, msg, sizeof(m_message)-1); return TRUE; } === modified file 'sql/sp.cc' --- a/sql/sp.cc 2008-08-27 22:14:03 +0000 +++ b/sql/sp.cc 2008-10-03 21:35:16 +0000 @@ -496,15 +496,26 @@ db_find_routine(THD *thd, int type, sp_n struct Silence_deprecated_warning : public Internal_error_handler { public: - virtual bool handle_condition(THD *thd, const SQL_condition *cond); + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); }; bool -Silence_deprecated_warning::handle_condition(THD *thd, - const SQL_condition *cond) -{ - if (cond->get_sql_errno() == ER_WARN_DEPRECATED_SYNTAX && - cond->get_level() == MYSQL_ERROR::WARN_LEVEL_WARN) +Silence_deprecated_warning::handle_condition( + THD *, + uint sql_errno, + const char*, + MYSQL_ERROR::enum_warning_level level, + const char*, + SQL_condition ** cond_hdl) +{ + *cond_hdl= NULL; + if (sql_errno == ER_WARN_DEPRECATED_SYNTAX && + level == MYSQL_ERROR::WARN_LEVEL_WARN) return TRUE; return FALSE; === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2008-10-01 18:27:26 +0000 +++ b/sql/sp_head.cc 2008-10-03 21:35:16 +0000 @@ -1529,7 +1529,7 @@ sp_head::execute_trigger(THD *thd, init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); thd->set_n_backup_active_arena(&call_arena, &backup_arena); - if (!(nctx= new sp_rcontext(mem_root, m_pcont, 0, octx)) || + if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) || nctx->init(thd)) { err_status= TRUE; @@ -1646,7 +1646,7 @@ sp_head::execute_function(THD *thd, Item init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); thd->set_n_backup_active_arena(&call_arena, &backup_arena); - if (!(nctx= new sp_rcontext(mem_root, m_pcont, return_value_fld, octx)) || + if (!(nctx= new sp_rcontext(m_pcont, return_value_fld, octx)) || nctx->init(thd)) { thd->restore_active_arena(&call_arena, &backup_arena); @@ -1850,7 +1850,7 @@ sp_head::execute_procedure(THD *thd, Lis save_spcont= octx= thd->spcont; if (! octx) { // Create a temporary old context - if (!(octx= new sp_rcontext(mem_root, m_pcont, NULL, octx)) || + if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || octx->init(thd)) { delete octx; /* Delete octx if it was init() that failed. */ @@ -1866,7 +1866,7 @@ sp_head::execute_procedure(THD *thd, Lis thd->spcont->callers_arena= thd; } - if (!(nctx= new sp_rcontext(mem_root, m_pcont, NULL, octx)) || + if (!(nctx= new sp_rcontext(m_pcont, NULL, octx)) || nctx->init(thd)) { delete nctx; /* Delete nctx if it was init() that failed. */ === modified file 'sql/sp_rcontext.cc' --- a/sql/sp_rcontext.cc 2008-10-01 18:27:26 +0000 +++ b/sql/sp_rcontext.cc 2008-10-03 21:35:16 +0000 @@ -29,7 +29,7 @@ #include "sp_pcontext.h" -sp_rcontext::sp_rcontext(MEM_ROOT *cond_root, sp_pcontext *root_parsing_ctx, +sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld, sp_rcontext *prev_runtime_ctx) :end_partial_result_set(FALSE), @@ -45,8 +45,7 @@ sp_rcontext::sp_rcontext(MEM_ROOT *cond_ m_hfound(-1), m_ccount(0), m_case_expr_holders(0), - m_prev_runtime_ctx(prev_runtime_ctx), - m_cond_root(cond_root) + m_prev_runtime_ctx(prev_runtime_ctx) { } @@ -71,17 +70,22 @@ sp_rcontext::~sp_rcontext() bool sp_rcontext::init(THD *thd) { uint handler_count= m_root_parsing_ctx->max_handler_index(); + uint i; in_sub_stmt= thd->in_sub_stmt; if (init_var_table(thd) || init_var_items()) return TRUE; + if (!(m_raised_conditions= new (thd->mem_root) SQL_condition[handler_count])) + return TRUE; + + for (i= 0; imem_root); + return !(m_handler= (sp_handler_t*)thd->alloc(handler_count * sizeof(sp_handler_t))) || - !(m_raised_conditions= - (SQL_condition**)thd->calloc(handler_count * sizeof(SQL_condition*))) || !(m_hstack= (uint*)thd->alloc(handler_count * sizeof(uint))) || !(m_in_handler= @@ -198,15 +202,19 @@ sp_rcontext::set_return_value(THD *thd, */ bool -sp_rcontext::find_handler(THD *thd, const SQL_condition *cond) +sp_rcontext::find_handler(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl) { if (m_hfound >= 0) - return 1; // Already got one - - uint sql_errno= cond->get_sql_errno(); - MYSQL_ERROR::enum_warning_level level= cond->get_level(); + { + *cond_hdl= NULL; + return TRUE; // Already got one + } - const char *sqlstate= cond->get_sqlstate(); int i= m_hcount, found= -1; /* @@ -270,18 +278,26 @@ sp_rcontext::find_handler(THD *thd, cons */ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR) - return m_prev_runtime_ctx->find_handler(thd, cond); + return m_prev_runtime_ctx->find_handler(thd, + sql_errno, + sqlstate, + level, + msg, + cond_hdl); + *cond_hdl= NULL; return FALSE; } m_hfound= found; - SQL_condition *raised; - raised= SQL_condition::deep_copy(thd, m_cond_root, cond) ; + SQL_condition *raised= NULL; DBUG_ASSERT(m_hfound >= 0); DBUG_ASSERT((uint) m_hfound < m_root_parsing_ctx->max_handler_index()); - m_raised_conditions[m_hfound]= raised; + raised= & m_raised_conditions[m_hfound]; + raised->clear(); + raised->set(sql_errno, sqlstate, level, msg); + *cond_hdl= raised; return TRUE; } @@ -307,22 +323,25 @@ sp_rcontext::find_handler(THD *thd, cons FALSE if no handler was found. */ bool -sp_rcontext::handle_condition(THD *thd, const SQL_condition *cond) +sp_rcontext::handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl) { + MYSQL_ERROR::enum_warning_level elevated_level= level; + + /* Depending on the sql_mode of execution, warnings may be considered errors */ - if ((cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) && + if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) && thd->really_abort_on_warning()) { - SQL_condition elevated_cond(thd->mem_root); - elevated_cond.set(thd, cond->m_sql_errno, - cond->get_message_text(), - MYSQL_ERROR::WARN_LEVEL_ERROR, - MYF(0)); - return find_handler(thd, & elevated_cond); + elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR; } - return find_handler(thd, cond); + return find_handler(thd, sql_errno, sqlstate, elevated_level, msg, cond_hdl); } void @@ -412,9 +431,7 @@ sp_rcontext::exit_handler() DBUG_ENTER("sp_rcontext::exit_handler"); DBUG_ASSERT(m_ihsp); uint hindex= m_in_handler[m_ihsp-1].index; - DBUG_ASSERT(m_raised_conditions[hindex]); - delete m_raised_conditions[hindex]; - m_raised_conditions[hindex]= NULL; + m_raised_conditions[hindex].clear(); m_ihsp-= 1; DBUG_PRINT("info", ("m_ihsp: %d", m_ihsp)); DBUG_VOID_RETURN; @@ -426,8 +443,7 @@ sp_rcontext::raised_condition() const if (m_ihsp > 0) { uint hindex= m_in_handler[m_ihsp - 1].index; - SQL_condition *raised= m_raised_conditions[hindex]; - DBUG_ASSERT(raised); + SQL_condition *raised= & m_raised_conditions[hindex]; return raised; } === modified file 'sql/sp_rcontext.h' --- a/sql/sp_rcontext.h 2008-10-01 18:27:26 +0000 +++ b/sql/sp_rcontext.h 2008-10-03 21:35:16 +0000 @@ -99,8 +99,8 @@ class sp_rcontext : public Sql_alloc sp_head *sp; #endif - sp_rcontext(MEM_ROOT *cond_root, sp_pcontext *root_parsing_ctx, - Field *return_value_fld, sp_rcontext *prev_runtime_ctx); + sp_rcontext(sp_pcontext *root_parsing_ctx, Field *return_value_fld, + sp_rcontext *prev_runtime_ctx); bool init(THD *thd); ~sp_rcontext(); @@ -129,10 +129,20 @@ class sp_rcontext : public Sql_alloc // Returns 1 if a handler was found, 0 otherwise. bool - find_handler(THD *thd, const SQL_condition *cond); + find_handler(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); // If there is an error handler for this error, handle it and return TRUE. - bool handle_condition(THD *thd, const SQL_condition *cond); + bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); // Returns handler type and sets *ip to location if one was found @@ -240,7 +250,7 @@ private: SQL conditions caught by each handler. This is an array indexed by handler index. */ - SQL_condition ** m_raised_conditions; + SQL_condition * m_raised_conditions; uint m_hcount; // Stack pointer for m_handler uint *m_hstack; // Return stack for continue handlers @@ -258,9 +268,6 @@ private: /* Previous runtime context (NULL if none) */ sp_rcontext *m_prev_runtime_ctx; - /** Memory root to use for SQL_condition caught by handlers. */ - MEM_ROOT *m_cond_root; - private: bool init_var_table(THD *thd); bool init_var_items(); === modified file 'sql/sql_acl.cc' --- a/sql/sql_acl.cc 2008-09-29 15:14:27 +0000 +++ b/sql/sql_acl.cc 2008-10-03 21:35:16 +0000 @@ -6132,7 +6132,12 @@ public: virtual ~Silence_routine_definer_errors() {} - virtual bool handle_condition(THD *thd, const SQL_condition *cond); + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); bool has_errors() { return is_grave; } @@ -6141,17 +6146,23 @@ private: }; bool -Silence_routine_definer_errors::handle_condition(THD *thd, - const SQL_condition *cond) +Silence_routine_definer_errors::handle_condition( + THD *thd, + uint sql_errno, + const char*, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl) { - if (cond->get_level() == MYSQL_ERROR::WARN_LEVEL_ERROR) + *cond_hdl= NULL; + if (level == MYSQL_ERROR::WARN_LEVEL_ERROR) { - switch (cond->get_sql_errno()) + switch (sql_errno) { case ER_NONEXISTING_PROC_GRANT: /* Convert the error into a warning. */ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - cond->get_sql_errno(), cond->get_message_text()); + sql_errno, msg); return TRUE; default: is_grave= TRUE; === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2008-10-01 18:27:26 +0000 +++ b/sql/sql_base.cc 2008-10-03 21:35:16 +0000 @@ -45,7 +45,12 @@ public: virtual ~Prelock_error_handler() {} - virtual bool handle_condition(THD *thd, const SQL_condition *cond); + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); bool safely_trapped_errors(); @@ -56,9 +61,15 @@ private: bool -Prelock_error_handler::handle_condition(THD *, const SQL_condition *cond) +Prelock_error_handler::handle_condition(THD *, + uint sql_errno, + const char*, + MYSQL_ERROR::enum_warning_level, + const char*, + SQL_condition ** cond_hdl) { - if (cond->get_sql_errno() == ER_NO_SUCH_TABLE) + *cond_hdl= NULL; + if (sql_errno == ER_NO_SUCH_TABLE) { m_handled_errors++; return TRUE; === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2008-10-01 18:27:26 +0000 +++ b/sql/sql_class.cc 2008-10-03 21:35:16 +0000 @@ -695,14 +695,24 @@ void THD::push_internal_handler(Internal } -bool THD::handle_condition(const SQL_condition *cond) +bool THD::handle_condition(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl) { if (m_internal_handler) { - return m_internal_handler->handle_condition(this, cond); + return m_internal_handler->handle_condition(this, + sql_errno, + sqlstate, + level, + msg, + cond_hdl); } - return FALSE; // 'FALSE', as per coding style + *cond_hdl= NULL; + return FALSE; } @@ -712,111 +722,144 @@ void THD::pop_internal_handler() m_internal_handler= NULL; } -void THD::raise_error(uint code, const char *str, myf MyFlags) +void THD::raise_error(uint sql_errno, const char *str, myf MyFlags) { - SQL_condition cond(this->mem_root); - cond.set(this, code, str, MYSQL_ERROR::WARN_LEVEL_ERROR, MyFlags); - raise_condition(& cond); + const char* sqlstate= mysql_errno_to_sqlstate(sql_errno); + (void) raise_condition(sql_errno, + sqlstate, + MYSQL_ERROR::WARN_LEVEL_ERROR, + str, + MyFlags); } -void THD::raise_error_printf(uint code, const char *format, myf MyFlags, ...) +void THD::raise_error_printf(uint sql_errno, const char *format, + myf MyFlags, ...) { va_list args; char ebuff[ERRMSGSIZE+20]; DBUG_ENTER("THD::raise_error_printf"); DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d Format: %s", - code, MyFlags, errno, format)); + sql_errno, MyFlags, errno, format)); va_start(args, MyFlags); my_vsnprintf(ebuff, sizeof(ebuff), format, args); va_end(args); - SQL_condition cond(this->mem_root); - cond.set(this, code, ebuff, MYSQL_ERROR::WARN_LEVEL_ERROR, MyFlags); - raise_condition(& cond); + const char* sqlstate= mysql_errno_to_sqlstate(sql_errno); + (void) raise_condition(sql_errno, + sqlstate, + MYSQL_ERROR::WARN_LEVEL_ERROR, + ebuff, + MyFlags); DBUG_VOID_RETURN; } -void THD::raise_warning(uint code, const char *msg) +void THD::raise_warning(uint sql_errno, const char *msg) { - SQL_condition cond(this->mem_root); - cond.set(this, code, msg, MYSQL_ERROR::WARN_LEVEL_WARN, MYF(0)); - raise_condition(& cond); + const char* sqlstate= mysql_errno_to_sqlstate(sql_errno); + (void) raise_condition(sql_errno, + sqlstate, + MYSQL_ERROR::WARN_LEVEL_WARN, + msg, + MYF(0)); } -void THD::raise_warning_printf(uint code, const char *format, ...) +void THD::raise_warning_printf(uint sql_errno, const char *format, ...) { va_list args; char ebuff[ERRMSGSIZE+20]; DBUG_ENTER("THD::raise_warning_printf"); - DBUG_PRINT("enter", ("warning: %u", code)); + DBUG_PRINT("enter", ("warning: %u", sql_errno)); va_start(args, format); my_vsnprintf(ebuff, sizeof(ebuff), format, args); va_end(args); - SQL_condition cond(this->mem_root); - cond.set(this, code, ebuff, MYSQL_ERROR::WARN_LEVEL_WARN, MYF(0)); - raise_condition(& cond); + const char* sqlstate= mysql_errno_to_sqlstate(sql_errno); + (void) raise_condition(sql_errno, + sqlstate, + MYSQL_ERROR::WARN_LEVEL_WARN, + ebuff, + MYF(0)); DBUG_VOID_RETURN; } -void THD::raise_note(uint code, const char *msg) +void THD::raise_note(uint sql_errno, const char *msg) { DBUG_ENTER("THD::raise_note"); - DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg)); + DBUG_PRINT("enter", ("code: %d, msg: %s", sql_errno, msg)); if (!(this->options & OPTION_SQL_NOTES)) DBUG_VOID_RETURN; - SQL_condition cond(this->mem_root); - cond.set(this, code, msg, MYSQL_ERROR::WARN_LEVEL_NOTE, MYF(0)); - raise_condition(& cond); + const char* sqlstate= mysql_errno_to_sqlstate(sql_errno); + (void) raise_condition(sql_errno, + sqlstate, + MYSQL_ERROR::WARN_LEVEL_NOTE, + msg, + MYF(0)); DBUG_VOID_RETURN; } -void THD::raise_note_printf(uint code, const char *format, ...) +void THD::raise_note_printf(uint sql_errno, const char *format, ...) { va_list args; char ebuff[ERRMSGSIZE+20]; DBUG_ENTER("THD::raise_note_printf"); - DBUG_PRINT("enter",("code: %u", code)); + DBUG_PRINT("enter",("code: %u", sql_errno)); if (!(this->options & OPTION_SQL_NOTES)) DBUG_VOID_RETURN; va_start(args, format); my_vsnprintf(ebuff, sizeof(ebuff), format, args); va_end(args); - SQL_condition cond(this->mem_root); - cond.set(this, code, ebuff, MYSQL_ERROR::WARN_LEVEL_NOTE, MYF(0)); - raise_condition(& cond); + const char* sqlstate= mysql_errno_to_sqlstate(sql_errno); + (void) raise_condition(sql_errno, + sqlstate, + MYSQL_ERROR::WARN_LEVEL_NOTE, + ebuff, + MYF(0)); DBUG_VOID_RETURN; } -void THD::raise_condition(const SQL_condition *cond) +SQL_condition* THD::raise_condition(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + myf flags) { - const char* msg= cond->get_message_text(); - + SQL_condition *cond= NULL; DBUG_ENTER("THD::raise_condition"); if (!(this->options & OPTION_SQL_NOTES) && - (cond->m_level == MYSQL_ERROR::WARN_LEVEL_NOTE)) - DBUG_VOID_RETURN; + (level == MYSQL_ERROR::WARN_LEVEL_NOTE)) + DBUG_RETURN(NULL); if (query_id != warn_id && !spcont) mysql_reset_errors(this, 0); - switch (cond->m_level) + if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) && + really_abort_on_warning()) + { + /* + FIXME: + push_warning and strict SQL_MODE case. + */ + level= MYSQL_ERROR::WARN_LEVEL_ERROR; + killed= THD::KILL_BAD_DATA; + } + + switch (level) { case MYSQL_ERROR::WARN_LEVEL_NOTE: case MYSQL_ERROR::WARN_LEVEL_WARN: got_warning= 1; break; case MYSQL_ERROR::WARN_LEVEL_ERROR: - if (cond->m_flags & ME_FATALERROR) + if (flags & ME_FATALERROR) is_fatal_error= 1; break; default: DBUG_ASSERT(FALSE); } - if (handle_condition(cond)) - DBUG_VOID_RETURN; + if (handle_condition(sql_errno, sqlstate, level, msg, &cond)) + DBUG_RETURN(cond); - if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR) + if (level == MYSQL_ERROR::WARN_LEVEL_ERROR) { is_slave_error= 1; // needed to catch query errors during replication @@ -835,8 +878,7 @@ void THD::raise_condition(const SQL_cond (int) is_fatal_error)); } else if (! main_da.is_error()) - main_da.set_error_status(this, cond->m_sql_errno, - msg, cond->get_sqlstate()); + main_da.set_error_status(this, sql_errno, msg, sqlstate); } /* @@ -844,49 +886,54 @@ void THD::raise_condition(const SQL_cond by the stored procedures code. */ if (!is_fatal_error && spcont && - spcont->handle_condition(this, cond)) + spcont->handle_condition(this, sql_errno, sqlstate, level, msg, &cond)) { /* Do not push any warnings, a handled error must be completely silenced. */ - DBUG_VOID_RETURN; + DBUG_RETURN(cond); } /* Un-handled conditions */ - raise_condition_no_handler(cond); - DBUG_VOID_RETURN; + cond= raise_condition_no_handler(sql_errno, sqlstate, level, msg); + DBUG_RETURN(cond); } -void THD::raise_condition_no_handler(const SQL_condition *cond) +SQL_condition* +THD::raise_condition_no_handler(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg) { + SQL_condition *cond= NULL; DBUG_ENTER("THD::raise_condition_no_handler"); query_cache_abort(& query_cache_tls); /* FIXME: broken special case */ - if (no_warnings_for_error && (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR)) - DBUG_VOID_RETURN; + if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR)) + DBUG_RETURN(NULL); if (! main_da.m_stmt_area.is_read_only()) { if (main_da.m_stmt_area.warn_list.elements < variables.max_error_count) { /* We have to use warn_root, as mem_root is freed after each query */ - SQL_condition *stored_cond; - stored_cond= SQL_condition::deep_copy(this, & warn_root, cond); - if (stored_cond) + cond= new (& warn_root) SQL_condition(& warn_root); + if (cond) { - main_da.m_stmt_area.warn_list.push_back(stored_cond, & warn_root); + cond->set(sql_errno, sqlstate, level, msg); + main_da.m_stmt_area.warn_list.push_back(cond, & warn_root); } } - main_da.m_stmt_area.warn_count[(uint) cond->m_level]++; + main_da.m_stmt_area.warn_count[(uint) level]++; } total_warn_count++; - DBUG_VOID_RETURN; + DBUG_RETURN(cond); } extern "C" === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2008-10-01 18:27:26 +0000 +++ b/sql/sql_class.h 2008-10-03 21:35:16 +0000 @@ -1168,6 +1168,20 @@ private: friend class sp_rcontext; /** + Default constructor. + This constructor is usefull when allocating arrays. + Note that the init() method should be called to complete the SQL_condition. + */ + SQL_condition(); + + /** + Complete the SQL_condition initialisation. + @param mem_root The memory root to use for the condition items + of this condition + */ + void init(MEM_ROOT *mem_root); + + /** Constructor. @param mem_root The memory root to use for the condition items of this condition @@ -1179,27 +1193,10 @@ private: {} /** - Deep copy (static method). - Builds a copy of a condition using a given memory root. - 'Deep copy' is useful to propagate SQL conditions raised from a short - lived runtime environment to a parent execution environment with a longer - life cycle. - For example, when proc_p1() calls proc_p2(), an exception raised in - proc_p2() should be copied when caught in proc_p1(), - before destroying the proc_p2() memory root. - @param thd the current thread. - @param mem_root the memory root to use for memory allocation. + Copy optional condition items attributes. @param cond the condition to copy. - @return the duplicated condition. */ - static SQL_condition* deep_copy(THD *thd, MEM_ROOT *mem_root, - const SQL_condition *cond); - - /** - Deep copy (instance method). - @param cond the condition to copy. - */ - void deep_copy(const SQL_condition *cond); + void copy_opt_attributes(const SQL_condition *cond); /** Set this condition area with a fixed message text. @@ -1209,19 +1206,9 @@ private: @param level the error level for this condition. @param MyFlags additional flags. */ - void set(THD *thd, uint code, const char *str, - MYSQL_ERROR::enum_warning_level level, myf MyFlags); - - /** - Set this condition area with formatting of the message text. - @param thd the current thread. - @param code the error number for this condition. - @param str the message text printf format for this condition. - @param level the error level for this condition. - @param MyFlags additional flags. - */ - void set_printf(THD *thd, uint code, const char *str, - MYSQL_ERROR::enum_warning_level level, myf MyFlags, ...); + void set(uint sql_errno, const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg); /** Set the condition message test. @@ -1233,9 +1220,18 @@ private: /** Set the SQLSTATE of this condition. */ void set_sqlstate(const char* sqlstate); + /** + Predicate, returns true if the condition item MESSAGE_TEXT was set. + @return True if MESSAGE_TEXT was set. + */ bool is_message_text_set() const { return m_message_text_set; } + /** + Clear this SQL condition. + */ + void clear(); + private: /** SQL CLASS_ORIGIN condition item. */ UTF8String64 m_class_origin; @@ -1293,9 +1289,6 @@ private: /** Severity (error, warning, note) of this condition. */ MYSQL_ERROR::enum_warning_level m_level; - /** Additional flags. */ - myf m_flags; - /** Memory root to use to hold condition item values. */ MEM_ROOT *m_mem_root; }; @@ -1336,7 +1329,13 @@ public: @param cond the condition raised. @return true if the condition is handled */ - virtual bool handle_condition(THD *thd, const SQL_condition *cond) = 0; + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl) = 0; + }; @@ -2637,7 +2636,11 @@ public: @param cond the sql condition to handle. @return true if the error is handled */ - virtual bool handle_condition(const SQL_condition *cond); + bool handle_condition(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); /** Remove the error handler last pushed. @@ -2724,14 +2727,23 @@ private: Raise a generic SQL condition. @param cond the condition to raise */ - void raise_condition(const SQL_condition *cond); + SQL_condition* + raise_condition(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + myf flags); /** Raise a generic SQL condition, without activation any SQL condition handlers. @param cond the condition to raise */ - void raise_condition_no_handler(const SQL_condition *cond); + SQL_condition* + raise_condition_no_handler(uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg); private: /** The current internal error handler for this thread, or NULL. */ === modified file 'sql/sql_fixstring.cc' --- a/sql/sql_fixstring.cc 2008-10-01 18:27:26 +0000 +++ b/sql/sql_fixstring.cc 2008-10-03 21:35:16 +0000 @@ -33,10 +33,7 @@ void Fixed_string::set(const char* str, if (str == NULL) { - m_ptr= NULL; - m_byte_length= 0; - m_allocated_length= 0; - m_truncated= FALSE; + clear(); return; } @@ -115,6 +112,14 @@ void Fixed_string::copy(const Fixed_stri set(str->m_ptr, str->m_byte_length, str->m_param->m_cs); } +void Fixed_string::clear() +{ + m_ptr= NULL; + m_byte_length= 0; + m_allocated_length= 0; + m_truncated= FALSE; +} + void Fixed_string::reserve(size_t len) { if ((m_ptr != NULL) && (m_allocated_length >= len)) === modified file 'sql/sql_fixstring.h' --- a/sql/sql_fixstring.h 2008-10-01 18:27:26 +0000 +++ b/sql/sql_fixstring.h 2008-10-03 21:35:16 +0000 @@ -59,6 +59,9 @@ public: m_ptr(NULL) {} + void init(MEM_ROOT *mem_root) + { m_mem_root= mem_root; } + /** Destructor. */ ~Fixed_string(); @@ -113,6 +116,8 @@ public: */ void copy(const Fixed_string *str); + void clear(); + private: /** Allocate memory for the string representation. @@ -176,6 +181,10 @@ public: : Fixed_string(& params, root) {} + UTF8String64() + : Fixed_string(& params, NULL) + {} + ~UTF8String64() {} @@ -197,6 +206,10 @@ public: : Fixed_string(& params, root) {} + UTF8String128() + : Fixed_string(& params, NULL) + {} + ~UTF8String128() {} === modified file 'sql/sql_signal.cc' --- a/sql/sql_signal.cc 2008-10-01 18:27:26 +0000 +++ b/sql/sql_signal.cc 2008-10-03 21:35:16 +0000 @@ -213,6 +213,60 @@ const LEX_STRING Diag_statement_item_nam }; +SQL_condition::SQL_condition() + : Sql_alloc(), + m_class_origin(), + m_subclass_origin(), + m_constraint_catalog(), + m_constraint_schema(), + m_constraint_name(), + m_catalog_name(), + m_schema_name(), + m_table_name(), + m_column_name(), + m_cursor_name(), + m_message_text(), + m_message_text_set(FALSE), + m_sql_errno(0), + m_level(MYSQL_ERROR::WARN_LEVEL_ERROR), + m_mem_root(NULL) +{ + memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate)); +} + +void SQL_condition::init(MEM_ROOT *mem_root) +{ + m_class_origin.init(mem_root); + m_subclass_origin.init(mem_root); + m_constraint_catalog.init(mem_root); + m_constraint_schema.init(mem_root); + m_constraint_name.init(mem_root); + m_catalog_name.init(mem_root); + m_schema_name.init(mem_root); + m_table_name.init(mem_root); + m_column_name.init(mem_root); + m_cursor_name.init(mem_root); + m_mem_root= mem_root; +} + +void SQL_condition::clear() +{ + m_class_origin.clear(); + m_subclass_origin.clear(); + m_constraint_catalog.clear(); + m_constraint_schema.clear(); + m_constraint_name.clear(); + m_catalog_name.clear(); + m_schema_name.clear(); + m_table_name.clear(); + m_column_name.clear(); + m_cursor_name.clear(); + m_message_text.length(0); + m_message_text_set= FALSE; + m_sql_errno= 0; + m_level= MYSQL_ERROR::WARN_LEVEL_ERROR; +} + SQL_condition::SQL_condition(MEM_ROOT *mem_root) : Sql_alloc(), m_class_origin(mem_root), @@ -229,42 +283,15 @@ SQL_condition::SQL_condition(MEM_ROOT *m m_message_text_set(FALSE), m_sql_errno(0), m_level(MYSQL_ERROR::WARN_LEVEL_ERROR), - m_flags(0), m_mem_root(mem_root) { memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate)); } -SQL_condition * -SQL_condition::deep_copy(THD *thd, MEM_ROOT *mem_root, - const SQL_condition *cond) -{ - SQL_condition *copy= new (mem_root) SQL_condition(mem_root); - if (copy) - copy->deep_copy(cond); - return copy; -} - void -SQL_condition::deep_copy(const SQL_condition *cond) +SQL_condition::copy_opt_attributes(const SQL_condition *cond) { - memcpy(m_returned_sqlstate, cond->m_returned_sqlstate, - sizeof(m_returned_sqlstate)); - - if (cond->m_message_text.length()) - { - const char* copy; - - copy= strdup_root(m_mem_root, cond->m_message_text.ptr()); - m_message_text.set(copy, cond->m_message_text.length(), - error_message_charset_info); - } - else - m_message_text.length(0); - - DBUG_ASSERT(! m_message_text.is_alloced()); - - m_message_text_set= cond->m_message_text_set; + DBUG_ASSERT(this != cond); m_class_origin.copy(& cond->m_class_origin); m_subclass_origin.copy(& cond->m_subclass_origin); m_constraint_catalog.copy(& cond->m_constraint_catalog); @@ -275,66 +302,28 @@ SQL_condition::deep_copy(const SQL_condi m_table_name.copy(& cond->m_table_name); m_column_name.copy(& cond->m_column_name); m_cursor_name.copy(& cond->m_cursor_name); - m_sql_errno= cond->m_sql_errno; - m_level= cond->m_level; - m_flags= cond->m_flags; } void -SQL_condition::set_printf(THD *thd, uint code, const char *str, - MYSQL_ERROR::enum_warning_level level, - myf flags, ...) +SQL_condition::set(uint sql_errno, const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, const char* msg) { - va_list args; - char ebuff[ERRMSGSIZE+20]; - - - DBUG_ENTER("SQL_condition::set_printf"); - - va_start(args, flags); - (void) my_vsnprintf (ebuff, sizeof(ebuff), str, args); - va_end(args); - - set(thd, code, ebuff, level, flags); - - DBUG_VOID_RETURN; -} - -void -SQL_condition::set(THD *thd, uint code, const char *str, - MYSQL_ERROR::enum_warning_level level, myf flags) -{ - const char* sqlstate; - /* TODO: replace by DBUG_ASSERT(code != 0) once all bugs similar to Bug#36760 are fixed: a SQL condition must have a real (!=0) error number so that it can be caught by handlers. */ - if (code == 0) - code= ER_UNKNOWN_ERROR; - if (str == NULL) - str= ER(code); - m_sql_errno= code; + if (sql_errno == 0) + sql_errno= ER_UNKNOWN_ERROR; + if (msg == NULL) + msg= ER(sql_errno); + m_sql_errno= sql_errno; - sqlstate= mysql_errno_to_sqlstate(m_sql_errno); memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH); m_returned_sqlstate[SQLSTATE_LENGTH]= '\0'; - set_builtin_message_text(str); - if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) && - thd->really_abort_on_warning()) - { - /* - FIXME: - push_warning and strict SQL_MODE case. - */ - m_level= MYSQL_ERROR::WARN_LEVEL_ERROR; - thd->killed= THD::KILL_BAD_DATA; - } - else - m_level= level; - m_flags= flags; + set_builtin_message_text(msg); + m_level= level; } void @@ -722,7 +711,16 @@ int Abstract_signal::raise_condition(THD DBUG_ASSERT((cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) || (cond->m_level == MYSQL_ERROR::WARN_LEVEL_ERROR)); - thd->raise_condition(cond); + SQL_condition *raised= NULL; + raised= thd->raise_condition(cond->get_sql_errno(), + cond->get_sqlstate(), + cond->get_level(), + cond->get_message_text(), + MYF(0)); + if (raised) + { + raised->copy_opt_attributes(cond); + } if (cond->m_level == MYSQL_ERROR::WARN_LEVEL_WARN) { @@ -780,11 +778,18 @@ int SQLCOM_resignal::execute(THD *thd) thd->main_da.m_stmt_area.warn_list.pop(); } - thd->raise_condition_no_handler(signaled); + SQL_condition *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); - SQL_condition new_cond(thd->mem_root); - new_cond.deep_copy(signaled); - result= raise_condition(thd, & new_cond); DBUG_RETURN(result); } === modified file 'sql/unireg.cc' --- a/sql/unireg.cc 2008-08-27 22:14:03 +0000 +++ b/sql/unireg.cc 2008-10-03 21:35:16 +0000 @@ -56,7 +56,12 @@ static bool make_empty_rec(THD *thd, int struct Pack_header_error_handler: public Internal_error_handler { - virtual bool handle_condition(THD *thd, const SQL_condition *cond); + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + SQL_condition ** cond_hdl); bool is_handled; Pack_header_error_handler() :is_handled(FALSE) {} }; @@ -64,9 +69,15 @@ struct Pack_header_error_handler: public bool Pack_header_error_handler:: -handle_condition(THD *, const SQL_condition *cond) +handle_condition(THD *, + uint sql_errno, + const char*, + MYSQL_ERROR::enum_warning_level, + const char*, + SQL_condition ** cond_hdl) { - is_handled= (cond->get_sql_errno() == ER_TOO_MANY_FIELDS); + *cond_hdl= NULL; + is_handled= (sql_errno == ER_TOO_MANY_FIELDS); return is_handled; }