mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-4.1
into sanja.is.com.ua:/home/bell/mysql/bk/work-prepared-4.1
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
12
sql/item.h
12
sql/item.h
@ -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);
|
||||
@ -996,8 +1002,10 @@ public:
|
||||
void bring_value();
|
||||
void cleanup()
|
||||
{
|
||||
DBUG_ENTER("Item_cache_row::cleanup");
|
||||
Item_cache::cleanup();
|
||||
values= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1023,8 +1031,10 @@ public:
|
||||
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 @@ 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; }
|
||||
};
|
||||
@ -207,9 +208,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;
|
||||
}
|
||||
};
|
||||
|
||||
@ -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; }
|
||||
|
@ -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(&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");
|
||||
|
||||
SELECT_LEX *select_lex= join->select_lex;
|
||||
if (changed)
|
||||
{
|
||||
DBUG_RETURN(RES_OK);
|
||||
}
|
||||
|
||||
THD *thd_tmp= join->thd;
|
||||
thd_tmp->where= "scalar IN/ALL/ANY subquery";
|
||||
SELECT_LEX *select_lex= join->select_lex;
|
||||
Statement backup;
|
||||
|
||||
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->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,62 +837,68 @@ 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;
|
||||
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(&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 @@ 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; }
|
||||
|
@ -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)
|
||||
@ -1244,6 +1244,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
|
||||
@ -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,15 @@ public:
|
||||
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 @@ 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
|
||||
|
@ -1624,7 +1624,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,7 @@ public:
|
||||
int prepare(THD *thd, select_result *result, ulong additional_options);
|
||||
int exec();
|
||||
int cleanup();
|
||||
void reinit_exec_mechanism();
|
||||
|
||||
bool check_updateable(char *db, char *table);
|
||||
void print(String *str);
|
||||
|
@ -752,14 +752,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
|
||||
@ -767,7 +774,7 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
|
||||
#endif
|
||||
)
|
||||
DBUG_RETURN(1);
|
||||
join->cleanup();
|
||||
unit->cleanup();
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@ -898,6 +905,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;
|
||||
@ -928,6 +936,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;
|
||||
@ -946,6 +955,7 @@ alloc_query_err:
|
||||
thd->stmt_map.erase(stmt);
|
||||
DBUG_RETURN(1);
|
||||
insert_stmt_err:
|
||||
thd->current_statement= 0;
|
||||
delete stmt;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
@ -979,6 +989,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;
|
||||
|
||||
/*
|
||||
@ -1010,17 +1021,21 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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))
|
||||
@ -1050,6 +1065,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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -474,3 +474,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,85 @@ 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));
|
||||
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 count(distinct b), group_concat(a) FROM t1";
|
||||
|
||||
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);");
|
||||
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(1 == my_process_stmt_result(stmt));
|
||||
mysql_stmt_close(stmt);
|
||||
}
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE t1");
|
||||
myquery(rc);
|
||||
}
|
||||
|
||||
/*
|
||||
Read and parse arguments and MySQL options from my.cnf
|
||||
@ -8234,6 +8313,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 +8420,10 @@ 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 */
|
||||
test_distinct(); /* distinct aggregate functions */
|
||||
|
||||
|
||||
end_time= time((time_t *)0);
|
||||
total_time+= difftime(end_time, start_time);
|
||||
|
Reference in New Issue
Block a user