From 7853f553be39b2e3470fd72bf60b4b814dea63f0 Mon Sep 17 00:00:00 2001 From: Evgeny Potemkin Date: Tue, 1 Dec 2009 21:28:45 +0300 Subject: [PATCH] Bug#48508: Crash on prepared statement re-execution. Actually there is two different bugs. The first one caused crash on queries with WHERE condition over views containing WHERE condition. A wrong check for prepared statement phase led to items for view fields being allocated in the execution memory and freed at the end of execution. Thus the optimized WHERE condition refers to unallocated memory on the second execution and server crashed. The second one caused by the Item_cond::compile function not saving changes it made to the item tree. Thus on the next execution changes weren't reverted and server crashed on dereferencing of unallocated space. The new helper function called is_stmt_prepare_or_first_stmt_execute is added to the Query_arena class. The find_field_in_view function now uses is_stmt_prepare_or_first_stmt_execute() to check whether newly created view items should be freed at the end of the query execution. The Item_cond::compile function now saves changes it makes to item tree. mysql-test/r/ps.result: Added a test case for the bug#48508. mysql-test/t/ps.test: Added a test case for the bug#48508. sql/item_cmpfunc.cc: Bug#48508: Crash on prepared statement re-execution. The Item_cond::compile function now saves changes it makes to item tree. sql/sql_base.cc: Bug#48508: Crash on prepared statement re-execution. The find_field_in_view function now uses is_stmt_prepare_or_first_stmt_execute() to check whether newly created view items should be freed at the end of the query execution. sql/sql_class.h: Bug#48508: Crash on prepared statement re-execution. The Query_arena::is_stmt_prepare_or_first_sp_execute function now correctly do its check. --- mysql-test/r/ps.result | 23 +++++++++++++++++++++++ mysql-test/t/ps.test | 21 +++++++++++++++++++++ sql/item_cmpfunc.cc | 2 +- sql/sql_base.cc | 3 ++- sql/sql_class.h | 2 ++ 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 43c50998e20..e7894388494 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1891,4 +1891,27 @@ execute stmt using @arg; ? -12345.5432100000 deallocate prepare stmt; +# +# Bug#48508: Crash on prepared statement re-execution. +# +create table t1(b int); +insert into t1 values (0); +create view v1 AS select 1 as a from t1 where b; +prepare stmt from "select * from v1 where a"; +execute stmt; +a +execute stmt; +a +drop table t1; +drop view v1; +create table t1(a bigint); +create table t2(b tinyint); +insert into t2 values (null); +prepare stmt from "select 1 from t1 join t2 on a xor b where b > 1 and a =1"; +execute stmt; +1 +execute stmt; +1 +drop table t1,t2; +# End of 5.0 tests. diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index d9e593fd76f..6134efb5c5c 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -1973,4 +1973,25 @@ select @arg; execute stmt using @arg; deallocate prepare stmt; +--echo # +--echo # Bug#48508: Crash on prepared statement re-execution. +--echo # +create table t1(b int); +insert into t1 values (0); +create view v1 AS select 1 as a from t1 where b; +prepare stmt from "select * from v1 where a"; +execute stmt; +execute stmt; +drop table t1; +drop view v1; + +create table t1(a bigint); +create table t2(b tinyint); +insert into t2 values (null); +prepare stmt from "select 1 from t1 join t2 on a xor b where b > 1 and a =1"; +execute stmt; +execute stmt; +drop table t1,t2; +--echo # + --echo End of 5.0 tests. diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 8c655cdc369..d03c68b3560 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -3907,7 +3907,7 @@ Item *Item_cond::compile(Item_analyzer analyzer, byte **arg_p, byte *arg_v= *arg_p; Item *new_item= item->compile(analyzer, &arg_v, transformer, arg_t); if (new_item && new_item != item) - li.replace(new_item); + current_thd->change_item_tree(li.ref(), new_item); } return Item_func::transform(transformer, arg_t); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 178c3e12e23..88d1e8879d1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3481,7 +3481,8 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, if (!my_strcasecmp(system_charset_info, field_it.name(), name)) { // in PS use own arena or data will be freed after prepare - if (register_tree_change && thd->stmt_arena->is_stmt_prepare_or_first_sp_execute()) + if (register_tree_change && + thd->stmt_arena->is_stmt_prepare_or_first_stmt_execute()) arena= thd->activate_stmt_arena_if_needed(&backup); /* create_item() may, or may not create a new Item, depending on diff --git a/sql/sql_class.h b/sql/sql_class.h index b41a5d5c6b7..ac058bca4f9 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -759,6 +759,8 @@ public: { return state == INITIALIZED_FOR_SP; } inline bool is_stmt_prepare_or_first_sp_execute() const { return (int)state < (int)PREPARED; } + inline bool is_stmt_prepare_or_first_stmt_execute() const + { return (int)state <= (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } inline bool is_stmt_execute() const { return state == PREPARED || state == EXECUTED; }