Skip to content

Commit 9fc124f

Browse files
committed
MDEV-25415 CASE function handles NULL inconsistently
SQL Standard specifies that a <simple case> should return the <result> from the left-most <simple when clause> where the comparison evaluates to TRUE. That is, it should not stop comparing on NULLs
1 parent 1ac4aeb commit 9fc124f

File tree

4 files changed

+28
-22
lines changed

4 files changed

+28
-22
lines changed

mysql-test/main/case.result

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
drop table if exists t1, t2;
21
select CASE "b" when "a" then 1 when "b" then 2 END as exp;
32
exp
43
2
@@ -572,6 +571,22 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
572571
Warnings:
573572
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` where case `test`.`t1`.`a` when `test`.`t1`.`b` then 1 end = 1 and case when `test`.`t1`.`a` then `test`.`t1`.`b` else 1 end = 3
574573
DROP TABLE t1;
575-
#
576574
# End of 10.3 test
577575
#
576+
# MDEV-25415 CASE function handles NULL inconsistently
577+
#
578+
select case 'X' when null then 1 when 'X' then 2 else 3 end;
579+
case 'X' when null then 1 when 'X' then 2 else 3 end
580+
2
581+
select case 'X' when 1/1 then 1 when 'X' then 2 else 3 end;
582+
case 'X' when 1/1 then 1 when 'X' then 2 else 3 end
583+
2
584+
Warnings:
585+
Warning 1292 Truncated incorrect DOUBLE value: 'X'
586+
select case 'X' when 1/0 then 1 when 'X' then 2 else 3 end;
587+
case 'X' when 1/0 then 1 when 'X' then 2 else 3 end
588+
2
589+
Warnings:
590+
Warning 1292 Truncated incorrect DOUBLE value: 'X'
591+
Warning 1365 Division by 0
592+
# End of 10.11 test

mysql-test/main/case.test

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22
# Testing of CASE
33
#
44

5-
6-
--disable_warnings
7-
drop table if exists t1, t2;
8-
--enable_warnings
9-
105
select CASE "b" when "a" then 1 when "b" then 2 END as exp;
116
select CASE "c" when "a" then 1 when "b" then 2 END as exp;
127
select CASE "c" when "a" then 1 when "b" then 2 ELSE 3 END as exp;
@@ -412,7 +407,13 @@ SELECT * FROM t1 WHERE
412407

413408
DROP TABLE t1;
414409

410+
--echo # End of 10.3 test
415411

416412
--echo #
417-
--echo # End of 10.3 test
413+
--echo # MDEV-25415 CASE function handles NULL inconsistently
418414
--echo #
415+
select case 'X' when null then 1 when 'X' then 2 else 3 end;
416+
select case 'X' when 1/1 then 1 when 'X' then 2 else 3 end;
417+
select case 'X' when 1/0 then 1 when 'X' then 2 else 3 end;
418+
419+
--echo # End of 10.11 test

sql/item_cmpfunc.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3096,7 +3096,8 @@ Item *Item_func_case_simple::find_item()
30963096
{
30973097
/* Compare every WHEN argument with it and return the first match */
30983098
uint idx;
3099-
if (!Predicant_to_list_comparator::cmp(this, &idx, NULL))
3099+
bool found_unknown_values;
3100+
if (!Predicant_to_list_comparator::cmp(this, &idx, &found_unknown_values))
31003101
return args[idx + when_count()];
31013102
Item **pos= Item_func_case_simple::else_expr_addr();
31023103
return pos ? pos[0] : 0;

sql/item_cmpfunc.h

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,15 +2284,8 @@ class Predicant_to_list_comparator
22842284
@param [OUT] idx - In case if a value that is equal to the predicant
22852285
was found, the index of the matching value is returned
22862286
here. Otherwise, *idx is not changed.
2287-
@param [IN/OUT] found_unknown_values - how to handle UNKNOWN results.
2288-
If found_unknown_values is NULL (e.g. Item_func_case),
2289-
cmp() returns immediately when the first UNKNOWN
2290-
result is found.
2291-
If found_unknown_values is non-NULL (Item_func_in),
2292-
cmp() does not return when an UNKNOWN result is found,
2293-
sets *found_unknown_values to true, and continues
2294-
to compare the remaining pairs to find FALSE
2295-
(i.e. the value that is equal to the predicant).
2287+
@param [OUT] found_unknown_values - set to true if the result of at least
2288+
one comparison was UNKNOWN
22962289
22972290
@retval false - Found a value that is equal to the predicant
22982291
@retval true - Didn't find an equal value
@@ -2309,11 +2302,7 @@ class Predicant_to_list_comparator
23092302
return false; // Found a matching value
23102303
}
23112304
if (rc == UNKNOWN)
2312-
{
2313-
if (!found_unknown_values)
2314-
return true;
23152305
*found_unknown_values= true;
2316-
}
23172306
}
23182307
return true; // Not found
23192308
}

0 commit comments

Comments
 (0)