Commit 952f99d4 authored by unknown's avatar unknown

merge


mysql-test/r/derived.result:
  Auto merged
mysql-test/t/derived.test:
  Auto merged
sql/item.cc:
  Auto merged
sql/item_cmpfunc.cc:
  Auto merged
sql/item_cmpfunc.h:
  Auto merged
sql/item_sum.h:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/sql_acl.cc:
  Auto merged
sql/sql_base.cc:
  Auto merged
sql/sql_class.cc:
  Auto merged
sql/sql_class.h:
  Auto merged
sql/sql_lex.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_union.cc:
  Auto merged
sql/sql_update.cc:
  Auto merged
parents 62cc89aa 6826a55b
......@@ -969,8 +969,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,
......@@ -1613,9 +1615,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 @@ public:
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);
......@@ -413,6 +419,7 @@ public:
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_int(name,value,max_length); }
void cleanup() { fixed= 1; } // to privent drop fixed flag
void print(String *str);
};
......@@ -900,6 +907,8 @@ public:
enum Type type() const { return CACHE_ITEM; }
static Item_cache* get_cache(Item_result type);
table_map used_tables() const { return used_table_map; }
virtual void keep_array() {}
void cleanup() { fixed= 1; } // to privent drop fixed flag
void print(String *str);
};
......@@ -952,8 +961,10 @@ class Item_cache_row: public Item_cache
{
Item_cache **values;
uint item_count;
bool save_array;
public:
Item_cache_row(): Item_cache(), values(0), item_count(2) {}
Item_cache_row()
:Item_cache(), values(0), item_count(2), save_array(0) {}
/*
'allocate' used only in row transformer, to preallocate space for row
......@@ -994,10 +1005,16 @@ public:
bool check_cols(uint c);
bool null_inside();
void bring_value();
void keep_array() { save_array= 1; }
void cleanup()
{
DBUG_ENTER("Item_cache_row::cleanup");
Item_cache::cleanup();
values= 0;
if (save_array)
bzero(values, item_count*sizeof(Item**));
else
values= 0;
DBUG_VOID_RETURN;
}
};
......@@ -1023,8 +1040,10 @@ public:
Field *example() { return field_example; }
void cleanup()
{
DBUG_ENTER("Item_type_holder::cleanup");
Item::cleanup();
item_type= orig_type;
DBUG_VOID_RETURN;
}
};
......
......@@ -500,7 +500,6 @@ bool Item_in_optimizer::fix_left(THD *thd,
}
bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref)
{
......@@ -526,6 +525,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
return 0;
}
longlong Item_in_optimizer::val_int()
{
cache->store(args[0]);
......@@ -539,18 +539,38 @@ longlong Item_in_optimizer::val_int()
return tmp;
}
void Item_in_optimizer::keep_top_level_cache()
{
cache->keep_array();
save_cache= 1;
}
void Item_in_optimizer::cleanup()
{
DBUG_ENTER("Item_in_optimizer::cleanup");
Item_bool_func::cleanup();
if (!save_cache)
cache= 0;
DBUG_VOID_RETURN;
}
bool Item_in_optimizer::is_null()
{
cache->store(args[0]);
return (null_value= (cache->null_value || args[1]->is_null()));
}
longlong Item_func_eq::val_int()
{
int value= cmp.compare();
return value == 0 ? 1 : 0;
}
/* Same as Item_func_eq, but NULL = NULL */
void Item_func_equal::fix_length_and_dec()
......
......@@ -93,9 +93,10 @@ class Item_in_optimizer: public Item_bool_func
{
protected:
Item_cache *cache;
bool save_cache;
public:
Item_in_optimizer(Item *a, Item_in_subselect *b):
Item_bool_func(a, (Item *)b), cache(0) {}
Item_bool_func(a, (Item *)b), cache(0), save_cache(0) {}
bool fix_fields(THD *, struct st_table_list *, Item **);
bool fix_left(THD *thd, struct st_table_list *tables, Item **ref);
bool is_null();
......@@ -107,8 +108,10 @@ public:
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; }
void keep_top_level_cache();
};
class Comp_creator
......@@ -209,9 +212,11 @@ public:
}
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;
}
};
......@@ -720,10 +725,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; }
......
......@@ -999,6 +999,7 @@ public:
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);
......@@ -1009,6 +1010,7 @@ public:
}
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();
engine->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,8 +268,12 @@ 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 &&
select_lex->item_list.elements == 1 &&
......@@ -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(stmt, &backup);
return RES_REDUCE;
}
return RES_OK;
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &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);
join->having= (join->having ?
new Item_cond_and(having, join->having) :
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,
new Item_null_helper(this, item,
(char *)"<no matter>",
(char *)"<result>"));
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->restore_backup_item_arena(stmt, &backup);
DBUG_RETURN(RES_REDUCE);
}
}
}
ok:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &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,62 +837,72 @@ 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;
// we will refer to apper level cache array => we have to save it in PS
optimizer->keep_top_level_cache();
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;
List_iterator_fast<Item> li(select_lex->item_list);
for (uint i= 0; i < n; i++)
{
Item *func= new Item_ref_null_helper(this,
select_lex->ref_pointer_array+i,
(char *) "<no matter>",
(char *) "<list ref>");
func=
eq_creator.create(new Item_ref((*optimizer->get_cache())->
addr(i),
NULL,
(char *)"<no matter>",
uint n= left_expr->cols();
List_iterator_fast<Item> li(select_lex->item_list);
for (uint i= 0; i < n; i++)
{
Item *func= new Item_ref_null_helper(this,
select_lex->ref_pointer_array+i,
(char *) "<no matter>",
(char *) "<list ref>");
func=
eq_creator.create(new Item_ref((*optimizer->get_cache())->
addr(i),
NULL,
(char *)"<no matter>",
(char *)in_left_expr_name),
func);
item= and_items(item, func);
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(stmt, &backup);
DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
DBUG_RETURN(RES_ERROR);
}
......@@ -894,13 +974,31 @@ 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;
join= 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 @@ public:
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 @@ public:
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 @@ public:
{}
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 @@ public:
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 @@ public:
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 @@ public:
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
......@@ -1104,6 +1105,7 @@ void Item_sum_count_distinct::cleanup()
use_tree= 0;
}
}
DBUG_VOID_RETURN;
}
......@@ -1672,6 +1674,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 )
......@@ -1692,6 +1695,7 @@ void Item_func_group_concat::cleanup()
delete_tree(tree);
}
}
DBUG_VOID_RETURN;
}
......
......@@ -60,8 +60,10 @@ public:
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; }
......
......@@ -350,6 +350,11 @@ inline THD *_current_thd(void)
#include "sql_udf.h"
#include "item.h"
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
/* sql_parse.cc */
void free_items(Item *item);
void cleanup_items(Item *item);
class THD;
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
#include "sql_class.h"
#include "opt_range.h"
......@@ -411,7 +416,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_change_db(THD *thd,const char *name);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
void free_items(Item *item);
bool alloc_query(THD *thd, char *packet, ulong packet_length);
void mysql_init_select(LEX *lex);
void mysql_init_query(THD *thd);
......@@ -688,7 +692,6 @@ bool rm_temporary_table(enum db_type base, char *path);
void free_io_cache(TABLE *entry);
void intern_close_table(TABLE *entry);
bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
void close_temporary_tables(THD *thd);
TABLE_LIST * find_table_in_list(TABLE_LIST *table,
const char *db_name, const char *table_name);
......@@ -766,9 +769,6 @@ uint check_word(TYPELIB *lib, const char *val, const char *end,
bool is_keyword(const char *name, uint len);
/* sql_parse.cc */
void free_items(Item *item);
void cleanup_items(Item *item);
#define MY_DB_OPT_FILE "db.opt"
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
......
......@@ -1631,6 +1631,14 @@ int open_and_lock_tables(THD *thd, TABLE_LIST *tables)
if (open_tables(thd, tables, &counter) || lock_tables(thd, tables, counter))
DBUG_RETURN(-1); /* purecov: inspected */
fix_tables_pointers(thd->lex->all_selects_list);
/*
open temporary memory pool, which will be closed in
mysql_test_select_fields, mysql_test_upd_fields or
mysql_test_insert_fields
*/
if (thd->current_statement)
thd->ps_setup_prepare_memory();
DBUG_RETURN(mysql_handle_derived(thd->lex));
}
......@@ -2080,6 +2088,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
{
if (!wild_num)
return 0;
Statement *stmt= thd->current_statement, backup;
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
reg2 Item *item;
List_iterator<Item> it(fields);
while ( wild_num && (item= it++))
......@@ -2091,7 +2102,11 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
uint elem= fields.elements;
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);
return (-1);
}
if (sum_func_list)
{
/*
......@@ -2104,6 +2119,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
wild_num--;
}
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
return 0;
}
......
......@@ -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)
......@@ -1247,6 +1247,27 @@ void Statement::set_statement(Statement *stmt)
}
void Statement::set_n_backup_item_arena(Statement *set, Statement *backup)
{
backup->set_item_arena(this);
set_item_arena(set);
}
void Statement::restore_backup_item_arena(Statement *set, Statement *backup)
{
set->set_item_arena(this);
set_item_arena(backup);
// reset backup mem_root to avoid its freeing
init_alloc_root(&backup->mem_root, 0, 0);
}
void Statement::set_item_arena(Statement *set)
{
mem_root= set->mem_root;
free_list= set->free_list;
}
Statement::~Statement()
{
free_root(&mem_root, MYF(0));
......
......@@ -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
......@@ -476,7 +476,7 @@ public:
char *query;
uint32 query_length; // current query length
/*
List of items created in the parser for this query. Every item puts
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;
......@@ -503,6 +503,32 @@ public:
void set_statement(Statement *stmt);
/* 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 Statement::set_item_arena(Statement *set);
};
......@@ -689,6 +715,10 @@ public:
#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
......@@ -850,34 +880,14 @@ public:
return 0;
#endif
}
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;
}
bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
const char *from, uint from_length,
CHARSET_INFO *from_cs);
inline gptr trans_alloc(unsigned int size)
{
return alloc_root(&transaction.mem_root,size);
}
bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
const char *from, uint from_length,
CHARSET_INFO *from_cs);
void add_changed_table(TABLE *table);
void add_changed_table(const char *key, long key_length);
CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
......@@ -900,6 +910,33 @@ public:
}
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
inline void ps_setup_prepare_memory()
{
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 ps_setup_free_memory()
{
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 */
......
......@@ -1500,11 +1500,17 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
{
if (ref_pointer_array)
return 0;
/*
We have to create array in prepared statement memory if it is
prepared statement
*/
Statement *stmt= thd->current_statement ? thd->current_statement : thd;
return (ref_pointer_array=
(Item **)thd->alloc(sizeof(Item*) *
(item_list.elements +
select_n_having_items +
order_group_num)* 5)) == 0;
(Item **)stmt->alloc(sizeof(Item*) *
(item_list.elements +
select_n_having_items +
order_group_num)* 5)) == 0;
}
......@@ -1629,7 +1635,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
*/
......@@ -355,6 +355,8 @@ public:
int prepare(THD *thd, select_result *result, ulong additional_options);
int exec();
int cleanup();
inline void unclean() { cleaned= 0; }
void reinit_exec_mechanism();
bool check_updateable(char *db, char *table);
void print(String *str);
......
......@@ -622,7 +622,12 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
DBUG_RETURN(1);
#endif
if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(1);
{
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
DBUG_RETURN(1);
}
table= table_list->table;
if ((values= its++))
......@@ -631,7 +636,12 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
ulong counter= 0;
if (check_insert_fields(thd,table,fields,*values,1))
{
thd->ps_setup_free_memory();
DBUG_RETURN(1);
}
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
value_count= values->elements;
its.rewind();
......@@ -648,6 +658,11 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt,
}
}
}
else
{
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
}
if (send_prep_stmt(stmt, 0))
DBUG_RETURN(1);
DBUG_RETURN(0);
......@@ -678,11 +693,20 @@ static bool mysql_test_upd_fields(Prepared_statement *stmt,
DBUG_RETURN(1);
#endif
if (open_and_lock_tables(thd, table_list))
{
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
DBUG_RETURN(1);
if (setup_tables(table_list) ||
setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
setup_conds(thd, table_list, &conds) || thd->net.report_error)
setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
setup_conds(thd, table_list, &conds) || thd->net.report_error)
{
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
DBUG_RETURN(1);
}
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
/*
Currently return only column list info only, and we are not
......@@ -737,39 +761,50 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
DBUG_RETURN(1);
if (open_and_lock_tables(thd, tables))
{
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
DBUG_RETURN(1);
}
if (lex->describe)
{
if (send_prep_stmt(stmt, 0))
DBUG_RETURN(1);
goto err;
}
else
{
if (!result && !(result= new select_send()))
{
send_error(thd, ER_OUT_OF_RESOURCES);
DBUG_RETURN(1);
goto err;
}
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))
DBUG_RETURN(1);
if (unit->prepare(thd, result, 0))
goto err_prep;
if (send_prep_stmt(stmt, fields.elements) ||
thd->protocol_simple.send_fields(&fields, 0)
#ifndef EMBEDDED_LIBRARY
|| net_flush(&thd->net)
|| net_flush(&thd->net)
#endif
)
DBUG_RETURN(1);
join->cleanup();
)
goto err_prep;
unit->cleanup();
}
DBUG_RETURN(0);
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
DBUG_RETURN(0);
err_prep:
unit->cleanup();
err:
// this memory pool was opened in open_and_lock_tables
thd->ps_setup_free_memory();
DBUG_RETURN(1);
}
......@@ -898,6 +933,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;
......@@ -925,9 +961,9 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
sl->prep_where= sl->where;
}
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;
......@@ -944,8 +980,10 @@ init_param_err:
alloc_query_err:
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
thd->current_statement= 0;
DBUG_RETURN(1);
insert_stmt_err:
thd->current_statement= 0;
delete stmt;
DBUG_RETURN(1);
}
......@@ -1010,24 +1048,36 @@ void mysql_stmt_execute(THD *thd, char *packet)
/* Fix ORDER list */
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*) sl->table_list.first;
tables;
tables= tables->next)
{
tables->table= 0; // safety - nasty init
tables->table_list= 0;
}
{
SELECT_LEX_UNIT *unit= sl->master_unit();
unit->unclean();
unit->types.empty();
// for derived tables & PS (which can't be reset bu Item_subquery)
unit->reinit_exec_mechanism();
}
}
/*
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;
tables;
tables= tables->next)
tables->table= 0; // safety - nasty init
#ifndef EMBEDDED_LIBRARY
if (stmt->param_count && setup_params_data(stmt))
DBUG_VOID_RETURN;
goto end;
#else
if (stmt->param_count && (*stmt->setup_params_data)(stmt))
DBUG_VOID_RETURN;
goto end;
#endif
if (!(specialflag & SPECIAL_NO_PRIOR))
......@@ -1048,8 +1098,10 @@ void mysql_stmt_execute(THD *thd, char *packet)
free_items(thd->free_list);
cleanup_items(stmt->free_list);
close_thread_tables(thd); // to close derived tables
free_root(&thd->mem_root, MYF(0));
thd->set_statement(&thd->stmt_backup);
end:
DBUG_VOID_RETURN;
}
......
......@@ -327,8 +327,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)) !=
......@@ -1519,10 +1518,10 @@ JOIN::cleanup()
lock=0; // It's faster to unlock later
join_free(1);
if (exec_tmp_table1)
free_tmp_table(thd, exec_tmp_table1);
if (exec_tmp_table2)
free_tmp_table(thd, exec_tmp_table2);
if (exec_tmp_table1)
free_tmp_table(thd, exec_tmp_table1);
if (exec_tmp_table2)
free_tmp_table(thd, exec_tmp_table2);
delete select;
delete_dynamic(&keyuse);
delete procedure;
......
......@@ -453,3 +453,9 @@ int st_select_lex_unit::cleanup()
}
DBUG_RETURN(error);
}
void st_select_lex_unit::reinit_exec_mechanism()
{
prepared= optimized= executed= 0;
}
......@@ -8189,6 +8189,90 @@ static void test_bug2247()
fprintf(stdout, "OK");
}
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, (select a x, b y from t2) tt WHERE x=a";
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));
mystmt_init(stmt);
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);
}
static void test_distinct()
{
MYSQL_STMT *stmt;
int rc, i;
const char *query=
"SELECT 2+count(distinct b), group_concat(a) FROM t1 group by a";
myheader("test_subquery");
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1");
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),\
(1,10), (2, 20), (3,30), (4,40), (5,50)\;");
myquery(rc);
for (i= 0; i < 3; i++)
{
stmt= mysql_prepare(mysql, query, strlen(query));
mystmt_init(stmt);
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");
myquery(rc);
}
/*
Test for bug#2248 "mysql_fetch without prior mysql_execute hangs"
*/
......@@ -8385,6 +8469,9 @@ int main(int argc, char **argv)
test_count= 1;
start_time= time((time_t *)0);
test_subqueries();
client_query(); /* simple client query test */
#if NOT_YET_WORKING
/* Used for internal new development debugging */
......@@ -8437,7 +8524,8 @@ int main(int argc, char **argv)
client_use_result(); /* usage of mysql_use_result() */
test_tran_bdb(); /* transaction test on BDB table type */
test_tran_innodb(); /* transaction test on InnoDB table type */
test_prepare_ext(); /* test prepare with all types conversion -- TODO */
test_prepare_ext(); /* test prepare with all types
conversion -- TODO */
test_prepare_syntax(); /* syntax check for prepares */
test_field_names(); /* test for field names */
test_field_flags(); /* test to help .NET provider team */
......@@ -8450,7 +8538,7 @@ int main(int argc, char **argv)
test_stmt_close(); /* mysql_stmt_close() test -- hangs */
test_prepare_field_result(); /* prepare meta info */
test_multi_stmt(); /* multi stmt test */
test_multi_statements(); /* test multi statement execution */
/* test_multi_statements(); *//* test multi statement execution */
test_store_result(); /* test the store_result */
test_store_result1(); /* test store result without buffers */
test_store_result2(); /* test store result for misc case */
......@@ -8497,6 +8585,10 @@ int main(int argc, char **argv)
test_bug2247(); /* test that mysql_stmt_affected_rows() returns
number of rows affected by last prepared
statement execution */
test_subqueries(); /* repeatable subqueries */
test_bad_union(); /* correct setup of UNION */
test_distinct(); /* distinct aggregate functions */
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