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 VIEW v;
|
||||||
DROP TABLE t1,t2;
|
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
|
# end of 5.3 tests
|
||||||
#
|
#
|
||||||
set optimizer_switch=@exit_optimizer_switch;
|
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 VIEW v;
|
||||||
DROP TABLE t1,t2;
|
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 #
|
||||||
--echo # end of 5.3 tests
|
--echo # end of 5.3 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -1054,6 +1054,7 @@ public:
|
|||||||
virtual bool view_used_tables_processor(uchar *arg) { return 0; }
|
virtual bool view_used_tables_processor(uchar *arg) { return 0; }
|
||||||
virtual bool eval_not_null_tables(uchar *opt_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 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)
|
virtual bool limit_index_condition_pushdown_processor(uchar *opt_arg)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -539,6 +539,8 @@ void Item_bool_func2::fix_length_and_dec()
|
|||||||
to the collation of A.
|
to the collation of A.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
sargable= true;
|
||||||
|
|
||||||
DTCollation coll;
|
DTCollation coll;
|
||||||
if (args[0]->result_type() == STRING_RESULT &&
|
if (args[0]->result_type() == STRING_RESULT &&
|
||||||
args[1]->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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
|
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
|
||||||
{
|
{
|
||||||
if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) ||
|
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)
|
void Item_func_between::fix_after_pullout(st_select_lex *new_parent, Item **ref)
|
||||||
{
|
{
|
||||||
/* This will re-calculate attributes of the arguments */
|
/* This will re-calculate attributes of the arguments */
|
||||||
@ -2173,6 +2185,7 @@ void Item_func_between::fix_length_and_dec()
|
|||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
max_length= 1;
|
max_length= 1;
|
||||||
compare_as_dates= 0;
|
compare_as_dates= 0;
|
||||||
|
sargable= true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
As some compare functions are generated after sql_yacc,
|
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 found_types= 0;
|
||||||
uint type_cnt= 0, i;
|
uint type_cnt= 0, i;
|
||||||
Item_result cmp_type= STRING_RESULT;
|
Item_result cmp_type= STRING_RESULT;
|
||||||
|
sargable= true;
|
||||||
left_result_type= args[0]->cmp_type();
|
left_result_type= args[0]->cmp_type();
|
||||||
if (!(found_types= collect_cmp_types(args, arg_count, true)))
|
if (!(found_types= collect_cmp_types(args, arg_count, true)))
|
||||||
return;
|
return;
|
||||||
@ -4638,6 +4652,7 @@ longlong Item_func_isnull::val_int()
|
|||||||
return args[0]->is_null() ? 1: 0;
|
return args[0]->is_null() ? 1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
longlong Item_is_not_null_test::val_int()
|
longlong Item_is_not_null_test::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
@ -4841,6 +4856,7 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_func_like::cleanup()
|
void Item_func_like::cleanup()
|
||||||
{
|
{
|
||||||
canDoTurboBM= FALSE;
|
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
|
@brief
|
||||||
@ -5920,6 +5944,7 @@ void Item_equal::fix_length_and_dec()
|
|||||||
Item *item= get_first(NO_PARTICULAR_TAB, NULL);
|
Item *item= get_first(NO_PARTICULAR_TAB, NULL);
|
||||||
eval_item= cmp_item::get_comparator(item->cmp_type(), item,
|
eval_item= cmp_item::get_comparator(item->cmp_type(), item,
|
||||||
item->collation.collation);
|
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(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||||
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
|
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
|
||||||
bool is_bool_func() { return 1; }
|
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; }
|
uint decimal_precision() const { return 1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -681,6 +681,7 @@ public:
|
|||||||
uint decimal_precision() const { return 1; }
|
uint decimal_precision() const { return 1; }
|
||||||
bool eval_not_null_tables(uchar *opt_arg);
|
bool eval_not_null_tables(uchar *opt_arg);
|
||||||
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
|
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();
|
CHARSET_INFO *compare_collation();
|
||||||
|
|
||||||
void set_context_field(Item_field *ctx_field) { context_field= ctx_field; }
|
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_fast,Item>;
|
||||||
friend class Item_equal_iterator<List_iterator,Item>;
|
friend class Item_equal_iterator<List_iterator,Item>;
|
||||||
friend Item *eliminate_item_equal(COND *cond, COND_EQUAL *upper_levels,
|
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();
|
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)
|
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
|
class Item_int_func :public Item_func
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
bool sargable;
|
||||||
public:
|
public:
|
||||||
Item_int_func() :Item_func() { max_length= 21; }
|
Item_int_func() :Item_func() { max_length= 21; }
|
||||||
Item_int_func(Item *a) :Item_func(a) { max_length= 21; }
|
Item_int_func(Item *a) :Item_func(a) { max_length= 21; }
|
||||||
@ -496,7 +498,8 @@ public:
|
|||||||
double val_real();
|
double val_real();
|
||||||
String *val_str(String*str);
|
String *val_str(String*str);
|
||||||
enum Item_result result_type () const { return INT_RESULT; }
|
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->fix_fields(thd, &embedded->on_expr)) ||
|
||||||
embedded->on_expr->check_cols(1))
|
embedded->on_expr->check_cols(1))
|
||||||
goto err_no_arena;
|
goto err_no_arena;
|
||||||
select_lex->cond_count++;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
If it's a semi-join nest, fix its "left expression", as it is used by
|
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)
|
if (dt_select->options & OPTION_SCHEMA_TABLE)
|
||||||
parent_lex->options |= OPTION_SCHEMA_TABLE;
|
parent_lex->options |= OPTION_SCHEMA_TABLE;
|
||||||
|
|
||||||
parent_lex->cond_count+= dt_select->cond_count;
|
|
||||||
|
|
||||||
if (!derived->get_unit()->prepared)
|
if (!derived->get_unit()->prepared)
|
||||||
{
|
{
|
||||||
dt_select->leaf_tables.empty();
|
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;
|
KEY_FIELD *key_fields, *end, *field;
|
||||||
uint sz;
|
uint sz;
|
||||||
uint m= max(select_lex->max_equal_elems,1);
|
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
|
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.
|
substitutions.
|
||||||
*/
|
*/
|
||||||
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
|
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
|
||||||
(((thd->lex->current_select->cond_count+1)*2 +
|
((sel->cond_count*2 + sel->between_count)*m+1);
|
||||||
thd->lex->current_select->between_count)*m+1);
|
|
||||||
if (!(key_fields=(KEY_FIELD*) thd->alloc(sz)))
|
if (!(key_fields=(KEY_FIELD*) thd->alloc(sz)))
|
||||||
return TRUE; /* purecov: inspected */
|
return TRUE; /* purecov: inspected */
|
||||||
and_level= 0;
|
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 *) left_item,
|
||||||
(Item_row *) right_item,
|
(Item_row *) right_item,
|
||||||
cond_equal, eq_list);
|
cond_equal, eq_list);
|
||||||
if (!is_converted)
|
|
||||||
thd->lex->current_select->cond_count++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
is_converted= check_simple_equality(left_item, right_item, 0, cond_equal);
|
is_converted= check_simple_equality(left_item, right_item, 0, cond_equal);
|
||||||
thd->lex->current_select->cond_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_converted)
|
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 &&
|
if (left_item->type() == Item::ROW_ITEM &&
|
||||||
right_item->type() == Item::ROW_ITEM)
|
right_item->type() == Item::ROW_ITEM)
|
||||||
{
|
{
|
||||||
thd->lex->current_select->cond_count--;
|
|
||||||
return check_row_equality(thd,
|
return check_row_equality(thd,
|
||||||
(Item_row *) left_item,
|
(Item_row *) left_item,
|
||||||
(Item_row *) right_item,
|
(Item_row *) right_item,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user