Commit 095b686c authored by unknown's avatar unknown

Fix for bug#4912 "mysqld crashs in case a statement is executed

 a second time". The bug was caused by incompatibility of
negations elimination algorithm and PS: during first statement 
execute a subtree with negation was replaced with equivalent 
subtree without NOTs.
The problem was that although this transformation was permanent, 
items of the new subtree were created in execute-local memory.
The patch adds means to check if it is the first execute of a
prepared statement, and if this is the case, to allocate items
in memory of the prepared statement.
The implementation:
- backports Item_arena from 5.0
- adds Item_arena::is_stmt_prepare(), 
  Item_arena::is_first_stmt_execute().
- deletes THD::allocate_temporary_pool_for_ps_preparing(),
  THD::free_temporary_pool_for_ps_preparing(); they
  were redundant.
and adds a few invariants:
- thd->free_list never contains junk (= freed items)
- thd->current_arena is never null. If there is no
  prepared statement, it points at the thd. 
The rest of the patch contains mainly mechanical changes and
cleanups.


mysql-test/r/ps.result:
  Test results updated (test case for Bug#4912)
mysql-test/t/ps.test:
  A test case for Bug#4912 "mysqld crashs in case a statement is 
  executed a second time"
sql/item_cmpfunc.cc:
  current_statement -> current_arena
sql/item_subselect.cc:
  Statement -> Item_arena, current_statement -> current_arena
sql/item_subselect.h:
  Item_subselect does not need to save thd->current_statement.
sql/item_sum.cc:
  Statement -> Item_arena
sql/item_sum.h:
  Statement -> Item_arena
sql/mysql_priv.h:
  Statement -> Item_arena
sql/sql_base.cc:
  current_statement -> current_arena
sql/sql_class.cc:
  - Item_arena
  - convenient set_n_backup_statement, restore_backup_statement
  (nice idea, Sanja)
sql/sql_class.h:
  - Item_arena: backport from 5.0
  - allocate_temporary_pool_for_ps_preparing,
    free_temporary_pool_for_ps_preparing removed.
sql/sql_derived.cc:
  current_statement -> current_arena
sql/sql_lex.cc:
  current_statement -> current_arena
sql/sql_parse.cc:
  Deploy invariant that thd->free_list never contains junk items
  (backport from 5.0).
sql/sql_prepare.cc:
  - backporting Item_arena
  - no need to allocate_temporary_pool_for_ps_preparing().
sql/sql_select.cc:
  Fix for bug#4912 "mysqld crashs in case a statement is 
  executed a second time": if this is the first execute of
  a prepared statement, negation elimination is
  done in memory of the prepared statement.
sql/sql_union.cc:
  Backporting Item_arena from 5.0.
parent b368cb3f
...@@ -219,3 +219,10 @@ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length I ...@@ -219,3 +219,10 @@ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length I
t1 MyISAM 9 Dynamic 0 0 0 4294967295 1024 0 NULL # # # latin1_swedish_ci NULL t1 MyISAM 9 Dynamic 0 0 0 4294967295 1024 0 NULL # # # latin1_swedish_ci NULL
deallocate prepare stmt1 ; deallocate prepare stmt1 ;
drop table t1; drop table t1;
create table t1(a varchar(2), b varchar(3));
prepare stmt1 from "select a, b from t1 where (not (a='aa' and b < 'zzz'))";
execute stmt1;
a b
execute stmt1;
a b
deallocate prepare stmt1;
...@@ -206,3 +206,15 @@ execute stmt1; ...@@ -206,3 +206,15 @@ execute stmt1;
show table status from test like 't1%' ; show table status from test like 't1%' ;
deallocate prepare stmt1 ; deallocate prepare stmt1 ;
drop table t1; drop table t1;
#
# Bug#4912 "mysqld crashs in case a statement is executed a second time":
# negation elimination should and prepared statemens
#
create table t1(a varchar(2), b varchar(3));
prepare stmt1 from "select a, b from t1 where (not (a='aa' and b < 'zzz'))";
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
...@@ -589,10 +589,8 @@ bool Item_in_optimizer::fix_left(THD *thd, ...@@ -589,10 +589,8 @@ bool Item_in_optimizer::fix_left(THD *thd,
/* /*
If it is preparation PS only then we do not know values of parameters => If it is preparation PS only then we do not know values of parameters =>
cant't get there values and do not need that values. cant't get there values and do not need that values.
TODO: during merge with 5.0 it should be changed on !thd->only_prepare()
*/ */
if (!thd->current_statement) if (! thd->current_arena->is_stmt_prepare())
cache->store(args[0]); cache->store(args[0]);
if (cache->cols() == 1) if (cache->cols() == 1)
{ {
......
...@@ -125,7 +125,6 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) ...@@ -125,7 +125,6 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param)); engine->set_thd((thd= thd_param));
stmt= thd->current_statement;
char const *save_where= thd->where; char const *save_where= thd->where;
int res; int res;
...@@ -306,7 +305,10 @@ Item_singlerow_subselect::select_transformer(JOIN *join) ...@@ -306,7 +305,10 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
return RES_OK; return RES_OK;
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
Statement backup;
/* Juggle with current arena only if we're in prepared statement prepare */
Item_arena *arena= join->thd->current_arena;
Item_arena backup;
if (!select_lex->master_unit()->first_select()->next_select() && if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements && !select_lex->table_list.elements &&
...@@ -341,8 +343,8 @@ Item_singlerow_subselect::select_transformer(JOIN *join) ...@@ -341,8 +343,8 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
if (join->conds || join->having) if (join->conds || join->having)
{ {
Item *cond; Item *cond;
if (stmt) if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(stmt, &backup); thd->set_n_backup_item_arena(arena, &backup);
if (!join->having) if (!join->having)
cond= join->conds; cond= join->conds;
...@@ -355,15 +357,15 @@ Item_singlerow_subselect::select_transformer(JOIN *join) ...@@ -355,15 +357,15 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
new Item_null()))) new Item_null())))
goto err; goto err;
} }
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
return RES_REDUCE; return RES_REDUCE;
} }
return RES_OK; return RES_OK;
err: err:
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
return RES_ERROR; return RES_ERROR;
} }
...@@ -640,11 +642,11 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -640,11 +642,11 @@ Item_in_subselect::single_value_transformer(JOIN *join,
} }
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
Statement backup; Item_arena *arena= join->thd->current_arena, backup;
thd->where= "scalar IN/ALL/ANY subquery"; thd->where= "scalar IN/ALL/ANY subquery";
if (stmt) if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(stmt, &backup); thd->set_n_backup_item_arena(arena, &backup);
if (select_lex->item_list.elements > 1) if (select_lex->item_list.elements > 1)
{ {
...@@ -857,21 +859,21 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -857,21 +859,21 @@ Item_in_subselect::single_value_transformer(JOIN *join,
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff); ER_SELECT_REDUCED, warn_buff);
} }
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_REDUCE); DBUG_RETURN(RES_REDUCE);
} }
} }
} }
ok: ok:
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_OK); DBUG_RETURN(RES_OK);
err: err:
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
} }
...@@ -885,12 +887,12 @@ Item_in_subselect::row_value_transformer(JOIN *join) ...@@ -885,12 +887,12 @@ Item_in_subselect::row_value_transformer(JOIN *join)
{ {
DBUG_RETURN(RES_OK); DBUG_RETURN(RES_OK);
} }
Statement backup; Item_arena *arena= join->thd->current_arena, backup;
Item *item= 0; Item *item= 0;
thd->where= "row IN/ALL/ANY subquery"; thd->where= "row IN/ALL/ANY subquery";
if (stmt) if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(stmt, &backup); thd->set_n_backup_item_arena(arena, &backup);
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
...@@ -974,13 +976,13 @@ Item_in_subselect::row_value_transformer(JOIN *join) ...@@ -974,13 +976,13 @@ Item_in_subselect::row_value_transformer(JOIN *join)
if (join->conds->fix_fields(thd, join->tables_list, 0)) if (join->conds->fix_fields(thd, join->tables_list, 0))
goto err; goto err;
} }
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_OK); DBUG_RETURN(RES_OK);
err: err:
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_ERROR); DBUG_RETURN(RES_ERROR);
} }
......
...@@ -36,8 +36,6 @@ class Item_subselect :public Item_result_field ...@@ -36,8 +36,6 @@ class Item_subselect :public Item_result_field
protected: protected:
/* thread handler, will be assigned in fix_fields only */ /* thread handler, will be assigned in fix_fields only */
THD *thd; THD *thd;
/* prepared statement, or 0 */
Statement *stmt;
/* substitution instead of subselect in case of optimization */ /* substitution instead of subselect in case of optimization */
Item *substitution; Item *substitution;
/* unit of subquery */ /* unit of subquery */
......
...@@ -64,28 +64,28 @@ Item_sum::Item_sum(THD *thd, Item_sum *item): ...@@ -64,28 +64,28 @@ Item_sum::Item_sum(THD *thd, Item_sum *item):
/* /*
Save copy of arguments if we are prepare prepared statement Save copy of arguments if we prepare prepared statement
(arguments can be rewritten in get_tmp_table_item()) (arguments can be rewritten in get_tmp_table_item())
SYNOPSIS SYNOPSIS
Item_sum::save_args_for_prepared_statements() Item_sum::save_args_for_prepared_statement()
thd - thread handler thd - thread handler
RETURN RETURN
0 - OK 0 - OK
1 - Error 1 - Error
*/ */
bool Item_sum::save_args_for_prepared_statements(THD *thd) bool Item_sum::save_args_for_prepared_statement(THD *thd)
{ {
if (thd->current_statement) if (thd->current_arena->is_stmt_prepare())
return save_args(thd->current_statement); return save_args(thd->current_arena);
return 0; return 0;
} }
bool Item_sum::save_args(Statement* stmt) bool Item_sum::save_args(Item_arena* arena)
{ {
if (!(args_copy= (Item**) stmt->alloc(sizeof(Item*)*arg_count))) if (!(args_copy= (Item**) arena->alloc(sizeof(Item*)*arg_count)))
return 1; return 1;
memcpy(args_copy, args, sizeof(Item*)*arg_count); memcpy(args_copy, args, sizeof(Item*)*arg_count);
return 0; return 0;
...@@ -214,7 +214,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -214,7 +214,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
if (save_args_for_prepared_statements(thd)) if (save_args_for_prepared_statement(thd))
return 1; return 1;
if (!thd->allow_sum_func) if (!thd->allow_sum_func)
...@@ -248,7 +248,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -248,7 +248,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
if (save_args_for_prepared_statements(thd)) if (save_args_for_prepared_statement(thd))
return 1; return 1;
Item *item= args[0]; Item *item= args[0];
...@@ -1947,7 +1947,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -1947,7 +1947,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
if (save_args_for_prepared_statements(thd)) if (save_args_for_prepared_statement(thd))
return 1; return 1;
uint i; /* for loop variable */ uint i; /* for loop variable */
......
...@@ -92,8 +92,8 @@ class Item_sum :public Item_result_field ...@@ -92,8 +92,8 @@ class Item_sum :public Item_result_field
virtual bool setup(THD *thd) {return 0;} virtual bool setup(THD *thd) {return 0;}
virtual void make_unique() {} virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
bool save_args_for_prepared_statements(THD *); bool save_args_for_prepared_statement(THD *);
bool save_args(Statement* stmt); bool save_args(Item_arena *arena);
bool walk (Item_processor processor, byte *argument); bool walk (Item_processor processor, byte *argument);
}; };
......
...@@ -295,7 +295,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); ...@@ -295,7 +295,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
struct st_table; struct st_table;
class THD; class THD;
class Statement; class Item_arena;
/* Struct to handle simple linked lists */ /* Struct to handle simple linked lists */
......
...@@ -2188,14 +2188,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, ...@@ -2188,14 +2188,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
{ {
if (!wild_num) if (!wild_num)
return 0; return 0;
Statement *stmt= thd->current_statement, backup; Item_arena *arena= thd->current_arena, backup;
/* /*
If we are in preparing prepared statement phase then we have change If we are in preparing prepared statement phase then we have change
temporary mem_root to statement mem root to save changes of SELECT list temporary mem_root to statement mem root to save changes of SELECT list
*/ */
if (stmt) if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(stmt, &backup); thd->set_n_backup_item_arena(arena, &backup);
reg2 Item *item; reg2 Item *item;
List_iterator<Item> it(fields); List_iterator<Item> it(fields);
while ( wild_num && (item= it++)) while ( wild_num && (item= it++))
...@@ -2219,8 +2220,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, ...@@ -2219,8 +2220,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
else if (insert_fields(thd,tables,((Item_field*) item)->db_name, else if (insert_fields(thd,tables,((Item_field*) item)->db_name,
((Item_field*) item)->table_name, &it)) ((Item_field*) item)->table_name, &it))
{ {
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
return (-1); return (-1);
} }
if (sum_func_list) if (sum_func_list)
...@@ -2235,8 +2236,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, ...@@ -2235,8 +2236,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
wild_num--; wild_num--;
} }
} }
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
return 0; return 0;
} }
...@@ -2449,7 +2450,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, ...@@ -2449,7 +2450,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{ {
table_map not_null_tables= 0; table_map not_null_tables= 0;
Statement *stmt= thd->current_statement, backup; Item_arena *arena= thd->current_arena, backup;
DBUG_ENTER("setup_conds"); DBUG_ENTER("setup_conds");
thd->set_query_id=1; thd->set_query_id=1;
...@@ -2488,12 +2489,12 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2488,12 +2489,12 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
!(specialflag & SPECIAL_NO_NEW_FUNC))) !(specialflag & SPECIAL_NO_NEW_FUNC)))
{ {
table->outer_join= 0; table->outer_join= 0;
if (stmt) if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(stmt, &backup); thd->set_n_backup_item_arena(arena, &backup);
*conds= and_conds(*conds, table->on_expr); *conds= and_conds(*conds, table->on_expr);
table->on_expr=0; table->on_expr=0;
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
if ((*conds) && !(*conds)->fixed && if ((*conds) && !(*conds)->fixed &&
(*conds)->fix_fields(thd, tables, conds)) (*conds)->fix_fields(thd, tables, conds))
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -2501,8 +2502,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2501,8 +2502,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
} }
if (table->natural_join) if (table->natural_join)
{ {
if (stmt) if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(stmt, &backup); thd->set_n_backup_item_arena(arena, &backup);
/* Make a join of all fields with have the same name */ /* Make a join of all fields with have the same name */
TABLE *t1= table->table; TABLE *t1= table->table;
TABLE *t2= table->natural_join->table; TABLE *t2= table->natural_join->table;
...@@ -2543,8 +2544,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2543,8 +2544,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{ {
*conds= and_conds(*conds, cond_and); *conds= and_conds(*conds, cond_and);
// fix_fields() should be made with temporary memory pool // fix_fields() should be made with temporary memory pool
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
if (*conds && !(*conds)->fixed) if (*conds && !(*conds)->fixed)
{ {
if ((*conds)->fix_fields(thd, tables, conds)) if ((*conds)->fix_fields(thd, tables, conds))
...@@ -2555,8 +2556,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2555,8 +2556,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{ {
table->on_expr= and_conds(table->on_expr, cond_and); table->on_expr= and_conds(table->on_expr, cond_and);
// fix_fields() should be made with temporary memory pool // fix_fields() should be made with temporary memory pool
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
if (table->on_expr && !table->on_expr->fixed) if (table->on_expr && !table->on_expr->fixed)
{ {
if (table->on_expr->fix_fields(thd, tables, &table->on_expr)) if (table->on_expr->fix_fields(thd, tables, &table->on_expr))
...@@ -2567,7 +2568,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2567,7 +2568,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
} }
} }
if (stmt) if (arena->is_stmt_prepare())
{ {
/* /*
We are in prepared statement preparation code => we should store We are in prepared statement preparation code => we should store
...@@ -2580,8 +2581,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2580,8 +2581,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
DBUG_RETURN(test(thd->net.report_error)); DBUG_RETURN(test(thd->net.report_error));
err: err:
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
......
...@@ -155,7 +155,7 @@ bool foreign_key_prefix(Key *a, Key *b) ...@@ -155,7 +155,7 @@ bool foreign_key_prefix(Key *a, Key *b)
** Thread specific functions ** Thread specific functions
****************************************************************************/ ****************************************************************************/
THD::THD():user_time(0), current_statement(0), is_fatal_error(0), THD::THD():user_time(0), current_arena(this), is_fatal_error(0),
last_insert_id_used(0), last_insert_id_used(0),
insert_id_used(0), rand_used(0), time_zone_used(0), insert_id_used(0), rand_used(0), time_zone_used(0),
in_lock_tables(0), global_read_lock(0), bootstrap(0) in_lock_tables(0), global_read_lock(0), bootstrap(0)
...@@ -1301,23 +1301,59 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) ...@@ -1301,23 +1301,59 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
} }
Item_arena::Item_arena(THD* thd)
:free_list(0),
state(INITIALIZED)
{
init_sql_alloc(&mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
}
/* This constructor is called when Item_arena is a subobject of THD */
Item_arena::Item_arena()
:free_list(0),
state(CONVENTIONAL_EXECUTION)
{
clear_alloc_root(&mem_root);
}
Item_arena::Item_arena(bool init_mem_root)
:free_list(0),
state(INITIALIZED)
{
if (init_mem_root)
clear_alloc_root(&mem_root);
}
Item_arena::Type Item_arena::type() const
{
DBUG_ASSERT("Item_arena::type()" == "abstract");
return STATEMENT;
}
Item_arena::~Item_arena()
{}
/* /*
Statement functions Statement functions
*/ */
Statement::Statement(THD *thd) Statement::Statement(THD *thd)
:id(++thd->statement_id_counter), :Item_arena(thd),
id(++thd->statement_id_counter),
set_query_id(1), set_query_id(1),
allow_sum_func(0), allow_sum_func(0),
lex(&main_lex), lex(&main_lex),
query(0), query(0),
query_length(0), query_length(0)
free_list(0)
{ {
name.str= NULL; name.str= NULL;
init_sql_alloc(&mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
} }
/* /*
...@@ -1332,14 +1368,12 @@ Statement::Statement() ...@@ -1332,14 +1368,12 @@ Statement::Statement()
allow_sum_func(0), /* initialized later */ allow_sum_func(0), /* initialized later */
lex(&main_lex), lex(&main_lex),
query(0), /* these two are set */ query(0), /* these two are set */
query_length(0), /* in alloc_query() */ query_length(0) /* in alloc_query() */
free_list(0)
{ {
bzero((char *) &mem_root, sizeof(mem_root));
} }
Statement::Type Statement::type() const Item_arena::Type Statement::type() const
{ {
return STATEMENT; return STATEMENT;
} }
...@@ -1356,14 +1390,29 @@ void Statement::set_statement(Statement *stmt) ...@@ -1356,14 +1390,29 @@ void Statement::set_statement(Statement *stmt)
} }
void Statement::set_n_backup_item_arena(Statement *set, Statement *backup) void
Statement::set_n_backup_statement(Statement *stmt, Statement *backup)
{
backup->set_statement(this);
set_statement(stmt);
}
void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
{
stmt->set_statement(this);
set_statement(backup);
}
void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
{ {
backup->set_item_arena(this); backup->set_item_arena(this);
set_item_arena(set); set_item_arena(set);
} }
void Statement::restore_backup_item_arena(Statement *set, Statement *backup) void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup)
{ {
set->set_item_arena(this); set->set_item_arena(this);
set_item_arena(backup); set_item_arena(backup);
...@@ -1371,10 +1420,11 @@ void Statement::restore_backup_item_arena(Statement *set, Statement *backup) ...@@ -1371,10 +1420,11 @@ void Statement::restore_backup_item_arena(Statement *set, Statement *backup)
init_alloc_root(&backup->mem_root, 0, 0); init_alloc_root(&backup->mem_root, 0, 0);
} }
void Statement::set_item_arena(Statement *set) void Item_arena::set_item_arena(Item_arena *set)
{ {
mem_root= set->mem_root; mem_root= set->mem_root;
free_list= set->free_list; free_list= set->free_list;
state= set->state;
} }
Statement::~Statement() Statement::~Statement()
......
...@@ -418,6 +418,61 @@ struct system_variables ...@@ -418,6 +418,61 @@ struct system_variables
void free_tmp_table(THD *thd, TABLE *entry); void free_tmp_table(THD *thd, TABLE *entry);
class Item_arena
{
public:
/*
List of items created in the parser for this query. Every item puts
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
MEM_ROOT mem_root;
static const int INITIALIZED= 0, PREPARED= 1, EXECUTED= 3,
CONVENTIONAL_EXECUTION= 2, ERROR= -1;
int state;
/* We build without RTTI, so dynamic_cast can't be used. */
enum Type
{
STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE
};
Item_arena(THD *thd);
Item_arena();
Item_arena(bool init_mem_root);
virtual Type type() const;
virtual ~Item_arena();
inline bool is_stmt_prepare() const { return state < PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; }
inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
inline gptr calloc(unsigned int size)
{
gptr ptr;
if ((ptr=alloc_root(&mem_root,size)))
bzero((char*) ptr,size);
return ptr;
}
inline char *strdup(const char *str)
{ return strdup_root(&mem_root,str); }
inline char *strmake(const char *str, uint size)
{ return strmake_root(&mem_root,str,size); }
inline char *memdup(const char *str, uint size)
{ return memdup_root(&mem_root,str,size); }
inline char *memdup_w_gap(const char *str, uint size, uint gap)
{
gptr ptr;
if ((ptr=alloc_root(&mem_root,size+gap)))
memcpy(ptr,str,size);
return ptr;
}
void set_n_backup_item_arena(Item_arena *set, Item_arena *backup);
void restore_backup_item_arena(Item_arena *set, Item_arena *backup);
void set_item_arena(Item_arena *set);
};
/* /*
State of a single command executed against this connection. State of a single command executed against this connection.
One connection can contain a lot of simultaneously running statements, One connection can contain a lot of simultaneously running statements,
...@@ -432,7 +487,7 @@ void free_tmp_table(THD *thd, TABLE *entry); ...@@ -432,7 +487,7 @@ void free_tmp_table(THD *thd, TABLE *entry);
be used explicitly. be used explicitly.
*/ */
class Statement class Statement: public Item_arena
{ {
Statement(const Statement &rhs); /* not implemented: */ Statement(const Statement &rhs); /* not implemented: */
Statement &operator=(const Statement &rhs); /* non-copyable */ Statement &operator=(const Statement &rhs); /* non-copyable */
...@@ -474,20 +529,8 @@ class Statement ...@@ -474,20 +529,8 @@ class Statement
*/ */
char *query; char *query;
uint32 query_length; // current query length uint32 query_length; // current query length
/*
List of items created in the parser for this query. Every item puts
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
MEM_ROOT mem_root;
public: public:
/* We build without RTTI, so dynamic_cast can't be used. */
enum Type
{
STATEMENT,
PREPARED_STATEMENT
};
/* /*
This constructor is called when statement is a subobject of THD: This constructor is called when statement is a subobject of THD:
...@@ -500,34 +543,10 @@ class Statement ...@@ -500,34 +543,10 @@ class Statement
/* Assign execution context (note: not all members) of given stmt to self */ /* Assign execution context (note: not all members) of given stmt to self */
void set_statement(Statement *stmt); void set_statement(Statement *stmt);
void set_n_backup_statement(Statement *stmt, Statement *backup);
void restore_backup_statement(Statement *stmt, Statement *backup);
/* return class type */ /* return class type */
virtual Type type() const; virtual Type type() const;
inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
inline gptr calloc(unsigned int size)
{
gptr ptr;
if ((ptr=alloc_root(&mem_root,size)))
bzero((char*) ptr,size);
return ptr;
}
inline char *strdup(const char *str)
{ return strdup_root(&mem_root,str); }
inline char *strmake(const char *str, uint size)
{ return strmake_root(&mem_root,str,size); }
inline char *memdup(const char *str, uint size)
{ return memdup_root(&mem_root,str,size); }
inline char *memdup_w_gap(const char *str, uint size, uint gap)
{
gptr ptr;
if ((ptr=alloc_root(&mem_root,size+gap)))
memcpy(ptr,str,size);
return ptr;
}
void set_n_backup_item_arena(Statement *set, Statement *backup);
void restore_backup_item_arena(Statement *set, Statement *backup);
void set_item_arena(Statement *set);
}; };
...@@ -760,9 +779,9 @@ class THD :public ilink, ...@@ -760,9 +779,9 @@ class THD :public ilink,
Vio* active_vio; Vio* active_vio;
#endif #endif
/* /*
Current prepared Statement if there one, or 0 Current prepared Item_arena if there one, or 0
*/ */
Statement *current_statement; Item_arena *current_arena;
/* /*
next_insert_id is set on SET INSERT_ID= #. This is used as the next next_insert_id is set on SET INSERT_ID= #. This is used as the next
generated auto_increment value in handler.cc generated auto_increment value in handler.cc
...@@ -983,33 +1002,6 @@ class THD :public ilink, ...@@ -983,33 +1002,6 @@ class THD :public ilink,
} }
inline CHARSET_INFO *charset() { return variables.character_set_client; } inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset(); void update_charset();
inline void allocate_temporary_memory_pool_for_ps_preparing()
{
DBUG_ASSERT(current_statement!=0);
/*
We do not want to have in PS memory all that junk,
which will be created by preparation => substitute memory
from original thread pool.
We know that PS memory pool is now copied to THD, we move it back
to allow some code use it.
*/
current_statement->set_item_arena(this);
init_sql_alloc(&mem_root,
variables.query_alloc_block_size,
variables.query_prealloc_size);
free_list= 0;
}
inline void free_temporary_memory_pool_for_ps_preparing()
{
DBUG_ASSERT(current_statement!=0);
cleanup_items(current_statement->free_list);
free_items(free_list);
close_thread_tables(this); // to close derived tables
free_root(&mem_root, MYF(0));
set_item_arena(current_statement);
}
}; };
/* Flags for the THD::system_thread (bitmap) variable */ /* Flags for the THD::system_thread (bitmap) variable */
......
...@@ -151,7 +151,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, ...@@ -151,7 +151,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
if it is preparation PS only then we do not need real data and we if it is preparation PS only then we do not need real data and we
can skip execution (and parameters is not defined, too) can skip execution (and parameters is not defined, too)
*/ */
if (!thd->current_statement) if (! thd->current_arena->is_stmt_prepare())
{ {
if (is_union) if (is_union)
{ {
......
...@@ -1527,9 +1527,9 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) ...@@ -1527,9 +1527,9 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
We have to create array in prepared statement memory if it is We have to create array in prepared statement memory if it is
prepared statement prepared statement
*/ */
Statement *stmt= thd->current_statement ? thd->current_statement : thd; Item_arena *arena= thd->current_arena;
return (ref_pointer_array= return (ref_pointer_array=
(Item **)stmt->alloc(sizeof(Item*) * (Item **)arena->alloc(sizeof(Item*) *
(item_list.elements + (item_list.elements +
select_n_having_items + select_n_having_items +
order_group_num)* 5)) == 0; order_group_num)* 5)) == 0;
......
...@@ -1543,6 +1543,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1543,6 +1543,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break; break;
mysqld_list_fields(thd,&table_list,fields); mysqld_list_fields(thd,&table_list,fields);
free_items(thd->free_list); free_items(thd->free_list);
thd->free_list= 0;
break; break;
} }
#endif #endif
...@@ -4047,6 +4048,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length) ...@@ -4047,6 +4048,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
} }
thd->proc_info="freeing items"; thd->proc_info="freeing items";
free_items(thd->free_list); /* Free strings used by items */ free_items(thd->free_list); /* Free strings used by items */
thd->free_list= 0;
lex_end(lex); lex_end(lex);
} }
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
...@@ -4073,6 +4075,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) ...@@ -4073,6 +4075,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first)) all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
error= 1; /* Ignore question */ error= 1; /* Ignore question */
free_items(thd->free_list); /* Free strings used by items */ free_items(thd->free_list); /* Free strings used by items */
thd->free_list= 0;
lex_end(lex); lex_end(lex);
return error; return error;
......
This diff is collapsed.
...@@ -4377,25 +4377,39 @@ COND *eliminate_not_funcs(THD *thd, COND *cond) ...@@ -4377,25 +4377,39 @@ COND *eliminate_not_funcs(THD *thd, COND *cond)
static COND * static COND *
optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value) optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
{ {
SELECT_LEX *select= thd->lex->current_select;
DBUG_ENTER("optimize_cond"); DBUG_ENTER("optimize_cond");
if (!conds) if (conds)
{
DBUG_EXECUTE("where", print_where(conds, "original"););
/* Eliminate NOT operators; in case of PS/SP do it once */
if (thd->current_arena->is_first_stmt_execute())
{
Item_arena *arena= thd->current_arena, backup;
thd->set_n_backup_item_arena(arena, &backup);
conds= eliminate_not_funcs(thd, conds);
select->prep_where= conds->copy_andor_structure(thd);
thd->restore_backup_item_arena(arena, &backup);
}
else
conds= eliminate_not_funcs(thd, conds);
DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
/* change field = field to field = const for each found field = const */
propagate_cond_constants((I_List<COND_CMP> *) 0, conds, conds);
/*
Remove all instances of item == item
Remove all and-levels where CONST item != CONST item
*/
DBUG_EXECUTE("where", print_where(conds, "after const change"););
conds= remove_eq_conds(thd, conds, cond_value);
DBUG_EXECUTE("info", print_where(conds, "after remove"););
}
else
{ {
*cond_value= Item::COND_TRUE; *cond_value= Item::COND_TRUE;
DBUG_RETURN(conds); select->prep_where= 0;
} }
DBUG_EXECUTE("where",print_where(conds,"original"););
/* eliminate NOT operators */
conds= eliminate_not_funcs(thd, conds);
DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
/* change field = field to field = const for each found field = const */
propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
/*
Remove all instances of item == item
Remove all and-levels where CONST item != CONST item
*/
DBUG_EXECUTE("where",print_where(conds,"after const change"););
conds= remove_eq_conds(thd, conds, cond_value) ;
DBUG_EXECUTE("info",print_where(conds,"after remove"););
DBUG_RETURN(conds); DBUG_RETURN(conds);
} }
......
...@@ -287,24 +287,23 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -287,24 +287,23 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= lex_select_save; thd_arg->lex->current_select= lex_select_save;
if (!item_list.elements) if (!item_list.elements)
{ {
Statement *stmt= thd->current_statement; Item_arena *arena= thd->current_arena, backup;
Statement backup; if (arena->is_stmt_prepare())
if (stmt) thd->set_n_backup_item_arena(arena, &backup);
thd->set_n_backup_item_arena(stmt, &backup);
Field **field; Field **field;
for (field= table->field; *field; field++) for (field= table->field; *field; field++)
{ {
Item_field *item= new Item_field(*field); Item_field *item= new Item_field(*field);
if (!item || item_list.push_back(item)) if (!item || item_list.push_back(item))
{ {
if (stmt) if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
} }
if (stmt) if (arena->is_stmt_prepare())
{ {
thd->restore_backup_item_arena(stmt, &backup); thd->restore_backup_item_arena(arena, &backup);
/* prepare fake select to initialize it correctly */ /* prepare fake select to initialize it correctly */
ulong options_tmp= init_prepare_fake_select_lex(thd); ulong options_tmp= init_prepare_fake_select_lex(thd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment