mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
merge
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
25
sql/item.h
25
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);
|
||||
@ -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");
|
||||
|
||||
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->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);
|
||||
|
Reference in New Issue
Block a user