Fixed bug mdev-5105.
The bug caused a memory overwrite in the function update_ref_and_keys() It happened due to a wrong value of SELECT_LEX::cond_count. This value historically was calculated by the fix_fields method. Now the logic of calling this method became too complicated and, as a result, this value is calculated not always correctly. The patch changes the way how and when the values of SELECT_LEX::cond_count and of SELECT_LEX::between_count are calculated. The new code does it just at the beginning of update_ref_and_keys().
This commit is contained in:
parent
ec226e553a
commit
7c87385e30
@ -2223,6 +2223,17 @@ a (SELECT SUM(a + c) FROM (SELECT b as c FROM t2) AS v1)
|
||||
DROP VIEW v;
|
||||
DROP TABLE t1,t2;
|
||||
#
|
||||
# mdev-5105: memory overwrite in multi-table update
|
||||
# using natuaral join with a view
|
||||
#
|
||||
create table t1(a int,b tinyint,c tinyint)engine=myisam;
|
||||
create table t2(a tinyint,b float,c int, d int, e int, f int, key (b), key(c), key(d), key(e), key(f))engine=myisam;
|
||||
create table t3(a int,b int,c int, d int, e int, f int, key(a), key(b), key(c), key(d), key(e), key(f))engine=myisam;
|
||||
create view v1 as select t2.b a, t1.b b, t2.c c, t2.d d, t2.e e, t2.f f from t1,t2 where t1.a=t2.a;
|
||||
update t3 natural join v1 set a:=1;
|
||||
drop view v1;
|
||||
drop table t1,t2,t3;
|
||||
#
|
||||
# end of 5.3 tests
|
||||
#
|
||||
set optimizer_switch=@exit_optimizer_switch;
|
||||
|
@ -1564,6 +1564,20 @@ SELECT a, (SELECT SUM(a + c) FROM (SELECT b as c FROM t2) AS v1) FROM t1;
|
||||
DROP VIEW v;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
--echo #
|
||||
--echo # mdev-5105: memory overwrite in multi-table update
|
||||
--echo # using natuaral join with a view
|
||||
--echo #
|
||||
|
||||
create table t1(a int,b tinyint,c tinyint)engine=myisam;
|
||||
create table t2(a tinyint,b float,c int, d int, e int, f int, key (b), key(c), key(d), key(e), key(f))engine=myisam;
|
||||
create table t3(a int,b int,c int, d int, e int, f int, key(a), key(b), key(c), key(d), key(e), key(f))engine=myisam;
|
||||
create view v1 as select t2.b a, t1.b b, t2.c c, t2.d d, t2.e e, t2.f f from t1,t2 where t1.a=t2.a;
|
||||
|
||||
update t3 natural join v1 set a:=1;
|
||||
drop view v1;
|
||||
drop table t1,t2,t3;
|
||||
|
||||
--echo #
|
||||
--echo # end of 5.3 tests
|
||||
--echo #
|
||||
|
@ -1054,6 +1054,7 @@ public:
|
||||
virtual bool view_used_tables_processor(uchar *arg) { return 0; }
|
||||
virtual bool eval_not_null_tables(uchar *opt_arg) { return 0; }
|
||||
virtual bool is_subquery_processor (uchar *opt_arg) { return 0; }
|
||||
virtual bool count_sargable_conds(uchar *arg) { return 0; }
|
||||
virtual bool limit_index_condition_pushdown_processor(uchar *opt_arg)
|
||||
{
|
||||
return FALSE;
|
||||
|
@ -539,6 +539,8 @@ void Item_bool_func2::fix_length_and_dec()
|
||||
to the collation of A.
|
||||
*/
|
||||
|
||||
sargable= true;
|
||||
|
||||
DTCollation coll;
|
||||
if (args[0]->result_type() == STRING_RESULT &&
|
||||
args[1]->result_type() == STRING_RESULT &&
|
||||
@ -1433,6 +1435,7 @@ bool Item_in_optimizer::eval_not_null_tables(uchar *opt_arg)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
|
||||
{
|
||||
if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) ||
|
||||
@ -2160,6 +2163,15 @@ bool Item_func_between::eval_not_null_tables(uchar *opt_arg)
|
||||
}
|
||||
|
||||
|
||||
bool Item_func_between::count_sargable_conds(uchar *arg)
|
||||
{
|
||||
SELECT_LEX *sel= (SELECT_LEX *) arg;
|
||||
sel->cond_count++;
|
||||
sel->between_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Item_func_between::fix_after_pullout(st_select_lex *new_parent, Item **ref)
|
||||
{
|
||||
/* This will re-calculate attributes of the arguments */
|
||||
@ -2173,6 +2185,7 @@ void Item_func_between::fix_length_and_dec()
|
||||
THD *thd= current_thd;
|
||||
max_length= 1;
|
||||
compare_as_dates= 0;
|
||||
sargable= true;
|
||||
|
||||
/*
|
||||
As some compare functions are generated after sql_yacc,
|
||||
@ -3852,6 +3865,7 @@ void Item_func_in::fix_length_and_dec()
|
||||
uint found_types= 0;
|
||||
uint type_cnt= 0, i;
|
||||
Item_result cmp_type= STRING_RESULT;
|
||||
sargable= true;
|
||||
left_result_type= args[0]->cmp_type();
|
||||
if (!(found_types= collect_cmp_types(args, arg_count, true)))
|
||||
return;
|
||||
@ -4638,6 +4652,7 @@ longlong Item_func_isnull::val_int()
|
||||
return args[0]->is_null() ? 1: 0;
|
||||
}
|
||||
|
||||
|
||||
longlong Item_is_not_null_test::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
@ -4841,6 +4856,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
void Item_func_like::cleanup()
|
||||
{
|
||||
canDoTurboBM= FALSE;
|
||||
@ -5868,6 +5884,14 @@ void Item_equal::update_used_tables()
|
||||
}
|
||||
|
||||
|
||||
bool Item_equal::count_sargable_conds(uchar *arg)
|
||||
{
|
||||
SELECT_LEX *sel= (SELECT_LEX *) arg;
|
||||
uint m= equal_items.elements;
|
||||
sel->cond_count+= m*(m-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief
|
||||
@ -5920,6 +5944,7 @@ void Item_equal::fix_length_and_dec()
|
||||
Item *item= get_first(NO_PARTICULAR_TAB, NULL);
|
||||
eval_item= cmp_item::get_comparator(item->cmp_type(), item,
|
||||
item->collation.collation);
|
||||
sargable= true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -118,7 +118,7 @@ public:
|
||||
Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
|
||||
bool is_bool_func() { return 1; }
|
||||
void fix_length_and_dec() { decimals=0; max_length=1; }
|
||||
void fix_length_and_dec() { decimals=0; max_length=1; sargable= true;}
|
||||
uint decimal_precision() const { return 1; }
|
||||
};
|
||||
|
||||
@ -681,6 +681,7 @@ public:
|
||||
uint decimal_precision() const { return 1; }
|
||||
bool eval_not_null_tables(uchar *opt_arg);
|
||||
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
|
||||
bool count_sargable_conds(uchar *arg);
|
||||
};
|
||||
|
||||
|
||||
@ -1747,6 +1748,7 @@ public:
|
||||
CHARSET_INFO *compare_collation();
|
||||
|
||||
void set_context_field(Item_field *ctx_field) { context_field= ctx_field; }
|
||||
bool count_sargable_conds(uchar *arg);
|
||||
friend class Item_equal_iterator<List_iterator_fast,Item>;
|
||||
friend class Item_equal_iterator<List_iterator,Item>;
|
||||
friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
|
||||
|
@ -733,6 +733,16 @@ double Item_int_func::val_real()
|
||||
return unsigned_flag ? (double) ((ulonglong) val_int()) : (double) val_int();
|
||||
}
|
||||
|
||||
bool Item_int_func::count_sargable_conds(uchar *arg)
|
||||
{
|
||||
if (sargable)
|
||||
{
|
||||
SELECT_LEX *sel= (SELECT_LEX *) arg;
|
||||
sel->cond_count++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
String *Item_int_func::val_str(String *str)
|
||||
{
|
||||
|
@ -485,6 +485,8 @@ class Item_num_op :public Item_func_numhybrid
|
||||
|
||||
class Item_int_func :public Item_func
|
||||
{
|
||||
protected:
|
||||
bool sargable;
|
||||
public:
|
||||
Item_int_func() :Item_func() { max_length= 21; }
|
||||
Item_int_func(Item *a) :Item_func(a) { max_length= 21; }
|
||||
@ -496,7 +498,8 @@ public:
|
||||
double val_real();
|
||||
String *val_str(String*str);
|
||||
enum Item_result result_type () const { return INT_RESULT; }
|
||||
void fix_length_and_dec() {}
|
||||
void fix_length_and_dec() { sargable= false; }
|
||||
bool count_sargable_conds(uchar *arg);
|
||||
};
|
||||
|
||||
|
||||
|
@ -8549,7 +8549,6 @@ int setup_conds(THD *thd, TABLE_LIST *tables, List<TABLE_LIST> &leaves,
|
||||
embedded->on_expr->fix_fields(thd, &embedded->on_expr)) ||
|
||||
embedded->on_expr->check_cols(1))
|
||||
goto err_no_arena;
|
||||
select_lex->cond_count++;
|
||||
}
|
||||
/*
|
||||
If it's a semi-join nest, fix its "left expression", as it is used by
|
||||
|
@ -394,8 +394,6 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
|
||||
if (dt_select->options & OPTION_SCHEMA_TABLE)
|
||||
parent_lex->options |= OPTION_SCHEMA_TABLE;
|
||||
|
||||
parent_lex->cond_count+= dt_select->cond_count;
|
||||
|
||||
if (!derived->get_unit()->prepared)
|
||||
{
|
||||
dt_select->leaf_tables.empty();
|
||||
|
@ -4733,6 +4733,32 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
||||
KEY_FIELD *key_fields, *end, *field;
|
||||
uint sz;
|
||||
uint m= max(select_lex->max_equal_elems,1);
|
||||
|
||||
SELECT_LEX *sel=thd->lex->current_select;
|
||||
sel->cond_count= 0;
|
||||
sel->between_count= 0;
|
||||
if (cond)
|
||||
cond->walk(&Item::count_sargable_conds, 0, (uchar*) sel);
|
||||
for (i=0 ; i < tables ; i++)
|
||||
{
|
||||
if (*join_tab[i].on_expr_ref)
|
||||
(*join_tab[i].on_expr_ref)->walk(&Item::count_sargable_conds,
|
||||
0, (uchar*) sel);
|
||||
}
|
||||
{
|
||||
List_iterator<TABLE_LIST> li(*join_tab->join->join_list);
|
||||
TABLE_LIST *table;
|
||||
while ((table= li++))
|
||||
{
|
||||
if (table->nested_join)
|
||||
{
|
||||
if (table->on_expr)
|
||||
table->on_expr->walk(&Item::count_sargable_conds, 0, (uchar*) sel);
|
||||
if (table->sj_on_expr)
|
||||
table->sj_on_expr->walk(&Item::count_sargable_conds, 0, (uchar*) sel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
We use the same piece of memory to store both KEY_FIELD
|
||||
@ -4756,8 +4782,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
||||
substitutions.
|
||||
*/
|
||||
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
|
||||
(((thd->lex->current_select->cond_count+1)*2 +
|
||||
thd->lex->current_select->between_count)*m+1);
|
||||
((sel->cond_count*2 + sel->between_count)*m+1);
|
||||
if (!(key_fields=(KEY_FIELD*) thd->alloc(sz)))
|
||||
return TRUE; /* purecov: inspected */
|
||||
and_level= 0;
|
||||
@ -11219,13 +11244,10 @@ static bool check_row_equality(THD *thd, Item *left_row, Item_row *right_row,
|
||||
(Item_row *) left_item,
|
||||
(Item_row *) right_item,
|
||||
cond_equal, eq_list);
|
||||
if (!is_converted)
|
||||
thd->lex->current_select->cond_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
is_converted= check_simple_equality(left_item, right_item, 0, cond_equal);
|
||||
thd->lex->current_select->cond_count++;
|
||||
}
|
||||
|
||||
if (!is_converted)
|
||||
@ -11284,7 +11306,6 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal,
|
||||
if (left_item->type() == Item::ROW_ITEM &&
|
||||
right_item->type() == Item::ROW_ITEM)
|
||||
{
|
||||
thd->lex->current_select->cond_count--;
|
||||
return check_row_equality(thd,
|
||||
(Item_row *) left_item,
|
||||
(Item_row *) right_item,
|
||||
|
Loading…
x
Reference in New Issue
Block a user