Commit 6c0f3dd3 authored by Galina Shalygina's avatar Galina Shalygina

MDEV-16090: Server crash in in Item_func_in::val_int or assertion `in_item'

            failure upon SELECT with impossible condition

The problem appears because of a wrong implementation of the
Item_func_in::build_clone() method. It didn't clone 'array' and 'cmp_fields'
fields for the cloned IN predicate and this could cause crashes.
The Item_func_in::fix_length_and_dec() method was refactored and a new method
named Item_func_in::create_array() was created. It allowed to create 'array'
for cloned IN predicates in a proper way.
parent 8b26fea8
......@@ -9458,3 +9458,18 @@ EXPLAIN
}
}
DROP TABLE t1,t2;
#
# MDEV-15765: pushing condition with IN subquery defined with constants
# using substitution
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2);
SELECT * FROM
(
SELECT DISTINCT * FROM t1
) der_tab
WHERE (a>0 AND a<2 OR a IN (2,3)) AND
(a=2 OR 0);
a
2
DROP TABLE t1;
......@@ -1729,3 +1729,19 @@ EVAL EXPLAIN $query;
EVAL EXPLAIN FORMAT=JSON $query;
DROP TABLE t1,t2;
--echo #
--echo # MDEV-15765: pushing condition with IN subquery defined with constants
--echo # using substitution
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2);
SELECT * FROM
(
SELECT DISTINCT * FROM t1
) der_tab
WHERE (a>0 AND a<2 OR a IN (2,3)) AND
(a=2 OR 0);
DROP TABLE t1;
......@@ -4117,6 +4117,67 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
(uchar *) y->ptr(),y->length());
}
/*
Create 'array' for this IN predicate with the respect to its result type
and put values from <in value list> in 'array'.
*/
bool Item_func_in::create_array(THD *thd)
{
Item *date_arg= 0;
switch (m_compare_type) {
case STRING_RESULT:
array=new (thd->mem_root) in_string(thd, arg_count - 1,
(qsort2_cmp) srtcmp_in,
cmp_collation.collation);
break;
case INT_RESULT:
array= new (thd->mem_root) in_longlong(thd, arg_count - 1);
break;
case REAL_RESULT:
array= new (thd->mem_root) in_double(thd, arg_count - 1);
break;
case ROW_RESULT:
/*
The row comparator was created at the beginning but only DATETIME
items comparators were initialized. Call store_value() to setup
others.
*/
((in_row*)array)->tmp.store_value(args[0]);
break;
case DECIMAL_RESULT:
array= new (thd->mem_root) in_decimal(thd, arg_count - 1);
break;
case TIME_RESULT:
date_arg= find_date_time_item(thd, args, arg_count, 0, true);
array= new (thd->mem_root) in_datetime(thd, date_arg, arg_count - 1);
break;
}
if (!array || thd->is_fatal_error) // OOM
return true;
uint j=0;
for (uint i=1 ; i < arg_count ; i++)
{
array->set(j,args[i]);
if (!args[i]->null_value)
j++; // include this cell in the array.
else
{
/*
We don't put NULL values in array to avoid erronous matches in
bisection.
*/
have_null= 1;
}
}
if ((array->used_count= j))
array->sort();
return false;
}
void Item_func_in::fix_length_and_dec()
{
Item **arg, **arg_end;
......@@ -4244,53 +4305,8 @@ void Item_func_in::fix_length_and_dec()
m_compare_type= INT_RESULT;
}
}
switch (m_compare_type) {
case STRING_RESULT:
array=new (thd->mem_root) in_string(thd, arg_count - 1,
(qsort2_cmp) srtcmp_in,
cmp_collation.collation);
break;
case INT_RESULT:
array= new (thd->mem_root) in_longlong(thd, arg_count - 1);
break;
case REAL_RESULT:
array= new (thd->mem_root) in_double(thd, arg_count - 1);
break;
case ROW_RESULT:
/*
The row comparator was created at the beginning but only DATETIME
items comparators were initialized. Call store_value() to setup
others.
*/
((in_row*)array)->tmp.store_value(args[0]);
break;
case DECIMAL_RESULT:
array= new (thd->mem_root) in_decimal(thd, arg_count - 1);
break;
case TIME_RESULT:
date_arg= find_date_time_item(thd, args, arg_count, 0, true);
array= new (thd->mem_root) in_datetime(thd, date_arg, arg_count - 1);
break;
}
if (!array || thd->is_fatal_error) // OOM
if (create_array(thd))
return;
uint j=0;
for (uint i=1 ; i < arg_count ; i++)
{
array->set(j,args[i]);
if (!args[i]->null_value)
j++; // include this cell in the array.
else
{
/*
We don't put NULL values in array, to avoid erronous matches in
bisection.
*/
have_null= 1;
}
}
if ((array->used_count= j))
array->sort();
}
else
{
......@@ -4399,6 +4415,19 @@ longlong Item_func_in::val_int()
}
Item *Item_func_in::build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_func_in *clone= (Item_func_in *) Item_func::build_clone(thd, mem_root);
if (clone)
{
if (array && clone->create_array(thd))
return NULL;
memcpy(&clone->cmp_items, &cmp_items, sizeof(cmp_items));
}
return clone;
}
longlong Item_func_bit_or::val_int()
{
DBUG_ASSERT(fixed == 1);
......
......@@ -1648,6 +1648,7 @@ class Item_func_in :public Item_func_opt_neg
}
longlong val_int();
bool fix_fields(THD *, Item **);
bool create_array(THD *thd);
void fix_length_and_dec();
void cleanup()
{
......@@ -1693,16 +1694,7 @@ class Item_func_in :public Item_func_opt_neg
bool count_sargable_conds(void *arg);
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_in>(thd, mem_root, this); }
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_func_in *clone= (Item_func_in *) Item_func::build_clone(thd, mem_root);
if (clone)
{
clone->array= 0;
bzero(&clone->cmp_items, sizeof(cmp_items));
}
return clone;
}
Item *build_clone(THD *thd, MEM_ROOT *mem_root);
};
class cmp_item_row :public cmp_item
......@@ -1731,6 +1723,7 @@ class in_row :public in_vector
~in_row();
void set(uint pos,Item *item);
uchar *get_value(Item *item);
friend bool Item_func_in::create_array(THD *thd);
friend void Item_func_in::fix_length_and_dec();
Item_result result_type() { return ROW_RESULT; }
cmp_item *get_cmp_item() { return &tmp; }
......
......@@ -8241,8 +8241,8 @@ Item* TABLE_LIST::build_pushable_cond_for_table(THD *thd, Item *cond)
new_cond->argument_list()->push_back(fix, thd->mem_root);
}
if (is_fix_needed)
new_cond->fix_fields(thd, 0);
if (is_fix_needed && new_cond->fix_fields(thd, 0))
return 0;
switch (new_cond->argument_list()->elements)
{
......
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