Ported WL#3220 to mysql-next-mr.
This commit is contained in:
parent
b21cd91780
commit
7aa8cd7a11
@ -5085,7 +5085,6 @@ sub valgrind_arguments {
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option
|
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, "--leak-check=yes");
|
||||||
mtr_add_arg($args, "--num-callers=16");
|
mtr_add_arg($args, "--num-callers=16");
|
||||||
mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)
|
mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)
|
||||||
|
@ -5,7 +5,7 @@ count(distinct n)
|
|||||||
100
|
100
|
||||||
explain extended select count(distinct n) from t1;
|
explain extended select count(distinct n) from t1;
|
||||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
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:
|
Warnings:
|
||||||
Note 1003 select count(distinct `test`.`t1`.`n`) AS `count(distinct n)` from `test`.`t1`
|
Note 1003 select count(distinct `test`.`t1`.`n`) AS `count(distinct n)` from `test`.`t1`
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
@ -1800,23 +1800,23 @@ b
|
|||||||
a
|
a
|
||||||
explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (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
|
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');
|
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
|
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');
|
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
|
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:
|
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'))
|
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');
|
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
|
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 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
|
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:
|
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');
|
select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||||
count(distinct a1,a2,b)
|
count(distinct a1,a2,b)
|
||||||
4
|
4
|
||||||
@ -1829,8 +1829,8 @@ count(distinct a1,a2,b)
|
|||||||
select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
|
select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
|
||||||
count(distinct b)
|
count(distinct b)
|
||||||
1
|
1
|
||||||
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');
|
||||||
ord(a1) + count(distinct a1,a2,b)
|
98 + count(distinct a1,a2,b)
|
||||||
104
|
104
|
||||||
explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
|
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
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
@ -2514,3 +2514,257 @@ a MAX(b)
|
|||||||
2 1
|
2 1
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
End of 5.1 tests
|
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 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 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 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) 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,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 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 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
|
# 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;
|
DROP TABLE t;
|
||||||
|
|
||||||
--echo End of 5.1 tests
|
--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
|
||||||
|
@ -1935,8 +1935,11 @@ public:
|
|||||||
my_decimal *val_decimal(my_decimal *);
|
my_decimal *val_decimal(my_decimal *);
|
||||||
int cmp(const uchar *a, const uchar *b)
|
int cmp(const uchar *a, const uchar *b)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(ptr == a);
|
DBUG_ASSERT(ptr == a || ptr == b);
|
||||||
|
if (ptr == a)
|
||||||
return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len));
|
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)
|
int cmp_binary_offset(uint row_offset)
|
||||||
{ return cmp_offset(row_offset); }
|
{ return cmp_offset(row_offset); }
|
||||||
|
1193
sql/item_sum.cc
1193
sql/item_sum.cc
File diff suppressed because it is too large
Load Diff
529
sql/item_sum.h
529
sql/item_sum.h
@ -22,7 +22,87 @@
|
|||||||
|
|
||||||
#include <my_tree.h>
|
#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
|
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
|
'set functions'. These expressions are formed with the help of aggregate
|
||||||
functions such as SUM, MAX, GROUP_CONCAT etc.
|
functions such as SUM, MAX, GROUP_CONCAT etc.
|
||||||
@ -217,11 +297,30 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class st_select_lex;
|
|
||||||
|
|
||||||
class Item_sum :public Item_result_field
|
class Item_sum :public Item_result_field
|
||||||
{
|
{
|
||||||
public:
|
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
|
enum Sumfunctype
|
||||||
{ COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
|
{ COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
|
||||||
AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_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)
|
Item_sum() :quick_group(1), arg_count(0), forced_const(FALSE)
|
||||||
{
|
{
|
||||||
mark_as_sum_func();
|
mark_as_sum_func();
|
||||||
|
init_aggregator();
|
||||||
}
|
}
|
||||||
Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args),
|
Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args),
|
||||||
orig_args(tmp_orig_args), forced_const(FALSE)
|
orig_args(tmp_orig_args), forced_const(FALSE)
|
||||||
{
|
{
|
||||||
args[0]=a;
|
args[0]=a;
|
||||||
mark_as_sum_func();
|
mark_as_sum_func();
|
||||||
|
init_aggregator();
|
||||||
}
|
}
|
||||||
Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args),
|
Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args),
|
||||||
orig_args(tmp_orig_args), forced_const(FALSE)
|
orig_args(tmp_orig_args), forced_const(FALSE)
|
||||||
{
|
{
|
||||||
args[0]=a; args[1]=b;
|
args[0]=a; args[1]=b;
|
||||||
mark_as_sum_func();
|
mark_as_sum_func();
|
||||||
|
init_aggregator();
|
||||||
}
|
}
|
||||||
Item_sum(List<Item> &list);
|
Item_sum(List<Item> &list);
|
||||||
//Copy constructor, need to perform subselects with temporary tables
|
//Copy constructor, need to perform subselects with temporary tables
|
||||||
Item_sum(THD *thd, Item_sum *item);
|
Item_sum(THD *thd, Item_sum *item);
|
||||||
enum Type type() const { return SUM_FUNC_ITEM; }
|
enum Type type() const { return SUM_FUNC_ITEM; }
|
||||||
virtual enum Sumfunctype sum_func () const=0;
|
virtual enum Sumfunctype sum_func () const=0;
|
||||||
|
inline bool reset() { aggregator_clear(); return aggregator_add(); };
|
||||||
/*
|
|
||||||
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;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Called when new group is started and results are being saved in
|
Called when new group is started and results are being saved in
|
||||||
@ -343,11 +423,6 @@ public:
|
|||||||
{ return new Item_field(field); }
|
{ return new Item_field(field); }
|
||||||
table_map used_tables() const { return used_tables_cache; }
|
table_map used_tables() const { return used_tables_cache; }
|
||||||
void update_used_tables ();
|
void update_used_tables ();
|
||||||
void cleanup()
|
|
||||||
{
|
|
||||||
Item::cleanup();
|
|
||||||
forced_const= FALSE;
|
|
||||||
}
|
|
||||||
bool is_null() { return null_value; }
|
bool is_null() { return null_value; }
|
||||||
void make_const ()
|
void make_const ()
|
||||||
{
|
{
|
||||||
@ -359,7 +434,9 @@ public:
|
|||||||
virtual void print(String *str, enum_query_type query_type);
|
virtual void print(String *str, enum_query_type query_type);
|
||||||
void fix_num_length_and_dec();
|
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
|
This function is called by the execution engine to assign 'NO ROWS
|
||||||
FOUND' value to an aggregate item, when the underlying result set
|
FOUND' value to an aggregate item, when the underlying result set
|
||||||
has no rows. Such value, in a general case, may be different from
|
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
|
may be initialized to 0 by clear() and to NULL by
|
||||||
no_rows_in_result().
|
no_rows_in_result().
|
||||||
*/
|
*/
|
||||||
void no_rows_in_result() { clear(); }
|
void no_rows_in_result()
|
||||||
|
{
|
||||||
virtual bool setup(THD *thd) {return 0;}
|
if (!aggr)
|
||||||
virtual void make_unique() {}
|
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);
|
Item *get_tmp_table_item(THD *thd);
|
||||||
virtual Field *create_tmp_field(bool group, TABLE *table,
|
virtual Field *create_tmp_field(bool group, TABLE *table,
|
||||||
uint convert_blob_length);
|
uint convert_blob_length);
|
||||||
@ -381,14 +463,178 @@ public:
|
|||||||
st_select_lex *depended_from()
|
st_select_lex *depended_from()
|
||||||
{ return (nest_level == aggr_level ? 0 : aggr_sel); }
|
{ return (nest_level == aggr_level ? 0 : aggr_sel); }
|
||||||
|
|
||||||
Item *get_arg(int i) { return args[i]; }
|
Item *get_arg(uint i) { return args[i]; }
|
||||||
Item *set_arg(int i, THD *thd, Item *new_val);
|
Item *set_arg(uint i, THD *thd, Item *new_val);
|
||||||
uint get_arg_count() { return arg_count; }
|
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
|
class Item_sum_num :public Item_sum
|
||||||
{
|
{
|
||||||
|
friend class Aggregator_distinct;
|
||||||
protected:
|
protected:
|
||||||
/*
|
/*
|
||||||
val_xxx() functions may be called several times during the execution of a
|
val_xxx() functions may be called several times during the execution of a
|
||||||
@ -443,9 +689,15 @@ protected:
|
|||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
|
|
||||||
public:
|
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);
|
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();
|
void clear();
|
||||||
bool add();
|
bool add();
|
||||||
double val_real();
|
double val_real();
|
||||||
@ -456,109 +708,50 @@ public:
|
|||||||
void reset_field();
|
void reset_field();
|
||||||
void update_field();
|
void update_field();
|
||||||
void no_rows_in_result() {}
|
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);
|
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
|
class Item_sum_count :public Item_sum_int
|
||||||
{
|
{
|
||||||
longlong count;
|
longlong count;
|
||||||
|
|
||||||
|
friend class Aggregator_distinct;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
bool add();
|
||||||
|
void cleanup();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Item_sum_count(Item *item_par)
|
Item_sum_count(Item *item_par)
|
||||||
:Item_sum_int(item_par),count(0)
|
: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_count(THD *thd, Item_sum_count *item)
|
||||||
:Item_sum_int(thd, item), count(item->count)
|
:Item_sum_int(thd, item), count(item->count)
|
||||||
{}
|
{}
|
||||||
enum Sumfunctype sum_func () const { return COUNT_FUNC; }
|
enum Sumfunctype sum_func () const
|
||||||
void clear();
|
{
|
||||||
|
return with_distinct ? COUNT_DISTINCT_FUNC : COUNT_FUNC;
|
||||||
|
}
|
||||||
void no_rows_in_result() { count=0; }
|
void no_rows_in_result() { count=0; }
|
||||||
bool add();
|
|
||||||
void make_const(longlong count_arg)
|
void make_const(longlong count_arg)
|
||||||
{
|
{
|
||||||
count=count_arg;
|
count=count_arg;
|
||||||
@ -566,76 +759,12 @@ class Item_sum_count :public Item_sum_int
|
|||||||
}
|
}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
void reset_field();
|
void reset_field();
|
||||||
void cleanup();
|
|
||||||
void update_field();
|
void update_field();
|
||||||
const char *func_name() const { return "count("; }
|
const char *func_name() const
|
||||||
Item *copy_or_same(THD* thd);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class TMP_TABLE_PARAM;
|
|
||||||
|
|
||||||
class Item_sum_count_distinct :public Item_sum_int
|
|
||||||
{
|
{
|
||||||
TABLE *table;
|
return with_distinct ? "count(distinct " : "count(";
|
||||||
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);
|
Item *copy_or_same(THD* thd);
|
||||||
void no_rows_in_result() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -674,13 +803,18 @@ public:
|
|||||||
uint prec_increment;
|
uint prec_increment;
|
||||||
uint f_precision, f_scale, dec_bin_size;
|
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_avg(THD *thd, Item_sum_avg *item)
|
||||||
:Item_sum_sum(thd, item), count(item->count),
|
:Item_sum_sum(thd, item), count(item->count),
|
||||||
prec_increment(item->prec_increment) {}
|
prec_increment(item->prec_increment) {}
|
||||||
|
|
||||||
void fix_length_and_dec();
|
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();
|
void clear();
|
||||||
bool add();
|
bool add();
|
||||||
double val_real();
|
double val_real();
|
||||||
@ -693,7 +827,10 @@ public:
|
|||||||
Item *result_item(Field *field)
|
Item *result_item(Field *field)
|
||||||
{ return new Item_avg_field(hybrid_type, this); }
|
{ return new Item_avg_field(hybrid_type, this); }
|
||||||
void no_rows_in_result() {}
|
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);
|
Item *copy_or_same(THD* thd);
|
||||||
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
|
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
|
||||||
void cleanup()
|
void cleanup()
|
||||||
|
184
sql/opt_range.cc
184
sql/opt_range.cc
@ -708,7 +708,8 @@ static
|
|||||||
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
|
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
|
||||||
double read_time);
|
double read_time);
|
||||||
static
|
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,
|
static double get_index_only_read_time(const PARAM* param, ha_rows records,
|
||||||
int keynr);
|
int keynr);
|
||||||
|
|
||||||
@ -2049,7 +2050,7 @@ public:
|
|||||||
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN
|
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool have_min, have_max;
|
bool have_min, have_max, have_agg_distinct;
|
||||||
KEY_PART_INFO *min_max_arg_part;
|
KEY_PART_INFO *min_max_arg_part;
|
||||||
uint group_prefix_len;
|
uint group_prefix_len;
|
||||||
uint used_key_parts;
|
uint used_key_parts;
|
||||||
@ -2061,11 +2062,13 @@ private:
|
|||||||
SEL_TREE *range_tree; /* Represents all range predicates in the query. */
|
SEL_TREE *range_tree; /* Represents all range predicates in the query. */
|
||||||
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */
|
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */
|
||||||
uint param_idx; /* Index of used key in param->key. */
|
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:
|
public:
|
||||||
|
/* Number of records selected by the ranges in index_tree. */
|
||||||
ha_rows quick_prefix_records;
|
ha_rows quick_prefix_records;
|
||||||
public:
|
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,
|
KEY_PART_INFO *min_max_arg_part_arg,
|
||||||
uint group_prefix_len_arg, uint used_key_parts_arg,
|
uint group_prefix_len_arg, uint used_key_parts_arg,
|
||||||
uint group_key_parts_arg, KEY *index_info_arg,
|
uint group_key_parts_arg, KEY *index_info_arg,
|
||||||
@ -2074,11 +2077,12 @@ public:
|
|||||||
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg,
|
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg,
|
||||||
uint param_idx_arg, ha_rows quick_prefix_records_arg)
|
uint param_idx_arg, ha_rows quick_prefix_records_arg)
|
||||||
: have_min(have_min_arg), have_max(have_max_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),
|
min_max_arg_part(min_max_arg_part_arg),
|
||||||
group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_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),
|
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(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)
|
quick_prefix_records(quick_prefix_records_arg)
|
||||||
{
|
{
|
||||||
if (key_infix_len)
|
if (key_infix_len)
|
||||||
@ -2088,6 +2092,7 @@ public:
|
|||||||
|
|
||||||
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
|
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
|
||||||
MEM_ROOT *parent_alloc);
|
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.
|
Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
|
||||||
Notice that it can be constructed no matter if there is a range tree.
|
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)
|
if (group_trp)
|
||||||
{
|
{
|
||||||
param.table->quick_condition_rows= min(group_trp->records,
|
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);
|
double *read_cost, ha_rows *records);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Test if this access method is applicable to a GROUP query with MIN/MAX
|
Test if this access method is applicable to a GROUP query with MIN/MAX
|
||||||
functions, and if so, construct a new TRP object.
|
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
|
DESCRIPTION
|
||||||
Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT.
|
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
|
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
|
- Lift the limitation in condition (B3), that is, make this access method
|
||||||
applicable to ROLLUP queries.
|
applicable to ROLLUP queries.
|
||||||
|
|
||||||
RETURN
|
@param param Parameter from test_quick_select
|
||||||
If mem_root != NULL
|
@param sel_tree Range tree generated by get_mm_tree
|
||||||
- valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for
|
@param read_time Best read time so far (=table/index scan time)
|
||||||
the query
|
@return table read plan
|
||||||
- NULL o/w.
|
@retval NULL Loose index scan not applicable or mem_root == NULL
|
||||||
If mem_root == NULL
|
@retval !NULL Loose index scan table read plan
|
||||||
- NULL
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static TRP_GROUP_MIN_MAX *
|
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;
|
THD *thd= param->thd;
|
||||||
JOIN *join= thd->lex->current_select->join;
|
JOIN *join= thd->lex->current_select->join;
|
||||||
@ -9198,25 +9197,33 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||||||
ORDER *tmp_group;
|
ORDER *tmp_group;
|
||||||
Item *item;
|
Item *item;
|
||||||
Item_field *item_field;
|
Item_field *item_field;
|
||||||
|
bool is_agg_distinct;
|
||||||
|
List<Item_field> agg_distinct_flds;
|
||||||
|
|
||||||
DBUG_ENTER("get_best_group_min_max");
|
DBUG_ENTER("get_best_group_min_max");
|
||||||
|
|
||||||
/* Perform few 'cheap' tests whether this access method is applicable. */
|
/* Perform few 'cheap' tests whether this access method is applicable. */
|
||||||
if (!join)
|
if (!join)
|
||||||
DBUG_RETURN(NULL); /* This is not a select statement. */
|
DBUG_RETURN(NULL); /* This is not a select statement. */
|
||||||
if ((join->tables != 1) || /* The query must reference one table. */
|
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 */
|
(join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
|
||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(NULL);
|
||||||
if (table->s->keys == 0) /* There are no indexes to use. */
|
if (table->s->keys == 0) /* There are no indexes to use. */
|
||||||
DBUG_RETURN(NULL);
|
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.*/
|
/* 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))
|
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
|
||||||
DBUG_RETURN(NULL);
|
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])
|
if (join->sum_funcs[0])
|
||||||
{
|
{
|
||||||
Item_sum *min_max_item;
|
Item_sum *min_max_item;
|
||||||
@ -9227,6 +9234,10 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||||||
have_min= TRUE;
|
have_min= TRUE;
|
||||||
else if (min_max_item->sum_func() == Item_sum::MAX_FUNC)
|
else if (min_max_item->sum_func() == Item_sum::MAX_FUNC)
|
||||||
have_max= TRUE;
|
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
|
else
|
||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(NULL);
|
||||||
|
|
||||||
@ -9243,13 +9254,12 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||||||
DBUG_RETURN(NULL);
|
DBUG_RETURN(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check (SA5). */
|
/* Check (SA5). */
|
||||||
if (join->select_distinct)
|
if (join->select_distinct)
|
||||||
{
|
{
|
||||||
while ((item= select_items_it++))
|
while ((item= select_items_it++))
|
||||||
{
|
{
|
||||||
if (item->type() != Item::FIELD_ITEM)
|
if (item->real_item()->type() != Item::FIELD_ITEM)
|
||||||
DBUG_RETURN(NULL);
|
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. */
|
/* Check (GA4) - that there are no expressions among the group attributes. */
|
||||||
for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next)
|
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);
|
DBUG_RETURN(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9276,6 +9286,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
|
|||||||
uint best_param_idx= 0;
|
uint best_param_idx= 0;
|
||||||
|
|
||||||
const uint pk= param->table->s->primary_key;
|
const uint pk= param->table->s->primary_key;
|
||||||
|
uint max_key_part;
|
||||||
SEL_ARG *cur_index_tree= NULL;
|
SEL_ARG *cur_index_tree= NULL;
|
||||||
ha_rows cur_quick_prefix_records= 0;
|
ha_rows cur_quick_prefix_records= 0;
|
||||||
uint cur_param_idx=MAX_KEY;
|
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.
|
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_prefix_len+= cur_part->store_length;
|
||||||
++cur_group_key_parts;
|
++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
|
else
|
||||||
goto next_index;
|
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
|
Later group_fields_array of ORDER objects is used to convert the query
|
||||||
to a GROUP query.
|
to a GROUP query.
|
||||||
*/
|
*/
|
||||||
else if (join->select_distinct)
|
if ((!join->group_list && join->select_distinct) ||
|
||||||
|
is_agg_distinct)
|
||||||
|
{
|
||||||
|
if (!is_agg_distinct)
|
||||||
{
|
{
|
||||||
select_items_it.rewind();
|
select_items_it.rewind();
|
||||||
used_key_parts_map.clear_all();
|
}
|
||||||
uint max_key_part= 0;
|
|
||||||
while ((item= select_items_it++))
|
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++)))
|
||||||
{
|
{
|
||||||
item_field= (Item_field*) item; /* (SA5) already checked above. */
|
/* (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. */
|
/* Find the order of the key part in the index. */
|
||||||
key_part_nr= get_field_keypart(cur_index_info, item_field->field);
|
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))
|
if (used_key_parts_map.is_set(key_part_nr))
|
||||||
continue;
|
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;
|
goto next_index;
|
||||||
cur_part= cur_index_info->key_part + key_part_nr - 1;
|
cur_part= cur_index_info->key_part + key_part_nr - 1;
|
||||||
cur_group_prefix_len+= cur_part->store_length;
|
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)
|
if (all_parts != cur_parts)
|
||||||
goto next_index;
|
goto next_index;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check (SA2). */
|
/* Check (SA2). */
|
||||||
if (min_max_arg_item)
|
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. */
|
/* The query passes all tests, so construct a new TRP object. */
|
||||||
read_plan= new (param->mem_root)
|
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_prefix_len, used_key_parts,
|
||||||
group_key_parts, index_info, index,
|
group_key_parts, index_info, index,
|
||||||
key_infix_len,
|
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->read_cost= best_read_cost;
|
||||||
read_plan->records= best_records;
|
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",
|
DBUG_PRINT("info",
|
||||||
("Returning group min/max plan: cost: %g, records: %lu",
|
("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,
|
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table,
|
||||||
param->thd->lex->current_select->join,
|
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,
|
group_prefix_len, group_key_parts,
|
||||||
used_key_parts, index_info, index,
|
used_key_parts, index_info, index,
|
||||||
read_cost, records, key_infix_len,
|
read_cost, records, key_infix_len,
|
||||||
key_infix, parent_alloc);
|
key_infix, parent_alloc, is_index_scan);
|
||||||
if (!quick)
|
if (!quick)
|
||||||
DBUG_RETURN(NULL);
|
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_len Length of the key infix appended to the group prefix
|
||||||
key_infix Infix of constants from equality predicates
|
key_infix Infix of constants from equality predicates
|
||||||
parent_alloc Memory pool for this and quick_prefix_select data
|
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
|
RETURN
|
||||||
None
|
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::
|
||||||
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
|
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,
|
KEY_PART_INFO *min_max_arg_part_arg,
|
||||||
uint group_prefix_len_arg, uint group_key_parts_arg,
|
uint group_prefix_len_arg, uint group_key_parts_arg,
|
||||||
uint used_key_parts_arg, KEY *index_info_arg,
|
uint used_key_parts_arg, KEY *index_info_arg,
|
||||||
uint use_index, double read_cost_arg,
|
uint use_index, double read_cost_arg,
|
||||||
ha_rows records_arg, uint key_infix_len_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),
|
:join(join_arg), index_info(index_info_arg),
|
||||||
group_prefix_len(group_prefix_len_arg),
|
group_prefix_len(group_prefix_len_arg),
|
||||||
group_key_parts(group_key_parts_arg), have_min(have_min_arg),
|
group_key_parts(group_key_parts_arg), have_min(have_min_arg),
|
||||||
have_max(have_max_arg), seen_first_key(FALSE),
|
have_max(have_max_arg), have_agg_distinct(have_agg_distinct_arg),
|
||||||
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg),
|
seen_first_key(FALSE), min_max_arg_part(min_max_arg_part_arg),
|
||||||
key_infix_len(key_infix_len_arg), min_functions_it(NULL),
|
key_infix(key_infix_arg), key_infix_len(key_infix_len_arg),
|
||||||
max_functions_it(NULL)
|
min_functions_it(NULL), max_functions_it(NULL),
|
||||||
|
is_index_scan(is_index_scan_arg)
|
||||||
{
|
{
|
||||||
head= table;
|
head= table;
|
||||||
file= head->file;
|
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.
|
Determine the prefix of the next group.
|
||||||
|
|
||||||
@ -10790,9 +10876,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Load the first key in this group into record. */
|
/* Load the first key in this group into record. */
|
||||||
result= file->index_read_map(record, group_prefix,
|
result= index_next_different (is_index_scan, file, index_info->key_part,
|
||||||
make_prev_keypart_map(group_key_parts),
|
record, group_prefix, group_prefix_len,
|
||||||
HA_READ_AFTER_KEY);
|
group_key_parts);
|
||||||
if (result)
|
if (result)
|
||||||
DBUG_RETURN(result);
|
DBUG_RETURN(result);
|
||||||
}
|
}
|
||||||
|
@ -616,6 +616,7 @@ private:
|
|||||||
uchar *last_prefix; /* Prefix of the last group for detecting EOF. */
|
uchar *last_prefix; /* Prefix of the last group for detecting EOF. */
|
||||||
bool have_min; /* Specify whether we are computing */
|
bool have_min; /* Specify whether we are computing */
|
||||||
bool have_max; /* a MIN, a MAX, or both. */
|
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.*/
|
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 */
|
KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */
|
||||||
/* of all MIN/MAX functions. */
|
/* of all MIN/MAX functions. */
|
||||||
@ -629,6 +630,11 @@ private:
|
|||||||
List<Item_sum> *max_functions;
|
List<Item_sum> *max_functions;
|
||||||
List_iterator<Item_sum> *min_functions_it;
|
List_iterator<Item_sum> *min_functions_it;
|
||||||
List_iterator<Item_sum> *max_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:
|
public:
|
||||||
/*
|
/*
|
||||||
The following two members are public to allow easy access from
|
The following two members are public to allow easy access from
|
||||||
@ -646,12 +652,13 @@ private:
|
|||||||
void update_max_result();
|
void update_max_result();
|
||||||
public:
|
public:
|
||||||
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
|
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 group_prefix_len, uint group_key_parts,
|
||||||
uint used_key_parts, KEY *index_info, uint
|
uint used_key_parts, KEY *index_info, uint
|
||||||
use_index, double read_cost, ha_rows records, uint
|
use_index, double read_cost, ha_rows records, uint
|
||||||
key_infix_len, uchar *key_infix, MEM_ROOT
|
key_infix_len, uchar *key_infix, MEM_ROOT
|
||||||
*parent_alloc);
|
*parent_alloc, bool is_index_scan);
|
||||||
~QUICK_GROUP_MIN_MAX_SELECT();
|
~QUICK_GROUP_MIN_MAX_SELECT();
|
||||||
bool add_range(SEL_ARG *sel_range);
|
bool add_range(SEL_ARG *sel_range);
|
||||||
void update_key_stat();
|
void update_key_stat();
|
||||||
@ -667,6 +674,12 @@ public:
|
|||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
void dbug_dump(int indent, bool verbose);
|
void dbug_dump(int indent, bool verbose);
|
||||||
#endif
|
#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;
|
const_result= 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
item_sum->set_aggregator (item_sum->with_distinct ?
|
||||||
|
Aggregator::DISTINCT_AGGREGATOR :
|
||||||
|
Aggregator::SIMPLE_AGGREGATOR);
|
||||||
if (!count)
|
if (!count)
|
||||||
{
|
{
|
||||||
/* If count == 0, then we know that is_exact_count == TRUE. */
|
/* 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
|
else
|
||||||
((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */
|
((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;
|
const_result= 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
item_sum->set_aggregator (item_sum->with_distinct ?
|
||||||
|
Aggregator::DISTINCT_AGGREGATOR :
|
||||||
|
Aggregator::SIMPLE_AGGREGATOR);
|
||||||
if (!count)
|
if (!count)
|
||||||
{
|
{
|
||||||
/* If count != 1, then we know that is_exact_count == TRUE. */
|
/* 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
|
else
|
||||||
((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */
|
((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
class Reprepare_observer
|
class Reprepare_observer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Reprepare_observer() {}
|
||||||
/**
|
/**
|
||||||
Check if a change of metadata is OK. In future
|
Check if a change of metadata is OK. In future
|
||||||
the signature of this method may be extended to accept the old
|
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 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 add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
|
||||||
static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr);
|
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 init_sum_functions(Item_sum **func, Item_sum **end);
|
||||||
static bool update_sum_func(Item_sum **func);
|
static bool update_sum_func(Item_sum **func);
|
||||||
static void select_describe(JOIN *join, bool need_tmp_table,bool need_order,
|
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) ||
|
if (test_if_subpart(group_list, order) ||
|
||||||
(!group_list && tmp_table_param.sum_func_count))
|
(!group_list && tmp_table_param.sum_func_count))
|
||||||
|
{
|
||||||
order=0;
|
order=0;
|
||||||
|
if (is_indexed_agg_distinct(this, NULL))
|
||||||
|
sort_and_group= 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Can't use sort on head table if using row cache
|
// Can't use sort on head table if using row cache
|
||||||
if (full_join)
|
if (full_join)
|
||||||
@ -1410,8 +1415,16 @@ JOIN::optimize()
|
|||||||
single table queries, thus it is sufficient to test only the first
|
single table queries, thus it is sufficient to test only the first
|
||||||
join_tab element of the plan for its access method.
|
join_tab element of the plan for its access method.
|
||||||
*/
|
*/
|
||||||
|
bool need_distinct= TRUE;
|
||||||
if (join_tab->is_using_loose_index_scan())
|
if (join_tab->is_using_loose_index_scan())
|
||||||
|
{
|
||||||
tmp_table_param.precomputed_group_by= TRUE;
|
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 */
|
/* Create a tmp table if distinct or if the sort is too complicated */
|
||||||
if (need_tmp)
|
if (need_tmp)
|
||||||
@ -1472,6 +1485,7 @@ JOIN::optimize()
|
|||||||
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
|
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
|
||||||
alloc_group_fields(this, group_list) ||
|
alloc_group_fields(this, group_list) ||
|
||||||
make_sum_func_list(all_fields, fields_list, 1) ||
|
make_sum_func_list(all_fields, fields_list, 1) ||
|
||||||
|
prepare_sum_aggregators(sum_funcs, need_distinct) ||
|
||||||
setup_sum_funcs(thd, sum_funcs))
|
setup_sum_funcs(thd, sum_funcs))
|
||||||
{
|
{
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
@ -1481,6 +1495,7 @@ JOIN::optimize()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (make_sum_func_list(all_fields, fields_list, 0) ||
|
if (make_sum_func_list(all_fields, fields_list, 0) ||
|
||||||
|
prepare_sum_aggregators(sum_funcs, need_distinct) ||
|
||||||
setup_sum_funcs(thd, sum_funcs))
|
setup_sum_funcs(thd, sum_funcs))
|
||||||
{
|
{
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
@ -1953,7 +1968,9 @@ JOIN::exec()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
|
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;
|
DBUG_VOID_RETURN;
|
||||||
curr_join->group_list= 0;
|
curr_join->group_list= 0;
|
||||||
if (!curr_join->sort_and_group &&
|
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,
|
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 ||
|
||||||
|
!curr_join->join_tab->is_using_agg_loose_index_scan()) ||
|
||||||
setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) ||
|
setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) ||
|
||||||
thd->is_fatal_error)
|
thd->is_fatal_error)
|
||||||
DBUG_VOID_RETURN;
|
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.
|
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,
|
item->walk(&Item::collect_item_field_processor, 0,
|
||||||
(uchar*) &indexed_fields);
|
(uchar*) &indexed_fields);
|
||||||
}
|
}
|
||||||
|
else if (is_indexed_agg_distinct(join, &indexed_fields))
|
||||||
|
{
|
||||||
|
join->sort_and_group= 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -10377,6 +10476,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list)
|
|||||||
bzero(share, sizeof(*share));
|
bzero(share, sizeof(*share));
|
||||||
table->field= field;
|
table->field= field;
|
||||||
table->s= share;
|
table->s= share;
|
||||||
|
table->temp_pool_slot= MY_BIT_NONE;
|
||||||
share->blob_field= blob_field;
|
share->blob_field= blob_field;
|
||||||
share->fields= field_count;
|
share->fields= field_count;
|
||||||
share->blob_ptr_size= portable_sizeof_char_ptr;
|
share->blob_ptr_size= portable_sizeof_char_ptr;
|
||||||
@ -14532,7 +14632,7 @@ setup_new_fields(THD *thd, List<Item> &fields,
|
|||||||
optimize away 'order by'.
|
optimize away 'order by'.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static ORDER *
|
ORDER *
|
||||||
create_distinct_group(THD *thd, Item **ref_pointer_array,
|
create_distinct_group(THD *thd, Item **ref_pointer_array,
|
||||||
ORDER *order_list, List<Item> &fields,
|
ORDER *order_list, List<Item> &fields,
|
||||||
List<Item> &all_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");
|
DBUG_ENTER("setup_sum_funcs");
|
||||||
while ((func= *(func_ptr++)))
|
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(TRUE);
|
||||||
}
|
}
|
||||||
DBUG_RETURN(FALSE);
|
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 */
|
/* If rollup, calculate the upper sum levels */
|
||||||
for ( ; *func_ptr ; func_ptr++)
|
for ( ; *func_ptr ; func_ptr++)
|
||||||
{
|
{
|
||||||
if ((*func_ptr)->add())
|
if ((*func_ptr)->aggregator_add())
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -15396,7 +15511,7 @@ update_sum_func(Item_sum **func_ptr)
|
|||||||
{
|
{
|
||||||
Item_sum *func;
|
Item_sum *func;
|
||||||
for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
|
for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
|
||||||
if (func->add())
|
if (func->aggregator_add())
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -16313,7 +16428,12 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
|||||||
if (key_read)
|
if (key_read)
|
||||||
{
|
{
|
||||||
if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
|
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"));
|
extra.append(STRING_WITH_LEN("; Using index for group-by"));
|
||||||
|
qgs->append_loose_scan_type(&extra);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
extra.append(STRING_WITH_LEN("; Using index"));
|
extra.append(STRING_WITH_LEN("; Using index"));
|
||||||
}
|
}
|
||||||
|
@ -218,6 +218,11 @@ typedef struct st_join_table {
|
|||||||
(select->quick->get_type() ==
|
(select->quick->get_type() ==
|
||||||
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
|
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;
|
} JOIN_TAB;
|
||||||
|
|
||||||
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
|
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,
|
const char *name, TABLE *table,
|
||||||
Item_field *item, uint convert_blob_length);
|
Item_field *item, uint convert_blob_length);
|
||||||
|
|
||||||
|
bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
|
||||||
|
|
||||||
/* functions from opt_sum.cc */
|
/* functions from opt_sum.cc */
|
||||||
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
|
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);
|
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
|
||||||
|
@ -8128,7 +8128,7 @@ sum_expr:
|
|||||||
}
|
}
|
||||||
| AVG_SYM '(' DISTINCT in_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)
|
if ($$ == NULL)
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
@ -8171,7 +8171,7 @@ sum_expr:
|
|||||||
{ Select->in_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)
|
if ($$ == NULL)
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
@ -8236,7 +8236,7 @@ sum_expr:
|
|||||||
}
|
}
|
||||||
| SUM_SYM '(' DISTINCT in_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)
|
if ($$ == NULL)
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user