Commit 0e656039 authored by Alexey Kopytov's avatar Alexey Kopytov

Bug#54477: Crash on IN / CASE with NULL arguments

Incorrect handling of NULL arguments could lead to a crash on
the IN or CASE operations when either NULL arguments were
passed explicitly as arguments (IN) or implicitly generated by
the WITH ROLLUP modifier (both IN and CASE).

Item_func_case::find_item() assumed all necessary comparators
to be instantiated in fix_length_and_dec(). However, in the
presence of WITH ROLLUP modifier, arguments could be
substituted with an Item_null leading to an "unexpected"
STRING_RESULT comparator being invoked.

In addition to the problem identical to the above,
Item_func_in::val_int() could crash even with explicitly passed
NULL arguments due to an optimization in fix_length_and_dec()
leading to NULL arguments being ignored during comparators
creation.


mysql-test/r/func_in.result:
  Test cases for bug#54477.
mysql-test/t/func_in.test:
  Test cases for bug#54477.
sql/item_cmpfunc.cc:
  Added additional checks for Item_nulls in 
  Item_func_case::find_item() and Item_func_in::val_int().
parent b36a0282
...@@ -750,4 +750,24 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -750,4 +750,24 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
DROP TABLE t1; DROP TABLE t1;
# #
# Bug#54477: Crash on IN / CASE with NULL arguments
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1), (2);
SELECT 1 IN (NULL, a) FROM t1;
1 IN (NULL, a)
1
NULL
SELECT a IN (a, a) FROM t1 GROUP BY a WITH ROLLUP;
a IN (a, a)
1
1
NULL
SELECT CASE a WHEN a THEN a END FROM t1 GROUP BY a WITH ROLLUP;
CASE a WHEN a THEN a END
1
2
NULL
DROP TABLE t1;
#
End of 5.1 tests End of 5.1 tests
...@@ -539,6 +539,21 @@ EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, NULL); ...@@ -539,6 +539,21 @@ EXPLAIN SELECT * FROM t1 WHERE c_char IN (NULL, NULL);
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # Bug#54477: Crash on IN / CASE with NULL arguments
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1), (2);
SELECT 1 IN (NULL, a) FROM t1;
SELECT a IN (a, a) FROM t1 GROUP BY a WITH ROLLUP;
SELECT CASE a WHEN a THEN a END FROM t1 GROUP BY a WITH ROLLUP;
DROP TABLE t1;
--echo # --echo #
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -2773,6 +2773,8 @@ Item *Item_func_case::find_item(String *str) ...@@ -2773,6 +2773,8 @@ Item *Item_func_case::find_item(String *str)
/* Compare every WHEN argument with it and return the first match */ /* Compare every WHEN argument with it and return the first match */
for (uint i=0 ; i < ncases ; i+=2) for (uint i=0 ; i < ncases ; i+=2)
{ {
if (args[i]->real_item()->type() == NULL_ITEM)
continue;
cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
DBUG_ASSERT(cmp_type != ROW_RESULT); DBUG_ASSERT(cmp_type != ROW_RESULT);
DBUG_ASSERT(cmp_items[(uint)cmp_type]); DBUG_ASSERT(cmp_items[(uint)cmp_type]);
...@@ -4002,9 +4004,17 @@ longlong Item_func_in::val_int() ...@@ -4002,9 +4004,17 @@ longlong Item_func_in::val_int()
return (longlong) (!null_value && tmp != negated); return (longlong) (!null_value && tmp != negated);
} }
if ((null_value= args[0]->real_item()->type() == NULL_ITEM))
return 0;
have_null= 0; have_null= 0;
for (uint i= 1 ; i < arg_count ; i++) for (uint i= 1 ; i < arg_count ; i++)
{ {
if (args[i]->real_item()->type() == NULL_ITEM)
{
have_null= TRUE;
continue;
}
Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type());
in_item= cmp_items[(uint)cmp_type]; in_item= cmp_items[(uint)cmp_type];
DBUG_ASSERT(in_item); DBUG_ASSERT(in_item);
......
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