#At file:///home/alik/MySQL/bzr/00/bug55847/mysql-trunk-bugfixing-bug55847.2/ based on revid:luis.soares@stripped
3421 Alexander Nozdrin 2010-12-11
A patch for Bug#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.
The fix is to remove that hack.
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.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 2010-12-11 20:17:36 +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 2010-12-11 20:17:36 +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 2010-11-18 16:34:56 +0000
+++ b/sql/sql_admin.cc 2010-12-11 20:17:36 +0000
@@ -336,13 +336,36 @@ static bool mysql_admin_table(THD* thd,
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;
+ Diagnostics_area da;
+ Warning_info wi(thd->query_id);
+ Diagnostics_area *da_saved= thd->stmt_da;
+ Warning_info *wi_saved= thd->warning_info;
+
+ if (!thd->locked_tables_mode && no_warnings_for_error)
+ {
+ thd->stmt_da= &da;
+ thd-> warning_info= &wi;
+ }
+
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 && no_warnings_for_error)
+ {
+ thd->stmt_da= da_saved;
+ thd->warning_info= wi_saved;
+
+ if (da.is_error())
+ {
+ thd->stmt_da->set_error_status(thd,
+ da.sql_errno(),
+ da.message(),
+ da.get_sqlstate());
+ }
+ }
+
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 2010-11-18 16:34:56 +0000
+++ b/sql/sql_class.cc 2010-12-11 20:17:36 +0000
@@ -584,7 +584,7 @@ THD::THD()
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;
@@ -857,10 +857,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 2010-11-29 16:27:58 +0000
+++ b/sql/sql_class.h 2010-12-11 20:17:36 +0000
@@ -2118,7 +2118,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 */
=== modified file 'sql/sql_error.h'
--- a/sql/sql_error.h 2010-11-18 16:34:56 +0000
+++ b/sql/sql_error.h 2010-12-11 20:17:36 +0000
@@ -398,6 +398,12 @@ public:
}
}
+ void remove_warning(const MYSQL_ERROR *warning)
+ {
+ m_warn_count[warning->get_level()]--;
+ m_statement_warn_count--;
+ }
+
/**
Conditional merge of related warning information areas.
*/
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2010-11-29 11:28:55 +0000
+++ b/sql/sql_parse.cc 2010-12-11 20:17:36 +0000
@@ -7267,6 +7267,7 @@ bool parse_sql(THD *thd,
/* Check that if MYSQLparse() failed, thd->is_error() is set. */
DBUG_ASSERT(!mysql_parse_status ||
+ (mysql_parse_status && thd->get_internal_handler()) ||
(mysql_parse_status && thd->is_error()));
/* Reset parser state. */
=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc 2010-12-06 13:12:51 +0000
+++ b/sql/sql_show.cc 2010-12-11 20:17:36 +0000
@@ -3403,6 +3403,27 @@ end:
}
+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
@@ -3552,7 +3573,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<LEX_STRING> table_names;
int res= make_table_name_list(thd, &table_names, lex,
&lookup_field_vals,
@@ -3601,9 +3621,16 @@ 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))
+ 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;
}
@@ -3613,7 +3640,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,
@@ -6676,7 +6702,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)
@@ -6727,8 +6752,58 @@ 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))
+ bool res;
+
+ {
+ Diagnostics_area da;
+ Diagnostics_area *da_saved= thd->stmt_da;
+ Warning_info wi(thd->query_id);
+ Warning_info *wi_saved= thd->warning_info;
+
+ thd->stmt_da= &da;
+ thd->warning_info= &wi;
+
+ res= table_list->schema_table->fill_table(thd, table_list,
+ tab->select_cond);
+
+ thd->stmt_da= da_saved;
+ thd->warning_info= wi_saved;
+
+ // Pass an error if any.
+
+ if (da.is_error())
+ {
+ thd->warning_info->push_warning(thd,
+ da.sql_errno(),
+ da.get_sqlstate(),
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ da.message());
+
+ thd->stmt_da->set_error_status(thd,
+ da.sql_errno(),
+ da.message(),
+ da.get_sqlstate());
+ }
+
+ // Pass warnings (if any).
+
+ List_iterator<MYSQL_ERROR> it(wi.warn_list());
+ while (true)
+ {
+ MYSQL_ERROR *err = it++;
+
+ if (!err)
+ break;
+
+ if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR)
+ continue;
+
+ wi.remove_warning(err);
+ it.remove();
+ }
+ thd->warning_info->append_warnings(thd, &wi.warn_list());
+ }
+ if (res)
{
result= 1;
join->error= 1;
@@ -6740,7 +6815,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 2010-11-29 16:27:58 +0000
+++ b/sql/sql_trigger.cc 2010-12-11 20:17:36 +0000
@@ -1219,13 +1219,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)) ||
@@ -1356,12 +1355,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.
Attachment: [text/bzr-bundle] bzr/alexander.nozdrin@oracle.com-20101211201736-si21uxfjw4aii9hk.bundle