#At file:///mnt/raid/alik/MySQL/bzr/bug43138/6.0-rt-bug43138.2/ based on revid:magne.mahre@stripped
2760 Alexander Nozdrin 2009-04-02
Fix for Bug#43138: DROP DATABASE failure does not clean up message list.
The problem was that the high-level function mysql_rm_db() invoked
low-level mysql_rm_table_part2(), which reported low-level error
(Unknown table) if SE refused to delete a table. Also when
mysql_rm_table_part2() reported an error, it didn't add corresponding
warning into the list (because it is used from other places where such
behaviour is required).
The fix is to
1. Remove no_warnings_for_error usage from sql_table.cc
2. Improve internal error handler support in THD, so that
a stack of error handlers is allowed.
3. Create an internal error handler (Drop_table_error_handler)
to silence useless warnings.
4. Use the handler in DROP DATABASE and DROP TABLE statements.
modified:
mysql-test/r/drop.result
mysql-test/t/drop.test
mysql-test/t/myisam-system.test
sql/sql_class.cc
sql/sql_class.h
sql/sql_db.cc
sql/sql_table.cc
=== modified file 'mysql-test/r/drop.result'
--- a/mysql-test/r/drop.result 2008-12-24 10:48:24 +0000
+++ b/mysql-test/r/drop.result 2009-04-02 10:23:04 +0000
@@ -141,3 +141,28 @@ Error 1146 Table 'mysql.proc' doesn't ex
# --
End of 5.1 tests
+
+# --
+# -- Bug#43138: DROP DATABASE failure does not clean up message list.
+# --
+
+DROP DATABASE IF EXISTS mysql_test;
+
+CREATE DATABASE mysql_test;
+CREATE TABLE mysql_test.t1(a INT);
+CREATE TABLE mysql_test.t2(b INT);
+CREATE TABLE mysql_test.t3(c INT);
+
+SET SESSION DEBUG = "+d,bug43138";
+
+DROP DATABASE mysql_test;
+Warnings:
+Error 1051 Unknown table 't3'
+Error 1051 Unknown table 't2'
+Error 1051 Unknown table 't1'
+
+SET SESSION DEBUG = "-d,bug43138";
+
+# --
+# -- End of Bug#43138.
+# --
=== modified file 'mysql-test/t/drop.test'
--- a/mysql-test/t/drop.test 2009-03-04 13:48:55 +0000
+++ b/mysql-test/t/drop.test 2009-04-02 10:23:04 +0000
@@ -232,3 +232,36 @@ DROP DATABASE mysql_test;
--echo
--echo End of 5.1 tests
+
+###########################################################################
+--echo
+--echo # --
+--echo # -- Bug#43138: DROP DATABASE failure does not clean up message list.
+--echo # --
+--echo
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysql_test;
+--enable_warnings
+
+--echo
+CREATE DATABASE mysql_test;
+CREATE TABLE mysql_test.t1(a INT);
+CREATE TABLE mysql_test.t2(b INT);
+CREATE TABLE mysql_test.t3(c INT);
+
+--echo
+SET SESSION DEBUG = "+d,bug43138";
+
+--echo
+DROP DATABASE mysql_test;
+
+--echo
+SET SESSION DEBUG = "-d,bug43138";
+
+--echo
+--echo # --
+--echo # -- End of Bug#43138.
+--echo # --
+
+###########################################################################
=== modified file 'mysql-test/t/myisam-system.test'
--- a/mysql-test/t/myisam-system.test 2007-12-12 17:19:24 +0000
+++ b/mysql-test/t/myisam-system.test 2009-04-02 10:23:04 +0000
@@ -12,11 +12,11 @@ let $MYSQLD_DATADIR= `select @@datadir`;
drop table if exists t1;
create table t1 (a int) engine=myisam;
--remove_file $MYSQLD_DATADIR/test/t1.MYI
---error 1051,6
+--error ER_BAD_TABLE_ERROR,6
drop table t1;
create table t1 (a int) engine=myisam;
--remove_file $MYSQLD_DATADIR/test/t1.MYD
---error 1105,6,29
+--error ER_BAD_TABLE_ERROR,6,29
drop table t1;
---error 1051
+--error ER_BAD_TABLE_ERROR
drop table t1;
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2009-03-27 22:06:26 +0000
+++ b/sql/sql_class.cc 2009-04-02 10:23:04 +0000
@@ -388,6 +388,30 @@ char *thd_security_context(THD *thd, cha
}
+bool Drop_table_error_handler::handle_condition(
+ THD *thd,
+ uint sql_errno,
+ const char *sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char *msg,
+ MYSQL_ERROR **condition)
+{
+ if (sql_errno == EE_DELETE || sql_errno == ER_TRG_NO_DEFINER)
+ return TRUE;
+
+ if (m_err_handler)
+ {
+ return m_err_handler->handle_condition(thd, sql_errno, sqlstate,
+ level, msg, condition);
+ }
+ else
+ {
+ *condition= NULL;
+ return FALSE;
+ }
+}
+
+
THD::THD()
:Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
/* statement id */ 0),
@@ -548,12 +572,15 @@ THD::THD()
void THD::push_internal_handler(Internal_error_handler *handler)
{
- /*
- TODO: The current implementation is limited to 1 handler at a time only.
- THD and sp_rcontext need to be modified to use a common handler stack.
- */
- DBUG_ASSERT(m_internal_handler == NULL);
- m_internal_handler= handler;
+ if (m_internal_handler)
+ {
+ handler->m_prev_internal_handler= m_internal_handler;
+ m_internal_handler= handler;
+ }
+ else
+ {
+ m_internal_handler= handler;
+ }
}
@@ -581,7 +608,7 @@ bool THD::handle_condition(uint sql_errn
void THD::pop_internal_handler()
{
DBUG_ASSERT(m_internal_handler != NULL);
- m_internal_handler= NULL;
+ m_internal_handler= m_internal_handler->m_prev_internal_handler;
}
void THD::raise_error(uint sql_errno)
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2009-03-18 21:09:40 +0000
+++ b/sql/sql_class.h 2009-04-02 10:23:04 +0000
@@ -1109,7 +1109,10 @@ show_system_thread(enum_thread_type thre
class Internal_error_handler
{
protected:
- Internal_error_handler() {}
+ Internal_error_handler() :
+ m_prev_internal_handler(NULL)
+ { }
+
virtual ~Internal_error_handler() {}
public:
@@ -1144,6 +1147,36 @@ public:
const char* msg,
MYSQL_ERROR ** cond_hdl) = 0;
+private:
+ Internal_error_handler *m_prev_internal_handler;
+ friend class THD;
+};
+
+
+/**
+ This class is an internal error handler implementation for DROP DATABASE
+ and DROP TABLE statements. The thing is that there may be warnings during
+ execution of these statements, which should not be exposed to the user.
+ This class is intended to silence such warnings.
+*/
+
+class Drop_table_error_handler : public Internal_error_handler
+{
+public:
+ Drop_table_error_handler(Internal_error_handler *err_handler)
+ :m_err_handler(err_handler)
+ { }
+
+public:
+ virtual bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char *sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char *msg,
+ MYSQL_ERROR **condition);
+
+private:
+ Internal_error_handler *m_err_handler;
};
/**
@@ -2281,6 +2314,9 @@ public:
thd_scheduler scheduler;
public:
+ inline Internal_error_handler *get_internal_handler()
+ { return m_internal_handler; }
+
/**
Add an internal error handler to the thread execution context.
@param handler the exception handler to add
=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc 2009-02-11 12:11:20 +0000
+++ b/sql/sql_db.cc 2009-04-02 10:23:04 +0000
@@ -913,6 +913,9 @@ bool mysql_rm_db(THD *thd,char *db,bool
}
else
{
+ Drop_table_error_handler err_handler(thd->get_internal_handler());
+ thd->push_internal_handler(&err_handler);
+
error= -1;
/*
We temporarily disable the binary log while dropping the objects
@@ -945,6 +948,8 @@ bool mysql_rm_db(THD *thd,char *db,bool
error = 0;
reenable_binlog(thd);
}
+
+ thd->pop_internal_handler();
}
if (!silent && deleted>=0)
{
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2009-03-27 22:06:26 +0000
+++ b/sql/sql_table.cc 2009-04-02 10:23:04 +0000
@@ -1498,6 +1498,8 @@ bool mysql_rm_table(THD *thd,TABLE_LIST
my_bool drop_temporary)
{
bool error, need_start_waiting= FALSE;
+ Drop_table_error_handler err_handler(thd->get_internal_handler());
+
DBUG_ENTER("mysql_rm_table");
/* mark for close and remove all cached entries */
@@ -1509,7 +1511,9 @@ bool mysql_rm_table(THD *thd,TABLE_LIST
DBUG_RETURN(TRUE);
}
+ thd->push_internal_handler(&err_handler);
error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0);
+ thd->pop_internal_handler();
if (need_start_waiting)
start_waiting_global_read_lock(thd);
@@ -1649,9 +1653,6 @@ int mysql_rm_table_part2(THD *thd, TABLE
}
}
- /* Don't give warnings for not found errors, as we already generate notes */
- thd->no_warnings_for_error= 1;
-
for (table= tables; table; table= table->next_local)
{
char *db=table->db;
@@ -1793,11 +1794,18 @@ int mysql_rm_table_part2(THD *thd, TABLE
wrong_tables.append(',');
wrong_tables.append(String(table->table_name,system_charset_info));
}
+
+ DBUG_EXECUTE_IF("bug43138",
+ my_printf_error(ER_BAD_TABLE_ERROR,
+ ER(ER_BAD_TABLE_ERROR), MYF(0),
+ table->table_name););
+
DBUG_PRINT("table", ("table: %p s: %p", table->table,
table->table ? table->table->s : (TABLE_SHARE *)-1));
}
thd->thread_specific_used|= tmp_table_deleted;
error= 0;
+
if (wrong_tables.length())
{
if (!foreign_key_error)
@@ -1890,7 +1898,6 @@ err:
}
end:
- thd->no_warnings_for_error= 0;
DBUG_RETURN(error);
}
Attachment: [text/bzr-bundle] bzr/alik@sun.com-20090402102304-e6wp5w2vr2jz57io.bundle