Commit 213476ef authored by unknown's avatar unknown

Fix for bug lp:992405

The patch backports two patches from mysql 5.6:
- BUG#12640437: USING SQL_BUFFER_RESULT RESULTS IN A DIFFERENT QUERY OUTPUT
- Bug#12578908: SELECT SQL_BUFFER_RESULT OUTPUTS TOO MANY ROWS WHEN GROUP IS OPTIMIZED AWAY

Original comment:
-----------------
3714 Jorgen Loland	2012-03-01
      BUG#12640437 - USING SQL_BUFFER_RESULT RESULTS IN A DIFFERENT 
                     QUERY OUTPUT
      
      For all but simple grouped queries, temporary tables are used to
      resolve grouping. In these cases, the list of grouping fields is
      stored in the temporary table and grouping is resolved
      there (e.g. by adding a unique constraint on the involved
      fields). Because of this, grouping is already done when the rows
      are read from the temporary table.
      
      In the case where a group clause may be optimized away, grouping
      does not have to be resolved using a temporary table. However, if
      a temporary table is explicitly requested (e.g. because the
      SQL_BUFFER_RESULT hint is used, or the statement is
      INSERT...SELECT), a temporary table is used anyway. In this case,
      the temporary table is created with an empty group list (because
      the group clause was optimized away) and it will therefore not
      create groups. Since the temporary table does not take care of
      grouping, JOIN::group shall not be set to false in 
      make_simple_join(). This was fixed in bug 12578908. 
      
      However, there is an exception where make_simple_join() should
      set JOIN::group to false even if the query uses a temporary table
      that was explicitly requested but is not strictly needed. That
      exception is if the loose index scan access method (explain
      says "Using index for group-by") is used to read into the 
      temporary table. With loose index scan, grouping is resolved 
      by the access method. This is exactly what happens in this bug.
parent c9a73aa2
......@@ -2005,4 +2005,58 @@ zzz
8
#TODO: in merge with 5.3 add original test suite
drop table t1, t2;
#
# Bug#12578908: SELECT SQL_BUFFER_RESULT OUTPUTS TOO MANY
# ROWS WHEN GROUP IS OPTIMIZED AWAY
#
CREATE TABLE t1 (col1 int, col2 int) ;
INSERT INTO t1 VALUES (10,1),(11,7);
CREATE TABLE t2 (col1 int, col2 int) ;
INSERT INTO t2 VALUES (10,8);
EXPLAIN SELECT SQL_BUFFER_RESULT t2.col2 FROM t2 JOIN t1 ON t1.col1 GROUP BY t2.col2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 system NULL NULL NULL NULL 1 Using temporary
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
SELECT SQL_BUFFER_RESULT t2.col2 FROM t2 JOIN t1 ON t1.col1 GROUP BY t2.col2;
col2
8
EXPLAIN SELECT t2.col2 FROM t2 JOIN t1 ON t1.col1 GROUP BY t2.col2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 system NULL NULL NULL NULL 1
1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using where
SELECT t2.col2 FROM t2 JOIN t1 ON t1.col1 GROUP BY t2.col2;
col2
8
DROP TABLE t1,t2;
#
# BUG#12640437: USING SQL_BUFFER_RESULT RESULTS IN A
# DIFFERENT QUERY OUTPUT
#
CREATE TABLE t1 (
a int,
b varchar(1),
KEY (b,a)
);
INSERT INTO t1 VALUES (1,NULL),(0,'a');
EXPLAIN SELECT SQL_BUFFER_RESULT MIN(a), b FROM t1 WHERE t1.b = 'a' GROUP BY b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range b b 9 NULL 2 Using where; Using index for group-by; Using temporary
SELECT SQL_BUFFER_RESULT MIN(a), b FROM t1 WHERE t1.b = 'a' GROUP BY b;
MIN(a) b
0 a
EXPLAIN SELECT MIN(a), b FROM t1 WHERE t1.b = 'a' GROUP BY b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range b b 9 NULL 2 Using where; Using index for group-by
SELECT MIN(a), b FROM t1 WHERE t1.b = 'a' GROUP BY b;
MIN(a) b
0 a
DROP TABLE t1;
# End of 5.2 tests
......@@ -1372,5 +1372,57 @@ GROUP BY zzz;
drop table t1, t2;
--echo # End of 5.2 tests
--echo #
--echo # Bug#12578908: SELECT SQL_BUFFER_RESULT OUTPUTS TOO MANY
--echo # ROWS WHEN GROUP IS OPTIMIZED AWAY
--echo #
CREATE TABLE t1 (col1 int, col2 int) ;
INSERT INTO t1 VALUES (10,1),(11,7);
CREATE TABLE t2 (col1 int, col2 int) ;
INSERT INTO t2 VALUES (10,8);
let $q_body=t2.col2 FROM t2 JOIN t1 ON t1.col1 GROUP BY t2.col2;
--echo
--eval EXPLAIN SELECT SQL_BUFFER_RESULT $q_body
--eval SELECT SQL_BUFFER_RESULT $q_body
--echo
--eval EXPLAIN SELECT $q_body
--eval SELECT $q_body
--echo
DROP TABLE t1,t2;
--echo #
--echo # BUG#12640437: USING SQL_BUFFER_RESULT RESULTS IN A
--echo # DIFFERENT QUERY OUTPUT
--echo #
CREATE TABLE t1 (
a int,
b varchar(1),
KEY (b,a)
);
INSERT INTO t1 VALUES (1,NULL),(0,'a');
let $query=
SELECT SQL_BUFFER_RESULT MIN(a), b FROM t1 WHERE t1.b = 'a' GROUP BY b;
--echo
--eval EXPLAIN $query
--echo
--eval $query
let $query= SELECT MIN(a), b FROM t1 WHERE t1.b = 'a' GROUP BY b;
--echo
--eval EXPLAIN $query
--echo
--eval $query
--echo
DROP TABLE t1;
--echo # End of 5.2 tests
......@@ -1306,7 +1306,6 @@ JOIN::optimize()
simple_order=1;
select_distinct= 0; // No need in distinct for 1 row
group_optimized_away= 1;
implicit_grouping= TRUE;
}
calc_group_buffer(this, group_list);
......@@ -6072,7 +6071,31 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table)
tmp_table_param.copy_field= tmp_table_param.copy_field_end=0;
first_record= sort_and_group=0;
send_records= (ha_rows) 0;
group= 0;
if (group_optimized_away && !tmp_table_param.precomputed_group_by)
{
/*
If grouping has been optimized away, a temporary table is
normally not needed unless we're explicitly requested to create
one (e.g. due to a SQL_BUFFER_RESULT hint or INSERT ... SELECT).
In this case (grouping was optimized away), temp_table was
created without a grouping expression and JOIN::exec() will not
perform the necessary grouping (by the use of end_send_group()
or end_write_group()) if JOIN::group is set to false.
There is one exception: if the loose index scan access method is
used to read into the temporary table, grouping and aggregate
functions are handled.
*/
// the temporary table was explicitly requested
DBUG_ASSERT(test(select_options & OPTION_BUFFER_RESULT));
// the temporary table does not have a grouping expression
DBUG_ASSERT(!temp_table->group);
}
else
group= false;
row_limit= unit->select_limit_cnt;
do_send_rows= row_limit ? 1 : 0;
......
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