Fixed bug #30396.

Recommit to 5.1.22.
The bug caused memory corruption for some queries with top OR level
in the WHERE condition if they contained equality predicates and 
other sargable predicates in disjunctive parts of the condition.

The corruption happened because the upper bound of the memory
allocated for KEY_FIELD and SARGABLE_PARAM internal structures
containing info about potential lookup keys was calculated incorrectly
in some cases. In particular it was calculated incorrectly when the
WHERE condition was an OR formula with disjuncts being AND formulas
including equalities and other sargable predicates.
parent 6e76e82e
......@@ -3980,4 +3980,61 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE f1 index inx inx 10 NULL 7 Using where; Using index
1 SIMPLE f2 ref inx inx 5 test.f1.b 1 Using where; Using index
DROP TABLE t1;
CREATE TABLE t1 (
c1 int(11) NOT NULL AUTO_INCREMENT,
c2 varchar(1000) DEFAULT NULL,
c3 bigint(20) DEFAULT NULL,
c4 bigint(20) DEFAULT NULL,
PRIMARY KEY (c1)
);
EXPLAIN EXTENDED
SELECT join_2.c1
FROM
t1 AS join_0,
t1 AS join_1,
t1 AS join_2,
t1 AS join_3,
t1 AS join_4,
t1 AS join_5,
t1 AS join_6,
t1 AS join_7
WHERE
join_0.c1=join_1.c1 AND
join_1.c1=join_2.c1 AND
join_2.c1=join_3.c1 AND
join_3.c1=join_4.c1 AND
join_4.c1=join_5.c1 AND
join_5.c1=join_6.c1 AND
join_6.c1=join_7.c1
OR
join_0.c2 < '?' AND
join_1.c2 < '?' AND
join_2.c2 > '?' AND
join_2.c2 < '!' AND
join_3.c2 > '?' AND
join_4.c2 = '?' AND
join_5.c2 <> '?' AND
join_6.c2 <> '?' AND
join_7.c2 >= '?' AND
join_0.c1=join_1.c1 AND
join_1.c1=join_2.c1 AND
join_2.c1=join_3.c1 AND
join_3.c1=join_4.c1 AND
join_4.c1=join_5.c1 AND
join_5.c1=join_6.c1 AND
join_6.c1=join_7.c1
GROUP BY
join_3.c1,
join_2.c1,
join_7.c1,
join_1.c1,
join_0.c1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
Warnings:
Note 1003 select '0' AS `c1` from `test`.`t1` `join_0` join `test`.`t1` `join_1` join `test`.`t1` `join_2` join `test`.`t1` `join_3` join `test`.`t1` `join_4` join `test`.`t1` `join_5` join `test`.`t1` `join_6` join `test`.`t1` `join_7` where 0 group by '0','0','0','0','0'
SHOW WARNINGS;
Level Code Message
Note 1003 select '0' AS `c1` from `test`.`t1` `join_0` join `test`.`t1` `join_1` join `test`.`t1` `join_2` join `test`.`t1` `join_3` join `test`.`t1` `join_4` join `test`.`t1` `join_5` join `test`.`t1` `join_6` join `test`.`t1` `join_7` where 0 group by '0','0','0','0','0'
DROP TABLE t1;
End of 5.0 tests
......@@ -3359,4 +3359,64 @@ EXPLAIN SELECT COUNT(*) FROM t1 f1 INNER JOIN t1 f2
WHERE 1 AND f1.b NOT IN (100,2232,3343,51111);
DROP TABLE t1;
#
# Bug #30396: crash for a join with equalities and sargable predicates
# in disjunctive parts of the WHERE condition
#
CREATE TABLE t1 (
c1 int(11) NOT NULL AUTO_INCREMENT,
c2 varchar(1000) DEFAULT NULL,
c3 bigint(20) DEFAULT NULL,
c4 bigint(20) DEFAULT NULL,
PRIMARY KEY (c1)
);
EXPLAIN EXTENDED
SELECT join_2.c1
FROM
t1 AS join_0,
t1 AS join_1,
t1 AS join_2,
t1 AS join_3,
t1 AS join_4,
t1 AS join_5,
t1 AS join_6,
t1 AS join_7
WHERE
join_0.c1=join_1.c1 AND
join_1.c1=join_2.c1 AND
join_2.c1=join_3.c1 AND
join_3.c1=join_4.c1 AND
join_4.c1=join_5.c1 AND
join_5.c1=join_6.c1 AND
join_6.c1=join_7.c1
OR
join_0.c2 < '?' AND
join_1.c2 < '?' AND
join_2.c2 > '?' AND
join_2.c2 < '!' AND
join_3.c2 > '?' AND
join_4.c2 = '?' AND
join_5.c2 <> '?' AND
join_6.c2 <> '?' AND
join_7.c2 >= '?' AND
join_0.c1=join_1.c1 AND
join_1.c1=join_2.c1 AND
join_2.c1=join_3.c1 AND
join_3.c1=join_4.c1 AND
join_4.c1=join_5.c1 AND
join_5.c1=join_6.c1 AND
join_6.c1=join_7.c1
GROUP BY
join_3.c1,
join_2.c1,
join_7.c1,
join_1.c1,
join_0.c1;
SHOW WARNINGS;
DROP TABLE t1;
--echo End of 5.0 tests
......@@ -1569,7 +1569,6 @@ public:
the current and level */
COND_EQUAL()
{
max_members= 0;
upper_levels= 0;
}
};
......
......@@ -6738,6 +6738,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns));
select_lex->cond_count= 0;
select_lex->between_count= 0;
select_lex->max_equal_elems= 0;
for (table= tables; table; table= table->next_local)
{
......
......@@ -1517,6 +1517,7 @@ void st_select_lex::init_query()
*/
parent_lex->push_context(&context);
cond_count= between_count= with_wild= 0;
max_equal_elems= 0;
conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
select_n_where_fields= 0;
......
......@@ -607,6 +607,7 @@ public:
uint select_n_having_items;
uint cond_count; /* number of arguments of and/or/xor in where/having/on */
uint between_count; /* number of between predicates in where/having/on */
uint max_equal_elems; /* maximal number of elements in multiple equalities */
/*
Number of fields used in select list or where clause of current select
and all inner subselects.
......
......@@ -3562,10 +3562,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
uint and_level,i,found_eq_constant;
KEY_FIELD *key_fields, *end, *field;
uint sz;
uint m= 1;
if (cond_equal && cond_equal->max_members)
m= cond_equal->max_members;
uint m= max(select_lex->max_equal_elems,1);
/*
We use the same piece of memory to store both KEY_FIELD
......@@ -3585,7 +3582,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
it is considered as sargable only for its first argument.
Multiple equality can add elements that are filled after
substitution of field arguments by equal fields. There
can be not more than cond_equal->max_members such substitutions.
can be not more than select_lex->max_equal_elems such
substitutions.
*/
sz= max(sizeof(KEY_FIELD),sizeof(SARGABLE_PARAM))*
(((thd->lex->current_select->cond_count+1)*2 +
......@@ -7387,8 +7385,7 @@ static bool check_equality(THD *thd, Item *item, COND_EQUAL *cond_equal,
just an argument of a comparison predicate.
The function also determines the maximum number of members in
equality lists of each Item_cond_and object assigning it to
cond_equal->max_members of this object and updating accordingly
the upper levels COND_EQUAL structures.
thd->lex->current_select->max_equal_elems.
NOTES
Multiple equality predicate =(f1,..fn) is equivalent to the conjuction of
......@@ -7433,7 +7430,6 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
COND_EQUAL *inherited)
{
Item_equal *item_equal;
uint members;
COND_EQUAL cond_equal;
cond_equal.upper_levels= inherited;
......@@ -7471,19 +7467,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
{
item_equal->fix_length_and_dec();
item_equal->update_used_tables();
members= item_equal->members();
if (cond_equal.max_members < members)
cond_equal.max_members= members;
}
members= cond_equal.max_members;
if (inherited && inherited->max_members < members)
{
do
{
inherited->max_members= members;
inherited= inherited->upper_levels;
}
while (inherited);
set_if_bigger(thd->lex->current_select->max_equal_elems,
item_equal->members());
}
((Item_cond_and*)cond)->cond_equal= cond_equal;
......@@ -7538,10 +7523,12 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
{
item_equal->fix_length_and_dec();
item_equal->update_used_tables();
return item_equal;
}
else
return eq_list.pop();
item_equal= (Item_equal *) eq_list.pop();
set_if_bigger(thd->lex->current_select->max_equal_elems,
item_equal->members());
return item_equal;
}
else
{
......@@ -7557,9 +7544,8 @@ static COND *build_equal_items_for_cond(THD *thd, COND *cond,
{
item_equal->fix_length_and_dec();
item_equal->update_used_tables();
members= item_equal->members();
if (cond_equal.max_members < members)
cond_equal.max_members= members;
set_if_bigger(thd->lex->current_select->max_equal_elems,
item_equal->members());
}
and_cond->cond_equal= cond_equal;
args->concat((List<Item> *)&cond_equal.current_level);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment