Below is the list of changes that have just been committed into a local
5.1 repository of davi. When davi does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-10-30 19:02:22-02:00, davi@stripped +15 -0
Bug#30882 Dropping a temporary table inside a stored function may cause a server crash
If a stored function that contains a drop temporary table statement
is invoked by a create temporary table of the same name may cause
a server crash. The problem is that when dropping a table no check
is done to ensure that table is not being used by some outer query
(or outer statement), potentially leaving the outer query with a
reference to a stale (freed) table.
The solution is when dropping a temporary table, always check if
the table is being used by some outer statement as a temporary
table can be dropped inside stored procedures.
The check is performed by looking at the query_id of the temporary
tables, it should always be zero for unused tables. But this was not
always the case because of a bug in prelocked mode that prevented the
query_id from being reset. Now, all temporary tables which were used by
a statement are marked as free for reuse after it's execution has been
completed.
mysql-test/include/handler.inc@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +32 -0
Add test case for side effect of Bug#30882
mysql-test/r/handler_innodb.result@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +62 -0
Add test case result for side effect of Bug#30882
mysql-test/r/handler_myisam.result@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +62 -0
Add test case result for side effect of Bug#30882
mysql-test/r/sp-error.result@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +48 -1
Add test case result for Bug#30882
mysql-test/t/sp-error.test@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +68 -4
Add test case for Bug#30882
sql/event_db_repository.cc@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +1 -1
Update close_thread_tables call, no more default values.
sql/mysql_priv.h@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +2 -2
Remove implicit default parameters values of the close_thread_tables
function as no callers are using it.
sql/slave.cc@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +1 -1
Update close_thread_tables call, no more default values.
sql/sp_head.cc@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +1 -1
Update close_thread_tables call, no more default values.
sql/sql_base.cc@stripped, 2007-10-30 19:02:19-02:00, davi@stripped +90 -50
When entering in prelocked mode, mark as free for reuse all temp
tables which are not in use by the main statement. Also re-factor
close_thread_tables() to not take LOCK_open unless there are open
tables.
sql/sql_handler.cc@stripped, 2007-10-30 19:02:20-02:00, davi@stripped +14 -0
Properly close temporary tables associated with a handler.
sql/sql_insert.cc@stripped, 2007-10-30 19:02:20-02:00, davi@stripped +1 -1
close_temporary_table is now merged into drop_temporary_table.
sql/sql_parse.cc@stripped, 2007-10-30 19:02:20-02:00, davi@stripped +6 -9
The condition doesn't cover all the possibilities under which
close_thread_tables should be called. It's safe to unconditionally
call close_thread_tables as the function was refactored to take
LOCK_open only when necessary.
sql/sql_table.cc@stripped, 2007-10-30 19:02:20-02:00, davi@stripped +16 -6
Use drop_temporary_table which perform checks to verify if
the table is not being used.
sql/table.h@stripped, 2007-10-30 19:02:20-02:00, davi@stripped +20 -2
Rename previously unused clear_query_id and document the usage of
query_id and open_by_handler.
diff -Nrup a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc
--- a/mysql-test/include/handler.inc 2007-10-10 21:39:19 -03:00
+++ b/mysql-test/include/handler.inc 2007-10-30 19:02:19 -02:00
@@ -566,3 +566,35 @@ reap;
connection default;
drop table t2;
disconnect flush;
+
+#
+# Bug#30882 Dropping a temporary table inside a stored function may cause a server crash
+#
+# Test HANDLER statements in conjunction with temporary tables. While the temporary table
+# is open by a HANDLER, no other statement can access it.
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create temporary table t1 (a int, b char(1), key a(a), key b(a,b));
+insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
+ (5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j");
+select a,b from t1;
+handler t1 open as a1;
+handler a1 read a first;
+handler a1 read a next;
+handler a1 read a next;
+--error ER_CANT_REOPEN_TABLE
+select a,b from t1;
+handler a1 read a prev;
+handler a1 read a prev;
+handler a1 read a=(6) where b="g";
+handler a1 close;
+select a,b from t1;
+handler t1 open as a2;
+handler a2 read a first;
+handler a2 read a last;
+handler a2 read a prev;
+handler a2 close;
+drop table t1;
diff -Nrup a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result
--- a/mysql-test/r/handler_innodb.result 2007-10-10 21:39:19 -03:00
+++ b/mysql-test/r/handler_innodb.result 2007-10-30 19:02:19 -02:00
@@ -575,3 +575,65 @@ ERROR 42S02: Table 'test.t1' doesn't exi
handler t1 close;
handler t2 close;
drop table t2;
+drop table if exists t1;
+create temporary table t1 (a int, b char(1), key a(a), key b(a,b));
+insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
+(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j");
+select a,b from t1;
+a b
+0 a
+1 b
+2 c
+3 d
+4 e
+5 f
+6 g
+7 h
+8 i
+9 j
+handler t1 open as a1;
+handler a1 read a first;
+a b
+0 a
+handler a1 read a next;
+a b
+1 b
+handler a1 read a next;
+a b
+2 c
+select a,b from t1;
+ERROR HY000: Can't reopen table: 'a1'
+handler a1 read a prev;
+a b
+1 b
+handler a1 read a prev;
+a b
+0 a
+handler a1 read a=(6) where b="g";
+a b
+6 g
+handler a1 close;
+select a,b from t1;
+a b
+0 a
+1 b
+2 c
+3 d
+4 e
+5 f
+6 g
+7 h
+8 i
+9 j
+handler t1 open as a2;
+handler a2 read a first;
+a b
+0 a
+handler a2 read a last;
+a b
+9 j
+handler a2 read a prev;
+a b
+8 i
+handler a2 close;
+drop table t1;
diff -Nrup a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result
--- a/mysql-test/r/handler_myisam.result 2007-10-10 21:39:20 -03:00
+++ b/mysql-test/r/handler_myisam.result 2007-10-30 19:02:19 -02:00
@@ -575,3 +575,65 @@ ERROR 42S02: Table 'test.t1' doesn't exi
handler t1 close;
handler t2 close;
drop table t2;
+drop table if exists t1;
+create temporary table t1 (a int, b char(1), key a(a), key b(a,b));
+insert into t1 values (0,"a"),(1,"b"),(2,"c"),(3,"d"),(4,"e"),
+(5,"f"),(6,"g"),(7,"h"),(8,"i"),(9,"j");
+select a,b from t1;
+a b
+0 a
+1 b
+2 c
+3 d
+4 e
+5 f
+6 g
+7 h
+8 i
+9 j
+handler t1 open as a1;
+handler a1 read a first;
+a b
+0 a
+handler a1 read a next;
+a b
+1 b
+handler a1 read a next;
+a b
+2 c
+select a,b from t1;
+ERROR HY000: Can't reopen table: 'a1'
+handler a1 read a prev;
+a b
+1 b
+handler a1 read a prev;
+a b
+0 a
+handler a1 read a=(6) where b="g";
+a b
+6 g
+handler a1 close;
+select a,b from t1;
+a b
+0 a
+1 b
+2 c
+3 d
+4 e
+5 f
+6 g
+7 h
+8 i
+9 j
+handler t1 open as a2;
+handler a2 read a first;
+a b
+0 a
+handler a2 read a last;
+a b
+9 j
+handler a2 read a prev;
+a b
+8 i
+handler a2 close;
+drop table t1;
diff -Nrup a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
--- a/mysql-test/r/sp-error.result 2007-10-17 00:47:02 -02:00
+++ b/mysql-test/r/sp-error.result 2007-10-30 19:02:19 -02:00
@@ -1428,7 +1428,6 @@ create function bug20701() returns varch
ERROR 42000: This version of MySQL doesn't yet support 'return value collation'
create function bug20701() returns varchar(25) return "test";
drop function bug20701;
-End of 5.1 tests
create procedure proc_26503_error_1()
begin
retry:
@@ -1523,3 +1522,51 @@ ERROR 42000: You have an error in your S
SELECT ..inexistent();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.inexistent()' at line 1
USE test;
+drop function if exists f1;
+drop function if exists f2;
+drop table if exists t1, t2;
+create function f1() returns int
+begin
+drop temporary table t1;
+return 1;
+end|
+create temporary table t1 as select f1();
+ERROR HY000: Can't reopen table: 't1'
+create function f2() returns int
+begin
+create temporary table t2 as select f1();
+return 1;
+end|
+create temporary table t1 as select f2();
+ERROR HY000: Can't reopen table: 't1'
+drop function f1;
+drop function f2;
+create function f1() returns int
+begin
+drop temporary table t2,t1;
+return 1;
+end|
+create function f2() returns int
+begin
+create temporary table t2 as select f1();
+return 1;
+end|
+create temporary table t1 as select f2();
+ERROR HY000: Can't reopen table: 't2'
+drop function f1;
+drop function f2;
+create temporary table t2(a int);
+select * from t2;
+a
+create function f2() returns int
+begin
+drop temporary table t2;
+return 1;
+end|
+select f2();
+f2()
+1
+drop function f2;
+drop table t2;
+ERROR 42S02: Unknown table 't2'
+End of 5.1 tests
diff -Nrup a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
--- a/mysql-test/t/sp-error.test 2007-10-16 19:41:27 -02:00
+++ b/mysql-test/t/sp-error.test 2007-10-30 19:02:19 -02:00
@@ -2078,10 +2078,6 @@ create function bug20701() returns varch
create function bug20701() returns varchar(25) return "test";
drop function bug20701;
-
---echo End of 5.1 tests
-
-
#
# Bug#26503 (Illegal SQL exception handler code causes the server to crash)
#
@@ -2221,6 +2217,74 @@ SELECT .inexistent();
--error ER_PARSE_ERROR
SELECT ..inexistent();
USE test;
+
+#
+# Bug#30882 Dropping a temporary table inside a stored function may cause a server crash
+#
+
+--disable_warnings
+drop function if exists f1;
+drop function if exists f2;
+drop table if exists t1, t2;
+--enable_warnings
+
+delimiter |;
+create function f1() returns int
+begin
+ drop temporary table t1;
+ return 1;
+end|
+delimiter ;|
+--error ER_CANT_REOPEN_TABLE
+create temporary table t1 as select f1();
+
+delimiter |;
+create function f2() returns int
+begin
+ create temporary table t2 as select f1();
+ return 1;
+end|
+delimiter ;|
+--error ER_CANT_REOPEN_TABLE
+create temporary table t1 as select f2();
+
+drop function f1;
+drop function f2;
+
+delimiter |;
+create function f1() returns int
+begin
+ drop temporary table t2,t1;
+ return 1;
+end|
+create function f2() returns int
+begin
+ create temporary table t2 as select f1();
+ return 1;
+end|
+delimiter ;|
+--error ER_CANT_REOPEN_TABLE
+create temporary table t1 as select f2();
+
+drop function f1;
+drop function f2;
+
+create temporary table t2(a int);
+select * from t2;
+delimiter |;
+create function f2() returns int
+begin
+ drop temporary table t2;
+ return 1;
+end|
+delimiter ;|
+select f2();
+
+drop function f2;
+--error ER_BAD_TABLE_ERROR
+drop table t2;
+
+--echo End of 5.1 tests
#
# BUG#NNNN: New bug synopsis
diff -Nrup a/sql/event_db_repository.cc b/sql/event_db_repository.cc
--- a/sql/event_db_repository.cc 2007-10-19 13:57:06 -02:00
+++ b/sql/event_db_repository.cc 2007-10-30 19:02:19 -02:00
@@ -549,7 +549,7 @@ Event_db_repository::open_event_table(TH
if (simple_open_n_lock_tables(thd, &tables))
{
- close_thread_tables(thd, FALSE, FALSE);
+ close_thread_tables(thd);
DBUG_RETURN(TRUE);
}
diff -Nrup a/sql/mysql_priv.h b/sql/mysql_priv.h
--- a/sql/mysql_priv.h 2007-10-29 12:07:15 -02:00
+++ b/sql/mysql_priv.h 2007-10-30 19:02:19 -02:00
@@ -679,7 +679,7 @@ extern my_decimal decimal_zero;
void free_items(Item *item);
void cleanup_items(Item *item);
class THD;
-void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
+void close_thread_tables(THD *thd);
bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);
bool check_single_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables, bool no_errors);
@@ -1420,7 +1420,7 @@ TABLE_LIST *unique_table(THD *thd, TABLE
bool check_alias);
TABLE *find_temporary_table(THD *thd, const char *db, const char *table_name);
TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list);
-bool close_temporary_table(THD *thd, TABLE_LIST *table_list);
+int drop_temporary_table(THD *thd, TABLE_LIST *table_list);
void close_temporary_table(THD *thd, TABLE *table, bool free_share,
bool delete_table);
void close_temporary(TABLE *table, bool free_share, bool delete_table);
diff -Nrup a/sql/slave.cc b/sql/slave.cc
--- a/sql/slave.cc 2007-10-19 19:20:35 -02:00
+++ b/sql/slave.cc 2007-10-30 19:02:19 -02:00
@@ -2353,7 +2353,7 @@ err:
change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
DBUG_ASSERT(thd->net.buff != 0);
net_end(&thd->net); // destructor will not free it, because net.vio is 0
- close_thread_tables(thd, 0);
+ close_thread_tables(thd);
pthread_mutex_lock(&LOCK_thread_count);
THD_CHECK_SENTRY(thd);
delete thd;
diff -Nrup a/sql/sp_head.cc b/sql/sp_head.cc
--- a/sql/sp_head.cc 2007-10-19 19:20:35 -02:00
+++ b/sql/sp_head.cc 2007-10-30 19:02:19 -02:00
@@ -1872,7 +1872,7 @@ sp_head::execute_procedure(THD *thd, Lis
we'll leave it here.
*/
if (!thd->in_sub_stmt)
- close_thread_tables(thd, 0, 0);
+ close_thread_tables(thd);
DBUG_PRINT("info",(" %.*s: eval args done",
(int) m_name.length, m_name.str));
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc 2007-10-29 12:07:15 -02:00
+++ b/sql/sql_base.cc 2007-10-30 19:02:19 -02:00
@@ -1054,6 +1054,29 @@ bool close_cached_connection_tables(THD
}
+/**
+ Mark all temporary tables which were used by the current substatement or
+ substatement as free for reuse, but only if the query_id can be cleared.
+
+ @param thd thread context
+
+ @remark For temp tables associated with a open SQL HANDLER the query_id
+ is not reset until the HANDLER is closed.
+*/
+
+static void mark_temp_tables_as_free_for_reuse(THD *thd)
+{
+ for (TABLE *table= thd->temporary_tables ; table ; table= table->next)
+ {
+ if ((table->query_id == thd->query_id) && ! table->open_by_handler)
+ {
+ table->query_id= 0;
+ table->file->ha_reset();
+ }
+ }
+}
+
+
/*
Mark all tables in the list which were used by current substatement
as free for reuse.
@@ -1090,6 +1113,42 @@ static void mark_used_tables_as_free_for
}
+/**
+ Auxiliary function to close all tables in the open_tables list.
+
+ @param thd Thread context.
+
+ @remark It should not ordinarily be called directly.
+*/
+
+static void close_open_tables(THD *thd)
+{
+ bool found_old_table= 0;
+
+ safe_mutex_assert_not_owner(&LOCK_open);
+
+ VOID(pthread_mutex_lock(&LOCK_open));
+
+ DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables));
+
+ while (thd->open_tables)
+ found_old_table|= close_thread_table(thd, &thd->open_tables);
+ thd->some_tables_deleted= 0;
+
+ /* Free tables to hold down open files */
+ while (open_cache.records > table_cache_size && unused_tables)
+ VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */
+ check_unused();
+ if (found_old_table)
+ {
+ /* Tell threads waiting for refresh that something has happened */
+ broadcast_refresh();
+ }
+
+ VOID(pthread_mutex_unlock(&LOCK_open));
+}
+
+
/*
Close all tables used by the current substatement, or all tables
used by this thread if we are on the upper level.
@@ -1097,10 +1156,6 @@ static void mark_used_tables_as_free_for
SYNOPSIS
close_thread_tables()
thd Thread handler
- lock_in_use Set to 1 (0 = default) if caller has a lock on
- LOCK_open
- skip_derived Set to 1 (0 = default) if we should not free derived
- tables.
stopper When closing tables from thd->open_tables(->next)*,
don't close/remove tables starting from stopper.
@@ -1108,15 +1163,14 @@ static void mark_used_tables_as_free_for
Unlocks tables and frees derived tables.
Put all normal tables used by thread in free list.
- When in prelocked mode it will only close/mark as free for reuse
- tables opened by this substatement, it will also check if we are
- closing tables after execution of complete query (i.e. we are on
- upper level) and will leave prelocked mode if needed.
+ It will only close/mark as free for reuse tables opened by this
+ substatement, it will also check if we are closing tables after
+ execution of complete query (i.e. we are on upper level) and will
+ leave prelocked mode if needed.
*/
-void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
+void close_thread_tables(THD *thd)
{
- bool found_old_table;
prelocked_mode_type prelocked_mode= thd->prelocked_mode;
DBUG_ENTER("close_thread_tables");
@@ -1131,7 +1185,7 @@ void close_thread_tables(THD *thd, bool
derived tables with (sub-)statement instead of thread and destroy
them at the end of its execution.
*/
- if (thd->derived_tables && !skip_derived)
+ if (thd->derived_tables)
{
TABLE *table, *next;
/*
@@ -1146,13 +1200,10 @@ void close_thread_tables(THD *thd, bool
thd->derived_tables= 0;
}
- if (prelocked_mode)
- {
- /*
- Mark all temporary tables used by this substatement as free for reuse.
- */
- mark_used_tables_as_free_for_reuse(thd, thd->temporary_tables);
- }
+ /*
+ Mark all temporary tables used by this statement as free for reuse.
+ */
+ mark_temp_tables_as_free_for_reuse(thd);
if (thd->locked_tables || prelocked_mode)
{
@@ -1216,28 +1267,8 @@ void close_thread_tables(THD *thd, bool
if (!thd->active_transaction())
thd->transaction.xid_state.xid.null();
- if (!lock_in_use)
- VOID(pthread_mutex_lock(&LOCK_open));
-
- DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables));
-
- found_old_table= 0;
- while (thd->open_tables)
- found_old_table|= close_thread_table(thd, &thd->open_tables);
- thd->some_tables_deleted=0;
-
- /* Free tables to hold down open files */
- while (open_cache.records > table_cache_size && unused_tables)
- VOID(hash_delete(&open_cache,(uchar*) unused_tables)); /* purecov: tested */
- check_unused();
- if (found_old_table)
- {
- /* Tell threads waiting for refresh that something has happened */
- broadcast_refresh();
- }
- if (!lock_in_use)
- VOID(pthread_mutex_unlock(&LOCK_open));
- /* VOID(pthread_sigmask(SIG_SETMASK,&thd->signals,NULL)); */
+ if (thd->open_tables)
+ close_open_tables(thd);
if (prelocked_mode == PRELOCKED)
{
@@ -1674,6 +1705,7 @@ TABLE *find_temporary_table(THD *thd, TA
Try to locate the table in the list of thd->temporary_tables.
If the table is found:
+ - if the table is being used by some outer statement, fail.
- if the table is in thd->locked_tables, unlock it and
remove it from the list of locked tables. Currently only transactional
temporary tables are present in the locked_tables list.
@@ -1688,24 +1720,34 @@ TABLE *find_temporary_table(THD *thd, TA
thd->temporary_tables list, it's impossible to tell here whether
we're dealing with an internal or a user temporary table.
- @retval TRUE the table was not found in the list of temporary tables
- of this thread
- @retval FALSE the table was found and dropped successfully.
+ @retval 0 the table was found and dropped successfully.
+ @retval 1 the table was not found in the list of temporary tables
+ of this thread
+ @retval -1 the table is in use by a outer query
*/
-bool close_temporary_table(THD *thd, TABLE_LIST *table_list)
+int drop_temporary_table(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
+ DBUG_ENTER("drop_temporary_table");
if (!(table= find_temporary_table(thd, table_list)))
- return 1;
+ DBUG_RETURN(1);
+
+ /* Table might be in use by some outer statement. */
+ if (table->query_id && table->query_id != thd->query_id)
+ {
+ my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
+ DBUG_RETURN(-1);
+ }
+
/*
If LOCK TABLES list is not empty and contains this table,
unlock the table and remove the table from this list.
*/
mysql_lock_remove(thd, thd->locked_tables, table, FALSE);
close_temporary_table(thd, table, 1, 1);
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -2284,8 +2326,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
is always represented by only one TABLE object in THD, and
it can not be cloned. Emit an error for an unsupported behaviour.
*/
- if (table->query_id == thd->query_id ||
- thd->prelocked_mode && table->query_id)
+ if (table->query_id)
{
DBUG_PRINT("error",
("query_id: %lu server_id: %u pseudo_thread_id: %lu",
@@ -2295,7 +2336,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
DBUG_RETURN(0);
}
table->query_id= thd->query_id;
- table->clear_query_id= 1;
+ table->open_by_handler= 0;
thd->thread_specific_used= TRUE;
DBUG_PRINT("info",("Using temporary table"));
goto reset;
@@ -4305,7 +4346,6 @@ void close_tables_for_reopen(THD *thd, T
sp_remove_not_own_routines(thd->lex);
for (TABLE_LIST *tmp= *tables; tmp; tmp= tmp->next_global)
tmp->table= 0;
- mark_used_tables_as_free_for_reuse(thd, thd->temporary_tables);
close_thread_tables(thd);
}
diff -Nrup a/sql/sql_handler.cc b/sql/sql_handler.cc
--- a/sql/sql_handler.cc 2007-10-12 10:56:44 -03:00
+++ b/sql/sql_handler.cc 2007-10-30 19:02:20 -02:00
@@ -151,6 +151,14 @@ static void mysql_ha_close_table(THD *th
}
VOID(pthread_mutex_unlock(&LOCK_open));
}
+ else if (tables->table)
+ {
+ /* Must be a temporary table */
+ TABLE *table= tables->table;
+ table->file->ha_index_or_rnd_end();
+ table->query_id= thd->query_id;
+ table->open_by_handler= 0;
+ }
}
/*
@@ -281,6 +289,12 @@ bool mysql_ha_open(THD *thd, TABLE_LIST
if (my_hash_insert(&thd->handler_tables_hash, (uchar*) hash_tables))
goto err;
}
+
+ /*
+ If it's a temp table, don't reset table->query_id as the table is
+ being used by this handler. Otherwise, no meaning at all.
+ */
+ tables->table->open_by_handler= 1;
if (! reopen)
send_ok(thd);
diff -Nrup a/sql/sql_insert.cc b/sql/sql_insert.cc
--- a/sql/sql_insert.cc 2007-10-23 12:02:25 -02:00
+++ b/sql/sql_insert.cc 2007-10-30 19:02:20 -02:00
@@ -3399,7 +3399,7 @@ static TABLE *create_table_from_items(TH
it preparable for open. But let us do close_temporary_table() here
just in case.
*/
- close_temporary_table(thd, create_table);
+ drop_temporary_table(thd, create_table);
}
}
}
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc 2007-10-23 13:10:27 -02:00
+++ b/sql/sql_parse.cc 2007-10-30 19:02:20 -02:00
@@ -997,9 +997,7 @@ bool dispatch_command(enum enum_server_c
/*
Multiple queries exits, execute them individually
*/
- if (thd->lock || thd->open_tables || thd->derived_tables ||
- thd->prelocked_mode)
- close_thread_tables(thd);
+ close_thread_tables(thd);
ulong length= (ulong)(packet_end - next_packet);
log_slow_statement(thd);
@@ -1336,12 +1334,11 @@ bool dispatch_command(enum enum_server_c
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
break;
}
- if (thd->lock || thd->open_tables || thd->derived_tables ||
- thd->prelocked_mode)
- {
- thd->proc_info="closing tables";
- close_thread_tables(thd); /* Free tables */
- }
+
+ thd->proc_info="closing tables";
+ /* Free tables */
+ close_thread_tables(thd);
+
/*
assume handlers auto-commit (if some doesn't - transaction handling
in MySQL should be redesigned to support it; it's a big change,
diff -Nrup a/sql/sql_table.cc b/sql/sql_table.cc
--- a/sql/sql_table.cc 2007-10-29 12:07:16 -02:00
+++ b/sql/sql_table.cc 2007-10-30 19:02:20 -02:00
@@ -1503,7 +1503,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
char path[FN_REFLEN], *alias;
uint path_length;
String wrong_tables;
- int error;
+ int error= 0;
int non_temp_tables_count= 0;
bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0;
String built_query;
@@ -1563,10 +1563,21 @@ int mysql_rm_table_part2(THD *thd, TABLE
enum legacy_db_type frm_db_type;
mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, 1);
- if (!close_temporary_table(thd, table))
- {
- tmp_table_deleted=1;
- continue; // removed temporary table
+
+ error= drop_temporary_table(thd, table);
+
+ switch (error) {
+ case 0:
+ // removed temporary table
+ tmp_table_deleted= 1;
+ continue;
+ case -1:
+ // table already in use
+ error= 1;
+ goto err_with_placeholders;
+ default:
+ // temporary table not found
+ error= 0;
}
/*
@@ -1593,7 +1604,6 @@ int mysql_rm_table_part2(THD *thd, TABLE
built_query.append("`,");
}
- error=0;
table_type= table->db_type;
if (!drop_temporary)
{
diff -Nrup a/sql/table.h b/sql/table.h
--- a/sql/table.h 2007-09-26 13:06:51 -03:00
+++ b/sql/table.h 2007-10-30 19:02:20 -02:00
@@ -499,6 +499,24 @@ struct st_table {
my_bitmap_map *bitmap_init_value;
MY_BITMAP def_read_set, def_write_set, tmp_set; /* containers */
MY_BITMAP *read_set, *write_set; /* Active column sets */
+ /*
+ The ID of the query that opened and is using this table. Has different
+ meanings depending on the table type.
+
+ Temporary tables:
+
+ table->query_id is set to thd->query_id for the duration of a statement
+ and is reset to 0 once it is closed by the same statement. A non-zero
+ table->query_id means that a statement is using the table even if it's
+ not the current statement (table is in use by some outer statement).
+
+ Non-temporary tables:
+
+ Under pre-locked or LOCK TABLES mode: query_id is set to thd->query_id
+ for the duration of a statement and is reset to 0 once it is closed by
+ the same statement. A non-zero query_id is used to control which tables
+ in the list of pre-opened and locked tables are actually being used.
+ */
query_id_t query_id;
/*
@@ -593,8 +611,8 @@ struct st_table {
my_bool locked_by_name;
my_bool fulltext_searched;
my_bool no_cache;
- /* To signal that we should reset query_id for tables and cols */
- my_bool clear_query_id;
+ /* To signal that the table is associated with a HANDLER statement */
+ my_bool open_by_handler;
/*
To indicate that a non-null value of the auto_increment field
was provided by the user or retrieved from the current record.