diff options
author | Igor Babaev <igor@askmonty.org> | 2016-11-21 10:33:06 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2016-11-21 10:33:39 -0800 |
commit | 665045f985787d77318a17ccddd67ec3ff92f7bc (patch) | |
tree | 9c5680ffaae3c4a6d35abac1418c0f99105e9eb1 /mysql-test | |
parent | 022aeda4c01a1be47abdfe90a59df2dc0b72828d (diff) | |
download | mariadb-git-665045f985787d77318a17ccddd67ec3ff92f7bc.tar.gz |
Fixed bug mdev-11081.
The idea of this fix was taken from the patch by Roy Lyseng
for mysql-5.6 bug iBug#14740889: "Wrong result for aggregate
functions when executing query through cursor".
Here's Roy's comment for his patch:
"
The problem was that a grouped query did not behave properly when
executed using a cursor. On further inspection, the query used one
intermediate temporary table for the grouping.
Then, Select_materialize::send_result_set_metadata created a temporary
table for storing the query result. Notice that get_unit_column_types()
is used to retrieve column meta-data for the query. The items contained
in this list are later modified so that their result_field points to
the row buffer of the materialized temporary table for the cursor.
But prior to this, these result_field objects have been prepared for
use in the grouping operation, by JOIN::make_tmp_tables_info(), hence
the grouping operation operates on wrong column buffers.
The problem is solved by using the list JOIN::fields when copying data
to the materialized table. This list is set by JOIN::make_tmp_tables_info()
and points to the columns of the last intermediate temporary table of
the executed query. For a UNION, it points to the temporary table
that is the result of the UNION query.
Notice that we have to assign a value to ::fields early in JOIN::optimize()
in case the optimization shortcuts due to a const plan detection.
A more optimal solution might be to avoid creating the final temporary
table when the query result is already stored in a temporary table.
"
The patch does not contain a test case, but the description of the
problem corresponds exactly what could be observed in the test
case for mdev-11081.
Diffstat (limited to 'mysql-test')
-rw-r--r-- | mysql-test/r/sp.result | 39 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 38 |
2 files changed, 77 insertions, 0 deletions
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 130e789d3eb..aca9458f124 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -8001,3 +8001,42 @@ return 1; end | ERROR 0A000: Not allowed to return a result set from a function drop table t1,t2; +# +# MDEV-11081: CURSOR for query with GROUP BY +# +CREATE TABLE t1 (name VARCHAR(10), value INT); +INSERT INTO t1 VALUES ('b',1); +INSERT INTO t1 VALUES ('b',1); +INSERT INTO t1 VALUES ('c',1); +INSERT INTO t1 VALUES ('a',1); +INSERT INTO t1 VALUES ('a',1); +INSERT INTO t1 VALUES ('a',1); +CREATE PROCEDURE p1 () +BEGIN +DECLARE done INT DEFAULT FALSE; +DECLARE v_name VARCHAR(10); +DECLARE v_total INT; +DECLARE c CURSOR FOR +SELECT name, SUM(value) AS total FROM t1 GROUP BY name; +DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; +OPEN c; +read_loop: +LOOP +FETCH c INTO v_name, v_total; +IF done THEN +LEAVE read_loop; +END IF; +SELECT v_name, v_total; +END LOOP; +CLOSE c; +END; +| +CALL p1(); +v_name v_total +a 3 +v_name v_total +b 2 +v_name v_total +c 1 +DROP PROCEDURE p1; +DROP TABLE t1; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index c80e1eaaa3e..aaab59bcb89 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -9446,3 +9446,41 @@ end | --delimiter ; drop table t1,t2; + +--echo # +--echo # MDEV-11081: CURSOR for query with GROUP BY +--echo # + +CREATE TABLE t1 (name VARCHAR(10), value INT); +INSERT INTO t1 VALUES ('b',1); +INSERT INTO t1 VALUES ('b',1); +INSERT INTO t1 VALUES ('c',1); +INSERT INTO t1 VALUES ('a',1); +INSERT INTO t1 VALUES ('a',1); +INSERT INTO t1 VALUES ('a',1); +DELIMITER |; +CREATE PROCEDURE p1 () +BEGIN + DECLARE done INT DEFAULT FALSE; + DECLARE v_name VARCHAR(10); + DECLARE v_total INT; + DECLARE c CURSOR FOR + SELECT name, SUM(value) AS total FROM t1 GROUP BY name; + DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; + OPEN c; +read_loop: + LOOP + FETCH c INTO v_name, v_total; + IF done THEN + LEAVE read_loop; + END IF; + SELECT v_name, v_total; + END LOOP; + CLOSE c; +END; +| +DELIMITER ;| +CALL p1(); +DROP PROCEDURE p1; +DROP TABLE t1; + |