Commit 6863f7dc authored by Martin Hansson's avatar Martin Hansson

Bug#47650: using group by with rollup without indexes

returns incorrect results with where

An outer join of a const table (outer) and a normal table
(inner) with GROUP BY on a field from the outer table would
optimize away GROUP BY, and thus trigger the optimization to
do away with a temporary table if grouping was performed on
columns from the const table, hence executing the query with
filesort without temporary table. But this should not be
done if there is a non-indexed access to the inner table,
since filesort does not handle joins. It expects either ref
access, range ditto or table scan. The join condition will
thus not be applied.

Fixed by always forcing execution with temporary table in
the case of ROLLUP with a query involving an outer join. This
is a slightly broader class of queries than need fixing, but
it is hard to ascertain the position of a ROLLUP field wrt
outer join with current query representation.

mysql-test/r/join_outer.result:
  Bug#47650: Test result
mysql-test/t/join_outer.test:
  Bug#47650: Test case
sql/sql_select.cc:
  Bug#47650: Fix
parent 4621d480
......@@ -1254,3 +1254,38 @@ SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WHERE c=1 AND d<=>NULL;
c e d
1 0 NULL
DROP TABLE t1,t2;
#
# Bug#47650: using group by with rollup without indexes returns incorrect
# results with where
#
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1);
CREATE TABLE t2 ( a INT, b INT );
INSERT INTO t2 VALUES (1, 1),(1, 2),(1, 3),(2, 4),(2, 5);
EXPLAIN
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 LEFT JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary; Using filesort
1 SIMPLE t2 ALL NULL NULL NULL NULL 5
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 LEFT JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP;
a COUNT( t2.b ) SUM( t2.b ) MAX( t2.b )
1 3 6 3
NULL 3 6 3
EXPLAIN
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 system NULL NULL NULL NULL 1 Using filesort
1 SIMPLE t2 ALL NULL NULL NULL NULL 5 Using where
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP;
a COUNT( t2.b ) SUM( t2.b ) MAX( t2.b )
1 3 6 3
NULL 3 6 3
DROP TABLE t1, t2;
......@@ -867,3 +867,32 @@ SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WHERE c=1 AND d<=>NULL;
DROP TABLE t1,t2;
--echo #
--echo # Bug#47650: using group by with rollup without indexes returns incorrect
--echo # results with where
--echo #
CREATE TABLE t1 ( a INT );
INSERT INTO t1 VALUES (1);
CREATE TABLE t2 ( a INT, b INT );
INSERT INTO t2 VALUES (1, 1),(1, 2),(1, 3),(2, 4),(2, 5);
EXPLAIN
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 LEFT JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP;
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 LEFT JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP;
EXPLAIN
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP;
SELECT t1.a, COUNT( t2.b ), SUM( t2.b ), MAX( t2.b )
FROM t1 JOIN t2 USING( a )
GROUP BY t1.a WITH ROLLUP;
DROP TABLE t1, t2;
......@@ -7124,7 +7124,19 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond,
for (order=first_order; order ; order=order->next)
{
table_map order_tables=order->item[0]->used_tables();
if (order->item[0]->with_sum_func)
if (order->item[0]->with_sum_func ||
/*
If the outer table of an outer join is const (either by itself or
after applying WHERE condition), grouping on a field from such a
table will be optimized away and filesort without temporary table
will be used unless we prevent that now. Filesort is not fit to
handle joins and the join condition is not applied. We can't detect
the case without an expensive test, however, so we force temporary
table for all queries containing more than one table, ROLLUP, and an
outer join.
*/
(join->tables > 1 && join->rollup.state == ROLLUP::STATE_INITED &&
join->outer_join))
*simple_order=0; // Must do a temp table to sort
else if (!(order_tables & not_const_tables))
{
......
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