From: Jon Olav Hauglid Date: July 4 2012 2:07pm Subject: bzr push into mysql-trunk-wl6406 branch (jon.hauglid:3969 to 3970) WL#6406 List-Archive: http://lists.mysql.com/commits/144367 Message-Id: <20120704140726.11746.80309.3970@atum08.no.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3970 Jon Olav Hauglid 2012-07-04 WL#6406 Stacked diagnostic areas Patch 2: Refactoring: - Combined Warning_info and Diagnostics_area and removed Warning_info. - Combined Sql_condition::init() and Sql_condition::set() with constructor modified: sql/sp_rcontext.cc sql/sql_error.cc sql/sql_error.h sql/sql_signal.cc 3969 Jon Olav Hauglid 2012-07-04 WL#6406 Stacked diagnostic areas Patch 1: - Added THD::push_diagnostics_area(), THD::pop_diagnostics_area() and THD::get_stacked_da(). Related code added to sql_error. - Removed push/pop of warning info, used push/pop da instead. - Removed set_stmt_da(), used push/pop da instead. modified: sql/rpl_master.cc sql/sp_head.cc sql/sql_admin.cc sql/sql_class.h sql/sql_error.cc sql/sql_error.h sql/sql_get_diagnostics.cc sql/sql_partition.cc sql/sql_prepare.cc sql/sql_show.cc === modified file 'sql/sp_rcontext.cc' --- a/sql/sp_rcontext.cc 2012-06-06 12:12:51 +0000 +++ b/sql/sp_rcontext.cc 2012-07-04 14:06:47 +0000 @@ -262,11 +262,12 @@ bool sp_rcontext::handle_sql_condition(T */ if (!found_condition) { - Sql_condition *condition= - new (callers_arena->mem_root) Sql_condition(callers_arena->mem_root); - condition->set(da->sql_errno(), da->get_sqlstate(), - Sql_condition::WARN_LEVEL_ERROR, - da->message()); + Sql_condition *condition= new (callers_arena->mem_root) + Sql_condition(callers_arena->mem_root, + da->sql_errno(), + da->get_sqlstate(), + Sql_condition::WARN_LEVEL_ERROR, + da->message()); found_condition= condition; } } === modified file 'sql/sql_error.cc' --- a/sql/sql_error.cc 2012-07-04 13:47:16 +0000 +++ b/sql/sql_error.cc 2012-07-04 14:06:47 +0000 @@ -170,7 +170,26 @@ using std::max; consequence of WL#751. */ -Sql_condition::Sql_condition() + +static void copy_string(MEM_ROOT *mem_root, String* dst, const String* src) +{ + size_t len= src->length(); + if (len) + { + char* copy= (char*) alloc_root(mem_root, len + 1); + if (copy) + { + memcpy(copy, src->ptr(), len); + copy[len]= '\0'; + dst->set(copy, len, src->charset()); + } + } + else + dst->length(0); +} + + +Sql_condition::Sql_condition(MEM_ROOT *mem_root) : Sql_alloc(), m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin), m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin), @@ -185,36 +204,17 @@ Sql_condition::Sql_condition() m_message_text(), m_sql_errno(0), m_level(Sql_condition::WARN_LEVEL_ERROR), - m_mem_root(NULL) + m_mem_root(mem_root) { + DBUG_ASSERT(mem_root != NULL); memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate)); } -void Sql_condition::init(MEM_ROOT *mem_root) -{ - DBUG_ASSERT(mem_root != NULL); - DBUG_ASSERT(m_mem_root == NULL); - m_mem_root= mem_root; -} -void Sql_condition::clear() -{ - m_class_origin.length(0); - m_subclass_origin.length(0); - m_constraint_catalog.length(0); - m_constraint_schema.length(0); - m_constraint_name.length(0); - m_catalog_name.length(0); - m_schema_name.length(0); - m_table_name.length(0); - m_column_name.length(0); - m_cursor_name.length(0); - m_message_text.length(0); - m_sql_errno= 0; - m_level= Sql_condition::WARN_LEVEL_ERROR; -} - -Sql_condition::Sql_condition(MEM_ROOT *mem_root) +Sql_condition::Sql_condition(MEM_ROOT *mem_root, uint sql_errno, + const char* sqlstate, + Sql_condition::enum_warning_level level, + const char* msg) : Sql_alloc(), m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin), m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin), @@ -227,33 +227,25 @@ Sql_condition::Sql_condition(MEM_ROOT *m m_column_name((const char*) NULL, 0, & my_charset_utf8_bin), m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin), m_message_text(), - m_sql_errno(0), - m_level(Sql_condition::WARN_LEVEL_ERROR), + m_sql_errno(sql_errno), + m_level(level), m_mem_root(mem_root) { DBUG_ASSERT(mem_root != NULL); + DBUG_ASSERT(sql_errno != 0); + DBUG_ASSERT(sqlstate != NULL); + DBUG_ASSERT(msg != NULL); + memset(m_returned_sqlstate, 0, sizeof(m_returned_sqlstate)); -} -static void copy_string(MEM_ROOT *mem_root, String* dst, const String* src) -{ - size_t len= src->length(); - if (len) - { - char* copy= (char*) alloc_root(mem_root, len + 1); - if (copy) - { - memcpy(copy, src->ptr(), len); - copy[len]= '\0'; - dst->set(copy, len, src->charset()); - } - } - else - dst->length(0); + set_builtin_message_text(msg); + set_sqlstate(sqlstate); + set_class_origin(); + set_subclass_origin(); } -void -Sql_condition::copy_opt_attributes(const Sql_condition *cond) + +void Sql_condition::copy_opt_attributes(const Sql_condition *cond) { DBUG_ASSERT(this != cond); copy_string(m_mem_root, & m_class_origin, & cond->m_class_origin); @@ -268,26 +260,8 @@ Sql_condition::copy_opt_attributes(const copy_string(m_mem_root, & m_cursor_name, & cond->m_cursor_name); } -void -Sql_condition::set(uint sql_errno, const char* sqlstate, - Sql_condition::enum_warning_level level, const char* msg) -{ - DBUG_ASSERT(sql_errno != 0); - DBUG_ASSERT(sqlstate != NULL); - DBUG_ASSERT(msg != NULL); - m_sql_errno= sql_errno; - memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH); - m_returned_sqlstate[SQLSTATE_LENGTH]= '\0'; - - set_class_origin(); - set_subclass_origin(); - set_builtin_message_text(msg); - m_level= level; -} - -void -Sql_condition::set_builtin_message_text(const char* str) +void Sql_condition::set_builtin_message_text(const char* str) { /* See the comments @@ -300,32 +274,21 @@ Sql_condition::set_builtin_message_text( DBUG_ASSERT(! m_message_text.is_alloced()); } -const char* -Sql_condition::get_message_text() const -{ - return m_message_text.ptr(); -} -int -Sql_condition::get_message_octet_length() const -{ - return m_message_text.length(); -} - -void -Sql_condition::set_sqlstate(const char* sqlstate) +void Sql_condition::set_sqlstate(const char* sqlstate) { memcpy(m_returned_sqlstate, sqlstate, SQLSTATE_LENGTH); m_returned_sqlstate[SQLSTATE_LENGTH]= '\0'; } + static LEX_CSTRING sqlstate_origin[]= { { STRING_WITH_LEN("ISO 9075") }, { STRING_WITH_LEN("MySQL") } }; -void -Sql_condition::set_class_origin() + +void Sql_condition::set_class_origin() { char cls[2]; LEX_CSTRING *origin; @@ -356,8 +319,8 @@ Sql_condition::set_class_origin() m_class_origin.set_ascii(origin->str, origin->length); } -void -Sql_condition::set_subclass_origin() + +void Sql_condition::set_subclass_origin() { LEX_CSTRING *origin; @@ -378,28 +341,67 @@ Sql_condition::set_subclass_origin() m_subclass_origin.set_ascii(origin->str, origin->length); } + +void Sql_condition::clear() +{ + m_class_origin.length(0); + m_subclass_origin.length(0); + m_constraint_catalog.length(0); + m_constraint_schema.length(0); + m_constraint_name.length(0); + m_catalog_name.length(0); + m_schema_name.length(0); + m_table_name.length(0); + m_column_name.length(0); + m_cursor_name.length(0); + m_message_text.length(0); + m_sql_errno= 0; + m_level= Sql_condition::WARN_LEVEL_ERROR; +} + + Diagnostics_area::Diagnostics_area() - : m_main_wi(0, false), m_stacked_da(NULL) + : m_stacked_da(NULL), + m_error_condition(NULL), + m_allow_unlimited_warnings(false), + m_read_only(false), + m_current_statement_warn_count(0), + m_current_row_for_warning(1), + m_warn_id(0) { + /* Initialize sub structures */ + init_sql_alloc(&m_warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); + m_warn_list.empty(); + memset(m_warn_count, 0, sizeof(m_warn_count)); reset_diagnostics_area(); } + Diagnostics_area::Diagnostics_area(ulonglong warning_info_id, bool allow_unlimited_warnings) - : m_main_wi(warning_info_id, allow_unlimited_warnings), - m_stacked_da(NULL) + : m_stacked_da(NULL), + m_error_condition(NULL), + m_allow_unlimited_warnings(allow_unlimited_warnings), + m_read_only(false), + m_current_statement_warn_count(0), + m_current_row_for_warning(1), + m_warn_id(warning_info_id) { + /* Initialize sub structures */ + init_sql_alloc(&m_warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); + m_warn_list.empty(); + memset(m_warn_count, 0, sizeof(m_warn_count)); reset_diagnostics_area(); } -/** - Clear this diagnostics area. - Normally called at the end of a statement. -*/ +Diagnostics_area::~Diagnostics_area() +{ + free_root(&m_warn_root,MYF(0)); +} -void -Diagnostics_area::reset_diagnostics_area() + +void Diagnostics_area::reset_diagnostics_area() { DBUG_ENTER("reset_diagnostics_area"); #ifdef DBUG_OFF @@ -411,7 +413,7 @@ Diagnostics_area::reset_diagnostics_area m_last_insert_id= 0; m_statement_warn_count= 0; #endif - m_main_wi.clear_error_condition(); + clear_error_condition(); set_is_sent(false); /** Tiny reset in debug mode to see garbage right away */ m_status= DA_EMPTY; @@ -419,15 +421,9 @@ Diagnostics_area::reset_diagnostics_area } -/** - Set OK status -- ends commands that do not return a - result set, e.g. INSERT/UPDATE/DELETE. -*/ - -void -Diagnostics_area::set_ok_status(ulonglong affected_rows, - ulonglong last_insert_id, - const char *message) +void Diagnostics_area::set_ok_status(ulonglong affected_rows, + ulonglong last_insert_id, + const char *message) { DBUG_ENTER("set_ok_status"); DBUG_ASSERT(! is_set()); @@ -450,12 +446,7 @@ Diagnostics_area::set_ok_status(ulonglon } -/** - Set EOF status. -*/ - -void -Diagnostics_area::set_eof_status(THD *thd) +void Diagnostics_area::set_eof_status(THD *thd) { DBUG_ENTER("set_eof_status"); /* Only allowed to report eof if has not yet reported an error */ @@ -480,16 +471,8 @@ Diagnostics_area::set_eof_status(THD *th DBUG_VOID_RETURN; } -/** - Set ERROR status in the Diagnostics Area. This function should be used to - report fatal errors (such as out-of-memory errors) when no further - processing is possible. - - @param sql_errno SQL-condition error number -*/ -void -Diagnostics_area::set_error_status(uint sql_errno) +void Diagnostics_area::set_error_status(uint sql_errno) { set_error_status(sql_errno, ER(sql_errno), @@ -497,23 +480,11 @@ Diagnostics_area::set_error_status(uint NULL); } -/** - Set ERROR status in the Diagnostics Area. - - @note error_condition may be NULL. It happens if a) OOM error is being - reported; or b) when Warning_info is full. - @param sql_errno SQL-condition error number - @param message SQL-condition message - @param sqlstate SQL-condition state - @param error_condition SQL-condition object representing the error state -*/ - -void -Diagnostics_area::set_error_status(uint sql_errno, - const char *message, - const char *sqlstate, - const Sql_condition *error_condition) +void Diagnostics_area::set_error_status(uint sql_errno, + const char *message, + const char *sqlstate, + const Sql_condition *error_condition) { DBUG_ENTER("set_error_status"); /* @@ -543,50 +514,22 @@ Diagnostics_area::set_error_status(uint m_sqlstate[SQLSTATE_LENGTH]= '\0'; strmake(m_message, message, sizeof(m_message)-1); - m_main_wi.set_error_condition(error_condition); + set_error_condition(error_condition); m_status= DA_ERROR; DBUG_VOID_RETURN; } -/** - Mark the diagnostics area as 'DISABLED'. - - This is used in rare cases when the COM_ command at hand sends a response - in a custom format. One example is the query cache, another is - COM_STMT_PREPARE. -*/ - -void -Diagnostics_area::disable_status() +void Diagnostics_area::disable_status() { DBUG_ASSERT(! is_set()); m_status= DA_DISABLED; } -Warning_info::Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings) - :m_current_statement_warn_count(0), - m_current_row_for_warning(1), - m_warn_id(warn_id_arg), - m_error_condition(NULL), - m_allow_unlimited_warnings(allow_unlimited_warnings), - m_read_only(FALSE) -{ - /* Initialize sub structures */ - init_sql_alloc(&m_warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); - m_warn_list.empty(); - memset(m_warn_count, 0, sizeof(m_warn_count)); -} - -Warning_info::~Warning_info() -{ - free_root(&m_warn_root,MYF(0)); -} - -bool Warning_info::has_sql_condition(const char *message_str, - ulong message_length) const +bool Diagnostics_area::has_sql_condition(const char *message_str, + ulong message_length) const { Diagnostics_area::Sql_condition_iterator it(m_warn_list); const Sql_condition *err; @@ -601,9 +544,9 @@ bool Warning_info::has_sql_condition(con } -void Warning_info::clear(ulonglong new_id) +void Diagnostics_area::clear_warning_info(ulonglong new_id) { - id(new_id); + set_warning_info_id(new_id); m_warn_list.empty(); m_marked_sql_conditions.empty(); free_root(&m_warn_root, MYF(0)); @@ -614,7 +557,7 @@ void Warning_info::clear(ulonglong new_i } -void Warning_info::append_warning_info(THD *thd, const Warning_info *source) +void Diagnostics_area::append_warning_info(THD *thd, const Diagnostics_area *source) { const Sql_condition *err; Diagnostics_area::Sql_condition_iterator it(source->m_warn_list); @@ -623,7 +566,7 @@ void Warning_info::append_warning_info(T while ((err= it++)) { // Do not use ::push_warning() to avoid invocation of THD-internal-handlers. - Sql_condition *new_error= Warning_info::push_warning(thd, err); + Sql_condition *new_error= Diagnostics_area::push_warning(thd, err); if (src_error_condition && src_error_condition == err) set_error_condition(new_error); @@ -637,7 +580,7 @@ void Warning_info::append_warning_info(T void Diagnostics_area::copy_non_errors_from_da(THD *thd, const Diagnostics_area *src_da) { - Sql_condition_iterator it(src_da->m_main_wi.m_warn_list); + Sql_condition_iterator it(src_da->m_warn_list); const Sql_condition *cond; while ((cond= it++)) @@ -645,15 +588,15 @@ void Diagnostics_area::copy_non_errors_f if (cond->get_level() == Sql_condition::WARN_LEVEL_ERROR) continue; - Sql_condition *new_condition= m_main_wi.push_warning(thd, cond); + Sql_condition *new_condition= push_warning(thd, cond); - if (src_da->m_main_wi.is_marked_for_removal(cond)) - m_main_wi.mark_condition_for_removal(new_condition); + if (src_da->is_marked_for_removal(cond)) + mark_condition_for_removal(new_condition); } } -void Warning_info::mark_sql_conditions_for_removal() +void Diagnostics_area::mark_sql_conditions_for_removal() { Sql_condition_list::Iterator it(m_warn_list); Sql_condition *cond; @@ -663,7 +606,7 @@ void Warning_info::mark_sql_conditions_f } -void Warning_info::remove_marked_sql_conditions() +void Diagnostics_area::remove_marked_sql_conditions() { List_iterator_fast it(m_marked_sql_conditions); Sql_condition *cond; @@ -681,7 +624,7 @@ void Warning_info::remove_marked_sql_con } -bool Warning_info::is_marked_for_removal(const Sql_condition *cond) const +bool Diagnostics_area::is_marked_for_removal(const Sql_condition *cond) const { List_iterator_fast it( const_cast&> (m_marked_sql_conditions)); @@ -697,16 +640,17 @@ bool Warning_info::is_marked_for_removal } -void Warning_info::reserve_space(THD *thd, uint count) +void Diagnostics_area::reserve_space(THD *thd, uint count) { while ((m_warn_list.elements() + count) > thd->variables.max_error_count) m_warn_list.remove(m_warn_list.front()); } -Sql_condition *Warning_info::push_warning(THD *thd, - uint sql_errno, const char* sqlstate, - Sql_condition::enum_warning_level level, - const char *msg) + +Sql_condition *Diagnostics_area::push_warning(THD *thd, + uint sql_errno, const char* sqlstate, + Sql_condition::enum_warning_level level, + const char *msg) { Sql_condition *cond= NULL; @@ -715,10 +659,10 @@ Sql_condition *Warning_info::push_warnin if (m_allow_unlimited_warnings || m_warn_list.elements() < thd->variables.max_error_count) { - cond= new (& m_warn_root) Sql_condition(& m_warn_root); + cond= new (& m_warn_root) Sql_condition(& m_warn_root, sql_errno, + sqlstate, level, msg); if (cond) { - cond->set(sql_errno, sqlstate, level, msg); m_warn_list.push_back(cond); } } @@ -729,7 +673,8 @@ Sql_condition *Warning_info::push_warnin return cond; } -Sql_condition *Warning_info::push_warning(THD *thd, const Sql_condition *sql_condition) + +Sql_condition *Diagnostics_area::push_warning(THD *thd, const Sql_condition *sql_condition) { Sql_condition *new_condition= push_warning(thd, sql_condition->get_sql_errno(), @@ -748,7 +693,7 @@ void Diagnostics_area::push_diagnostics_ { DBUG_ASSERT(da->m_stacked_da == NULL); da->m_stacked_da= this; - da->m_main_wi.append_warning_info(thd, &m_main_wi); + da->append_warning_info(thd, this); } === modified file 'sql/sql_error.h' --- a/sql/sql_error.h 2012-07-04 13:47:16 +0000 +++ b/sql/sql_error.h 2012-07-04 14:06:47 +0000 @@ -48,13 +48,15 @@ public: Get the MESSAGE_TEXT of this condition. @return the message text. */ - const char* get_message_text() const; + const char* get_message_text() const + { return m_message_text.ptr(); } /** Get the MESSAGE_OCTET_LENGTH of this condition. @return the length in bytes of the message text. */ - int get_message_octet_length() const; + int get_message_octet_length() const + { return m_message_text.length(); } /** Get the SQLSTATE of this condition. @@ -91,7 +93,7 @@ private: which should be used. */ friend class THD; - friend class Warning_info; + friend class Diagnostics_area; friend class Sql_cmd_common_signal; friend class Sql_cmd_signal; friend class Sql_cmd_resignal; @@ -99,25 +101,26 @@ private: friend class Condition_information_item; /** - Default constructor. - This constructor is usefull when allocating arrays. - Note that the init() method should be called to complete the Sql_condition. - */ - Sql_condition(); + Constructor. - /** - Complete the Sql_condition initialisation. - @param mem_root The memory root to use for the condition items - of this condition + @param mem_root Memory root to use for the condition items + of this condition. */ - void init(MEM_ROOT *mem_root); + Sql_condition(MEM_ROOT *mem_root); /** Constructor. - @param mem_root The memory root to use for the condition items - of this condition - */ - Sql_condition(MEM_ROOT *mem_root); + + @param mem_root Memory root to use for the condition items + of this condition. + @param sql_errno Error number. + @param sqlstate SQLSTATE. + @param level Condition level - error, warning or note. + @param msg Message text. + */ + Sql_condition(MEM_ROOT *mem_root, uint sql_errno, const char* sqlstate, + Sql_condition::enum_warning_level level, + const char *msg); /** Destructor. */ ~Sql_condition() @@ -130,18 +133,6 @@ private: void copy_opt_attributes(const Sql_condition *cond); /** - Set this condition area with a fixed message text. - @param thd the current thread. - @param code the error number for this condition. - @param str the message text for this condition. - @param level the error level for this condition. - @param MyFlags additional flags. - */ - void set(uint sql_errno, const char* sqlstate, - Sql_condition::enum_warning_level level, - const char* msg); - - /** Set the condition message test. @param str Message text, expressed in the character set derived from the server --language option @@ -157,9 +148,7 @@ private: /** Set the SUBCLASS_ORIGIN of this condition. */ void set_subclass_origin(); - /** - Clear this SQL condition. - */ + /** Clear this SQL condition. */ void clear(); private: @@ -218,307 +207,6 @@ private: /////////////////////////////////////////////////////////////////////////// -/** - Information about warnings of the current connection. -*/ -class Warning_info -{ - /** The type of the counted and doubly linked list of conditions. */ - typedef I_P_List, - I_P_List_counter, - I_P_List_fast_push_back > - Sql_condition_list; - - /** A memory root to allocate warnings and errors */ - MEM_ROOT m_warn_root; - - /** List of warnings of all severities (levels). */ - Sql_condition_list m_warn_list; - - /** A break down of the number of warnings per severity (level). */ - uint m_warn_count[(uint) Sql_condition::WARN_LEVEL_END]; - - /** - The number of warnings of the current statement. Warning_info - life cycle differs from statement life cycle -- it may span - multiple statements. In that case we get - m_current_statement_warn_count 0, whereas m_warn_list is not empty. - */ - uint m_current_statement_warn_count; - - /* - Row counter, to print in errors and warnings. Not increased in - create_sort_index(); may differ from examined_row_count. - */ - ulong m_current_row_for_warning; - - /** Used to optionally clear warnings only once per statement. */ - ulonglong m_warn_id; - - /** - A pointer to an element of m_warn_list. It determines SQL-condition - instance which corresponds to the error state in Diagnostics_area. - - This is needed for properly processing SQL-conditions in SQL-handlers. - When an SQL-handler is found for the current error state in Diagnostics_area, - this pointer is needed to remove the corresponding SQL-condition from the - Warning_info list. - - @note m_error_condition might be NULL in the following cases: - - Diagnostics_area set to fatal error state (like OOM); - - Max number of Warning_info elements has been reached (thus, there is - no corresponding SQL-condition object in Warning_info). - */ - const Sql_condition *m_error_condition; - - /** Indicates if push_warning() allows unlimited number of warnings. */ - bool m_allow_unlimited_warnings; - - /** Read only status. */ - bool m_read_only; - - List m_marked_sql_conditions; - - Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings); - ~Warning_info(); - - Warning_info(const Warning_info &rhs); /* Not implemented */ - Warning_info& operator=(const Warning_info &rhs); /* Not implemented */ - - /** - Checks if Warning_info contains SQL-condition with the given message. - - @param message_str Message string. - @param message_length Length of message string. - - @return true if the Warning_info contains an SQL-condition with the given - message. - */ - bool has_sql_condition(const char *message_str, ulong message_length) const; - - /** - Reset the warning information. Clear all warnings, - the number of warnings, reset current row counter - to point to the first row. - - @param new_id new Warning_info id. - */ - void clear(ulonglong new_id); - - /** - Only clear warning info if haven't yet done that already - for the current query. Allows to be issued at any time - during the query, without risk of clearing some warnings - that have been generated by the current statement. - - @todo: This is a sign of sloppy coding. Instead we need to - designate one place in a statement life cycle where we call - Warning_info::clear(). - - @param query_id Current query id. - */ - void opt_clear(ulonglong query_id) - { - if (query_id != m_warn_id) - clear(query_id); - } - - /** - Concatenate the list of warnings. - - It's considered tolerable to lose an SQL-condition in case of OOM-error, - or if the number of SQL-conditions in the Warning_info reached top limit. - - @param thd Thread context. - @param source Warning_info object to copy SQL-conditions from. - */ - void append_warning_info(THD *thd, const Warning_info *source); - - /** - Reset between two COM_ commands. Warnings are preserved - between commands, but statement_warn_count indicates - the number of warnings of this particular statement only. - */ - void reset_for_next_command() - { m_current_statement_warn_count= 0; } - - /** - Mark active SQL-conditions for later removal. - This is done to simulate stacked DAs for HANDLER statements. - */ - void mark_sql_conditions_for_removal(); - - /** - Unmark SQL-conditions, which were marked for later removal. - This is done to simulate stacked DAs for HANDLER statements. - */ - void unmark_sql_conditions_from_removal() - { m_marked_sql_conditions.empty(); } - - /** - Remove SQL-conditions that are marked for deletion. - This is done to simulate stacked DAs for HANDLER statements. - */ - void remove_marked_sql_conditions(); - - /** - Check if the given SQL-condition is marked for removal in this Warning_info - instance. - - @param cond the SQL-condition. - - @retval true if the given SQL-condition is marked for removal in this - Warning_info instance. - @retval false otherwise. - */ - bool is_marked_for_removal(const Sql_condition *cond) const; - - /** - Mark a single SQL-condition for removal (add the given SQL-condition to the - removal list of this Warning_info instance). - */ - void mark_condition_for_removal(Sql_condition *cond) - { m_marked_sql_conditions.push_back(cond, &m_warn_root); } - - /** - Used for @@warning_count system variable, which prints - the number of rows returned by SHOW WARNINGS. - */ - ulong warn_count() const - { - /* - This may be higher than warn_list.elements() if we have - had more warnings than thd->variables.max_error_count. - */ - return (m_warn_count[(uint) Sql_condition::WARN_LEVEL_NOTE] + - m_warn_count[(uint) Sql_condition::WARN_LEVEL_ERROR] + - m_warn_count[(uint) Sql_condition::WARN_LEVEL_WARN]); - } - - /** - The number of errors, or number of rows returned by SHOW ERRORS, - also the value of session variable @@error_count. - */ - ulong error_count() const - { return m_warn_count[(uint) Sql_condition::WARN_LEVEL_ERROR]; } - - /** - The number of conditions (errors, warnings and notes) in the list. - */ - uint cond_count() const - { - return m_warn_list.elements(); - } - - /** Id of the warning information area. */ - ulonglong id() const { return m_warn_id; } - - /** Set id of the warning information area. */ - void id(ulonglong id) { m_warn_id= id; } - - /** Do we have any errors and warnings that we can *show*? */ - bool is_empty() const { return m_warn_list.is_empty(); } - - /** Increment the current row counter to point at the next row. */ - void inc_current_row_for_warning() { m_current_row_for_warning++; } - - /** Reset the current row counter. Start counting from the first row. */ - void reset_current_row_for_warning() { m_current_row_for_warning= 1; } - - /** Return the current counter value. */ - ulong current_row_for_warning() const { return m_current_row_for_warning; } - - /** Return the number of warnings thrown by the current statement. */ - ulong current_statement_warn_count() const - { return m_current_statement_warn_count; } - - /** Make sure there is room for the given number of conditions. */ - void reserve_space(THD *thd, uint count); - - /** - Add a new SQL-condition to the current list and increment the respective - counters. - - @param thd Thread context. - @param sql_errno SQL-condition error number. - @param sqlstate SQL-condition state. - @param level SQL-condition level. - @param msg SQL-condition message. - - @return a pointer to the added SQL-condition. - */ - Sql_condition *push_warning(THD *thd, - uint sql_errno, - const char* sqlstate, - Sql_condition::enum_warning_level level, - const char* msg); - - /** - Add a new SQL-condition to the current list and increment the respective - counters. - - @param thd Thread context. - @param sql_condition SQL-condition to copy values from. - - @return a pointer to the added SQL-condition. - */ - Sql_condition *push_warning(THD *thd, const Sql_condition *sql_condition); - - /** - Set the read only status for this statement area. - This is a privileged operation, reserved for the implementation of - diagnostics related statements, to enforce that the statement area is - left untouched during execution. - The diagnostics statements are: - - SHOW WARNINGS - - SHOW ERRORS - - GET DIAGNOSTICS - @param read_only the read only property to set. - */ - void set_read_only(bool read_only) - { m_read_only= read_only; } - - /** - Read only status. - @return the read only property. - */ - bool is_read_only() const - { return m_read_only; } - - /** - @return SQL-condition, which corresponds to the error state in - Diagnostics_area. - - @see m_error_condition. - */ - const Sql_condition *get_error_condition() const - { return m_error_condition; } - - /** - Set SQL-condition, which corresponds to the error state in Diagnostics_area. - - @see m_error_condition. - */ - void set_error_condition(const Sql_condition *error_condition) - { m_error_condition= error_condition; } - - /** - Reset SQL-condition, which corresponds to the error state in - Diagnostics_area. - - @see m_error_condition. - */ - void clear_error_condition() - { m_error_condition= NULL; } - - // for: - // - is_marked_for_removal() - friend class Diagnostics_area; -}; - uint err_conv(char *buff, size_t to_length, const char *from, size_t from_length, const CHARSET_INFO *from_cs); @@ -579,9 +267,18 @@ public: */ class Diagnostics_area { + /** The type of the counted and doubly linked list of conditions. */ + typedef I_P_List, + I_P_List_counter, + I_P_List_fast_push_back > + Sql_condition_list; + public: /** Const iterator used to iterate through the warning list. */ - typedef Warning_info::Sql_condition_list::Const_Iterator + typedef Sql_condition_list::Const_Iterator Sql_condition_iterator; enum enum_diagnostics_status @@ -598,6 +295,10 @@ public: DA_DISABLED }; + Diagnostics_area(); + Diagnostics_area(ulonglong warning_info_id, bool allow_unlimited_warnings); + ~Diagnostics_area(); + void set_overwrite_status(bool can_overwrite_status) { m_can_overwrite_status= can_overwrite_status; } @@ -605,21 +306,58 @@ public: void set_is_sent(bool is_sent) { m_is_sent= is_sent; } + /** + Set OK status -- ends commands that do not return a + result set, e.g. INSERT/UPDATE/DELETE. + */ void set_ok_status(ulonglong affected_rows, ulonglong last_insert_id, const char *message); + /** + Set EOF status. + */ void set_eof_status(THD *thd); - void set_error_status(uint sql_errno); + /** + Set ERROR status in the Diagnostics Area. This function should be used to + report fatal errors (such as out-of-memory errors) when no further + processing is possible. + + @param sql_errno SQL-condition error number + */ + void set_error_status(uint sql_errno); + + /** + Set ERROR status in the Diagnostics Area. + + @note error_condition may be NULL. It happens if a) OOM error is being + reported; or b) when Warning_info is full. + @param sql_errno SQL-condition error number + @param message SQL-condition message + @param sqlstate SQL-condition state + @param error_condition SQL-condition object representing the error state + */ void set_error_status(uint sql_errno, const char *message, const char *sqlstate, const Sql_condition *error_condition); + /** + Mark the diagnostics area as 'DISABLED'. + + This is used in rare cases when the COM_ command at hand sends a response + in a custom format. One example is the query cache, another is + COM_STMT_PREPARE. + */ void disable_status(); + /** + Clear this diagnostics area. + + Normally called at the end of a statement. + */ void reset_diagnostics_area(); bool is_set() const { return m_status != DA_EMPTY; } @@ -655,14 +393,13 @@ public: return m_statement_warn_count; } - Diagnostics_area(); - Diagnostics_area(ulonglong warning_info_id, bool allow_unlimited_warnings); - + /** Set id of the warning information area. */ void set_warning_info_id(ulonglong id) - { m_main_wi.id(id); } + { m_warn_id= id; } + /** Id of the warning information area. */ ulonglong warning_info_id() const - { return m_main_wi.id(); } + { return m_warn_id; } /** Compare given current and given diagnostic area @@ -675,82 +412,188 @@ public: @return false if they are equal, true if they are not. */ bool diagnostics_area_changed(const Diagnostics_area *da) const - { return m_main_wi.id() != da->m_main_wi.id(); } + { return warning_info_id() != da->warning_info_id(); } + /** Do we have any errors and warnings that we can *show*? */ bool is_warning_info_empty() const - { return m_main_wi.is_empty(); } + { return m_warn_list.is_empty(); } + /** Return the number of warnings thrown by the current statement. */ ulong current_statement_warn_count() const - { return m_main_wi.current_statement_warn_count(); } - - bool has_sql_condition(const char *message_str, ulong message_length) const - { return m_main_wi.has_sql_condition(message_str, message_length); } + { return m_current_statement_warn_count; } + /** + Reset between two COM_ commands. Warnings are preserved + between commands, but statement_warn_count indicates + the number of warnings of this particular statement only. + */ void reset_for_next_command() - { m_main_wi.reset_for_next_command(); } + { m_current_statement_warn_count= 0; } + + /** + Checks if Warning_info contains SQL-condition with the given message. + + @param message_str Message string. + @param message_length Length of message string. + + @return true if the Warning_info contains an SQL-condition with the given + message. + */ + bool has_sql_condition(const char *message_str, ulong message_length) const; + + /** + Reset the warning information. Clear all warnings, + the number of warnings, reset current row counter + to point to the first row. + + @param new_id new Warning_info id. + */ + void clear_warning_info(ulonglong id); + + /** + Only clear warning info if haven't yet done that already + for the current query. Allows to be issued at any time + during the query, without risk of clearing some warnings + that have been generated by the current statement. - void clear_warning_info(ulonglong id) - { m_main_wi.clear(id); } + @todo: This is a sign of sloppy coding. Instead we need to + designate one place in a statement life cycle where we call + Warning_info::clear(). + @param query_id Current query id. + */ void opt_clear_warning_info(ulonglong query_id) - { m_main_wi.opt_clear(query_id); } + { + if (query_id != m_warn_id) + clear_warning_info(query_id); + } + /** Return the current counter value. */ ulong current_row_for_warning() const - { return m_main_wi.current_row_for_warning(); } + { return m_current_row_for_warning; } + /** Increment the current row counter to point at the next row. */ void inc_current_row_for_warning() - { m_main_wi.inc_current_row_for_warning(); } + { m_current_row_for_warning++; } + /** Reset the current row counter. Start counting from the first row. */ void reset_current_row_for_warning() - { m_main_wi.reset_current_row_for_warning(); } + { m_current_row_for_warning= 1; } + /** + Read only status. + @return the read only property. + */ bool is_warning_info_read_only() const - { return m_main_wi.is_read_only(); } + { return m_read_only; } + /** + Set the read only status for this statement area. + This is a privileged operation, reserved for the implementation of + diagnostics related statements, to enforce that the statement area is + left untouched during execution. + The diagnostics statements are: + - SHOW WARNINGS + - SHOW ERRORS + - GET DIAGNOSTICS + @param read_only the read only property to set. + */ void set_warning_info_read_only(bool read_only) - { m_main_wi.set_read_only(read_only); } + { m_read_only= read_only; } + /** + The number of errors, or number of rows returned by SHOW ERRORS, + also the value of session variable @@error_count. + */ ulong error_count() const - { return m_main_wi.error_count(); } + { return m_warn_count[(uint) Sql_condition::WARN_LEVEL_ERROR]; } + /** + Used for @@warning_count system variable, which prints + the number of rows returned by SHOW WARNINGS. + */ ulong warn_count() const - { return m_main_wi.warn_count(); } + { + /* + This may be higher than warn_list.elements() if we have + had more warnings than thd->variables.max_error_count. + */ + return (m_warn_count[(uint) Sql_condition::WARN_LEVEL_NOTE] + + m_warn_count[(uint) Sql_condition::WARN_LEVEL_ERROR] + + m_warn_count[(uint) Sql_condition::WARN_LEVEL_WARN]); + } + /** + The number of conditions (errors, warnings and notes) in the list. + */ uint cond_count() const - { return m_main_wi.cond_count(); } + { return m_warn_list.elements(); } Sql_condition_iterator sql_conditions() const - { return m_main_wi.m_warn_list; } + { return m_warn_list; } + + /** Make sure there is room for the given number of conditions. */ + void reserve_space(THD *thd, uint count); + + /** + Add a new SQL-condition to the current list and increment the respective + counters. + + @param thd Thread context. + @param sql_condition SQL-condition to copy values from. + + @return a pointer to the added SQL-condition. + */ + Sql_condition *push_warning(THD *thd, const Sql_condition *sql_condition); - void reserve_space(THD *thd, uint count) - { m_main_wi.reserve_space(thd, count); } + /** + Add a new SQL-condition to the current list and increment the respective + counters. - Sql_condition *push_warning(THD *thd, const Sql_condition *sql_condition) - { return m_main_wi.push_warning(thd, sql_condition); } + @param thd Thread context. + @param sql_errno SQL-condition error number. + @param sqlstate SQL-condition state. + @param level SQL-condition level. + @param msg SQL-condition message. + @return a pointer to the added SQL-condition. + */ Sql_condition *push_warning(THD *thd, uint sql_errno, const char* sqlstate, Sql_condition::enum_warning_level level, - const char* msg) - { - return m_main_wi.push_warning(thd, sql_errno, sqlstate, level, msg); - } + const char* msg); + + /** + @return SQL-condition, which corresponds to the error state in + Diagnostics_area. - void mark_sql_conditions_for_removal() - { m_main_wi.mark_sql_conditions_for_removal(); } + @see m_error_condition. + */ + const Sql_condition *get_error_condition() const + { return m_error_condition; } - void unmark_sql_conditions_from_removal() - { m_main_wi.unmark_sql_conditions_from_removal(); } + /** + Mark active SQL-conditions for later removal. + This is done to simulate stacked DAs for HANDLER statements. + */ + void mark_sql_conditions_for_removal(); - void remove_marked_sql_conditions() - { m_main_wi.remove_marked_sql_conditions(); } + /** + Unmark SQL-conditions, which were marked for later removal. + This is done to simulate stacked DAs for HANDLER statements. + */ + void unmark_sql_conditions_from_removal() + { m_marked_sql_conditions.empty(); } - const Sql_condition *get_error_condition() const - { return m_main_wi.get_error_condition(); } + /** + Remove SQL-conditions that are marked for deletion. + This is done to simulate stacked DAs for HANDLER statements. + */ + void remove_marked_sql_conditions(); void copy_sql_conditions_from_da(THD *thd, const Diagnostics_area *src_da) - { m_main_wi.append_warning_info(thd, &src_da->m_main_wi); } + { append_warning_info(thd, src_da); } /** Copy Sql_conditions that are not WARN_LEVEL_ERROR from the source @@ -795,23 +638,106 @@ private: { return m_stacked_da; } private: + /** + Concatenate the list of warnings. + + It's considered tolerable to lose an SQL-condition in case of OOM-error, + or if the number of SQL-conditions in the Warning_info reached top limit. + + @param thd Thread context. + @param source Warning_info object to copy SQL-conditions from. + */ + void append_warning_info(THD *thd, const Diagnostics_area *source); + + /** + Check if the given SQL-condition is marked for removal in this Warning_info + instance. + + @param cond the SQL-condition. + + @retval true if the given SQL-condition is marked for removal in this + Warning_info instance. + @retval false otherwise. + */ + bool is_marked_for_removal(const Sql_condition *cond) const; + + /** + Mark a single SQL-condition for removal (add the given SQL-condition to the + removal list of this Warning_info instance). + */ + void mark_condition_for_removal(Sql_condition *cond) + { m_marked_sql_conditions.push_back(cond, &m_warn_root); } + + /** + Set SQL-condition, which corresponds to the error state in Diagnostics_area. + + @see m_error_condition. + */ + void set_error_condition(const Sql_condition *error_condition) + { m_error_condition= error_condition; } + + /** + Reset SQL-condition, which corresponds to the error state in + Diagnostics_area. + + @see m_error_condition. + */ + void clear_error_condition() + { m_error_condition= NULL; } + +private: + /** Pointer to the diagnostic area below on the stack. */ + Diagnostics_area *m_stacked_da; + + /** A memory root to allocate warnings and errors */ + MEM_ROOT m_warn_root; + + /** List of warnings of all severities (levels). */ + Sql_condition_list m_warn_list; + + /** + A pointer to an element of m_warn_list. It determines SQL-condition + instance which corresponds to the error state in Diagnostics_area. + + This is needed for properly processing SQL-conditions in SQL-handlers. + When an SQL-handler is found for the current error state in Diagnostics_area, + this pointer is needed to remove the corresponding SQL-condition from the + Warning_info list. + + @note m_error_condition might be NULL in the following cases: + - Diagnostics_area set to fatal error state (like OOM); + - Max number of Warning_info elements has been reached (thus, there is + no corresponding SQL-condition object in Warning_info). + */ + const Sql_condition *m_error_condition; + + List m_marked_sql_conditions; + /** True if status information is sent to the client. */ bool m_is_sent; /** Set to make set_error_status after set_{ok,eof}_status possible. */ bool m_can_overwrite_status; + /** Indicates if push_warning() allows unlimited number of warnings. */ + bool m_allow_unlimited_warnings; + + /** Read only status. */ + bool m_read_only; + /** Message buffer. Can be used by OK or ERROR status. */ char m_message[MYSQL_ERRMSG_SIZE]; + char m_sqlstate[SQLSTATE_LENGTH+1]; + + enum_diagnostics_status m_status; + /** SQL error number. One of ER_ codes from share/errmsg.txt. Set by set_error_status. */ uint m_sql_errno; - char m_sqlstate[SQLSTATE_LENGTH+1]; - /** The number of rows affected by the last statement. This is semantically close to thd->row_count_func, but has a different @@ -840,12 +766,25 @@ private: */ uint m_statement_warn_count; - enum_diagnostics_status m_status; + /** + The number of warnings of the current statement. Warning_info + life cycle differs from statement life cycle -- it may span + multiple statements. In that case we get + m_current_statement_warn_count 0, whereas m_warn_list is not empty. + */ + uint m_current_statement_warn_count; - Warning_info m_main_wi; + /** A break down of the number of warnings per severity (level). */ + uint m_warn_count[(uint) Sql_condition::WARN_LEVEL_END]; - /** Pointer to the diagnostic area below on the stack. */ - Diagnostics_area *m_stacked_da; + /** + Row counter, to print in errors and warnings. Not increased in + create_sort_index(); may differ from examined_row_count. + */ + ulong m_current_row_for_warning; + + /** Used to optionally clear warnings only once per statement. */ + ulonglong m_warn_id; friend class THD; }; === modified file 'sql/sql_signal.cc' --- a/sql/sql_signal.cc 2012-03-19 17:59:14 +0000 +++ b/sql/sql_signal.cc 2012-07-04 14:06:47 +0000 @@ -18,6 +18,7 @@ #include "sp_pcontext.h" #include "sp_rcontext.h" #include "sql_signal.h" +#include "sql_error.h" /* The parser accepts any error code (desired) @@ -123,15 +124,15 @@ void Sql_cmd_common_signal::eval_default DBUG_ASSERT(sqlstate); /* SQLSTATE class "00": illegal, rejected in the parser. */ - DBUG_ASSERT((sqlstate[0] != '0') || (sqlstate[1] != '0')); + DBUG_ASSERT(!is_sqlstate_completion(sqlstate)); - if ((sqlstate[0] == '0') && (sqlstate[1] == '1')) + if (is_sqlstate_warning(sqlstate)) { /* SQLSTATE class "01": warning. */ assign_defaults(cond, set_defaults, Sql_condition::WARN_LEVEL_WARN, ER_SIGNAL_WARN); } - else if ((sqlstate[0] == '0') && (sqlstate[1] == '2')) + else if (is_sqlstate_not_found(sqlstate)) { /* SQLSTATE class "02": not found. */ assign_defaults(cond, set_defaults, @@ -503,11 +504,11 @@ bool Sql_cmd_resignal::execute(THD *thd) DBUG_RETURN(true); } - Sql_condition signaled_err(thd->mem_root); - signaled_err.set(signaled->sql_errno, - signaled->sql_state, - signaled->level, - signaled->message); + Sql_condition signaled_err(thd->mem_root, + signaled->sql_errno, + signaled->sql_state, + signaled->level, + signaled->message); if (m_cond) // RESIGNAL with signal_value. No bundle (reason: useless for push emails).