Commit 16227c28 authored by unknown's avatar unknown

PS and SP made compatible in mechanism used for preparing query for rexecutions (Bug #2266)


mysql-test/r/sp.result:
  test suite for Bug #2266
mysql-test/t/sp.test:
  test suite for Bug #2266
sql/item_subselect.cc:
  made ancestor for Statement (Item_arena)
sql/item_subselect.h:
  made ancestor for Statement (Item_arena)
sql/item_sum.cc:
  made ancestor for Statement (Item_arena)
sql/item_sum.h:
  made ancestor for Statement (Item_arena)
sql/mysql_priv.h:
  reset_stmt_for_execute use PS and SP
sql/sp_head.cc:
  sp_head use Item_arena as ancestor to be PS cleunup compatible
  SP use PS storing/restoring/cleanup mechanisms
  cleanup() of SP Items added
  Items created in temporary memory pool during SP execution saved for normal freeing after SP execution
sql/sp_head.h:
  sp_head use Item_arena
sql/sql_base.cc:
  made ancestor for Statement (Item_arena)
  results of wild_setup made permanent
  setup_conds make natural joins expanding only once and store results in PS/SP memory
sql/sql_class.cc:
  made ancestor for Statement (Item_arena)
sql/sql_class.h:
  made ancestor for Statement (Item_arena)
  method to detect PS preparation added
sql/sql_delete.cc:
  storing where for DELETE and mark first execution
sql/sql_derived.cc:
  use method
sql/sql_insert.cc:
  mark first execution for INSERT
sql/sql_lex.cc:
  flags to correctly make transformations of query and storing them in memory of PS/SP
  made ancestor for Statement (Item_arena)
sql/sql_lex.h:
  reved variable od SP ol saving data
  flags to correctly make transformations of query and storing them in memory of PS/SP
sql/sql_parse.cc:
  cleunup unit for any query
sql/sql_prepare.cc:
  made ancestor for Statement (Item_arena)
  storing where moved to preparation
  changed interface of reset_stmt_for_execute to use it is SP
  do not restore where/order by/group by before first execution (but tables and unit can be chenged without execution and should be prepared (subqueries executes on demand))
sql/sql_select.cc:
  storing where for SELECT/multi-DELETE/... and mark first execution
sql/sql_union.cc:
  made ancestor for Statement (Item_arena)
sql/sql_update.cc:
  storing where for UPDATE and mark first execution
parent 8d18ae39
......@@ -1305,3 +1305,13 @@ test bar PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINE
drop procedure bar|
drop table t1;
drop table t2;
create procedure p1 () select (select s1 from t1) from t1;
create table t1 (s1 int);
call p1();
(select s1 from t1)
insert into t1 values (1);
call p1();
(select s1 from t1)
1
drop procedure p1;
drop table t1;
......@@ -1444,3 +1444,15 @@ drop procedure bar|
delimiter ;|
drop table t1;
drop table t2;
#
# rexecution
#
create procedure p1 () select (select s1 from t1) from t1;
create table t1 (s1 int);
call p1();
insert into t1 values (1);
call p1();
drop procedure p1;
drop table t1;
......@@ -104,7 +104,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
stmt= thd->current_statement;
arena= thd->current_arena;
char const *save_where= thd->where;
int res= engine->prepare();
......@@ -316,8 +316,8 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
if (join->conds || join->having)
{
Item *cond;
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
if (!join->having)
cond= join->conds;
......@@ -330,15 +330,15 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
new Item_null())))
goto err;
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
return RES_REDUCE;
}
return RES_OK;
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
return RES_ERROR;
}
......@@ -618,8 +618,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
Statement backup;
thd->where= "scalar IN/ALL/ANY subquery";
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
if (select_lex->item_list.elements > 1)
{
......@@ -823,21 +823,21 @@ Item_in_subselect::single_value_transformer(JOIN *join,
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_REDUCE);
}
}
}
ok:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_ERROR);
}
......@@ -855,8 +855,8 @@ Item_in_subselect::row_value_transformer(JOIN *join)
Item *item= 0;
thd->where= "row IN/ALL/ANY subquery";
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
SELECT_LEX *select_lex= join->select_lex;
......@@ -940,13 +940,13 @@ Item_in_subselect::row_value_transformer(JOIN *join)
if (join->conds->fix_fields(thd, join->tables_list, 0))
goto err;
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_ERROR);
}
......
......@@ -26,7 +26,7 @@ class JOIN;
class select_subselect;
class subselect_engine;
class Item_bool_func2;
class Statement;
class Item_arena;
/* base class for subselects */
......@@ -36,8 +36,8 @@ class Item_subselect :public Item_result_field
protected:
/* thread handler, will be assigned in fix_fields only */
THD *thd;
/* prepared statement, or 0 */
Statement *stmt;
/* Item_arena used or 0 */
Item_arena *arena;
/* substitution instead of subselect in case of optimization */
Item *substitution;
/* unit of subquery */
......
......@@ -77,15 +77,15 @@ Item_sum::Item_sum(THD *thd, Item_sum *item):
*/
bool Item_sum::save_args_for_prepared_statements(THD *thd)
{
if (thd->current_statement)
return save_args(thd->current_statement);
if (thd->current_arena && args_copy == 0)
return save_args(thd->current_arena);
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;
memcpy(args_copy, args, sizeof(Item*)*arg_count);
return 0;
......
......@@ -23,6 +23,8 @@
#include <my_tree.h>
class Item_arena;
class Item_sum :public Item_result_field
{
public:
......@@ -93,7 +95,7 @@ public:
virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd);
bool save_args_for_prepared_statements(THD *);
bool save_args(Statement* stmt);
bool save_args(Item_arena* stmt);
bool walk (Item_processor processor, byte *argument);
};
......
......@@ -681,6 +681,7 @@ void mysql_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
List<Item> &values, ulong counter);
void reset_stmt_for_execute(THD *thd, LEX *lex);
/* sql_error.cc */
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
......
......@@ -186,8 +186,8 @@ sp_head::operator new(size_t size)
bzero((char *)&own_root, sizeof(own_root));
init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
sp= (sp_head *)alloc_root(&own_root, size);
sp->m_mem_root= own_root;
sp->mem_root= own_root;
DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
DBUG_RETURN(sp);
}
......@@ -198,16 +198,18 @@ sp_head::operator delete(void *ptr, size_t size)
MEM_ROOT own_root;
sp_head *sp= (sp_head *)ptr;
DBUG_PRINT("info", ("root: %lx", &sp->m_mem_root));
memcpy(&own_root, (const void *)&sp->m_mem_root, sizeof(MEM_ROOT));
memcpy(&own_root, (const void *)&sp->mem_root, sizeof(MEM_ROOT));
DBUG_PRINT("info", ("mem_root 0x%lx moved to 0x%lx",
(ulong) &sp->mem_root, (ulong) &own_root));
free_root(&own_root, MYF(0));
DBUG_VOID_RETURN;
}
sp_head::sp_head()
: Sql_alloc(), m_returns_cs(NULL), m_has_return(FALSE), m_simple_case(FALSE),
m_multi_results(FALSE), m_free_list(NULL)
:Item_arena((bool)FALSE), m_returns_cs(NULL), m_has_return(FALSE),
m_simple_case(FALSE), m_multi_results(FALSE)
{
DBUG_ENTER("sp_head::sp_head");
......@@ -216,6 +218,7 @@ sp_head::sp_head()
DBUG_VOID_RETURN;
}
void
sp_head::init(LEX *lex)
{
......@@ -359,7 +362,7 @@ sp_head::destroy()
delete i;
delete_dynamic(&m_instr);
m_pcont->destroy();
free_items(m_free_list);
free_items(free_list);
while ((lex= (LEX *)m_lex.pop()))
{
if (lex != &m_thd->main_lex) // We got interrupted and have lex'es left
......@@ -392,6 +395,7 @@ sp_head::execute(THD *thd)
if (ctx)
ctx->clear_handler();
thd->query_error= 0;
thd->current_arena= this;
do
{
sp_instr *i;
......@@ -430,6 +434,9 @@ sp_head::execute(THD *thd)
done:
DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
ret, thd->killed, thd->query_error));
if (thd->current_arena)
cleanup_items(thd->current_arena->free_list);
thd->current_arena= 0;
if (thd->killed || thd->query_error || thd->net.report_error)
ret= -1;
/* If the DB has changed, the pointer has changed too, but the
......@@ -687,21 +694,6 @@ sp_head::restore_lex(THD *thd)
// Update some state in the old one first
oldlex->ptr= sublex->ptr;
oldlex->next_state= sublex->next_state;
for (sl= sublex->all_selects_list ;
sl ;
sl= sl->next_select_in_list())
{
// Save WHERE clause pointers to avoid damaging by optimisation
sl->prep_where= sl->where;
if (sl->with_wild)
{
// Copy item_list. We will restore it before calling the
// sub-statement, so it's ok to pop them.
sl->item_list_copy.empty();
while (Item *it= sl->item_list.pop())
sl->item_list_copy.push_back(it);
}
}
// Collect some data from the sub statement lex.
sp_merge_funs(oldlex, sublex);
......@@ -792,19 +784,19 @@ sp_head::set_info(char *definer, uint definerlen,
if (! p)
p= definer; // Weird...
len= p-definer;
m_definer_user.str= strmake_root(&m_mem_root, definer, len);
m_definer_user.str= strmake_root(&mem_root, definer, len);
m_definer_user.length= len;
len= definerlen-len-1;
m_definer_host.str= strmake_root(&m_mem_root, p+1, len);
m_definer_host.str= strmake_root(&mem_root, p+1, len);
m_definer_host.length= len;
m_created= created;
m_modified= modified;
m_chistics= (st_sp_chistics *)alloc_root(&m_mem_root, sizeof(st_sp_chistics));
m_chistics= (st_sp_chistics *)alloc_root(&mem_root, sizeof(st_sp_chistics));
memcpy(m_chistics, chistics, sizeof(st_sp_chistics));
if (m_chistics->comment.length == 0)
m_chistics->comment.str= 0;
else
m_chistics->comment.str= strmake_root(&m_mem_root,
m_chistics->comment.str= strmake_root(&mem_root,
m_chistics->comment.str,
m_chistics->comment.length);
}
......@@ -812,26 +804,33 @@ sp_head::set_info(char *definer, uint definerlen,
void
sp_head::reset_thd_mem_root(THD *thd)
{
DBUG_ENTER("sp_head::reset_thd_mem_root");
m_thd_root= thd->mem_root;
thd->mem_root= m_mem_root;
m_free_list= thd->free_list; // Keep the old list
thd->mem_root= mem_root;
DBUG_PRINT("info", ("mem_root 0x%lx moved to thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root));
free_list= thd->free_list; // Keep the old list
thd->free_list= NULL; // Start a new one
/* Copy the db, since substatements will point to it */
m_thd_db= thd->db;
thd->db= strmake_root(&thd->mem_root, thd->db, thd->db_length);
m_thd= thd;
DBUG_VOID_RETURN;
}
void
sp_head::restore_thd_mem_root(THD *thd)
{
Item *flist= m_free_list; // The old list
m_free_list= thd->free_list; // Get the new one
DBUG_ENTER("sp_head::restore_thd_mem_root");
Item *flist= free_list; // The old list
set_item_arena(thd); // Get new fre_list and mem_root
DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
(ulong) &mem_root, (ulong) &thd->mem_root));
thd->free_list= flist; // Restore the old one
thd->db= m_thd_db; // Restore the original db pointer
m_mem_root= thd->mem_root;
thd->mem_root= m_thd_root;
m_thd= NULL;
DBUG_VOID_RETURN;
}
......@@ -919,7 +918,6 @@ int
sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
{
LEX *olex; // The other lex
Item *freelist;
SELECT_LEX *sl;
int res;
......@@ -927,94 +925,24 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex)
thd->lex= lex; // Use my own lex
thd->lex->thd = thd; // QQ Not reentrant!
thd->lex->unit.thd= thd; // QQ Not reentrant
freelist= thd->free_list;
thd->free_list= NULL;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id= query_id++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
// Copy WHERE clause pointers to avoid damaging by optimisation
// Also clear ref_pointer_arrays.
for (sl= lex->all_selects_list ;
sl ;
sl= sl->next_select_in_list())
{
if (lex->sql_command == SQLCOM_CREATE_TABLE ||
lex->sql_command == SQLCOM_INSERT_SELECT)
{ // Destroys sl->table_list.first
sl->table_list_first_copy= sl->table_list.first;
}
if (sl->with_wild)
{
// Restore item_list
// Note: We have to do this before executing the sub-statement,
// to make sure that the list nodes are in the right
// memroot.
List_iterator_fast<Item> li(sl->item_list_copy);
sl->item_list.empty();
while (Item *it= li++)
sl->item_list.push_back(it);
}
sl->ref_pointer_array= 0;
if (sl->prep_where)
sl->where= sl->prep_where->copy_andor_structure(thd);
for (ORDER *order= (ORDER *)sl->order_list.first ;
order ;
order= order->next)
{
order->item_copy= order->item;
}
for (ORDER *group= (ORDER *)sl->group_list.first ;
group ;
group= group->next)
{
group->item_copy= group->item;
}
}
reset_stmt_for_execute(thd, lex);
res= mysql_execute_command(thd);
lex->unit.cleanup();
if (thd->lock || thd->open_tables || thd->derived_tables)
{
thd->proc_info="closing tables";
close_thread_tables(thd); /* Free tables */
}
for (sl= lex->all_selects_list ;
sl ;
sl= sl->next_select_in_list())
{
TABLE_LIST *tabs;
if (lex->sql_command == SQLCOM_CREATE_TABLE ||
lex->sql_command == SQLCOM_INSERT_SELECT)
{ // Restore sl->table_list.first
sl->table_list.first= sl->table_list_first_copy;
}
// We have closed all tables, get rid of pointers to them
for (tabs=(TABLE_LIST *)sl->table_list.first ;
tabs ;
tabs= tabs->next)
{
tabs->table= NULL;
}
for (ORDER *order= (ORDER *)sl->order_list.first ;
order ;
order= order->next)
{
order->item= order->item_copy;
}
for (ORDER *group= (ORDER *)sl->group_list.first ;
group ;
group= group->next)
{
group->item= group->item_copy;
}
}
thd->lex= olex; // Restore the other lex
thd->free_list= freelist;
return res;
}
......
......@@ -70,7 +70,7 @@ sp_name *
sp_name_current_db_new(THD *thd, LEX_STRING name);
class sp_head : public Sql_alloc
class sp_head :private Item_arena
{
sp_head(const sp_head &); /* Prevent use of these */
void operator=(sp_head &);
......@@ -206,9 +206,7 @@ public:
private:
MEM_ROOT m_mem_root; // My own mem_root
MEM_ROOT m_thd_root; // Temp. store for thd's mem_root
Item *m_free_list; // Where the items go
THD *m_thd; // Set if we have reset mem_root
char *m_thd_db; // Original thd->db pointer
......
......@@ -2158,14 +2158,14 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
{
if (!wild_num)
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
temporary mem_root to statement mem root to save changes of SELECT list
*/
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
reg2 Item *item;
List_iterator<Item> it(fields);
while ( wild_num && (item= it++))
......@@ -2178,8 +2178,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
if (insert_fields(thd,tables,((Item_field*) item)->db_name,
((Item_field*) item)->table_name, &it))
{
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
return (-1);
}
if (sum_func_list)
......@@ -2194,8 +2194,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
wild_num--;
}
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
{
/* make * substituting permanent */
SELECT_LEX *select_lex= thd->lex->current_select;
select_lex->with_wild= 0;
select_lex->item_list= fields;
thd->restore_backup_item_arena(arena, &backup);
}
return 0;
}
......@@ -2408,12 +2415,17 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
table_map not_null_tables= 0;
Statement *stmt= thd->current_statement, backup;
SELECT_LEX *select_lex= thd->lex->current_select;
Item_arena *arena= ((thd->current_arena &&
!select_lex->conds_processed_with_permanent_arena) ?
thd->current_arena :
0);
Item_arena backup;
DBUG_ENTER("setup_conds");
thd->set_query_id=1;
thd->lex->current_select->cond_count= 0;
select_lex->cond_count= 0;
if (*conds)
{
thd->where="where clause";
......@@ -2436,7 +2448,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
table->on_expr->check_cols(1))
DBUG_RETURN(1);
thd->lex->current_select->cond_count++;
select_lex->cond_count++;
/*
If it's a normal join or a LEFT JOIN which can be optimized away
......@@ -2447,12 +2459,12 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
!(specialflag & SPECIAL_NO_NEW_FUNC)))
{
table->outer_join= 0;
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
*conds= and_conds(*conds, table->on_expr);
table->on_expr=0;
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
if ((*conds) && !(*conds)->fixed &&
(*conds)->fix_fields(thd, tables, conds))
DBUG_RETURN(1);
......@@ -2460,8 +2472,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
}
if (table->natural_join)
{
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
/* Make a join of all fields with have the same name */
TABLE *t1= table->table;
TABLE *t2= table->natural_join->table;
......@@ -2491,7 +2503,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
t2->used_keys.intersect(t2_field->part_of_key);
}
}
thd->lex->current_select->cond_count+= cond_and->list.elements;
select_lex->cond_count+= cond_and->list.elements;
// to prevent natural join processing during PS re-execution
table->natural_join= 0;
......@@ -2500,8 +2512,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
*conds= and_conds(*conds, cond_and);
// fix_fields() should be made with temporary memory pool
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
if (*conds && !(*conds)->fixed)
{
if ((*conds)->fix_fields(thd, tables, conds))
......@@ -2512,8 +2524,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
table->on_expr= and_conds(table->on_expr, cond_and);
// fix_fields() should be made with temporary memory pool
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
if (table->on_expr && !table->on_expr->fixed)
{
if (table->on_expr->fix_fields(thd, tables, &table->on_expr))
......@@ -2523,21 +2535,22 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
}
}
if (stmt)
if (arena)
{
/*
We are in prepared statement preparation code => we should store
WHERE clause changing for next executions.
We do this ON -> WHERE transformation only once per PS statement.
We do this ON -> WHERE transformation only once per PS/SP statement.
*/
thd->lex->current_select->where= *conds;
select_lex->where= *conds;
select_lex->conds_processed_with_permanent_arena= 1;
}
DBUG_RETURN(test(thd->net.report_error));
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(1);
}
......
......@@ -86,7 +86,7 @@ extern "C" void free_user_var(user_var_entry *entry)
** Thread specific functions
****************************************************************************/
THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
THD::THD():user_time(0), current_arena(0), is_fatal_error(0),
last_insert_id_used(0),
insert_id_used(0), rand_used(0), in_lock_tables(0),
global_read_lock(0), bootstrap(0), spcont(NULL)
......@@ -1210,23 +1210,47 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
}
Item_arena::Item_arena(THD* thd)
:free_list(0)
{
init_sql_alloc(&mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
}
Item_arena::Item_arena()
:free_list(0)
{
bzero((char *) &mem_root, sizeof(mem_root));
}
Item_arena::Item_arena(bool init_mem_root)
:free_list(0)
{
if (init_mem_root)
bzero((char *) &mem_root, sizeof(mem_root));
}
Item_arena::~Item_arena()
{}
/*
Statement functions
*/
Statement::Statement(THD *thd)
:id(++thd->statement_id_counter),
:Item_arena(thd),
id(++thd->statement_id_counter),
set_query_id(1),
allow_sum_func(0),
lex(&main_lex),
query(0),
query_length(0),
free_list(0)
{
init_sql_alloc(&mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
}
query_length(0)
{}
/*
This constructor is called when statement is a subobject of THD:
......@@ -1235,15 +1259,14 @@ Statement::Statement(THD *thd)
*/
Statement::Statement()
:id(0),
:Item_arena(),
id(0),
set_query_id(1),
allow_sum_func(0), /* initialized later */
lex(&main_lex),
query(0), /* these two are set */
query_length(0), /* in alloc_query() */
free_list(0)
query_length(0) /* in alloc_query() */
{
bzero((char *) &mem_root, sizeof(mem_root));
}
......@@ -1264,14 +1287,14 @@ void Statement::set_statement(Statement *stmt)
}
void Statement::set_n_backup_item_arena(Statement *set, Statement *backup)
void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
{
backup->set_item_arena(this);
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_item_arena(backup);
......@@ -1279,7 +1302,7 @@ void Statement::restore_backup_item_arena(Statement *set, Statement *backup)
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;
free_list= set->free_list;
......
......@@ -434,6 +434,48 @@ struct system_variables
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;
Item_arena(THD *thd);
Item_arena();
Item_arena(bool init_mem_root);
~Item_arena();
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.
One connection can contain a lot of simultaneously running statements,
......@@ -448,7 +490,7 @@ void free_tmp_table(THD *thd, TABLE *entry);
be used explicitly.
*/
class Statement
class Statement: public Item_arena
{
Statement(const Statement &rhs); /* not implemented: */
Statement &operator=(const Statement &rhs); /* non-copyable */
......@@ -489,12 +531,6 @@ public:
*/
char *query;
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:
/* We build without RTTI, so dynamic_cast can't be used. */
......@@ -518,31 +554,6 @@ public:
/* return class type */
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);
};
......@@ -746,9 +757,9 @@ public:
Vio* active_vio;
#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
generated auto_increment value in handler.cc
......@@ -969,7 +980,7 @@ public:
inline void allocate_temporary_memory_pool_for_ps_preparing()
{
DBUG_ASSERT(current_statement!=0);
DBUG_ASSERT(current_arena!=0);
/*
We do not want to have in PS memory all that junk,
which will be created by preparation => substitute memory
......@@ -978,7 +989,7 @@ public:
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);
current_arena->set_item_arena(this);
init_sql_alloc(&mem_root,
variables.query_alloc_block_size,
variables.query_prealloc_size);
......@@ -986,12 +997,16 @@ public:
}
inline void free_temporary_memory_pool_for_ps_preparing()
{
DBUG_ASSERT(current_statement!=0);
cleanup_items(current_statement->free_list);
DBUG_ASSERT(current_arena!=0);
cleanup_items(current_arena->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);
set_item_arena(current_arena);
}
inline bool only_prepare()
{
return command == COM_PREPARE;
}
};
......
......@@ -264,10 +264,11 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
{
TABLE_LIST *delete_table_list= ((TABLE_LIST*) thd->lex->
select_lex.table_list.first);
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_delete");
if (setup_conds(thd, delete_table_list, conds) ||
setup_ftfuncs(&thd->lex->select_lex))
setup_ftfuncs(select_lex))
DBUG_RETURN(-1);
if (find_real_table_in_list(table_list->next,
table_list->db, table_list->real_name))
......@@ -275,6 +276,11 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
DBUG_RETURN(-1);
}
if (thd->current_arena && select_lex->first_execution)
{
select_lex->prep_where= select_lex->where;
select_lex->first_execution= 0;
}
DBUG_RETURN(0);
}
......
......@@ -152,7 +152,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
can skip execution (and parameters is not defined, too)
*/
if (!thd->current_statement)
if (!thd->only_prepare())
{
if (is_union)
{
......
......@@ -460,6 +460,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
DBUG_RETURN(-1);
}
thd->lex->select_lex.first_execution= 0;
DBUG_RETURN(0);
}
......
......@@ -1011,10 +1011,12 @@ void st_select_lex::init_query()
having_fix_field= 0;
resolve_mode= NOMATTER_MODE;
cond_count= with_wild= 0;
conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
select_n_having_items= 0;
prep_where= 0;
explicit_limit= 0;
first_execution= 1;
}
void st_select_lex::init_select()
......@@ -1414,7 +1416,9 @@ bool st_select_lex::add_order_to_list(THD *thd, Item *item, bool asc)
bool st_select_lex::add_item_to_list(THD *thd, Item *item)
{
return item_list.push_back(item);
DBUG_ENTER("st_select_lex::add_item_to_list");
DBUG_PRINT("info", ("Item: %p", item));
DBUG_RETURN(item_list.push_back(item));
}
......@@ -1500,12 +1504,12 @@ 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
prepared statement
*/
Statement *stmt= thd->current_statement ? thd->current_statement : thd;
Item_arena *arena= thd->current_arena ? thd->current_arena : thd;
return (ref_pointer_array=
(Item **)stmt->alloc(sizeof(Item*) *
(item_list.elements +
select_n_having_items +
order_group_num)* 5)) == 0;
(Item **)arena->alloc(sizeof(Item*) *
(item_list.elements +
select_n_having_items +
order_group_num)* 5)) == 0;
}
......
......@@ -405,8 +405,6 @@ public:
enum olap_type olap;
SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */
List<Item> item_list; /* list of fields & expressions */
List<Item> item_list_copy; /* For SPs */
byte *table_list_first_copy; /* For SPs */
List<String> interval_list, use_index, *use_index_ptr,
ignore_index, *ignore_index_ptr;
/*
......@@ -435,6 +433,11 @@ public:
uint cond_count; /* number of arguments of and/or/xor in where/having */
enum_parsing_place parsing_place; /* where we are parsing expression */
bool with_sum_func; /* sum function indicator */
/*
PS or SP cond natural joins was alredy processed with permanent
arena and all additional items which we need alredy stored in it
*/
bool conds_processed_with_permanent_arena;
ulong table_join_options;
uint in_sum_expr;
......@@ -445,6 +448,7 @@ public:
bool having_fix_field;
/* explicit LIMIT clause was used */
bool explicit_limit;
bool first_execution; /* first execution in SP or PS */
/*
SELECT for SELECT command st_select_lex. Used to privent scaning
......
......@@ -4182,12 +4182,14 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
query_cache_end_of_result(thd);
}
}
lex->unit.cleanup();
}
else
{
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
query_cache_abort(&thd->net);
lex->unit.cleanup();
if (thd->lex->sphead)
{
/* Clean up after failed stored procedure/function */
......
......@@ -1357,7 +1357,7 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
mysql_log.write(thd, COM_PREPARE, "%s", packet);
thd->current_statement= stmt;
thd->current_arena= stmt;
lex= lex_start(thd, (uchar *) thd->query, thd->query_length);
mysql_init_query(thd);
lex->safe_to_cache_query= 0;
......@@ -1381,7 +1381,7 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
stmt->set_item_arena(thd);
thd->set_statement(&thd->stmt_backup);
thd->set_item_arena(&thd->stmt_backup);
thd->current_statement= 0;
thd->current_arena= 0;
if (error)
{
......@@ -1389,43 +1389,33 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
thd->stmt_map.erase(stmt);
/* error is sent inside yyparse/send_prepare_results */
}
else
{
SELECT_LEX *sl= stmt->lex->all_selects_list;
/*
Save WHERE clause pointers, because they may be changed during query
optimisation.
*/
for (; sl; sl= sl->next_select_in_list())
{
sl->prep_where= sl->where;
}
}
DBUG_VOID_RETURN;
}
/* Reinit statement before execution */
static void reset_stmt_for_execute(Prepared_statement *stmt)
void reset_stmt_for_execute(THD *thd, LEX *lex)
{
THD *thd= stmt->thd;
SELECT_LEX *sl= stmt->lex->all_selects_list;
SELECT_LEX *sl= lex->all_selects_list;
for (; sl; sl= sl->next_select_in_list())
{
/*
Copy WHERE clause pointers to avoid damaging they by optimisation
*/
if (sl->prep_where)
sl->where= sl->prep_where->copy_andor_structure(thd);
DBUG_ASSERT(sl->join == 0);
ORDER *order;
/* Fix GROUP list */
for (order= (ORDER *)sl->group_list.first; order; order= order->next)
order->item= &order->item_ptr;
/* Fix ORDER list */
for (order= (ORDER *)sl->order_list.first; order; order= order->next)
order->item= &order->item_ptr;
if (!sl->first_execution)
{
/*
Copy WHERE clause pointers to avoid damaging they by optimisation
*/
if (sl->prep_where)
sl->where= sl->prep_where->copy_andor_structure(thd);
DBUG_ASSERT(sl->join == 0);
ORDER *order;
/* Fix GROUP list */
for (order= (ORDER *)sl->group_list.first; order; order= order->next)
order->item= &order->item_ptr;
/* Fix ORDER list */
for (order= (ORDER *)sl->order_list.first; order; order= order->next)
order->item= &order->item_ptr;
}
/*
TODO: When the new table structure is ready, then have a status bit
......@@ -1443,7 +1433,6 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
tables->table= 0;
tables->table_list= 0;
}
{
SELECT_LEX_UNIT *unit= sl->master_unit();
unit->unclean();
......@@ -1506,7 +1495,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt);
reset_stmt_for_execute(stmt);
reset_stmt_for_execute(thd, stmt->lex);
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count)
{
......
......@@ -367,7 +367,14 @@ JOIN::prepare(Item ***rref_pointer_array,
Item_subselect::trans_res res;
if ((res= subselect->select_transformer(this)) !=
Item_subselect::RES_OK)
{
if (thd->current_arena && select_lex->first_execution)
{
select_lex->prep_where= select_lex->where;
select_lex->first_execution= 0;
}
DBUG_RETURN((res == Item_subselect::RES_ERROR));
}
}
}
......@@ -470,6 +477,11 @@ JOIN::prepare(Item ***rref_pointer_array,
if (alloc_func_list())
goto err;
if (thd->current_arena && select_lex->first_execution)
{
select_lex->prep_where= select_lex->where;
select_lex->first_execution= 0;
}
DBUG_RETURN(0); // All OK
err:
......
......@@ -262,27 +262,32 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= lex_select_save;
if (!item_list.elements)
{
Statement *stmt= thd->current_statement;
Statement backup;
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
Item_arena *arena= thd->current_arena;
Item_arena backup;
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
Field **field;
for (field= table->field; *field; field++)
{
Item_field *item= new Item_field(*field);
if (!item || item_list.push_back(item))
{
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena)
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(-1);
}
}
if (stmt)
if (arena)
{
thd->restore_backup_item_arena(stmt, &backup);
thd->restore_backup_item_arena(arena, &backup);
/* prepare fake select to initialize it correctly */
ulong options_tmp= init_prepare_fake_select_lex(thd);
/*
it should be done only once (because item_list builds only onece
per statement)
*/
DBUG_ASSERT(fake_select_lex->join == 0);
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
result)))
{
......
......@@ -425,6 +425,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
TABLE *table= table_list->table;
TABLE_LIST tables;
List<Item> all_fields;
SELECT_LEX *select_lex= &thd->lex->select_lex;
DBUG_ENTER("mysql_prepare_update");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
......@@ -437,10 +438,10 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
if (setup_tables(update_table_list) ||
setup_conds(thd, update_table_list, conds) ||
thd->lex->select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
select_lex->setup_ref_array(thd, order_num) ||
setup_order(thd, select_lex->ref_pointer_array,
update_table_list, all_fields, all_fields, order) ||
setup_ftfuncs(&thd->lex->select_lex))
setup_ftfuncs(select_lex))
DBUG_RETURN(-1);
/* Check that we are not using table that we are updating in a sub select */
......@@ -450,6 +451,11 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
DBUG_RETURN(-1);
}
if (thd->current_arena && select_lex->first_execution)
{
select_lex->prep_where= select_lex->where;
select_lex->first_execution= 0;
}
DBUG_RETURN(0);
}
......
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