Skip to content

Commit 3d9abaf

Browse files
author
Alexander Barkov
committed
MDEV-8752 Wrong result for SELECT..WHERE CASE enum_field WHEN 1 THEN 1 ELSE 0 END AND a='5'
1 parent 67dbfab commit 3d9abaf

File tree

4 files changed

+296
-16
lines changed

4 files changed

+296
-16
lines changed

mysql-test/r/case.result

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,3 +231,138 @@ case t1.f1 when '00:00:00' then 1 end
231231
1
232232
NULL
233233
drop table t1;
234+
#
235+
# Start of 10.1 test
236+
#
237+
#
238+
# MDEV-8752 Wrong result for SELECT..WHERE CASE enum_field WHEN 1 THEN 1 ELSE 0 END AND a='5'
239+
#
240+
CREATE TABLE t1 (a ENUM('5','6') CHARACTER SET BINARY);
241+
INSERT INTO t1 VALUES ('5'),('6');
242+
SELECT * FROM t1 WHERE a='5';
243+
a
244+
5
245+
SELECT * FROM t1 WHERE a=1;
246+
a
247+
5
248+
SELECT * FROM t1 WHERE CASE a WHEN 1 THEN 1 ELSE 0 END;
249+
a
250+
5
251+
SELECT * FROM t1 WHERE CASE a WHEN 1 THEN 1 ELSE 0 END AND a='5';
252+
a
253+
5
254+
# Multiple comparison types in CASE, not Ok to propagate
255+
EXPLAIN EXTENDED
256+
SELECT * FROM t1 WHERE CASE a WHEN 1 THEN 1 ELSE 0 END AND a='5';
257+
id select_type table type possible_keys key key_len ref rows filtered Extra
258+
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
259+
Warnings:
260+
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = '5') and (case `test`.`t1`.`a` when 1 then 1 else 0 end))
261+
DROP TABLE t1;
262+
CREATE TABLE t1 (a ENUM('a','b','100'));
263+
INSERT INTO t1 VALUES ('a'),('b'),('100');
264+
SELECT * FROM t1 WHERE a='a';
265+
a
266+
a
267+
SELECT * FROM t1 WHERE CASE a WHEN 'a' THEN 1 ELSE 0 END;
268+
a
269+
a
270+
SELECT * FROM t1 WHERE CASE a WHEN 'a' THEN 1 ELSE 0 END AND a='a';
271+
a
272+
a
273+
# String comparison in CASE and in the equality, ok to propagate
274+
EXPLAIN EXTENDED
275+
SELECT * FROM t1 WHERE CASE a WHEN 'a' THEN 1 ELSE 0 END AND a='a';
276+
id select_type table type possible_keys key key_len ref rows filtered Extra
277+
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
278+
Warnings:
279+
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` = 'a')
280+
SELECT * FROM t1 WHERE a=3;
281+
a
282+
100
283+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END;
284+
a
285+
100
286+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END AND a=3;
287+
a
288+
100
289+
# Integer comparison in CASE and in the equality, not ok to propagate
290+
# ENUM does not support this type of propagation yet.
291+
# This can change in the future. See MDEV-8748.
292+
EXPLAIN EXTENDED
293+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END AND a=3;
294+
id select_type table type possible_keys key key_len ref rows filtered Extra
295+
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
296+
Warnings:
297+
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((case `test`.`t1`.`a` when 3 then 1 else 0 end) and (`test`.`t1`.`a` = 3))
298+
SELECT * FROM t1 WHERE a=3;
299+
a
300+
100
301+
SELECT * FROM t1 WHERE CASE a WHEN '100' THEN 1 ELSE 0 END;
302+
a
303+
100
304+
SELECT * FROM t1 WHERE CASE a WHEN '100' THEN 1 ELSE 0 END AND a=3;
305+
a
306+
100
307+
# String comparison in CASE, integer comparison in the equality, not Ok to propagate
308+
EXPLAIN EXTENDED
309+
SELECT * FROM t1 WHERE CASE a WHEN '100' THEN 1 ELSE 0 END AND a=3;
310+
id select_type table type possible_keys key key_len ref rows filtered Extra
311+
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
312+
Warnings:
313+
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((case `test`.`t1`.`a` when '100' then 1 else 0 end) and (`test`.`t1`.`a` = 3))
314+
SELECT * FROM t1 WHERE a='100';
315+
a
316+
100
317+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END;
318+
a
319+
100
320+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END AND a='100';
321+
a
322+
100
323+
# Integer comparison in CASE, string comparison in the equality, not Ok to propagate
324+
EXPLAIN EXTENDED
325+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END AND a='100';
326+
id select_type table type possible_keys key key_len ref rows filtered Extra
327+
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
328+
Warnings:
329+
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = '100') and (case `test`.`t1`.`a` when 3 then 1 else 0 end))
330+
SELECT * FROM t1 WHERE a='100';
331+
a
332+
100
333+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END;
334+
a
335+
100
336+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END AND a='100';
337+
a
338+
100
339+
# Multiple type comparison in CASE, string comparison in the equality, not Ok to propagate
340+
EXPLAIN EXTENDED
341+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END AND a='100';
342+
id select_type table type possible_keys key key_len ref rows filtered Extra
343+
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
344+
Warnings:
345+
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((`test`.`t1`.`a` = '100') and (case `test`.`t1`.`a` when 3 then 1 when '100' then 1 else 0 end))
346+
SELECT * FROM t1 WHERE a=3;
347+
a
348+
100
349+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END;
350+
a
351+
100
352+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END AND a=3;
353+
a
354+
100
355+
# Multiple type comparison in CASE, integer comparison in the equality, not Ok to propagate
356+
EXPLAIN EXTENDED
357+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END AND a=3;
358+
id select_type table type possible_keys key key_len ref rows filtered Extra
359+
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
360+
Warnings:
361+
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where ((case `test`.`t1`.`a` when 3 then 1 when '100' then 1 else 0 end) and (`test`.`t1`.`a` = 3))
362+
DROP TABLE t1;
363+
#
364+
# End of MDEV-8752
365+
#
366+
#
367+
# End of 10.1 test
368+
#

mysql-test/t/case.test

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,3 +193,75 @@ insert t1 values ('00:00:00'),('00:01:00');
193193
select case t1.f1 when '00:00:00' then 1 end from t1;
194194
drop table t1;
195195

196+
--echo #
197+
--echo # Start of 10.1 test
198+
--echo #
199+
200+
--echo #
201+
--echo # MDEV-8752 Wrong result for SELECT..WHERE CASE enum_field WHEN 1 THEN 1 ELSE 0 END AND a='5'
202+
--echo #
203+
CREATE TABLE t1 (a ENUM('5','6') CHARACTER SET BINARY);
204+
INSERT INTO t1 VALUES ('5'),('6');
205+
SELECT * FROM t1 WHERE a='5';
206+
SELECT * FROM t1 WHERE a=1;
207+
SELECT * FROM t1 WHERE CASE a WHEN 1 THEN 1 ELSE 0 END;
208+
SELECT * FROM t1 WHERE CASE a WHEN 1 THEN 1 ELSE 0 END AND a='5';
209+
--echo # Multiple comparison types in CASE, not Ok to propagate
210+
EXPLAIN EXTENDED
211+
SELECT * FROM t1 WHERE CASE a WHEN 1 THEN 1 ELSE 0 END AND a='5';
212+
DROP TABLE t1;
213+
214+
CREATE TABLE t1 (a ENUM('a','b','100'));
215+
INSERT INTO t1 VALUES ('a'),('b'),('100');
216+
SELECT * FROM t1 WHERE a='a';
217+
SELECT * FROM t1 WHERE CASE a WHEN 'a' THEN 1 ELSE 0 END;
218+
SELECT * FROM t1 WHERE CASE a WHEN 'a' THEN 1 ELSE 0 END AND a='a';
219+
--echo # String comparison in CASE and in the equality, ok to propagate
220+
EXPLAIN EXTENDED
221+
SELECT * FROM t1 WHERE CASE a WHEN 'a' THEN 1 ELSE 0 END AND a='a';
222+
223+
SELECT * FROM t1 WHERE a=3;
224+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END;
225+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END AND a=3;
226+
--echo # Integer comparison in CASE and in the equality, not ok to propagate
227+
--echo # ENUM does not support this type of propagation yet.
228+
--echo # This can change in the future. See MDEV-8748.
229+
EXPLAIN EXTENDED
230+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END AND a=3;
231+
232+
SELECT * FROM t1 WHERE a=3;
233+
SELECT * FROM t1 WHERE CASE a WHEN '100' THEN 1 ELSE 0 END;
234+
SELECT * FROM t1 WHERE CASE a WHEN '100' THEN 1 ELSE 0 END AND a=3;
235+
--echo # String comparison in CASE, integer comparison in the equality, not Ok to propagate
236+
EXPLAIN EXTENDED
237+
SELECT * FROM t1 WHERE CASE a WHEN '100' THEN 1 ELSE 0 END AND a=3;
238+
239+
SELECT * FROM t1 WHERE a='100';
240+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END;
241+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END AND a='100';
242+
--echo # Integer comparison in CASE, string comparison in the equality, not Ok to propagate
243+
EXPLAIN EXTENDED
244+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 ELSE 0 END AND a='100';
245+
246+
SELECT * FROM t1 WHERE a='100';
247+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END;
248+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END AND a='100';
249+
--echo # Multiple type comparison in CASE, string comparison in the equality, not Ok to propagate
250+
EXPLAIN EXTENDED
251+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END AND a='100';
252+
253+
SELECT * FROM t1 WHERE a=3;
254+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END;
255+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END AND a=3;
256+
--echo # Multiple type comparison in CASE, integer comparison in the equality, not Ok to propagate
257+
EXPLAIN EXTENDED
258+
SELECT * FROM t1 WHERE CASE a WHEN 3 THEN 1 WHEN '100' THEN 1 ELSE 0 END AND a=3;
259+
260+
DROP TABLE t1;
261+
--echo #
262+
--echo # End of MDEV-8752
263+
--echo #
264+
265+
--echo #
266+
--echo # End of 10.1 test
267+
--echo #

sql/item_cmpfunc.cc

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,7 +2779,7 @@ Item_func_nullif::is_null()
27792779
Item_func_case::Item_func_case(THD *thd, List<Item> &list,
27802780
Item *first_expr_arg, Item *else_expr_arg):
27812781
Item_func_hybrid_field_type(thd), first_expr_num(-1), else_expr_num(-1),
2782-
left_cmp_type(INT_RESULT), case_item(0)
2782+
left_cmp_type(INT_RESULT), case_item(0), m_found_types(0)
27832783
{
27842784
ncases= list.elements;
27852785
if (first_expr_arg)
@@ -3010,9 +3010,9 @@ void Item_func_case::fix_length_and_dec()
30103010
{
30113011
Item **agg= arg_buffer;
30123012
uint nagg;
3013-
uint found_types= 0;
30143013
THD *thd= current_thd;
30153014

3015+
m_found_types= 0;
30163016
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
30173017
maybe_null= 1;
30183018

@@ -3079,14 +3079,14 @@ void Item_func_case::fix_length_and_dec()
30793079
for (nagg= 0; nagg < ncases/2 ; nagg++)
30803080
agg[nagg+1]= args[nagg*2];
30813081
nagg++;
3082-
if (!(found_types= collect_cmp_types(agg, nagg)))
3082+
if (!(m_found_types= collect_cmp_types(agg, nagg)))
30833083
return;
30843084

30853085
Item *date_arg= 0;
3086-
if (found_types & (1U << TIME_RESULT))
3086+
if (m_found_types & (1U << TIME_RESULT))
30873087
date_arg= find_date_time_item(args, arg_count, 0);
30883088

3089-
if (found_types & (1U << STRING_RESULT))
3089+
if (m_found_types & (1U << STRING_RESULT))
30903090
{
30913091
/*
30923092
If we'll do string comparison, we also need to aggregate
@@ -3127,7 +3127,7 @@ void Item_func_case::fix_length_and_dec()
31273127

31283128
for (i= 0; i <= (uint)TIME_RESULT; i++)
31293129
{
3130-
if (found_types & (1U << i) && !cmp_items[i])
3130+
if (m_found_types & (1U << i) && !cmp_items[i])
31313131
{
31323132
DBUG_ASSERT((Item_result)i != ROW_RESULT);
31333133

@@ -3137,6 +3137,18 @@ void Item_func_case::fix_length_and_dec()
31373137
return;
31383138
}
31393139
}
3140+
/*
3141+
If only one type was found and it matches args[0]->cmp_type(),
3142+
set args[0]->cmp_context to this type. This is needed to make sure that
3143+
equal field propagation for args[0] works correctly, according to the
3144+
type found.
3145+
Otherwise, in case of multiple types or in case of a single type that
3146+
differs from args[0]->cmp_type(), it's Okey to keep args[0]->cmp_context
3147+
equal to IMPOSSIBLE_RESULT, as propagation for args[0] won't be
3148+
performed anyway.
3149+
*/
3150+
if (m_found_types == (1UL << left_cmp_type))
3151+
args[0]->cmp_context= left_cmp_type;
31403152
/*
31413153
Set cmp_context of all WHEN arguments. This prevents
31423154
Item_field::propagate_equal_fields() from transforming a
@@ -3149,6 +3161,60 @@ void Item_func_case::fix_length_and_dec()
31493161
}
31503162

31513163

3164+
Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
3165+
{
3166+
if (first_expr_num == -1)
3167+
{
3168+
// None of the arguments are in a comparison context
3169+
Item_args::propagate_equal_fields(thd, IDENTITY_SUBST, cond);
3170+
return this;
3171+
}
3172+
3173+
for (uint i= 0; i < arg_count; i++)
3174+
{
3175+
/*
3176+
Even "i" values cover items that are in a comparison context:
3177+
CASE x0 WHEN x1 .. WHEN x2 .. WHEN x3 ..
3178+
Odd "i" values cover items that are not in comparison:
3179+
CASE ... THEN y1 ... THEN y2 ... THEN y3 ... ELSE y4 END
3180+
*/
3181+
Item *new_item= 0;
3182+
if ((int) i == first_expr_num) // Then CASE (the switch) argument
3183+
{
3184+
/*
3185+
Cannot replace the CASE (the switch) argument if
3186+
there are multiple comparison types were found.
3187+
*/
3188+
if (m_found_types == (1UL << left_cmp_type))
3189+
new_item= args[i]->propagate_equal_fields(thd,
3190+
Context(
3191+
ANY_SUBST,
3192+
cmp_collation.collation),
3193+
cond);
3194+
}
3195+
else if ((i % 2) == 0) // WHEN arguments
3196+
{
3197+
/*
3198+
These arguments are in comparison.
3199+
Allow invariants of the same value during propagation.
3200+
*/
3201+
new_item= args[i]->propagate_equal_fields(thd,
3202+
Context(
3203+
ANY_SUBST,
3204+
cmp_collation.collation),
3205+
cond);
3206+
}
3207+
else // THEN and ELSE arguments (they are not in comparison)
3208+
{
3209+
new_item= args[i]->propagate_equal_fields(thd, IDENTITY_SUBST, cond);
3210+
}
3211+
if (new_item && new_item != args[i])
3212+
thd->change_item_tree(&args[i], new_item);
3213+
}
3214+
return this;
3215+
}
3216+
3217+
31523218
uint Item_func_case::decimal_precision() const
31533219
{
31543220
int max_int_part=0;

0 commit comments

Comments
 (0)