mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 19:11:46 +01:00
Merge from mysql-next-mr.
This commit is contained in:
commit
03d124c036
14 changed files with 1620 additions and 882 deletions
|
@ -5085,7 +5085,6 @@ sub valgrind_arguments {
|
|||
else
|
||||
{
|
||||
mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option
|
||||
mtr_add_arg($args, "--alignment=8");
|
||||
mtr_add_arg($args, "--leak-check=yes");
|
||||
mtr_add_arg($args, "--num-callers=16");
|
||||
mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)
|
||||
|
|
|
@ -5,7 +5,7 @@ count(distinct n)
|
|||
100
|
||||
explain extended select count(distinct n) from t1;
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t1 index NULL n 4 NULL 200 100.00 Using index
|
||||
1 SIMPLE t1 range NULL n 4 NULL 10 100.00 Using index for group-by
|
||||
Warnings:
|
||||
Note 1003 select count(distinct `test`.`t1`.`n`) AS `count(distinct n)` from `test`.`t1`
|
||||
drop table t1;
|
||||
|
|
|
@ -1800,23 +1800,23 @@ b
|
|||
a
|
||||
explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index
|
||||
1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
|
||||
explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index
|
||||
1 SIMPLE t1 range NULL idx_t1_1 163 NULL 65 Using where; Using index for group-by (scanning)
|
||||
explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 128 75.00 Using where; Using index
|
||||
1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 100.00 Using where; Using index for group-by
|
||||
Warnings:
|
||||
Note 1003 select count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`) AS `count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`b` = 'c') and (`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a'))
|
||||
explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index
|
||||
explain extended select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
|
||||
explain extended select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 128 75.00 Using where; Using index
|
||||
1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 100.00 Using where; Using index for group-by
|
||||
Warnings:
|
||||
Note 1003 select (ord(`test`.`t1`.`a1`) + count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`)) AS `ord(a1) + count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a'))
|
||||
Note 1003 select (98 + count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`)) AS `98 + count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a'))
|
||||
select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||
count(distinct a1,a2,b)
|
||||
4
|
||||
|
@ -1829,8 +1829,8 @@ count(distinct a1,a2,b)
|
|||
select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||
count(distinct b)
|
||||
1
|
||||
select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
|
||||
ord(a1) + count(distinct a1,a2,b)
|
||||
select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
|
||||
98 + count(distinct a1,a2,b)
|
||||
104
|
||||
explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
|
@ -2514,3 +2514,257 @@ a MAX(b)
|
|||
2 1
|
||||
DROP TABLE t;
|
||||
End of 5.1 tests
|
||||
#
|
||||
# WL#3220 (Loose index scan for COUNT DISTINCT)
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b INT, c INT, KEY (a,b));
|
||||
INSERT INTO t1 VALUES (1,1,1), (1,2,1), (1,3,1), (1,4,1);
|
||||
INSERT INTO t1 SELECT a, b + 4, 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 1, b, 1 FROM t1;
|
||||
CREATE TABLE t2 (a INT, b INT, c INT, d INT, e INT, f INT, KEY (a,b,c));
|
||||
INSERT INTO t2 VALUES (1,1,1,1,1,1), (1,2,1,1,1,1), (1,3,1,1,1,1),
|
||||
(1,4,1,1,1,1);
|
||||
INSERT INTO t2 SELECT a, b + 4, c,d,e,f FROM t2;
|
||||
INSERT INTO t2 SELECT a + 1, b, c,d,e,f FROM t2;
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT a) FROM t1;
|
||||
COUNT(DISTINCT a)
|
||||
2
|
||||
EXPLAIN SELECT COUNT(DISTINCT a,b) FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT a,b) FROM t1;
|
||||
COUNT(DISTINCT a,b)
|
||||
16
|
||||
EXPLAIN SELECT COUNT(DISTINCT b,a) FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT b,a) FROM t1;
|
||||
COUNT(DISTINCT b,a)
|
||||
16
|
||||
EXPLAIN SELECT COUNT(DISTINCT b) FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL a 10 NULL 16 Using index
|
||||
SELECT COUNT(DISTINCT b) FROM t1;
|
||||
COUNT(DISTINCT b)
|
||||
8
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a;
|
||||
COUNT(DISTINCT a)
|
||||
1
|
||||
1
|
||||
EXPLAIN SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
|
||||
COUNT(DISTINCT b)
|
||||
8
|
||||
8
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL a 10 NULL 16 Using index; Using filesort
|
||||
SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b;
|
||||
COUNT(DISTINCT a)
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
2
|
||||
EXPLAIN SELECT DISTINCT COUNT(DISTINCT a) FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL a 10 NULL 16 Using index
|
||||
SELECT DISTINCT COUNT(DISTINCT a) FROM t1;
|
||||
COUNT(DISTINCT a)
|
||||
2
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b + 0) FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL a 10 NULL 16 Using index
|
||||
SELECT COUNT(DISTINCT a, b + 0) FROM t1;
|
||||
COUNT(DISTINCT a, b + 0)
|
||||
16
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10;
|
||||
COUNT(DISTINCT a)
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL NULL NULL NULL NULL 16
|
||||
SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10;
|
||||
COUNT(DISTINCT a)
|
||||
2
|
||||
EXPLAIN SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by
|
||||
SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10;
|
||||
1
|
||||
1
|
||||
EXPLAIN SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
|
||||
SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1;
|
||||
1
|
||||
1
|
||||
1
|
||||
EXPLAIN SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1_1 index NULL a 10 NULL 16 Using index; Using temporary; Using filesort
|
||||
1 SIMPLE t1_2 index NULL a 10 NULL 16 Using index; Using join buffer
|
||||
SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a;
|
||||
COUNT(DISTINCT t1_1.a)
|
||||
1
|
||||
1
|
||||
EXPLAIN SELECT COUNT(DISTINCT a), 12 FROM t1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT a), 12 FROM t1;
|
||||
COUNT(DISTINCT a) 12
|
||||
2 12
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b, c) FROM t2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT a, b, c) FROM t2;
|
||||
COUNT(DISTINCT a, b, c)
|
||||
16
|
||||
EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2;
|
||||
COUNT(DISTINCT a) SUM(DISTINCT a) AVG(DISTINCT a)
|
||||
2 3 1.5000
|
||||
EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 16
|
||||
SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2;
|
||||
COUNT(DISTINCT a) SUM(DISTINCT a) AVG(DISTINCT f)
|
||||
2 3 1.0000
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2;
|
||||
COUNT(DISTINCT a, b) COUNT(DISTINCT b, a)
|
||||
16 16
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 16
|
||||
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2;
|
||||
COUNT(DISTINCT a, b) COUNT(DISTINCT b, f)
|
||||
16 8
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 16
|
||||
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2;
|
||||
COUNT(DISTINCT a, b) COUNT(DISTINCT b, d)
|
||||
16 8
|
||||
EXPLAIN SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by
|
||||
SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c;
|
||||
a c COUNT(DISTINCT c, a, b)
|
||||
1 1 1
|
||||
1 1 1
|
||||
1 1 1
|
||||
1 1 1
|
||||
1 1 1
|
||||
1 1 1
|
||||
1 1 1
|
||||
2 1 1
|
||||
2 1 1
|
||||
2 1 1
|
||||
2 1 1
|
||||
2 1 1
|
||||
2 1 1
|
||||
2 1 1
|
||||
2 1 1
|
||||
2 1 1
|
||||
EXPLAIN SELECT COUNT(DISTINCT c, a, b) FROM t2
|
||||
WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range a a 15 NULL 1 Using where; Using index for group-by
|
||||
SELECT COUNT(DISTINCT c, a, b) FROM t2
|
||||
WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c;
|
||||
COUNT(DISTINCT c, a, b)
|
||||
EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5
|
||||
GROUP BY b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ref a a 5 const 1 Using where; Using index
|
||||
SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5
|
||||
GROUP BY b;
|
||||
COUNT(DISTINCT b) SUM(DISTINCT b)
|
||||
EXPLAIN SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by
|
||||
SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
|
||||
a COUNT(DISTINCT b) SUM(DISTINCT b)
|
||||
2 8 36
|
||||
2 8 36
|
||||
EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by
|
||||
SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
|
||||
COUNT(DISTINCT b) SUM(DISTINCT b)
|
||||
8 36
|
||||
8 36
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 16 Using where
|
||||
SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42;
|
||||
COUNT(DISTINCT a, b)
|
||||
0
|
||||
EXPLAIN SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2
|
||||
WHERE b = 13 AND c = 42 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 15 NULL 9 Using where; Using index for group-by
|
||||
SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2
|
||||
WHERE b = 13 AND c = 42 GROUP BY a;
|
||||
a COUNT(DISTINCT a) SUM(DISTINCT a)
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 10 NULL 9 Using where; Using index for group-by
|
||||
SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42;
|
||||
COUNT(DISTINCT a, b) SUM(DISTINCT a)
|
||||
0 NULL
|
||||
EXPLAIN SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by
|
||||
SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a;
|
||||
SUM(DISTINCT a) MAX(b)
|
||||
1 8
|
||||
2 8
|
||||
EXPLAIN SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by
|
||||
SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c;
|
||||
42 * (a + c + COUNT(DISTINCT c, a, b))
|
||||
126
|
||||
126
|
||||
126
|
||||
126
|
||||
126
|
||||
126
|
||||
126
|
||||
168
|
||||
168
|
||||
168
|
||||
168
|
||||
168
|
||||
168
|
||||
168
|
||||
168
|
||||
168
|
||||
EXPLAIN SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by
|
||||
SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a;
|
||||
(SUM(DISTINCT a) + MAX(b))
|
||||
9
|
||||
10
|
||||
DROP TABLE t1,t2;
|
||||
# end of WL#3220 tests
|
||||
|
|
|
@ -570,13 +570,13 @@ explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
|
|||
explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
|
||||
explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
|
||||
explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||
explain extended select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
|
||||
explain extended select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
|
||||
|
||||
select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||
select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
|
||||
select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
|
||||
select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||
select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
|
||||
select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
|
||||
|
||||
#
|
||||
# Queries with expressions in the select clause
|
||||
|
@ -1033,3 +1033,124 @@ SELECT a, MAX(b) FROM t WHERE b GROUP BY a;
|
|||
DROP TABLE t;
|
||||
|
||||
--echo End of 5.1 tests
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # WL#3220 (Loose index scan for COUNT DISTINCT)
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT, b INT, c INT, KEY (a,b));
|
||||
INSERT INTO t1 VALUES (1,1,1), (1,2,1), (1,3,1), (1,4,1);
|
||||
INSERT INTO t1 SELECT a, b + 4, 1 FROM t1;
|
||||
INSERT INTO t1 SELECT a + 1, b, 1 FROM t1;
|
||||
CREATE TABLE t2 (a INT, b INT, c INT, d INT, e INT, f INT, KEY (a,b,c));
|
||||
INSERT INTO t2 VALUES (1,1,1,1,1,1), (1,2,1,1,1,1), (1,3,1,1,1,1),
|
||||
(1,4,1,1,1,1);
|
||||
INSERT INTO t2 SELECT a, b + 4, c,d,e,f FROM t2;
|
||||
INSERT INTO t2 SELECT a + 1, b, c,d,e,f FROM t2;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1;
|
||||
SELECT COUNT(DISTINCT a) FROM t1;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a,b) FROM t1;
|
||||
SELECT COUNT(DISTINCT a,b) FROM t1;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT b,a) FROM t1;
|
||||
SELECT COUNT(DISTINCT b,a) FROM t1;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT b) FROM t1;
|
||||
SELECT COUNT(DISTINCT b) FROM t1;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a;
|
||||
SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
|
||||
SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b;
|
||||
SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b;
|
||||
|
||||
EXPLAIN SELECT DISTINCT COUNT(DISTINCT a) FROM t1;
|
||||
SELECT DISTINCT COUNT(DISTINCT a) FROM t1;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b + 0) FROM t1;
|
||||
SELECT COUNT(DISTINCT a, b + 0) FROM t1;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10;
|
||||
SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10;
|
||||
SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10;
|
||||
|
||||
EXPLAIN SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10;
|
||||
SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10;
|
||||
|
||||
EXPLAIN SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1;
|
||||
SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a;
|
||||
SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a), 12 FROM t1;
|
||||
SELECT COUNT(DISTINCT a), 12 FROM t1;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b, c) FROM t2;
|
||||
SELECT COUNT(DISTINCT a, b, c) FROM t2;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2;
|
||||
SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2;
|
||||
SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2;
|
||||
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2;
|
||||
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2;
|
||||
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2;
|
||||
|
||||
EXPLAIN SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c;
|
||||
SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT c, a, b) FROM t2
|
||||
WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c;
|
||||
SELECT COUNT(DISTINCT c, a, b) FROM t2
|
||||
WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5
|
||||
GROUP BY b;
|
||||
SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5
|
||||
GROUP BY b;
|
||||
|
||||
EXPLAIN SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
|
||||
SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
|
||||
SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42;
|
||||
SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42;
|
||||
|
||||
EXPLAIN SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2
|
||||
WHERE b = 13 AND c = 42 GROUP BY a;
|
||||
SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2
|
||||
WHERE b = 13 AND c = 42 GROUP BY a;
|
||||
|
||||
EXPLAIN SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42;
|
||||
SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42;
|
||||
|
||||
EXPLAIN SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a;
|
||||
SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a;
|
||||
|
||||
EXPLAIN SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c;
|
||||
SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c;
|
||||
|
||||
EXPLAIN SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a;
|
||||
SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a;
|
||||
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
--echo # end of WL#3220 tests
|
||||
|
|
|
@ -1934,9 +1934,12 @@ public:
|
|||
virtual bool str_needs_quotes() { return TRUE; }
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
int cmp(const uchar *a, const uchar *b)
|
||||
{
|
||||
DBUG_ASSERT(ptr == a);
|
||||
return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len));
|
||||
{
|
||||
DBUG_ASSERT(ptr == a || ptr == b);
|
||||
if (ptr == a)
|
||||
return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len));
|
||||
else
|
||||
return Field_bit::key_cmp(a, bytes_in_rec+test(bit_len)) * -1;
|
||||
}
|
||||
int cmp_binary_offset(uint row_offset)
|
||||
{ return cmp_offset(row_offset); }
|
||||
|
|
1201
sql/item_sum.cc
1201
sql/item_sum.cc
File diff suppressed because it is too large
Load diff
535
sql/item_sum.h
535
sql/item_sum.h
|
@ -22,7 +22,87 @@
|
|||
|
||||
#include <my_tree.h>
|
||||
|
||||
/*
|
||||
class Item_sum;
|
||||
class Aggregator_distinct;
|
||||
class Aggregator_simple;
|
||||
|
||||
/**
|
||||
The abstract base class for the Aggregator_* classes.
|
||||
It implements the data collection functions (setup/add/clear)
|
||||
as either pass-through to the real functionality or
|
||||
as collectors into an Unique (for distinct) structure.
|
||||
|
||||
Note that update_field/reset_field are not in that
|
||||
class, because they're simply not called when
|
||||
GROUP BY/DISTINCT can be handled with help of index on grouped
|
||||
fields (quick_group = 0);
|
||||
*/
|
||||
|
||||
class Aggregator : public Sql_alloc
|
||||
{
|
||||
friend class Item_sum;
|
||||
friend class Item_sum_sum;
|
||||
friend class Item_sum_count;
|
||||
friend class Item_sum_avg;
|
||||
|
||||
/*
|
||||
All members are protected as this class is not usable outside of an
|
||||
Item_sum descendant.
|
||||
*/
|
||||
protected:
|
||||
/* the aggregate function class to act on */
|
||||
Item_sum *item_sum;
|
||||
|
||||
/**
|
||||
When feeding back the data in endup() from Unique/temp table back to
|
||||
Item_sum::add() methods we must read the data from Unique (and not
|
||||
recalculate the functions that are given as arguments to the aggregate
|
||||
function.
|
||||
This flag is to tell the add() methods to take the data from the Unique
|
||||
instead by calling the relevant val_..() method
|
||||
*/
|
||||
|
||||
bool use_distinct_values;
|
||||
|
||||
public:
|
||||
Aggregator (Item_sum *arg): item_sum(arg), use_distinct_values(FALSE) {}
|
||||
virtual ~Aggregator () {} /* Keep gcc happy */
|
||||
|
||||
enum Aggregator_type { SIMPLE_AGGREGATOR, DISTINCT_AGGREGATOR };
|
||||
virtual Aggregator_type Aggrtype() = 0;
|
||||
|
||||
/**
|
||||
Called before adding the first row.
|
||||
Allocates and sets up the internal aggregation structures used,
|
||||
e.g. the Unique instance used to calculate distinct.
|
||||
*/
|
||||
virtual bool setup(THD *) = 0;
|
||||
|
||||
/**
|
||||
Called when we need to wipe out all the data from the aggregator :
|
||||
all the values acumulated and all the state.
|
||||
Cleans up the internal structures and resets them to their initial state.
|
||||
*/
|
||||
virtual void clear() = 0;
|
||||
|
||||
/**
|
||||
Called when there's a new value to be aggregated.
|
||||
Updates the internal state of the aggregator to reflect the new value.
|
||||
*/
|
||||
virtual bool add() = 0;
|
||||
|
||||
/**
|
||||
Called when there are no more data and the final value is to be retrieved.
|
||||
Finalises the state of the aggregator, so the final result can be retrieved.
|
||||
*/
|
||||
virtual void endup() = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class st_select_lex;
|
||||
|
||||
/**
|
||||
Class Item_sum is the base class used for special expressions that SQL calls
|
||||
'set functions'. These expressions are formed with the help of aggregate
|
||||
functions such as SUM, MAX, GROUP_CONCAT etc.
|
||||
|
@ -215,13 +295,32 @@
|
|||
TODO: to catch queries where the limit is exceeded to make the
|
||||
code clean here.
|
||||
|
||||
*/
|
||||
|
||||
class st_select_lex;
|
||||
*/
|
||||
|
||||
class Item_sum :public Item_result_field
|
||||
{
|
||||
public:
|
||||
/**
|
||||
Aggregator class instance. Not set initially. Allocated only after
|
||||
it is determined if the incoming data are already distinct.
|
||||
*/
|
||||
Aggregator *aggr;
|
||||
|
||||
/**
|
||||
Used in making ROLLUP. Set for the ROLLUP copies of the original
|
||||
Item_sum and passed to create_tmp_field() to cause it to work
|
||||
over the temp table buffer that is referenced by
|
||||
Item_result_field::result_field.
|
||||
*/
|
||||
bool force_copy_fields;
|
||||
|
||||
/**
|
||||
Indicates how the aggregate function was specified by the parser :
|
||||
1 if it was written as AGGREGATE(DISTINCT),
|
||||
0 if it was AGGREGATE()
|
||||
*/
|
||||
bool with_distinct;
|
||||
|
||||
enum Sumfunctype
|
||||
{ COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
|
||||
AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC,
|
||||
|
@ -263,47 +362,28 @@ public:
|
|||
Item_sum() :quick_group(1), arg_count(0), forced_const(FALSE)
|
||||
{
|
||||
mark_as_sum_func();
|
||||
init_aggregator();
|
||||
}
|
||||
Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args),
|
||||
orig_args(tmp_orig_args), forced_const(FALSE)
|
||||
{
|
||||
args[0]=a;
|
||||
mark_as_sum_func();
|
||||
init_aggregator();
|
||||
}
|
||||
Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args),
|
||||
orig_args(tmp_orig_args), forced_const(FALSE)
|
||||
{
|
||||
args[0]=a; args[1]=b;
|
||||
mark_as_sum_func();
|
||||
init_aggregator();
|
||||
}
|
||||
Item_sum(List<Item> &list);
|
||||
//Copy constructor, need to perform subselects with temporary tables
|
||||
Item_sum(THD *thd, Item_sum *item);
|
||||
enum Type type() const { return SUM_FUNC_ITEM; }
|
||||
virtual enum Sumfunctype sum_func () const=0;
|
||||
|
||||
/*
|
||||
This method is similar to add(), but it is called when the current
|
||||
aggregation group changes. Thus it performs a combination of
|
||||
clear() and add().
|
||||
*/
|
||||
inline bool reset() { clear(); return add(); };
|
||||
|
||||
/*
|
||||
Prepare this item for evaluation of an aggregate value. This is
|
||||
called by reset() when a group changes, or, for correlated
|
||||
subqueries, between subquery executions. E.g. for COUNT(), this
|
||||
method should set count= 0;
|
||||
*/
|
||||
virtual void clear()= 0;
|
||||
|
||||
/*
|
||||
This method is called for the next row in the same group. Its
|
||||
purpose is to aggregate the new value to the previous values in
|
||||
the group (i.e. since clear() was called last time). For example,
|
||||
for COUNT(), do count++.
|
||||
*/
|
||||
virtual bool add()=0;
|
||||
inline bool reset() { aggregator_clear(); return aggregator_add(); };
|
||||
|
||||
/*
|
||||
Called when new group is started and results are being saved in
|
||||
|
@ -343,11 +423,6 @@ public:
|
|||
{ return new Item_field(field); }
|
||||
table_map used_tables() const { return used_tables_cache; }
|
||||
void update_used_tables ();
|
||||
void cleanup()
|
||||
{
|
||||
Item::cleanup();
|
||||
forced_const= FALSE;
|
||||
}
|
||||
bool is_null() { return null_value; }
|
||||
void make_const ()
|
||||
{
|
||||
|
@ -359,7 +434,9 @@ public:
|
|||
virtual void print(String *str, enum_query_type query_type);
|
||||
void fix_num_length_and_dec();
|
||||
|
||||
/*
|
||||
/**
|
||||
Mark an aggregate as having no rows.
|
||||
|
||||
This function is called by the execution engine to assign 'NO ROWS
|
||||
FOUND' value to an aggregate item, when the underlying result set
|
||||
has no rows. Such value, in a general case, may be different from
|
||||
|
@ -367,10 +444,15 @@ public:
|
|||
may be initialized to 0 by clear() and to NULL by
|
||||
no_rows_in_result().
|
||||
*/
|
||||
void no_rows_in_result() { clear(); }
|
||||
|
||||
virtual bool setup(THD *thd) {return 0;}
|
||||
virtual void make_unique() {}
|
||||
void no_rows_in_result()
|
||||
{
|
||||
if (!aggr)
|
||||
set_aggregator(with_distinct ?
|
||||
Aggregator::DISTINCT_AGGREGATOR :
|
||||
Aggregator::SIMPLE_AGGREGATOR);
|
||||
reset();
|
||||
}
|
||||
virtual void make_unique() { force_copy_fields= TRUE; }
|
||||
Item *get_tmp_table_item(THD *thd);
|
||||
virtual Field *create_tmp_field(bool group, TABLE *table,
|
||||
uint convert_blob_length);
|
||||
|
@ -381,14 +463,178 @@ public:
|
|||
st_select_lex *depended_from()
|
||||
{ return (nest_level == aggr_level ? 0 : aggr_sel); }
|
||||
|
||||
Item *get_arg(int i) { return args[i]; }
|
||||
Item *set_arg(int i, THD *thd, Item *new_val);
|
||||
Item *get_arg(uint i) { return args[i]; }
|
||||
Item *set_arg(uint i, THD *thd, Item *new_val);
|
||||
uint get_arg_count() { return arg_count; }
|
||||
|
||||
/* Initialization of distinct related members */
|
||||
void init_aggregator()
|
||||
{
|
||||
aggr= NULL;
|
||||
with_distinct= FALSE;
|
||||
force_copy_fields= FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
Called to initialize the aggregator.
|
||||
*/
|
||||
|
||||
inline bool aggregator_setup(THD *thd) { return aggr->setup(thd); };
|
||||
|
||||
/**
|
||||
Called to cleanup the aggregator.
|
||||
*/
|
||||
|
||||
inline void aggregator_clear() { aggr->clear(); }
|
||||
|
||||
/**
|
||||
Called to add value to the aggregator.
|
||||
*/
|
||||
|
||||
inline bool aggregator_add() { return aggr->add(); };
|
||||
|
||||
/* stores the declared DISTINCT flag (from the parser) */
|
||||
void set_distinct(bool distinct)
|
||||
{
|
||||
with_distinct= distinct;
|
||||
quick_group= with_distinct ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Set the type of aggregation : DISTINCT or not.
|
||||
|
||||
Called when the final determination is done about the aggregation
|
||||
type and the object is about to be used.
|
||||
*/
|
||||
|
||||
int set_aggregator(Aggregator::Aggregator_type aggregator);
|
||||
virtual void clear()= 0;
|
||||
virtual bool add()= 0;
|
||||
virtual bool setup(THD *thd) {return 0;}
|
||||
|
||||
void cleanup ();
|
||||
};
|
||||
|
||||
|
||||
class Unique;
|
||||
|
||||
|
||||
/**
|
||||
The distinct aggregator.
|
||||
Implements AGGFN (DISTINCT ..)
|
||||
Collects all the data into an Unique (similarly to what Item_sum_distinct
|
||||
does currently) and then (if applicable) iterates over the list of
|
||||
unique values and pumps them back into its object
|
||||
*/
|
||||
|
||||
class Aggregator_distinct : public Aggregator
|
||||
{
|
||||
friend class Item_sum_sum;
|
||||
friend class Item_sum_count;
|
||||
friend class Item_sum_avg;
|
||||
protected:
|
||||
|
||||
/*
|
||||
flag to prevent consecutive runs of endup(). Normally in endup there are
|
||||
expensive calculations (like walking the distinct tree for example)
|
||||
which we must do only once if there are no data changes.
|
||||
We can re-use the data for the second and subsequent val_xxx() calls.
|
||||
endup_done set to TRUE also means that the calculated values for
|
||||
the aggregate functions are correct and don't need recalculation.
|
||||
*/
|
||||
bool endup_done;
|
||||
|
||||
/*
|
||||
Used depending on the type of the aggregate function and the presence of
|
||||
blob columns in it:
|
||||
- For COUNT(DISTINCT) and no blob fields this points to a real temporary
|
||||
table. It's used as a hash table.
|
||||
- For AVG/SUM(DISTINCT) or COUNT(DISTINCT) with blob fields only the
|
||||
in-memory data structure of a temporary table is constructed.
|
||||
It's used by the Field classes to transform data into row format.
|
||||
*/
|
||||
TABLE *table;
|
||||
|
||||
/*
|
||||
An array of field lengths on row allocated and used only for
|
||||
COUNT(DISTINCT) with multiple columns and no blobs. Used in
|
||||
Aggregator_distinct::composite_key_cmp (called from Unique to compare
|
||||
nodes
|
||||
*/
|
||||
uint32 *field_lengths;
|
||||
|
||||
/*
|
||||
used in conjunction with 'table' to support the access to Field classes
|
||||
for COUNT(DISTINCT). Needed by copy_fields()/copy_funcs().
|
||||
*/
|
||||
TMP_TABLE_PARAM *tmp_table_param;
|
||||
|
||||
/*
|
||||
If there are no blobs in the COUNT(DISTINCT) arguments, we can use a tree,
|
||||
which is faster than heap table. In that case, we still use the table
|
||||
to help get things set up, but we insert nothing in it.
|
||||
For AVG/SUM(DISTINCT) we always use this tree (as it takes a single
|
||||
argument) to get the distinct rows.
|
||||
*/
|
||||
Unique *tree;
|
||||
|
||||
/*
|
||||
The length of the temp table row. Must be a member of the class as it
|
||||
gets passed down to simple_raw_key_cmp () as a compare function argument
|
||||
to Unique. simple_raw_key_cmp () is used as a fast comparison function
|
||||
when the entire row can be binary compared.
|
||||
*/
|
||||
uint tree_key_length;
|
||||
|
||||
/*
|
||||
Set to true if the result is known to be always NULL.
|
||||
If set deactivates creation and usage of the temporary table (in the
|
||||
'table' member) and the Unique instance (in the 'tree' member) as well as
|
||||
the calculation of the final value on the first call to
|
||||
Item_[sum|avg|count]::val_xxx().
|
||||
*/
|
||||
bool always_null;
|
||||
|
||||
public:
|
||||
Aggregator_distinct (Item_sum *sum) :
|
||||
Aggregator(sum), table(NULL), tmp_table_param(NULL), tree(NULL),
|
||||
always_null(FALSE) {}
|
||||
virtual ~Aggregator_distinct ();
|
||||
Aggregator_type Aggrtype() { return DISTINCT_AGGREGATOR; }
|
||||
|
||||
bool setup(THD *);
|
||||
void clear();
|
||||
bool add();
|
||||
void endup();
|
||||
|
||||
bool unique_walk_function(void *element);
|
||||
static int composite_key_cmp(void* arg, uchar* key1, uchar* key2);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
The pass-through aggregator.
|
||||
Implements AGGFN (DISTINCT ..) by knowing it gets distinct data on input.
|
||||
So it just pumps them back to the Item_sum descendant class.
|
||||
*/
|
||||
class Aggregator_simple : public Aggregator
|
||||
{
|
||||
public:
|
||||
|
||||
Aggregator_simple (Item_sum *sum) :
|
||||
Aggregator(sum) {}
|
||||
Aggregator_type Aggrtype() { return Aggregator::SIMPLE_AGGREGATOR; }
|
||||
|
||||
bool setup(THD * thd) { return item_sum->setup(thd); }
|
||||
void clear() { item_sum->clear(); }
|
||||
bool add() { return item_sum->add(); }
|
||||
void endup() {};
|
||||
};
|
||||
|
||||
|
||||
class Item_sum_num :public Item_sum
|
||||
{
|
||||
friend class Aggregator_distinct;
|
||||
protected:
|
||||
/*
|
||||
val_xxx() functions may be called several times during the execution of a
|
||||
|
@ -443,9 +689,15 @@ protected:
|
|||
void fix_length_and_dec();
|
||||
|
||||
public:
|
||||
Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {}
|
||||
Item_sum_sum(Item *item_par, bool distinct= FALSE) :Item_sum_num(item_par)
|
||||
{
|
||||
set_distinct(distinct);
|
||||
}
|
||||
Item_sum_sum(THD *thd, Item_sum_sum *item);
|
||||
enum Sumfunctype sum_func () const {return SUM_FUNC;}
|
||||
enum Sumfunctype sum_func () const
|
||||
{
|
||||
return with_distinct ? SUM_DISTINCT_FUNC : SUM_FUNC;
|
||||
}
|
||||
void clear();
|
||||
bool add();
|
||||
double val_real();
|
||||
|
@ -456,109 +708,50 @@ public:
|
|||
void reset_field();
|
||||
void update_field();
|
||||
void no_rows_in_result() {}
|
||||
const char *func_name() const { return "sum("; }
|
||||
const char *func_name() const
|
||||
{
|
||||
return with_distinct ? "sum(distinct " : "sum(";
|
||||
}
|
||||
Item *copy_or_same(THD* thd);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Common class for SUM(DISTINCT), AVG(DISTINCT) */
|
||||
|
||||
class Unique;
|
||||
|
||||
class Item_sum_distinct :public Item_sum_num
|
||||
{
|
||||
protected:
|
||||
/* storage for the summation result */
|
||||
ulonglong count;
|
||||
Hybrid_type val;
|
||||
/* storage for unique elements */
|
||||
Unique *tree;
|
||||
TABLE *table;
|
||||
enum enum_field_types table_field_type;
|
||||
uint tree_key_length;
|
||||
protected:
|
||||
Item_sum_distinct(THD *thd, Item_sum_distinct *item);
|
||||
public:
|
||||
Item_sum_distinct(Item *item_par);
|
||||
~Item_sum_distinct();
|
||||
|
||||
bool setup(THD *thd);
|
||||
void clear();
|
||||
void cleanup();
|
||||
bool add();
|
||||
double val_real();
|
||||
my_decimal *val_decimal(my_decimal *);
|
||||
longlong val_int();
|
||||
String *val_str(String *str);
|
||||
|
||||
/* XXX: does it need make_unique? */
|
||||
|
||||
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
|
||||
void reset_field() {} // not used
|
||||
void update_field() {} // not used
|
||||
virtual void no_rows_in_result() {}
|
||||
void fix_length_and_dec();
|
||||
enum Item_result result_type () const { return val.traits->type(); }
|
||||
virtual void calculate_val_and_count();
|
||||
virtual bool unique_walk_function(void *elem);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Item_sum_sum_distinct - implementation of SUM(DISTINCT expr).
|
||||
See also: MySQL manual, chapter 'Adding New Functions To MySQL'
|
||||
and comments in item_sum.cc.
|
||||
*/
|
||||
|
||||
class Item_sum_sum_distinct :public Item_sum_distinct
|
||||
{
|
||||
private:
|
||||
Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item)
|
||||
:Item_sum_distinct(thd, item) {}
|
||||
public:
|
||||
Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {}
|
||||
|
||||
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
|
||||
const char *func_name() const { return "sum(distinct "; }
|
||||
Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); }
|
||||
};
|
||||
|
||||
|
||||
/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */
|
||||
|
||||
class Item_sum_avg_distinct: public Item_sum_distinct
|
||||
{
|
||||
private:
|
||||
Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original)
|
||||
:Item_sum_distinct(thd, original) {}
|
||||
public:
|
||||
uint prec_increment;
|
||||
Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {}
|
||||
|
||||
void fix_length_and_dec();
|
||||
virtual void calculate_val_and_count();
|
||||
enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; }
|
||||
const char *func_name() const { return "avg(distinct "; }
|
||||
Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); }
|
||||
};
|
||||
|
||||
|
||||
class Item_sum_count :public Item_sum_int
|
||||
{
|
||||
longlong count;
|
||||
|
||||
friend class Aggregator_distinct;
|
||||
|
||||
void clear();
|
||||
bool add();
|
||||
void cleanup();
|
||||
|
||||
public:
|
||||
Item_sum_count(Item *item_par)
|
||||
:Item_sum_int(item_par),count(0)
|
||||
{}
|
||||
|
||||
/**
|
||||
Constructs an instance for COUNT(DISTINCT)
|
||||
|
||||
@param list a list of the arguments to the aggregate function
|
||||
|
||||
This constructor is called by the parser only for COUNT (DISTINCT).
|
||||
*/
|
||||
|
||||
Item_sum_count(List<Item> &list)
|
||||
:Item_sum_int(list),count(0)
|
||||
{
|
||||
set_distinct(TRUE);
|
||||
}
|
||||
Item_sum_count(THD *thd, Item_sum_count *item)
|
||||
:Item_sum_int(thd, item), count(item->count)
|
||||
{}
|
||||
enum Sumfunctype sum_func () const { return COUNT_FUNC; }
|
||||
void clear();
|
||||
enum Sumfunctype sum_func () const
|
||||
{
|
||||
return with_distinct ? COUNT_DISTINCT_FUNC : COUNT_FUNC;
|
||||
}
|
||||
void no_rows_in_result() { count=0; }
|
||||
bool add();
|
||||
void make_const(longlong count_arg)
|
||||
{
|
||||
count=count_arg;
|
||||
|
@ -566,79 +759,15 @@ class Item_sum_count :public Item_sum_int
|
|||
}
|
||||
longlong val_int();
|
||||
void reset_field();
|
||||
void cleanup();
|
||||
void update_field();
|
||||
const char *func_name() const { return "count("; }
|
||||
const char *func_name() const
|
||||
{
|
||||
return with_distinct ? "count(distinct " : "count(";
|
||||
}
|
||||
Item *copy_or_same(THD* thd);
|
||||
};
|
||||
|
||||
|
||||
class TMP_TABLE_PARAM;
|
||||
|
||||
class Item_sum_count_distinct :public Item_sum_int
|
||||
{
|
||||
TABLE *table;
|
||||
uint32 *field_lengths;
|
||||
TMP_TABLE_PARAM *tmp_table_param;
|
||||
bool force_copy_fields;
|
||||
/*
|
||||
If there are no blobs, we can use a tree, which
|
||||
is faster than heap table. In that case, we still use the table
|
||||
to help get things set up, but we insert nothing in it
|
||||
*/
|
||||
Unique *tree;
|
||||
/*
|
||||
Storage for the value of count between calls to val_int() so val_int()
|
||||
will not recalculate on each call. Validitiy of the value is stored in
|
||||
is_evaluated.
|
||||
*/
|
||||
longlong count;
|
||||
/*
|
||||
Following is 0 normal object and pointer to original one for copy
|
||||
(to correctly free resources)
|
||||
*/
|
||||
Item_sum_count_distinct *original;
|
||||
uint tree_key_length;
|
||||
|
||||
|
||||
bool always_null; // Set to 1 if the result is always NULL
|
||||
|
||||
|
||||
friend int composite_key_cmp(void* arg, uchar* key1, uchar* key2);
|
||||
friend int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2);
|
||||
|
||||
public:
|
||||
Item_sum_count_distinct(List<Item> &list)
|
||||
:Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0),
|
||||
force_copy_fields(0), tree(0), count(0),
|
||||
original(0), always_null(FALSE)
|
||||
{ quick_group= 0; }
|
||||
Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item)
|
||||
:Item_sum_int(thd, item), table(item->table),
|
||||
field_lengths(item->field_lengths),
|
||||
tmp_table_param(item->tmp_table_param),
|
||||
force_copy_fields(0), tree(item->tree), count(item->count),
|
||||
original(item), tree_key_length(item->tree_key_length),
|
||||
always_null(item->always_null)
|
||||
{}
|
||||
~Item_sum_count_distinct();
|
||||
|
||||
void cleanup();
|
||||
|
||||
enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
|
||||
void clear();
|
||||
bool add();
|
||||
longlong val_int();
|
||||
void reset_field() { return ;} // Never called
|
||||
void update_field() { return ; } // Never called
|
||||
const char *func_name() const { return "count(distinct "; }
|
||||
bool setup(THD *thd);
|
||||
void make_unique();
|
||||
Item *copy_or_same(THD* thd);
|
||||
void no_rows_in_result() {}
|
||||
};
|
||||
|
||||
|
||||
/* Item to get the value of a stored sum function */
|
||||
|
||||
class Item_sum_avg;
|
||||
|
@ -674,13 +803,18 @@ public:
|
|||
uint prec_increment;
|
||||
uint f_precision, f_scale, dec_bin_size;
|
||||
|
||||
Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {}
|
||||
Item_sum_avg(Item *item_par, bool distinct= FALSE)
|
||||
:Item_sum_sum(item_par, distinct), count(0)
|
||||
{}
|
||||
Item_sum_avg(THD *thd, Item_sum_avg *item)
|
||||
:Item_sum_sum(thd, item), count(item->count),
|
||||
prec_increment(item->prec_increment) {}
|
||||
|
||||
void fix_length_and_dec();
|
||||
enum Sumfunctype sum_func () const {return AVG_FUNC;}
|
||||
enum Sumfunctype sum_func () const
|
||||
{
|
||||
return with_distinct ? AVG_DISTINCT_FUNC : AVG_FUNC;
|
||||
}
|
||||
void clear();
|
||||
bool add();
|
||||
double val_real();
|
||||
|
@ -693,7 +827,10 @@ public:
|
|||
Item *result_item(Field *field)
|
||||
{ return new Item_avg_field(hybrid_type, this); }
|
||||
void no_rows_in_result() {}
|
||||
const char *func_name() const { return "avg("; }
|
||||
const char *func_name() const
|
||||
{
|
||||
return with_distinct ? "avg(distinct " : "avg(";
|
||||
}
|
||||
Item *copy_or_same(THD* thd);
|
||||
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
|
||||
void cleanup()
|
||||
|
|
188
sql/opt_range.cc
188
sql/opt_range.cc
|
@ -708,7 +708,8 @@ static
|
|||
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
|
||||
double read_time);
|
||||
static
|
||||
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree);
|
||||
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree,
|
||||
double read_time);
|
||||
static double get_index_only_read_time(const PARAM* param, ha_rows records,
|
||||
int keynr);
|
||||
|
||||
|
@ -2049,7 +2050,7 @@ public:
|
|||
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN
|
||||
{
|
||||
private:
|
||||
bool have_min, have_max;
|
||||
bool have_min, have_max, have_agg_distinct;
|
||||
KEY_PART_INFO *min_max_arg_part;
|
||||
uint group_prefix_len;
|
||||
uint used_key_parts;
|
||||
|
@ -2061,11 +2062,13 @@ private:
|
|||
SEL_TREE *range_tree; /* Represents all range predicates in the query. */
|
||||
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */
|
||||
uint param_idx; /* Index of used key in param->key. */
|
||||
/* Number of records selected by the ranges in index_tree. */
|
||||
bool is_index_scan; /* Use index_next() instead of random read */
|
||||
public:
|
||||
/* Number of records selected by the ranges in index_tree. */
|
||||
ha_rows quick_prefix_records;
|
||||
public:
|
||||
TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg,
|
||||
TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg,
|
||||
bool have_agg_distinct_arg,
|
||||
KEY_PART_INFO *min_max_arg_part_arg,
|
||||
uint group_prefix_len_arg, uint used_key_parts_arg,
|
||||
uint group_key_parts_arg, KEY *index_info_arg,
|
||||
|
@ -2074,11 +2077,12 @@ public:
|
|||
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg,
|
||||
uint param_idx_arg, ha_rows quick_prefix_records_arg)
|
||||
: have_min(have_min_arg), have_max(have_max_arg),
|
||||
have_agg_distinct(have_agg_distinct_arg),
|
||||
min_max_arg_part(min_max_arg_part_arg),
|
||||
group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_arg),
|
||||
group_key_parts(group_key_parts_arg), index_info(index_info_arg),
|
||||
index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg),
|
||||
index_tree(index_tree_arg), param_idx(param_idx_arg),
|
||||
index_tree(index_tree_arg), param_idx(param_idx_arg), is_index_scan(FALSE),
|
||||
quick_prefix_records(quick_prefix_records_arg)
|
||||
{
|
||||
if (key_infix_len)
|
||||
|
@ -2088,6 +2092,7 @@ public:
|
|||
|
||||
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
|
||||
MEM_ROOT *parent_alloc);
|
||||
void use_index_scan() { is_index_scan= TRUE; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -2349,7 +2354,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||
Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
|
||||
Notice that it can be constructed no matter if there is a range tree.
|
||||
*/
|
||||
group_trp= get_best_group_min_max(¶m, tree);
|
||||
group_trp= get_best_group_min_max(¶m, tree, best_read_time);
|
||||
if (group_trp)
|
||||
{
|
||||
param.table->quick_condition_rows= min(group_trp->records,
|
||||
|
@ -9048,15 +9053,10 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
|
|||
double *read_cost, ha_rows *records);
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
Test if this access method is applicable to a GROUP query with MIN/MAX
|
||||
functions, and if so, construct a new TRP object.
|
||||
|
||||
SYNOPSIS
|
||||
get_best_group_min_max()
|
||||
param Parameter from test_quick_select
|
||||
sel_tree Range tree generated by get_mm_tree
|
||||
|
||||
DESCRIPTION
|
||||
Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT.
|
||||
Queries computable via a QUICK_GROUP_MIN_MAX_SELECT must satisfy the
|
||||
|
@ -9167,17 +9167,16 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
|
|||
- Lift the limitation in condition (B3), that is, make this access method
|
||||
applicable to ROLLUP queries.
|
||||
|
||||
RETURN
|
||||
If mem_root != NULL
|
||||
- valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for
|
||||
the query
|
||||
- NULL o/w.
|
||||
If mem_root == NULL
|
||||
- NULL
|
||||
@param param Parameter from test_quick_select
|
||||
@param sel_tree Range tree generated by get_mm_tree
|
||||
@param read_time Best read time so far (=table/index scan time)
|
||||
@return table read plan
|
||||
@retval NULL Loose index scan not applicable or mem_root == NULL
|
||||
@retval !NULL Loose index scan table read plan
|
||||
*/
|
||||
|
||||
static TRP_GROUP_MIN_MAX *
|
||||
get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
||||
get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
|
||||
{
|
||||
THD *thd= param->thd;
|
||||
JOIN *join= thd->lex->current_select->join;
|
||||
|
@ -9198,25 +9197,33 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
ORDER *tmp_group;
|
||||
Item *item;
|
||||
Item_field *item_field;
|
||||
bool is_agg_distinct;
|
||||
List<Item_field> agg_distinct_flds;
|
||||
|
||||
DBUG_ENTER("get_best_group_min_max");
|
||||
|
||||
/* Perform few 'cheap' tests whether this access method is applicable. */
|
||||
if (!join)
|
||||
DBUG_RETURN(NULL); /* This is not a select statement. */
|
||||
if ((join->tables != 1) || /* The query must reference one table. */
|
||||
((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
|
||||
(!join->select_distinct)) ||
|
||||
(join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
|
||||
DBUG_RETURN(NULL);
|
||||
if (table->s->keys == 0) /* There are no indexes to use. */
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
/* Analyze the query in more detail. */
|
||||
List_iterator<Item> select_items_it(join->fields_list);
|
||||
|
||||
/* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
|
||||
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
List_iterator<Item> select_items_it(join->fields_list);
|
||||
is_agg_distinct = is_indexed_agg_distinct(join, &agg_distinct_flds);
|
||||
|
||||
if ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
|
||||
(!join->select_distinct) &&
|
||||
!is_agg_distinct)
|
||||
DBUG_RETURN(NULL);
|
||||
/* Analyze the query in more detail. */
|
||||
|
||||
if (join->sum_funcs[0])
|
||||
{
|
||||
Item_sum *min_max_item;
|
||||
|
@ -9227,6 +9234,10 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
have_min= TRUE;
|
||||
else if (min_max_item->sum_func() == Item_sum::MAX_FUNC)
|
||||
have_max= TRUE;
|
||||
else if (min_max_item->sum_func() == Item_sum::COUNT_DISTINCT_FUNC ||
|
||||
min_max_item->sum_func() == Item_sum::SUM_DISTINCT_FUNC ||
|
||||
min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC)
|
||||
continue;
|
||||
else
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
|
@ -9243,13 +9254,12 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
DBUG_RETURN(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check (SA5). */
|
||||
if (join->select_distinct)
|
||||
{
|
||||
while ((item= select_items_it++))
|
||||
{
|
||||
if (item->type() != Item::FIELD_ITEM)
|
||||
if (item->real_item()->type() != Item::FIELD_ITEM)
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
}
|
||||
|
@ -9257,7 +9267,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
/* Check (GA4) - that there are no expressions among the group attributes. */
|
||||
for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next)
|
||||
{
|
||||
if ((*tmp_group->item)->type() != Item::FIELD_ITEM)
|
||||
if ((*tmp_group->item)->real_item()->type() != Item::FIELD_ITEM)
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
|
@ -9276,6 +9286,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
uint best_param_idx= 0;
|
||||
|
||||
const uint pk= param->table->s->primary_key;
|
||||
uint max_key_part;
|
||||
SEL_ARG *cur_index_tree= NULL;
|
||||
ha_rows cur_quick_prefix_records= 0;
|
||||
uint cur_param_idx=MAX_KEY;
|
||||
|
@ -9329,6 +9340,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
}
|
||||
}
|
||||
|
||||
max_key_part= 0;
|
||||
used_key_parts_map.clear_all();
|
||||
/*
|
||||
Check (GA1) for GROUP BY queries.
|
||||
*/
|
||||
|
@ -9352,6 +9365,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
{
|
||||
cur_group_prefix_len+= cur_part->store_length;
|
||||
++cur_group_key_parts;
|
||||
max_key_part= cur_part - cur_index_info->key_part + 1;
|
||||
used_key_parts_map.set_bit(max_key_part);
|
||||
}
|
||||
else
|
||||
goto next_index;
|
||||
|
@ -9365,14 +9380,26 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
Later group_fields_array of ORDER objects is used to convert the query
|
||||
to a GROUP query.
|
||||
*/
|
||||
else if (join->select_distinct)
|
||||
if ((!join->group_list && join->select_distinct) ||
|
||||
is_agg_distinct)
|
||||
{
|
||||
select_items_it.rewind();
|
||||
used_key_parts_map.clear_all();
|
||||
uint max_key_part= 0;
|
||||
while ((item= select_items_it++))
|
||||
if (!is_agg_distinct)
|
||||
{
|
||||
item_field= (Item_field*) item; /* (SA5) already checked above. */
|
||||
select_items_it.rewind();
|
||||
}
|
||||
|
||||
List_iterator<Item_field> agg_distinct_flds_it (agg_distinct_flds);
|
||||
while (NULL != (item = (is_agg_distinct ?
|
||||
(Item *) agg_distinct_flds_it++ : select_items_it++)))
|
||||
{
|
||||
/* (SA5) already checked above. */
|
||||
item_field= (Item_field*) item->real_item();
|
||||
DBUG_ASSERT(item->real_item()->type() == Item::FIELD_ITEM);
|
||||
|
||||
/* not doing loose index scan for derived tables */
|
||||
if (!item_field->field)
|
||||
goto next_index;
|
||||
|
||||
/* Find the order of the key part in the index. */
|
||||
key_part_nr= get_field_keypart(cur_index_info, item_field->field);
|
||||
/*
|
||||
|
@ -9381,7 +9408,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
*/
|
||||
if (used_key_parts_map.is_set(key_part_nr))
|
||||
continue;
|
||||
if (key_part_nr < 1 || key_part_nr > join->fields_list.elements)
|
||||
if (key_part_nr < 1 ||
|
||||
(!is_agg_distinct && key_part_nr > join->fields_list.elements))
|
||||
goto next_index;
|
||||
cur_part= cur_index_info->key_part + key_part_nr - 1;
|
||||
cur_group_prefix_len+= cur_part->store_length;
|
||||
|
@ -9401,10 +9429,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
if (all_parts != cur_parts)
|
||||
goto next_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/* Check (SA2). */
|
||||
if (min_max_arg_item)
|
||||
|
@ -9558,7 +9582,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
|
||||
/* The query passes all tests, so construct a new TRP object. */
|
||||
read_plan= new (param->mem_root)
|
||||
TRP_GROUP_MIN_MAX(have_min, have_max, min_max_arg_part,
|
||||
TRP_GROUP_MIN_MAX(have_min, have_max, is_agg_distinct,
|
||||
min_max_arg_part,
|
||||
group_prefix_len, used_key_parts,
|
||||
group_key_parts, index_info, index,
|
||||
key_infix_len,
|
||||
|
@ -9572,6 +9597,11 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||
|
||||
read_plan->read_cost= best_read_cost;
|
||||
read_plan->records= best_records;
|
||||
if (read_time < best_read_cost && is_agg_distinct)
|
||||
{
|
||||
read_plan->read_cost= 0;
|
||||
read_plan->use_index_scan();
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",
|
||||
("Returning group min/max plan: cost: %g, records: %lu",
|
||||
|
@ -10077,11 +10107,12 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
|
|||
|
||||
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table,
|
||||
param->thd->lex->current_select->join,
|
||||
have_min, have_max, min_max_arg_part,
|
||||
have_min, have_max,
|
||||
have_agg_distinct, min_max_arg_part,
|
||||
group_prefix_len, group_key_parts,
|
||||
used_key_parts, index_info, index,
|
||||
read_cost, records, key_infix_len,
|
||||
key_infix, parent_alloc);
|
||||
key_infix, parent_alloc, is_index_scan);
|
||||
if (!quick)
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
|
@ -10161,6 +10192,9 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
|
|||
key_infix_len Length of the key infix appended to the group prefix
|
||||
key_infix Infix of constants from equality predicates
|
||||
parent_alloc Memory pool for this and quick_prefix_select data
|
||||
is_index_scan get the next different key not by jumping on it via
|
||||
index read, but by scanning until the end of the
|
||||
rows with equal key value.
|
||||
|
||||
RETURN
|
||||
None
|
||||
|
@ -10168,20 +10202,22 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
|
|||
|
||||
QUICK_GROUP_MIN_MAX_SELECT::
|
||||
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
|
||||
bool have_max_arg,
|
||||
bool have_max_arg, bool have_agg_distinct_arg,
|
||||
KEY_PART_INFO *min_max_arg_part_arg,
|
||||
uint group_prefix_len_arg, uint group_key_parts_arg,
|
||||
uint used_key_parts_arg, KEY *index_info_arg,
|
||||
uint use_index, double read_cost_arg,
|
||||
ha_rows records_arg, uint key_infix_len_arg,
|
||||
uchar *key_infix_arg, MEM_ROOT *parent_alloc)
|
||||
uchar *key_infix_arg, MEM_ROOT *parent_alloc,
|
||||
bool is_index_scan_arg)
|
||||
:join(join_arg), index_info(index_info_arg),
|
||||
group_prefix_len(group_prefix_len_arg),
|
||||
group_key_parts(group_key_parts_arg), have_min(have_min_arg),
|
||||
have_max(have_max_arg), seen_first_key(FALSE),
|
||||
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg),
|
||||
key_infix_len(key_infix_len_arg), min_functions_it(NULL),
|
||||
max_functions_it(NULL)
|
||||
have_max(have_max_arg), have_agg_distinct(have_agg_distinct_arg),
|
||||
seen_first_key(FALSE), min_max_arg_part(min_max_arg_part_arg),
|
||||
key_infix(key_infix_arg), key_infix_len(key_infix_len_arg),
|
||||
min_functions_it(NULL), max_functions_it(NULL),
|
||||
is_index_scan(is_index_scan_arg)
|
||||
{
|
||||
head= table;
|
||||
file= head->file;
|
||||
|
@ -10744,6 +10780,56 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max()
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Find the next different key value by skiping all the rows with the same key
|
||||
value.
|
||||
|
||||
Implements a specialized loose index access method for queries
|
||||
containing aggregate functions with distinct of the form:
|
||||
SELECT [SUM|COUNT|AVG](DISTINCT a,...) FROM t
|
||||
This method comes to replace the index scan + Unique class
|
||||
(distinct selection) for loose index scan that visits all the rows of a
|
||||
covering index instead of jumping in the begining of each group.
|
||||
TODO: Placeholder function. To be replaced by a handler API call
|
||||
|
||||
@param is_index_scan hint to use index scan instead of random index read
|
||||
to find the next different value.
|
||||
@param file table handler
|
||||
@param key_part group key to compare
|
||||
@param record row data
|
||||
@param group_prefix current key prefix data
|
||||
@param group_prefix_len length of the current key prefix data
|
||||
@param group_key_parts number of the current key prefix columns
|
||||
@return status
|
||||
@retval 0 success
|
||||
@retval !0 failure
|
||||
*/
|
||||
|
||||
static int index_next_different (bool is_index_scan, handler *file,
|
||||
KEY_PART_INFO *key_part, uchar * record,
|
||||
const uchar * group_prefix,
|
||||
uint group_prefix_len,
|
||||
uint group_key_parts)
|
||||
{
|
||||
if (is_index_scan)
|
||||
{
|
||||
int result= 0;
|
||||
|
||||
while (!key_cmp (key_part, group_prefix, group_prefix_len))
|
||||
{
|
||||
result= file->index_next(record);
|
||||
if (result)
|
||||
return(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
return file->index_read_map(record, group_prefix,
|
||||
make_prev_keypart_map(group_key_parts),
|
||||
HA_READ_AFTER_KEY);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Determine the prefix of the next group.
|
||||
|
||||
|
@ -10790,9 +10876,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
|
|||
else
|
||||
{
|
||||
/* Load the first key in this group into record. */
|
||||
result= file->index_read_map(record, group_prefix,
|
||||
make_prev_keypart_map(group_key_parts),
|
||||
HA_READ_AFTER_KEY);
|
||||
result= index_next_different (is_index_scan, file, index_info->key_part,
|
||||
record, group_prefix, group_prefix_len,
|
||||
group_key_parts);
|
||||
if (result)
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
|
|
@ -616,6 +616,7 @@ private:
|
|||
uchar *last_prefix; /* Prefix of the last group for detecting EOF. */
|
||||
bool have_min; /* Specify whether we are computing */
|
||||
bool have_max; /* a MIN, a MAX, or both. */
|
||||
bool have_agg_distinct;/* aggregate_function(DISTINCT ...). */
|
||||
bool seen_first_key; /* Denotes whether the first key was retrieved.*/
|
||||
KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */
|
||||
/* of all MIN/MAX functions. */
|
||||
|
@ -629,6 +630,11 @@ private:
|
|||
List<Item_sum> *max_functions;
|
||||
List_iterator<Item_sum> *min_functions_it;
|
||||
List_iterator<Item_sum> *max_functions_it;
|
||||
/*
|
||||
Use index scan to get the next different key instead of jumping into it
|
||||
through index read
|
||||
*/
|
||||
bool is_index_scan;
|
||||
public:
|
||||
/*
|
||||
The following two members are public to allow easy access from
|
||||
|
@ -646,12 +652,13 @@ private:
|
|||
void update_max_result();
|
||||
public:
|
||||
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
|
||||
bool have_max, KEY_PART_INFO *min_max_arg_part,
|
||||
bool have_max, bool have_agg_distinct,
|
||||
KEY_PART_INFO *min_max_arg_part,
|
||||
uint group_prefix_len, uint group_key_parts,
|
||||
uint used_key_parts, KEY *index_info, uint
|
||||
use_index, double read_cost, ha_rows records, uint
|
||||
key_infix_len, uchar *key_infix, MEM_ROOT
|
||||
*parent_alloc);
|
||||
*parent_alloc, bool is_index_scan);
|
||||
~QUICK_GROUP_MIN_MAX_SELECT();
|
||||
bool add_range(SEL_ARG *sel_range);
|
||||
void update_key_stat();
|
||||
|
@ -667,6 +674,12 @@ public:
|
|||
#ifndef DBUG_OFF
|
||||
void dbug_dump(int indent, bool verbose);
|
||||
#endif
|
||||
bool is_agg_distinct() { return have_agg_distinct; }
|
||||
virtual void append_loose_scan_type(String *str)
|
||||
{
|
||||
if (is_index_scan)
|
||||
str->append(STRING_WITH_LEN(" (scanning)"));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -355,10 +355,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
|||
const_result= 0;
|
||||
break;
|
||||
}
|
||||
item_sum->set_aggregator (item_sum->with_distinct ?
|
||||
Aggregator::DISTINCT_AGGREGATOR :
|
||||
Aggregator::SIMPLE_AGGREGATOR);
|
||||
if (!count)
|
||||
{
|
||||
/* If count == 0, then we know that is_exact_count == TRUE. */
|
||||
((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */
|
||||
((Item_sum_min*) item_sum)->aggregator_clear(); /* Set to NULL. */
|
||||
}
|
||||
else
|
||||
((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */
|
||||
|
@ -443,10 +446,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
|||
const_result= 0;
|
||||
break;
|
||||
}
|
||||
item_sum->set_aggregator (item_sum->with_distinct ?
|
||||
Aggregator::DISTINCT_AGGREGATOR :
|
||||
Aggregator::SIMPLE_AGGREGATOR);
|
||||
if (!count)
|
||||
{
|
||||
/* If count != 1, then we know that is_exact_count == TRUE. */
|
||||
((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */
|
||||
((Item_sum_max*) item_sum)->aggregator_clear(); /* Set to NULL. */
|
||||
}
|
||||
else
|
||||
((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
class Reprepare_observer
|
||||
{
|
||||
public:
|
||||
Reprepare_observer() {}
|
||||
/**
|
||||
Check if a change of metadata is OK. In future
|
||||
the signature of this method may be extended to accept the old
|
||||
|
|
|
@ -222,6 +222,7 @@ static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
|
|||
static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end);
|
||||
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
|
||||
static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr);
|
||||
static bool prepare_sum_aggregators(Item_sum **func_ptr, bool need_distinct);
|
||||
static bool init_sum_functions(Item_sum **func, Item_sum **end);
|
||||
static bool update_sum_func(Item_sum **func);
|
||||
static void select_describe(JOIN *join, bool need_tmp_table,bool need_order,
|
||||
|
@ -1232,7 +1233,11 @@ JOIN::optimize()
|
|||
|
||||
if (test_if_subpart(group_list, order) ||
|
||||
(!group_list && tmp_table_param.sum_func_count))
|
||||
{
|
||||
order=0;
|
||||
if (is_indexed_agg_distinct(this, NULL))
|
||||
sort_and_group= 0;
|
||||
}
|
||||
|
||||
// Can't use sort on head table if using row cache
|
||||
if (full_join)
|
||||
|
@ -1410,8 +1415,16 @@ JOIN::optimize()
|
|||
single table queries, thus it is sufficient to test only the first
|
||||
join_tab element of the plan for its access method.
|
||||
*/
|
||||
bool need_distinct= TRUE;
|
||||
if (join_tab->is_using_loose_index_scan())
|
||||
{
|
||||
tmp_table_param.precomputed_group_by= TRUE;
|
||||
if (join_tab->is_using_agg_loose_index_scan())
|
||||
{
|
||||
need_distinct= FALSE;
|
||||
tmp_table_param.precomputed_group_by= FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a tmp table if distinct or if the sort is too complicated */
|
||||
if (need_tmp)
|
||||
|
@ -1472,6 +1485,7 @@ JOIN::optimize()
|
|||
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
|
||||
alloc_group_fields(this, group_list) ||
|
||||
make_sum_func_list(all_fields, fields_list, 1) ||
|
||||
prepare_sum_aggregators(sum_funcs, need_distinct) ||
|
||||
setup_sum_funcs(thd, sum_funcs))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
|
@ -1481,6 +1495,7 @@ JOIN::optimize()
|
|||
else
|
||||
{
|
||||
if (make_sum_func_list(all_fields, fields_list, 0) ||
|
||||
prepare_sum_aggregators(sum_funcs, need_distinct) ||
|
||||
setup_sum_funcs(thd, sum_funcs))
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
|
@ -1953,7 +1968,9 @@ JOIN::exec()
|
|||
}
|
||||
}
|
||||
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
|
||||
1, TRUE))
|
||||
1, TRUE) ||
|
||||
prepare_sum_aggregators(curr_join->sum_funcs,
|
||||
!curr_join->join_tab->is_using_agg_loose_index_scan()))
|
||||
DBUG_VOID_RETURN;
|
||||
curr_join->group_list= 0;
|
||||
if (!curr_join->sort_and_group &&
|
||||
|
@ -2056,6 +2073,8 @@ JOIN::exec()
|
|||
|
||||
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
|
||||
1, TRUE) ||
|
||||
prepare_sum_aggregators (curr_join->sum_funcs, !curr_join->join_tab ||
|
||||
!curr_join->join_tab->is_using_agg_loose_index_scan()) ||
|
||||
setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) ||
|
||||
thd->is_fatal_error)
|
||||
DBUG_VOID_RETURN;
|
||||
|
@ -3937,6 +3956,82 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Check for the presence of AGGFN(DISTINCT a) queries that may be subject
|
||||
to loose index scan.
|
||||
|
||||
|
||||
Check if the query is a subject to AGGFN(DISTINCT) using loose index scan
|
||||
(QUICK_GROUP_MIN_MAX_SELECT).
|
||||
Optionally (if out_args is supplied) will push the arguments of
|
||||
AGGFN(DISTINCT) to the list
|
||||
|
||||
@param join the join to check
|
||||
@param[out] out_args list of aggregate function arguments
|
||||
@return does the query qualify for indexed AGGFN(DISTINCT)
|
||||
@retval true it does
|
||||
@retval false AGGFN(DISTINCT) must apply distinct in it.
|
||||
*/
|
||||
|
||||
bool
|
||||
is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
|
||||
{
|
||||
Item_sum **sum_item_ptr;
|
||||
bool result= false;
|
||||
|
||||
if (join->tables != 1 || /* reference more than 1 table */
|
||||
join->select_distinct || /* or a DISTINCT */
|
||||
join->select_lex->olap == ROLLUP_TYPE) /* Check (B3) for ROLLUP */
|
||||
return false;
|
||||
|
||||
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
|
||||
return false;
|
||||
|
||||
for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++)
|
||||
{
|
||||
Item_sum *sum_item= *sum_item_ptr;
|
||||
Item *expr;
|
||||
/* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */
|
||||
switch (sum_item->sum_func())
|
||||
{
|
||||
case Item_sum::MIN_FUNC:
|
||||
case Item_sum::MAX_FUNC:
|
||||
continue;
|
||||
case Item_sum::COUNT_DISTINCT_FUNC:
|
||||
break;
|
||||
case Item_sum::AVG_DISTINCT_FUNC:
|
||||
case Item_sum::SUM_DISTINCT_FUNC:
|
||||
if (sum_item->get_arg_count() == 1)
|
||||
break;
|
||||
/* fall through */
|
||||
default: return false;
|
||||
}
|
||||
/*
|
||||
We arrive here for every COUNT(DISTINCT),AVG(DISTINCT) or SUM(DISTINCT).
|
||||
Collect the arguments of the aggregate functions to a list.
|
||||
We don't worry about duplicates as these will be sorted out later in
|
||||
get_best_group_min_max
|
||||
*/
|
||||
for (uint i= 0; i < sum_item->get_arg_count(); i++)
|
||||
{
|
||||
expr= sum_item->get_arg(i);
|
||||
/* The AGGFN(DISTINCT) arg is not an attribute? */
|
||||
if (expr->real_item()->type() != Item::FIELD_ITEM)
|
||||
return false;
|
||||
|
||||
/*
|
||||
If we came to this point the AGGFN(DISTINCT) loose index scan
|
||||
optimization is applicable
|
||||
*/
|
||||
if (out_args)
|
||||
out_args->push_back((Item_field *) expr);
|
||||
result= true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Discover the indexes that can be used for GROUP BY or DISTINCT queries.
|
||||
|
||||
|
@ -3979,6 +4074,10 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
|
|||
item->walk(&Item::collect_item_field_processor, 0,
|
||||
(uchar*) &indexed_fields);
|
||||
}
|
||||
else if (is_indexed_agg_distinct(join, &indexed_fields))
|
||||
{
|
||||
join->sort_and_group= 1;
|
||||
}
|
||||
else
|
||||
return;
|
||||
|
||||
|
@ -10377,6 +10476,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list)
|
|||
bzero(share, sizeof(*share));
|
||||
table->field= field;
|
||||
table->s= share;
|
||||
table->temp_pool_slot= MY_BIT_NONE;
|
||||
share->blob_field= blob_field;
|
||||
share->fields= field_count;
|
||||
share->blob_ptr_size= portable_sizeof_char_ptr;
|
||||
|
@ -14532,7 +14632,7 @@ setup_new_fields(THD *thd, List<Item> &fields,
|
|||
optimize away 'order by'.
|
||||
*/
|
||||
|
||||
static ORDER *
|
||||
ORDER *
|
||||
create_distinct_group(THD *thd, Item **ref_pointer_array,
|
||||
ORDER *order_list, List<Item> &fields,
|
||||
List<Item> &all_fields,
|
||||
|
@ -15334,7 +15434,22 @@ static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr)
|
|||
DBUG_ENTER("setup_sum_funcs");
|
||||
while ((func= *(func_ptr++)))
|
||||
{
|
||||
if (func->setup(thd))
|
||||
if (func->aggregator_setup(thd))
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
static bool prepare_sum_aggregators(Item_sum **func_ptr, bool need_distinct)
|
||||
{
|
||||
Item_sum *func;
|
||||
DBUG_ENTER("setup_sum_funcs");
|
||||
while ((func= *(func_ptr++)))
|
||||
{
|
||||
if (func->set_aggregator(need_distinct && func->with_distinct ?
|
||||
Aggregator::DISTINCT_AGGREGATOR :
|
||||
Aggregator::SIMPLE_AGGREGATOR))
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
|
@ -15384,7 +15499,7 @@ init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr)
|
|||
/* If rollup, calculate the upper sum levels */
|
||||
for ( ; *func_ptr ; func_ptr++)
|
||||
{
|
||||
if ((*func_ptr)->add())
|
||||
if ((*func_ptr)->aggregator_add())
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -15396,7 +15511,7 @@ update_sum_func(Item_sum **func_ptr)
|
|||
{
|
||||
Item_sum *func;
|
||||
for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
|
||||
if (func->add())
|
||||
if (func->aggregator_add())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -16313,7 +16428,12 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||
if (key_read)
|
||||
{
|
||||
if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
|
||||
{
|
||||
QUICK_GROUP_MIN_MAX_SELECT *qgs=
|
||||
(QUICK_GROUP_MIN_MAX_SELECT *) tab->select->quick;
|
||||
extra.append(STRING_WITH_LEN("; Using index for group-by"));
|
||||
qgs->append_loose_scan_type(&extra);
|
||||
}
|
||||
else
|
||||
extra.append(STRING_WITH_LEN("; Using index"));
|
||||
}
|
||||
|
|
|
@ -218,6 +218,11 @@ typedef struct st_join_table {
|
|||
(select->quick->get_type() ==
|
||||
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
|
||||
}
|
||||
bool is_using_agg_loose_index_scan ()
|
||||
{
|
||||
return (is_using_loose_index_scan() &&
|
||||
((QUICK_GROUP_MIN_MAX_SELECT *)select->quick)->is_agg_distinct());
|
||||
}
|
||||
} JOIN_TAB;
|
||||
|
||||
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
|
||||
|
@ -564,6 +569,8 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field,
|
|||
const char *name, TABLE *table,
|
||||
Item_field *item, uint convert_blob_length);
|
||||
|
||||
bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
|
||||
|
||||
/* functions from opt_sum.cc */
|
||||
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
|
||||
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
|
||||
|
|
|
@ -8182,7 +8182,7 @@ sum_expr:
|
|||
}
|
||||
| AVG_SYM '(' DISTINCT in_sum_expr ')'
|
||||
{
|
||||
$$= new (YYTHD->mem_root) Item_sum_avg_distinct($4);
|
||||
$$= new (YYTHD->mem_root) Item_sum_avg($4, TRUE);
|
||||
if ($$ == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
|
@ -8225,7 +8225,7 @@ sum_expr:
|
|||
{ Select->in_sum_expr--; }
|
||||
')'
|
||||
{
|
||||
$$= new (YYTHD->mem_root) Item_sum_count_distinct(* $5);
|
||||
$$= new (YYTHD->mem_root) Item_sum_count(* $5);
|
||||
if ($$ == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
|
@ -8290,7 +8290,7 @@ sum_expr:
|
|||
}
|
||||
| SUM_SYM '(' DISTINCT in_sum_expr ')'
|
||||
{
|
||||
$$= new (YYTHD->mem_root) Item_sum_sum_distinct($4);
|
||||
$$= new (YYTHD->mem_root) Item_sum_sum($4, TRUE);
|
||||
if ($$ == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue