Commit d8703464 authored by unknown's avatar unknown

fixed subquery with PS (BUG#2462)

fixed UNION preparation


sql/item.cc:
  debug output added
sql/item.h:
  debug output added
sql/item_cmpfunc.cc:
  correct cleunup() for Item_in_optimizer
sql/item_cmpfunc.h:
  correct cleunup() for Item_in_optimizer
  debug output added
sql/item_func.h:
  debug output added
sql/item_subselect.cc:
  support of prepared statemnts added - mostly memorry allocation manegement, only one trabsformatio & correct cleupup()
sql/item_subselect.h:
  support of prepared statemnts added - mostly memorry allocation manegement, only one trabsformatio & correct cleupup()
sql/item_sum.cc:
  debug output added
sql/item_sum.h:
  debug output added
sql/sql_class.cc:
  function to switch allocation arena for Items
sql/sql_class.h:
  function to switch allocation arena for Items
  pointer on current prepared statement added
sql/sql_lex.cc:
  comment fixed
sql/sql_lex.h:
  item cleanup support
sql/sql_prepare.cc:
  - fixed preparation of PS to avoid storing junk in its memory + correct work with union
  - fixed tables cleanup for UNION & subqueries
sql/sql_select.cc:
  removed condition which is always true for now
  fixed layout
sql/sql_union.cc:
  support of UNION subquery cleanup
tests/client_test.c:
  test of repeatable subqueries
  test of correct UNION initialisation
parent 4522e177
......@@ -966,8 +966,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
void Item_field::cleanup()
{
DBUG_ENTER("Item_field::cleanup");
Item_ident::cleanup();
field= result_field= 0;
DBUG_VOID_RETURN;
}
void Item::init_make_field(Send_field *tmp_field,
......@@ -1610,9 +1612,11 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
void Item_ref::cleanup()
{
DBUG_ENTER("Item_ref::cleanup");
Item_ident::cleanup();
if (hook_ptr)
*hook_ptr= orig_item;
DBUG_VOID_RETURN;
}
......
......@@ -128,7 +128,13 @@ class Item {
virtual ~Item() { name=0; } /*lint -e1509 */
void set_name(const char *str,uint length, CHARSET_INFO *cs);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual void cleanup() { fixed=0; }
virtual void cleanup()
{
DBUG_ENTER("Item::cleanup");
DBUG_PRINT("info", ("Type: %d", (int)type()));
fixed=0;
DBUG_VOID_RETURN;
}
virtual void make_field(Send_field *field);
virtual bool fix_fields(THD *, struct st_table_list *, Item **);
virtual int save_in_field(Field *field, bool no_conversions);
......@@ -996,8 +1002,10 @@ class Item_cache_row: public Item_cache
void bring_value();
void cleanup()
{
DBUG_ENTER("Item_cache_row::cleanup");
Item_cache::cleanup();
values= 0;
DBUG_VOID_RETURN;
}
};
......@@ -1023,8 +1031,10 @@ class Item_type_holder: public Item
Field *example() { return field_example; }
void cleanup()
{
DBUG_ENTER("Item_type_holder::cleanup");
Item::cleanup();
item_type= orig_type;
DBUG_VOID_RETURN;
}
};
......
......@@ -484,6 +484,14 @@ longlong Item_in_optimizer::val_int()
return tmp;
}
void Item_in_optimizer::cleanup()
{
DBUG_ENTER("Item_in_optimizer::cleanup");
Item_bool_func::cleanup();
cache= 0;
DBUG_VOID_RETURN;
}
bool Item_in_optimizer::is_null()
{
cache->store(args[0]);
......
......@@ -105,6 +105,7 @@ class Item_in_optimizer: public Item_bool_func
Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
*/
longlong val_int();
void cleanup();
const char *func_name() const { return "<in_optimizer>"; }
Item_cache **get_cache() { return &cache; }
};
......@@ -207,9 +208,11 @@ class Item_bool_rowready_func2 :public Item_bool_func2
}
void cleanup()
{
DBUG_ENTER("Item_bool_rowready_func2::cleanup");
Item_bool_func2::cleanup();
tmp_arg[0]= orig_a;
tmp_arg[1]= orig_b;
DBUG_VOID_RETURN;
}
};
......@@ -718,10 +721,12 @@ class Item_func_in :public Item_int_func
void fix_length_and_dec();
void cleanup()
{
DBUG_ENTER("Item_func_in::cleanup");
delete array;
delete in_item;
array= 0;
in_item= 0;
DBUG_VOID_RETURN;
}
optimize_type select_optimize() const
{ return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
......
......@@ -991,6 +991,7 @@ class Item_func_match :public Item_real_func
join_key(0), ft_handler(0), table(0), master(0), concat(0) { }
void cleanup()
{
DBUG_ENTER("Item_func_match");
if (!master && ft_handler)
{
ft_handler->please->close_search(ft_handler);
......@@ -1001,6 +1002,7 @@ class Item_func_match :public Item_real_func
}
if (concat)
delete concat;
DBUG_VOID_RETURN;
}
enum Functype functype() const { return FT_FUNC; }
const char *func_name() const { return "match"; }
......
......@@ -35,9 +35,9 @@ inline Item * and_items(Item* cond, Item *item)
}
Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), substitution(0),
engine(0), used_tables_cache(0), have_to_be_excluded(0),
const_item_cache(1), engine_changed(0)
Item_result_field(), value_assigned(0), thd(0), substitution(0),
engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
const_item_cache(1), engine_changed(0), changed(0)
{
reset();
/*
......@@ -54,9 +54,10 @@ void Item_subselect::init(st_select_lex *select_lex,
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
unit= select_lex->master_unit();
if (select_lex->next_select())
engine= new subselect_union_engine(select_lex->master_unit(), result,
engine= new subselect_union_engine(unit, result,
this);
else
engine= new subselect_single_select_engine(select_lex, result, this);
......@@ -65,8 +66,26 @@ void Item_subselect::init(st_select_lex *select_lex,
void Item_subselect::cleanup()
{
DBUG_ENTER("Item_subselect::cleanup");
Item_result_field::cleanup();
if (old_engine)
{
engine->cleanup();
engine= old_engine;
old_engine= 0;
}
engine->cleanup();
reset();
value_assigned= 0;
DBUG_VOID_RETURN;
}
void Item_singlerow_subselect::cleanup()
{
DBUG_ENTER("Item_singlerow_subselect::cleanup");
value= 0; row= 0;
Item_subselect::cleanup();
DBUG_VOID_RETURN;
}
Item_subselect::~Item_subselect()
......@@ -85,13 +104,22 @@ Item_subselect::select_transformer(JOIN *join)
bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{
engine->set_thd((thd= thd_param));
stmt= thd->current_statement;
char const *save_where= thd->where;
int res= engine->prepare();
// all transformetion is done (used by prepared statements)
changed= 1;
if (!res)
{
if (substitution)
{
// did we changed top item of WHERE condition
if (unit->outer_select()->where == (*ref))
unit->outer_select()->where= substitution; // correct WHERE for PS
(*ref)= substitution;
substitution->name= name;
if (have_to_be_excluded)
......@@ -240,7 +268,11 @@ void Item_singlerow_subselect::reset()
Item_subselect::trans_res
Item_singlerow_subselect::select_transformer(JOIN *join)
{
if (changed)
return RES_OK;
SELECT_LEX *select_lex= join->select_lex;
Statement backup;
if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements &&
......@@ -275,20 +307,30 @@ 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 (!join->having)
cond= join->conds;
else if (!join->conds)
cond= join->having;
else
if (!(cond= new Item_cond_and(join->conds, join->having)))
return RES_ERROR;
goto err;
if (!(substitution= new Item_func_if(cond, substitution,
new Item_null())))
return RES_ERROR;
goto err;
}
if (stmt)
thd->restore_backup_item_arena(&backup);
return RES_REDUCE;
}
return RES_OK;
err:
if (stmt)
thd->restore_backup_item_arena(&backup);
return RES_ERROR;
}
void Item_singlerow_subselect::store(uint i, Item *item)
......@@ -550,15 +592,22 @@ Item_in_subselect::single_value_transformer(JOIN *join,
{
DBUG_ENTER("Item_in_subselect::single_value_transformer");
if (changed)
{
DBUG_RETURN(RES_OK);
}
SELECT_LEX *select_lex= join->select_lex;
Statement backup;
THD *thd_tmp= join->thd;
thd_tmp->where= "scalar IN/ALL/ANY subquery";
thd->where= "scalar IN/ALL/ANY subquery";
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (select_lex->item_list.elements > 1)
{
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
DBUG_RETURN(RES_ERROR);
goto err;
}
if ((abort_on_null || (upper_not && upper_not->top_level())) &&
......@@ -567,7 +616,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (substitution)
{
// It is second (third, ...) SELECT of UNION => All is done
DBUG_RETURN(RES_OK);
goto ok;
}
Item *subs;
......@@ -597,10 +646,9 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->item_list.empty();
select_lex->item_list.push_back(item);
if (item->fix_fields(thd_tmp, join->tables_list, &item))
{
DBUG_RETURN(RES_ERROR);
}
if (item->fix_fields(thd, join->tables_list, &item))
goto err;
subs= new Item_singlerow_subselect(select_lex);
}
else
......@@ -611,16 +659,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
subs= new Item_maxmin_subselect(this, select_lex, func->l_op());
}
// left expression belong to outer select
SELECT_LEX *current= thd_tmp->lex->current_select, *up;
thd_tmp->lex->current_select= up= current->return_after_parsing();
if (left_expr->fix_fields(thd_tmp, up->get_table_list(), &left_expr))
SELECT_LEX *current= thd->lex->current_select, *up;
thd->lex->current_select= up= current->return_after_parsing();
if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
{
thd_tmp->lex->current_select= current;
DBUG_RETURN(RES_ERROR);
thd->lex->current_select= current;
goto err;
}
thd_tmp->lex->current_select= current;
thd->lex->current_select= current;
substitution= func->create(left_expr, subs);
DBUG_RETURN(RES_OK);
goto ok;
}
if (!substitution)
......@@ -629,16 +677,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
SELECT_LEX_UNIT *unit= select_lex->master_unit();
substitution= optimizer= new Item_in_optimizer(left_expr, this);
SELECT_LEX *current= thd_tmp->lex->current_select, *up;
SELECT_LEX *current= thd->lex->current_select, *up;
thd_tmp->lex->current_select= up= current->return_after_parsing();
thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd_tmp, up->get_table_list(), 0))
if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
thd_tmp->lex->current_select= current;
DBUG_RETURN(RES_ERROR);
thd->lex->current_select= current;
goto err;
}
thd_tmp->lex->current_select= current;
thd->lex->current_select= current;
/*
As far as Item_ref_in_optimizer do not substitude itself on fix_fields
......@@ -665,12 +713,12 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->ref_pointer_array,
(char *)"<ref>",
this->full_name()));
join->having= and_items(join->having, item);
select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd_tmp, join->tables_list, &join->having))
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR);
goto err;
}
select_lex->having_fix_field= 0;
}
......@@ -687,39 +735,42 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (!abort_on_null)
{
having= new Item_is_not_null_test(this, having);
select_lex->having=
join->having= (join->having ?
new Item_cond_and(having, join->having) :
having);
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd_tmp, join->tables_list,
if (join->having->fix_fields(thd, join->tables_list,
&join->having))
{
select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR);
goto err;
}
select_lex->having_fix_field= 0;
item= new Item_cond_or(item,
new Item_func_isnull(isnull));
}
item->name= (char *)in_additional_cond;
join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd_tmp, join->tables_list, &join->conds))
DBUG_RETURN(RES_ERROR);
select_lex->where= join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd, join->tables_list, &join->conds))
goto err;
}
else
{
if (select_lex->master_unit()->first_select()->next_select())
{
join->having= func->create(expr,
select_lex->having=
join->having=
func->create(expr,
new Item_null_helper(this, item,
(char *)"<no matter>",
(char *)"<result>"));
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd_tmp, join->tables_list,
if (join->having->fix_fields(thd, join->tables_list,
&join->having))
{
select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR);
goto err;
}
select_lex->having_fix_field= 0;
}
......@@ -730,18 +781,29 @@ Item_in_subselect::single_value_transformer(JOIN *join,
// fix_field of item will be done in time of substituting
substitution= item;
have_to_be_excluded= 1;
if (thd_tmp->lex->describe)
if (thd->lex->describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
push_warning(thd_tmp, MYSQL_ERROR::WARN_LEVEL_NOTE,
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
if (stmt)
thd->set_item_arena(&backup);
DBUG_RETURN(RES_REDUCE);
}
}
}
ok:
if (stmt)
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(RES_ERROR);
}
......@@ -750,15 +812,23 @@ Item_in_subselect::row_value_transformer(JOIN *join)
{
DBUG_ENTER("Item_in_subselect::row_value_transformer");
THD *thd_tmp= join->thd;
thd_tmp->where= "row IN/ALL/ANY subquery";
if (changed)
{
DBUG_RETURN(RES_OK);
}
Statement backup;
Item *item= 0;
thd->where= "row IN/ALL/ANY subquery";
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
SELECT_LEX *select_lex= join->select_lex;
if (select_lex->item_list.elements != left_expr->cols())
{
my_error(ER_OPERAND_COLUMNS, MYF(0), left_expr->cols());
DBUG_RETURN(RES_ERROR);
goto err;
}
if (!substitution)
......@@ -767,25 +837,24 @@ Item_in_subselect::row_value_transformer(JOIN *join)
SELECT_LEX_UNIT *unit= select_lex->master_unit();
substitution= optimizer= new Item_in_optimizer(left_expr, this);
SELECT_LEX *current= thd_tmp->lex->current_select, *up;
thd_tmp->lex->current_select= up= current->return_after_parsing();
SELECT_LEX *current= thd->lex->current_select, *up;
thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd_tmp, up->get_table_list(), 0))
if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
thd_tmp->lex->current_select= current;
DBUG_RETURN(RES_ERROR);
thd->lex->current_select= current;
goto err;
}
thd_tmp->lex->current_select= current;
thd->lex->current_select= current;
unit->uncacheable|= UNCACHEABLE_DEPENDENT;
}
uint n= left_expr->cols();
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
select_lex->setup_ref_array(thd_tmp,
select_lex->setup_ref_array(thd,
select_lex->order_list.elements +
select_lex->group_list.elements);
Item *item= 0;
{
uint n= left_expr->cols();
List_iterator_fast<Item> li(select_lex->item_list);
for (uint i= 0; i < n; i++)
{
......@@ -802,27 +871,34 @@ Item_in_subselect::row_value_transformer(JOIN *join)
func);
item= and_items(item, func);
}
}
if (join->having || select_lex->with_sum_func ||
select_lex->group_list.first ||
!select_lex->table_list.elements)
{
join->having= and_items(join->having, item);
select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd_tmp, join->tables_list, &join->having))
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR);
goto err;
}
select_lex->having_fix_field= 0;
}
else
{
join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd_tmp, join->tables_list, &join->having))
DBUG_RETURN(RES_ERROR);
select_lex->where= join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd, join->tables_list, &join->having))
goto err;
}
if (stmt)
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(RES_ERROR);
}
......@@ -894,13 +970,30 @@ subselect_single_select_engine(st_select_lex *select,
this->select_lex= select_lex;
}
void subselect_single_select_engine::cleanup()
{
prepared= 0;
optimized= 0;
executed= 0;
DBUG_ENTER("subselect_single_select_engine::cleanup");
prepared= optimized= executed= 0;
DBUG_VOID_RETURN;
}
void subselect_union_engine::cleanup()
{
DBUG_ENTER("subselect_union_engine::cleanup");
unit->reinit_exec_mechanism();
DBUG_VOID_RETURN;
}
void subselect_uniquesubquery_engine::cleanup()
{
DBUG_ENTER("subselect_uniquesubquery_engine::cleanup");
DBUG_VOID_RETURN;
}
subselect_union_engine::subselect_union_engine(st_select_lex_unit *u,
select_subselect *result_arg,
Item_subselect *item_arg)
......
......@@ -26,6 +26,7 @@ class JOIN;
class select_subselect;
class subselect_engine;
class Item_bool_func2;
class Statement;
/* base class for subselects */
......@@ -35,22 +36,30 @@ 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;
/* substitution instead of subselect in case of optimization */
Item *substitution;
/* unit of subquery */
st_select_lex_unit *unit;
/* engine that perform execution of subselect (single select or union) */
subselect_engine *engine;
/* old engine if engine was changed */
subselect_engine *old_engine;
/* cache of used external tables */
table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */
uint max_columns;
/* work with 'substitution' */
bool have_to_be_excluded;
/* cache of constante state */
/* cache of constant state */
bool const_item_cache;
public:
/* changed engine indicator */
bool engine_changed;
/* subquery is transformed */
bool changed;
enum trans_res {RES_OK, RES_REDUCE, RES_ERROR};
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
......@@ -94,6 +103,7 @@ class Item_subselect :public Item_result_field
void print(String *str);
bool change_engine(subselect_engine *eng)
{
old_engine= engine;
engine= eng;
engine_changed= 1;
return eng == 0;
......@@ -116,6 +126,7 @@ class Item_singlerow_subselect :public Item_subselect
Item_singlerow_subselect(st_select_lex *select_lex);
Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
void cleanup();
subs_type substype() { return SINGLEROW_SUBS; }
void reset();
......@@ -200,13 +211,6 @@ class Item_in_subselect :public Item_exists_subselect
{}
void cleanup()
{
Item_exists_subselect::cleanup();
abort_on_null= 0;
transformed= 0;
upper_not= 0;
}
subs_type substype() { return IN_SUBS; }
void reset()
{
......@@ -269,7 +273,7 @@ class subselect_engine: public Sql_alloc
maybe_null= 0;
}
virtual ~subselect_engine() {}; // to satisfy compiler
virtual void cleanup() {}
virtual void cleanup()= 0;
// set_thd should be called before prepare()
void set_thd(THD *thd_arg) { thd= thd_arg; }
......@@ -318,6 +322,7 @@ class subselect_union_engine: public subselect_engine
subselect_union_engine(st_select_lex_unit *u,
select_subselect *result,
Item_subselect *item);
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec();
......@@ -345,6 +350,7 @@ class subselect_uniquesubquery_engine: public subselect_engine
set_thd(thd_arg);
}
~subselect_uniquesubquery_engine();
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec();
......
......@@ -1084,6 +1084,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
void Item_sum_count_distinct::cleanup()
{
DBUG_ENTER("Item_sum_count_distinct::cleanup");
Item_sum_int::cleanup();
/*
Free table and tree if they belong to this item (if item have not pointer
......@@ -1099,6 +1100,7 @@ void Item_sum_count_distinct::cleanup()
table= 0;
use_tree= 0;
}
DBUG_VOID_RETURN;
}
bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
......@@ -1666,6 +1668,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
void Item_func_group_concat::cleanup()
{
DBUG_ENTER("Item_func_group_concat::cleanup");
/*
Free table and tree if they belong to this item (if item have not pointer
to original item from which was made copy => it own its objects )
......@@ -1679,6 +1682,7 @@ void Item_func_group_concat::cleanup()
if (tree_mode)
delete_tree(tree);
}
DBUG_VOID_RETURN;
}
Item_func_group_concat::~Item_func_group_concat()
......
......@@ -60,8 +60,10 @@ class Item_sum :public Item_result_field
Item_sum(THD *thd, Item_sum *item);
void cleanup()
{
DBUG_ENTER("Item_sum::cleanup");
Item_result_field::cleanup();
result_field=0;
DBUG_VOID_RETURN;
}
enum Type type() const { return SUM_FUNC_ITEM; }
......
......@@ -83,7 +83,7 @@ extern "C" void free_user_var(user_var_entry *entry)
** Thread specific functions
****************************************************************************/
THD::THD():user_time(0), is_fatal_error(0),
THD::THD():user_time(0), current_statement(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)
......@@ -1232,6 +1232,21 @@ void Statement::set_statement(Statement *stmt)
mem_root= stmt->mem_root;
}
void Statement::set_n_backup_item_arena(Statement *set, Statement *backup)
{
backup->mem_root= mem_root;
backup->free_list= free_list;
set_item_arena(set);
}
void Statement::set_item_arena(Statement *set)
{
mem_root= set->mem_root;
free_list= set->free_list;
}
Statement::~Statement()
{
......
......@@ -427,7 +427,7 @@ class Statement
public:
/* FIXME: must be private */
LEX main_lex;
public:
/*
Uniquely identifies each statement object in thread scope; change during
statement lifetime. FIXME: must be const
......@@ -503,6 +503,15 @@ class Statement
void set_statement(Statement *stmt);
/* return class type */
virtual Type type() const;
void set_n_backup_item_arena(Statement *set, Statement *backup);
inline void restore_backup_item_arena(Statement *backup)
{
set_item_arena(backup);
// reset backup mem_root to avoid its freeing
init_alloc_root(&backup->mem_root, 0, 0);
}
void set_item_arena(Statement *set);
};
......@@ -688,6 +697,10 @@ class THD :public ilink,
#ifdef SIGNAL_WITH_VIO_CLOSE
Vio* active_vio;
#endif
/*
Current prepared Statement if there one, or 0
*/
Statement *current_statement;
/*
next_insert_id is set on SET INSERT_ID= #. This is used as the next
generated auto_increment value in handler.cc
......
......@@ -1561,7 +1561,11 @@ void st_select_lex::print_limit(THD *thd, String *str)
/*
There are st_select_lex::add_table_to_list &
st_select_lex::set_lock_for_tables in sql_parse.cc
st_select_lex::set_lock_for_tables are in sql_parse.cc
st_select_lex::print is in sql_select.h
st_select_lex_unit::prepare, st_select_lex_unit::exec,
st_select_lex_unit::cleanup, st_select_lex_unit::reinit_exec_mechanism
are in sql_union.cc
*/
......@@ -354,6 +354,7 @@ class st_select_lex_unit: public st_select_lex_node {
int prepare(THD *thd, select_result *result, ulong additional_options);
int exec();
int cleanup();
void reinit_exec_mechanism();
void print(String *str);
......
......@@ -753,14 +753,21 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
DBUG_RETURN(1);
}
JOIN *join= new JOIN(thd, fields, select_options, result);
thd->used_tables= 0; // Updated by setup_fields
if (join->prepare(&select_lex->ref_pointer_array,
(TABLE_LIST*)select_lex->get_table_list(),
wild_num, conds, og_num, order, group, having, proc,
select_lex, unit))
Statement backup;
/*
we do not want to have in statement memory all that junk,
which will be created by preparation => substitute memory
from original thread pool
*/
thd->set_n_backup_item_arena(&thd->stmt_backup, &backup);
if ((unit->prepare(thd, result, 0)))
{
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(1);
}
thd->restore_backup_item_arena(&backup);
if (send_prep_stmt(stmt, fields.elements) ||
thd->protocol_simple.send_fields(&fields, 0)
#ifndef EMBEDDED_LIBRARY
......@@ -768,7 +775,7 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
#endif
)
DBUG_RETURN(1);
join->cleanup();
unit->cleanup();
}
DBUG_RETURN(0);
}
......@@ -899,6 +906,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt);
thd->current_statement= stmt;
if (alloc_query(thd, packet, packet_length))
goto alloc_query_err;
......@@ -929,6 +937,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
cleanup_items(thd->free_list);
stmt->set_statement(thd);
thd->set_statement(&thd->stmt_backup);
thd->current_statement= 0;
if (init_param_items(stmt))
goto init_param_err;
......@@ -947,6 +956,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
thd->stmt_map.erase(stmt);
DBUG_RETURN(1);
insert_stmt_err:
thd->current_statement= 0;
delete stmt;
DBUG_RETURN(1);
}
......@@ -980,6 +990,7 @@ void mysql_stmt_execute(THD *thd, char *packet)
stmt->query_id= thd->query_id;
thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt);
thd->current_statement= stmt;
thd->free_list= 0;
/*
......@@ -1009,17 +1020,21 @@ void mysql_stmt_execute(THD *thd, char *packet)
order->item= (Item **)(order+1);
for (order=(ORDER *)sl->order_list.first ; order ; order=order->next)
order->item= (Item **)(order+1);
}
/*
TODO: When the new table structure is ready, then have a status bit
to indicate the table is altered, and re-do the setup_*
and open the tables back.
*/
for (TABLE_LIST *tables= (TABLE_LIST*) stmt->lex->select_lex.table_list.first;
for (TABLE_LIST *tables= (TABLE_LIST*) sl->table_list.first;
tables;
tables= tables->next)
{
tables->table= 0; // safety - nasty init
tables->table_list= 0;
}
}
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count && setup_params_data(stmt))
......@@ -1049,6 +1064,7 @@ void mysql_stmt_execute(THD *thd, char *packet)
cleanup_items(stmt->free_list);
free_root(&thd->mem_root, MYF(0));
thd->set_statement(&thd->stmt_backup);
thd->current_statement= 0;
DBUG_VOID_RETURN;
}
......
......@@ -330,8 +330,7 @@ JOIN::prepare(Item ***rref_pointer_array,
// Is it subselect
{
Item_subselect *subselect;
if ((subselect= select_lex->master_unit()->item) &&
select_lex->linkage != GLOBAL_OPTIONS_TYPE)
if ((subselect= select_lex->master_unit()->item))
{
Item_subselect::trans_res res;
if ((res= subselect->select_transformer(this)) !=
......
......@@ -468,3 +468,9 @@ int st_select_lex_unit::cleanup()
}
DBUG_RETURN(error);
}
void st_select_lex_unit::reinit_exec_mechanism()
{
prepared= optimized= executed= 0;
}
......@@ -8095,6 +8095,53 @@ static void test_bug1946()
rc= mysql_query(mysql,"DROP TABLE prepare_command");
}
static void test_subqueries()
{
MYSQL_STMT *stmt;
int rc, i;
const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s, (a-1,b-1) in (select a,b from t2) as in_row_s FROM t1";
myheader("test_subquery");
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2");
myquery(rc);
rc= mysql_query(mysql,"CREATE TABLE t1 (a int , b int);");
myquery(rc);
rc= mysql_query(mysql,
"insert into t1 values (1,1), (2, 2), (3,3), (4,4), (5,5);");
myquery(rc);
rc= mysql_query(mysql,"create table t2 select * from t1;");
myquery(rc);
stmt= mysql_prepare(mysql, query, strlen(query));
for (i= 0; i < 3; i++)
{
rc= mysql_execute(stmt);
mystmt(stmt, rc);
assert(5 == my_process_stmt_result(stmt));
}
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE t1,t2");
myquery(rc);
}
static void test_bad_union()
{
MYSQL_STMT *stmt;
const char *query= "SELECT 1, 2 union SELECT 1";
myheader("test_bad_union");
stmt= mysql_prepare(mysql, query, strlen(query));
assert(stmt == 0);
myerror(NULL);
}
/*
Read and parse arguments and MySQL options from my.cnf
......@@ -8234,6 +8281,7 @@ int main(int argc, char **argv)
test_count= 1;
start_time= time((time_t *)0);
client_query(); /* simple client query test */
#if NOT_YET_WORKING
/* Used for internal new development debugging */
......@@ -8340,6 +8388,9 @@ int main(int argc, char **argv)
test_bug1644(); /* BUG#1644 */
test_bug1946(); /* test that placeholders are allowed only in
prepared queries */
test_subqueries(); /* repeatable subqueries */
test_bad_union(); /* correct setup of UNION */
end_time= time((time_t *)0);
total_time+= difftime(end_time, start_time);
......
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