Commit a8cbfd38 authored by Igor Babaev's avatar Igor Babaev

Fixed LP bug #884175.

If in the where clause of the a query some comparison conditions on the
field under a MIN/MAX aggregate function contained constants whose sizes
exceeded the size of the field then the query could return a wrong result
when the optimizer had chosen to apply the MIN/MAX optimization.
With such conditions the MIN/MAX optimization still could be applied, yet
it would require a more thorough analysis of the keys built to find
the value of MIN/MAX aggregate functions with index look-ups.   
The current patch just prohibits using the MIN/MAX optimization in this
situation.
parent 2fe2a237
......@@ -1828,4 +1828,51 @@ NULL
NULL
DROP TABLE t1,t2,t3;
#
# Bug #884175: MIN/MAX for short varchar = long const
#
CREATE TABLE t1 (f1 varchar(1), f2 varchar(1), KEY (f2));
INSERT INTO t1 VALUES ('b', 'b'), ('a','a');
EXPLAIN
SELECT MAX(f1) FROM t1 WHERE f1 = 'abc';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
SELECT MAX(f1) FROM t1 WHERE f1 = 'abc';
MAX(f1)
NULL
EXPLAIN
SELECT MAX(f2) FROM t1 WHERE f2 = 'abc';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref f2 f2 4 const 1 Using where; Using index
SELECT MAX(f2) FROM t1 WHERE f2 = 'abc';
MAX(f2)
NULL
EXPLAIN
SELECT MIN(f1) FROM t1 WHERE f1 >= 'abc';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
SELECT MIN(f1) FROM t1 WHERE f1 >= 'abc';
MIN(f1)
b
EXPLAIN
SELECT MIN(f2) FROM t1 WHERE f2 >= 'abc';
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index f2 f2 4 NULL 2 Using where; Using index
SELECT MIN(f2) FROM t1 WHERE f2 >= 'abc';
MIN(f2)
b
EXPLAIN
SELECT MIN(f1) FROM t1 WHERE f1 BETWEEN 'abc' AND 'b' ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
SELECT MIN(f1) FROM t1 WHERE f1 BETWEEN 'abc' AND 'b' ;
MIN(f1)
b
EXPLAIN
SELECT MIN(f2) FROM t1 WHERE f2 BETWEEN 'abc' AND 'b' ;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index f2 f2 4 NULL 2 Using where; Using index
SELECT MIN(f2) FROM t1 WHERE f2 BETWEEN 'abc' AND 'b' ;
MIN(f2)
b
DROP TABLE t1;
End of 5.2 tests
......@@ -1194,4 +1194,37 @@ SELECT (SELECT MIN(t1.a) FROM t1,t2 WHERE t2.a = t3.b) FROM t3;
DROP TABLE t1,t2,t3;
--echo #
--echo # Bug #884175: MIN/MAX for short varchar = long const
--echo #
CREATE TABLE t1 (f1 varchar(1), f2 varchar(1), KEY (f2));
INSERT INTO t1 VALUES ('b', 'b'), ('a','a');
EXPLAIN
SELECT MAX(f1) FROM t1 WHERE f1 = 'abc';
SELECT MAX(f1) FROM t1 WHERE f1 = 'abc';
EXPLAIN
SELECT MAX(f2) FROM t1 WHERE f2 = 'abc';
SELECT MAX(f2) FROM t1 WHERE f2 = 'abc';
EXPLAIN
SELECT MIN(f1) FROM t1 WHERE f1 >= 'abc';
SELECT MIN(f1) FROM t1 WHERE f1 >= 'abc';
EXPLAIN
SELECT MIN(f2) FROM t1 WHERE f2 >= 'abc';
SELECT MIN(f2) FROM t1 WHERE f2 >= 'abc';
EXPLAIN
SELECT MIN(f1) FROM t1 WHERE f1 BETWEEN 'abc' AND 'b' ;
SELECT MIN(f1) FROM t1 WHERE f1 BETWEEN 'abc' AND 'b' ;
EXPLAIN
SELECT MIN(f2) FROM t1 WHERE f2 BETWEEN 'abc' AND 'b' ;
SELECT MIN(f2) FROM t1 WHERE f2 BETWEEN 'abc' AND 'b' ;
DROP TABLE t1;
--echo End of 5.2 tests
......@@ -469,8 +469,8 @@ int opt_sum_query(THD *thd,
'const op field'
@retval
0 func_item is a simple predicate: a field is compared with
constants
0 func_item is a simple predicate: a field is compared with a constant
whose length does not exceed the max length of the field values
@retval
1 Otherwise
*/
......@@ -490,6 +490,8 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
return 0;
if (!(args[1]= item_equal->get_const()))
return 0;
if (args[0]->max_length < args[1]->max_length)
return 0;
}
break;
case 1:
......@@ -521,6 +523,8 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
}
else
return 0;
if (args[0]->max_length < args[1]->max_length)
return 0;
break;
case 3:
/* field BETWEEN const AND const */
......@@ -534,6 +538,8 @@ bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
if (!item->const_item())
return 0;
args[i]= item;
if (args[0]->max_length < args[i]->max_length)
return 0;
}
}
else
......
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