From: Alexander Nozdrin Date: March 22 2011 2:36pm Subject: bzr commit into mysql-trunk branch (alexander.nozdrin:3306) Bug#11763166 List-Archive: http://lists.mysql.com/commits/133531 X-Bug: 11763166 Message-Id: <201103221436.p2MEatJW012285@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============2672015620103923037==" --===============2672015620103923037== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/alik/MySQL/bzr/00/bug55847/mysql-trunk-bug55847/ based on revid:vinay.fisrekar@stripped 3306 Alexander Nozdrin 2011-03-22 A patch for Bug#11763166 (55847: SHOW WARNINGS returns empty result set when SQLEXCEPTION is active. The problem was in a hackish THD::no_warnings_for_error attribute. When it was set, an error was not written to Warning_info -- only Diagnostics_area state was changed. That means, Diagnostics_area might contain error state, which is not present in Warning_info. The user-visible problem was that in some cases SHOW WARNINGS returned empty result set (i.e. there were no warnings) while the previous SQL statement failed. According to the MySQL protocol errors must be presented in warning list. The fix is to remove THD::no_warnings_for_error. This patch is needed to fix Bug 55843. modified: mysql-test/r/warnings.result mysql-test/t/warnings.test sql/sql_admin.cc sql/sql_class.cc sql/sql_class.h sql/sql_error.cc sql/sql_error.h sql/sql_parse.cc sql/sql_show.cc sql/sql_trigger.cc === modified file 'mysql-test/r/warnings.result' --- a/mysql-test/r/warnings.result 2010-08-30 06:38:09 +0000 +++ b/mysql-test/r/warnings.result 2011-03-22 14:36:29 +0000 @@ -316,3 +316,25 @@ SHOW ERRORS; Level Code Message Error 1051 Unknown table 'test.t1' End of 5.0 tests + +-- Bug#55847 + +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; +CREATE TABLE t1(a INT UNIQUE); +CREATE FUNCTION f1(x INT) RETURNS INT +BEGIN +INSERT INTO t1 VALUES(x); +INSERT INTO t1 VALUES(x); +RETURN x; +END| + +SHOW TABLES WHERE f1(11) = 11; +ERROR 23000: Duplicate entry '11' for key 'a' + +SHOW WARNINGS; +Level Code Message +Error 1062 Duplicate entry '11' for key 'a' + +DROP TABLE t1; +DROP FUNCTION f1; === modified file 'mysql-test/t/warnings.test' --- a/mysql-test/t/warnings.test 2009-11-13 10:17:53 +0000 +++ b/mysql-test/t/warnings.test 2011-03-22 14:36:29 +0000 @@ -228,3 +228,43 @@ DROP TABLE t1; SHOW ERRORS; --echo End of 5.0 tests + +# +# Bug#55847: SHOW WARNINGS returns empty result set when SQLEXCEPTION is active +# + +--echo +--echo -- Bug#55847 +--echo + +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +CREATE TABLE t1(a INT UNIQUE); + +delimiter |; + +CREATE FUNCTION f1(x INT) RETURNS INT +BEGIN + INSERT INTO t1 VALUES(x); + INSERT INTO t1 VALUES(x); + RETURN x; +END| + +delimiter ;| + +--echo + +--error ER_DUP_ENTRY +SHOW TABLES WHERE f1(11) = 11; + +--echo + +SHOW WARNINGS; + +--echo + +DROP TABLE t1; +DROP FUNCTION f1; === modified file 'sql/sql_admin.cc' --- a/sql/sql_admin.cc 2011-03-08 09:21:39 +0000 +++ b/sql/sql_admin.cc 2011-03-22 14:36:29 +0000 @@ -263,7 +263,7 @@ static bool mysql_admin_table(THD* thd, const char *operator_name, thr_lock_type lock_type, bool open_for_modify, - bool no_warnings_for_error, + bool repair_table_use_frm, uint extra_open_options, int (*prepare_func)(THD *, TABLE_LIST *, HA_CHECK_OPT *), @@ -331,18 +331,43 @@ static bool mysql_admin_table(THD* thd, lex->query_tables= table; lex->query_tables_last= &table->next_global; lex->query_tables_own_last= 0; - /* - Under locked tables, we know that the table can be opened, - so any errors opening the table are logical errors. - In these cases it makes sense to report them. - */ - if (!thd->locked_tables_mode) - thd->no_warnings_for_error= no_warnings_for_error; + if (view_operator_func == NULL) table->required_type=FRMTYPE_TABLE; - open_error= open_and_lock_tables(thd, table, TRUE, 0); - thd->no_warnings_for_error= 0; + if (!thd->locked_tables_mode && repair_table_use_frm) + { + /* + If we're not under LOCK TABLES and we're executing REPAIR TABLE + USE_FRM, we need to ignore errors from open_and_lock_tables(). + REPAIR TABLE USE_FRM is a heavy weapon used when a table is + critically damaged, so open_and_lock_tables() will most likely + report errors. Those errors are not interesting for the user + because it's already known that the table is badly damaged. + */ + + Warning_info wi(thd->query_id); + Warning_info *wi_saved= thd->warning_info; + + thd->warning_info= &wi; + + open_error= open_and_lock_tables(thd, table, TRUE, 0); + + thd->warning_info= wi_saved; + } + else + { + /* + It's assumed that even if it is REPAIR TABLE USE_FRM, the table + can be opened if we're under LOCK TABLES (otherwise LOCK TABLES + would fail). Thus, the only errors we could have from + open_and_lock_tables() are about improper locking mode and stuff. + It does make sense for the user to see such errors. + */ + + open_error= open_and_lock_tables(thd, table, TRUE, 0); + } + table->next_global= save_next_global; table->next_local= save_next_local; thd->open_options&= ~extra_open_options; === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2011-03-09 20:54:55 +0000 +++ b/sql/sql_class.cc 2011-03-22 14:36:29 +0000 @@ -587,7 +587,7 @@ THD::THD(bool enable_plugins) client_capabilities= 0; // minimalistic client ull=0; system_thread= NON_SYSTEM_THREAD; - cleanup_done= abort_on_warning= no_warnings_for_error= 0; + cleanup_done= abort_on_warning= 0; peer_port= 0; // For SHOW PROCESSLIST transaction.m_pending_rows_event= 0; transaction.on= 1; @@ -663,6 +663,10 @@ bool THD::handle_condition(uint sql_errn const char* msg, MYSQL_ERROR ** cond_hdl) { +#ifndef DBUG_OFF + m_condition_handled= false; +#endif + if (!m_internal_handler) { *cond_hdl= NULL; @@ -676,6 +680,9 @@ bool THD::handle_condition(uint sql_errn if (error_handler->handle_condition(this, sql_errno, sqlstate, level, msg, cond_hdl)) { +#ifndef DBUG_OFF + m_condition_handled= true; +#endif return TRUE; } } @@ -860,10 +867,6 @@ MYSQL_ERROR* THD::raise_condition(uint s query_cache_abort(&query_cache_tls); - /* FIXME: broken special case */ - if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR)) - DBUG_RETURN(NULL); - /* When simulating OOM, skip writing to error log to avoid mtr errors */ DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(NULL);); === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2011-03-11 09:35:38 +0000 +++ b/sql/sql_class.h 2011-03-22 14:36:29 +0000 @@ -2148,7 +2148,6 @@ public: bool enable_slow_log; /* enable slow log for current statement */ bool abort_on_warning; bool got_warning; /* Set on call to push_warning() */ - bool no_warnings_for_error; /* no warnings on call to my_error() */ /* set during loop of derived table processing */ bool derived_tables_processing; my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ @@ -2789,6 +2788,16 @@ public: inline Internal_error_handler *get_internal_handler() { return m_internal_handler; } +#ifndef DBUG_OFF + /** + Indicates if an internal error handler processed SQL condition. + This operation is intended for debugging only and is used in + parse_sql() in DBUG_ASSERT() macro. + */ + inline bool is_condition_handled() const + { return m_condition_handled; } +#endif + /** Add an internal error handler to the thread execution context. @param handler the exception handler to add @@ -2938,6 +2947,15 @@ private: /** The current internal error handler for this thread, or NULL. */ Internal_error_handler *m_internal_handler; + +#ifndef DBUG_OFF + /** + Indicates if an internal error handler processed SQL condition. + @see is_condition_handled(). + */ + bool m_condition_handled; +#endif + /** The lex to hold the parsed tree of conventional (non-prepared) queries. Whereas for prepared and stored procedure statements we use an own lex === modified file 'sql/sql_error.cc' --- a/sql/sql_error.cc 2011-03-09 20:54:55 +0000 +++ b/sql/sql_error.cc 2011-03-22 14:36:29 +0000 @@ -558,6 +558,20 @@ MYSQL_ERROR *Warning_info::push_warning( return cond; } +MYSQL_ERROR *Warning_info::push_warning(THD *thd, const MYSQL_ERROR *sql_condition) +{ + MYSQL_ERROR *new_condition= push_warning(thd, + sql_condition->get_sql_errno(), + sql_condition->get_sqlstate(), + sql_condition->get_level(), + sql_condition->get_message_text()); + + if (new_condition) + new_condition->copy_opt_attributes(sql_condition); + + return new_condition; +} + /* Push the warning to error list if there is still room in the list === modified file 'sql/sql_error.h' --- a/sql/sql_error.h 2011-03-09 20:54:55 +0000 +++ b/sql/sql_error.h 2011-03-22 14:36:29 +0000 @@ -383,19 +383,13 @@ public: void append_warnings(THD *thd, List *src) { MYSQL_ERROR *err; - MYSQL_ERROR *copy; List_iterator_fast it(*src); /* Don't use ::push_warning() to avoid invocation of condition handlers or escalation of warnings to errors. */ while ((err= it++)) - { - copy= Warning_info::push_warning(thd, err->get_sql_errno(), err->get_sqlstate(), - err->get_level(), err->get_message_text()); - if (copy) - copy->copy_opt_attributes(err); - } + Warning_info::push_warning(thd, err); } /** @@ -461,6 +455,9 @@ public: MYSQL_ERROR::enum_warning_level level, const char* msg); + /** Add a new condition to the current list. */ + MYSQL_ERROR *push_warning(THD *thd, const MYSQL_ERROR *sql_condition); + /** Set the read only status for this statement area. This is a privileged operation, reserved for the implementation of === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2011-03-11 09:35:38 +0000 +++ b/sql/sql_parse.cc 2011-03-22 14:36:29 +0000 @@ -7283,10 +7283,18 @@ bool parse_sql(THD *thd, bool mysql_parse_status= MYSQLparse(thd) != 0; - /* Check that if MYSQLparse() failed, thd->is_error() is set. */ + /* + Check that if MYSQLparse() failed either thd->is_error() is set, or an + internal error handler is set. + + If there is an internal error handler, it might have caught a parsing + error, so thd->is_error() is not set. + */ DBUG_ASSERT(!mysql_parse_status || - (mysql_parse_status && thd->is_error())); + (mysql_parse_status && thd->is_error()) || + (mysql_parse_status && thd->get_internal_handler() && + thd->is_condition_handled())); /* Reset parser state. */ === modified file 'sql/sql_show.cc' --- a/sql/sql_show.cc 2011-03-11 18:53:12 +0000 +++ b/sql/sql_show.cc 2011-03-22 14:36:29 +0000 @@ -3414,6 +3414,45 @@ end: /** + Trigger_error_handler is intended to intercept and silence SQL conditions + that might happen during trigger loading for SHOW statements. + The potential SQL conditions are: + + - ER_PARSE_ERROR -- this error is thrown if a trigger definition file + is damaged or contains invalid CREATE TRIGGER statement. That should + not happen in normal life. + + - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a + trigger created/imported in/from the version of MySQL, which does not + support trigger definers. + + - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a + trigger created/imported in/from the version of MySQL, which does not + support trigger creation contexts. +*/ + +class Trigger_error_handler : public Internal_error_handler +{ +public: + bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) + { + if (sql_errno == ER_PARSE_ERROR || + sql_errno == ER_TRG_NO_DEFINER || + sql_errno == ER_TRG_NO_CREATION_CTX) + return true; + + return false; + } +}; + + + +/** @brief Fill I_S tables whose data are retrieved from frm files and storage engine @@ -3562,7 +3601,6 @@ int get_all_tables(THD *thd, TABLE_LIST acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0)) #endif { - thd->no_warnings_for_error= 1; List table_names; int res= make_table_name_list(thd, &table_names, lex, &lookup_field_vals, @@ -3611,9 +3649,23 @@ int get_all_tables(THD *thd, TABLE_LIST if (!(table_open_method & ~OPEN_FRM_ONLY) && !with_i_schema) { - if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name, - table_name, schema_table_idx, - can_deadlock)) + /* + Here we need to filter out warnings, which can happen + during loading of triggers in fill_schema_table_from_frm(), + because we don't need those warnings to pollute output of + SELECT from I_S / SHOW-statements. + */ + + Trigger_error_handler err_handler; + thd->push_internal_handler(&err_handler); + + int res= fill_schema_table_from_frm(thd, tables, schema_table, db_name, + table_name, schema_table_idx, + can_deadlock); + + thd->pop_internal_handler(); + + if (!res) continue; } @@ -3623,7 +3675,6 @@ int get_all_tables(THD *thd, TABLE_LIST Set the parent lex of 'sel' because it is needed by sel.init_query() which is called inside make_table_list. */ - thd->no_warnings_for_error= 1; sel.parent_lex= lex; /* db_name can be changed in make_table_list() func */ if (!thd->make_lex_string(&orig_db_name, db_name->str, @@ -6665,6 +6716,81 @@ int make_schema_select(THD *thd, SELECT_ } +/** + Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area / + Warning_info state after itself. + + This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which + may "partially silence" some errors. The thing is that during + fill_table() many errors might be emitted. These errors stem from the + nature of fill_table(). + + For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx' + results in a number of 'Table .xxx does not exist' errors, + because fill_table() tries to open the 'xxx' table in every possible + database. + + Those errors are cleared (the error status is cleared from + Diagnostics_area) inside fill_table(), but they remain in Warning_info + (Warning_info is not cleared because it may contain useful warnings). + + THD::no_warnings_for_error used to be set before calling fill_table(), + thus those errors didn't go to Warning_info. This is not the case now + (THD::no_warnings_for_error was eliminated as a hack), so we need to take + care of those warnings here. + + @param thd Thread context. + @param table_list I_S table. + @param join_table JOIN/SELECT table. + + @return Error status. + @retval TRUE Error. + @retval FALSE Success. +*/ +static bool do_fill_table(THD *thd, + TABLE_LIST *table_list, + JOIN_TAB *join_table) +{ + Warning_info wi(thd->query_id); + Warning_info *wi_saved= thd->warning_info; + + thd->warning_info= &wi; + + bool res= table_list->schema_table->fill_table( + thd, table_list, join_table->select_cond); + + thd->warning_info= wi_saved; + + // Pass an error if any. + + if (thd->stmt_da->is_error()) + { + thd->warning_info->push_warning(thd, + thd->stmt_da->sql_errno(), + thd->stmt_da->get_sqlstate(), + MYSQL_ERROR::WARN_LEVEL_ERROR, + thd->stmt_da->message()); + } + + // Pass warnings (if any). + // + // Filter out warnings with WARN_LEVEL_ERROR level, because they + // correspond to the errors which were filtered out in fill_table(). + + + List_iterator_fast it(wi.warn_list()); + MYSQL_ERROR *err; + + while ((err= it++)) + { + if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR) + thd->warning_info->push_warning(thd, err); + } + + return res; +} + + /* Fill temporary schema tables before SELECT @@ -6687,7 +6813,6 @@ bool get_schema_tables_result(JOIN *join bool result= 0; DBUG_ENTER("get_schema_tables_result"); - thd->no_warnings_for_error= 1; for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++) { if (!tab->table || !tab->table->pos_in_table_list) @@ -6738,8 +6863,7 @@ bool get_schema_tables_result(JOIN *join else table_list->table->file->stats.records= 0; - if (table_list->schema_table->fill_table(thd, table_list, - tab->select_cond)) + if (do_fill_table(thd, table_list, tab)) { result= 1; join->error= 1; @@ -6751,7 +6875,6 @@ bool get_schema_tables_result(JOIN *join table_list->schema_table_state= executed_place; } } - thd->no_warnings_for_error= 0; DBUG_RETURN(result); } === modified file 'sql/sql_trigger.cc' --- a/sql/sql_trigger.cc 2011-03-10 08:33:54 +0000 +++ b/sql/sql_trigger.cc 2011-03-22 14:36:29 +0000 @@ -1225,13 +1225,12 @@ bool Table_triggers_list::check_n_load(T DBUG_RETURN(1); // EOM } - - if (!thd->no_warnings_for_error) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRG_NO_CREATION_CTX, - ER(ER_TRG_NO_CREATION_CTX), - (const char*) db, - (const char*) table_name); + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRG_NO_CREATION_CTX, + ER(ER_TRG_NO_CREATION_CTX), + (const char*) db, + (const char*) table_name); if (!(trg_client_cs_name= alloc_lex_string(&table->mem_root)) || !(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) || @@ -1362,12 +1361,12 @@ bool Table_triggers_list::check_n_load(T MySQL, which does not support triggers definers. We should emit warning here. */ - if (!thd->no_warnings_for_error) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER), - (const char*) db, - (const char*) sp->m_name.str); - + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER), + (const char*) db, + (const char*) sp->m_name.str); + /* Set definer to the '' to correct displaying in the information schema. --===============2672015620103923037== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/alexander.nozdrin@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: alexander.nozdrin@stripped\ # p5swumasor8vlwe1 # target_branch: file:///home/alik/MySQL/bzr/00/bug55847/mysql-trunk-\ # bug55847/ # testament_sha1: 4b9fc573391ae1ad62a753ad2b57166d251417ae # timestamp: 2011-03-22 17:36:34 +0300 # base_revision_id: vinay.fisrekar@stripped\ # 0aohyeegnment1i0 # # Begin bundle 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 6RoOiVgxRn/F3JFOFCQ8XS6HAA== --===============2672015620103923037==--