Merge from mysql-next-mr.

This commit is contained in:
Alexander Nozdrin 2009-10-02 16:02:56 +04:00
commit 03d124c036
14 changed files with 1620 additions and 882 deletions

View file

@ -5085,7 +5085,6 @@ sub valgrind_arguments {
else
{
mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option
mtr_add_arg($args, "--alignment=8");
mtr_add_arg($args, "--leak-check=yes");
mtr_add_arg($args, "--num-callers=16");
mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)

View file

@ -5,7 +5,7 @@ count(distinct n)
100
explain extended select count(distinct n) from t1;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index NULL n 4 NULL 200 100.00 Using index
1 SIMPLE t1 range NULL n 4 NULL 10 100.00 Using index for group-by
Warnings:
Note 1003 select count(distinct `test`.`t1`.`n`) AS `count(distinct n)` from `test`.`t1`
drop table t1;

View file

@ -1800,23 +1800,23 @@ b
a
explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index
1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by
explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index
1 SIMPLE t1 range NULL idx_t1_1 163 NULL 65 Using where; Using index for group-by (scanning)
explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 128 75.00 Using where; Using index
1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 100.00 Using where; Using index for group-by
Warnings:
Note 1003 select count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`) AS `count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`b` = 'c') and (`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a'))
explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index
explain extended select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
explain extended select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 index idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_2 147 NULL 128 75.00 Using where; Using index
1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 100.00 Using where; Using index for group-by
Warnings:
Note 1003 select (ord(`test`.`t1`.`a1`) + count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`)) AS `ord(a1) + count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a'))
Note 1003 select (98 + count(distinct `test`.`t1`.`a1`,`test`.`t1`.`a2`,`test`.`t1`.`b`)) AS `98 + count(distinct a1,a2,b)` from `test`.`t1` where ((`test`.`t1`.`a1` > 'a') and (`test`.`t1`.`a2` > 'a'))
select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
count(distinct a1,a2,b)
4
@ -1829,8 +1829,8 @@ count(distinct a1,a2,b)
select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
count(distinct b)
1
select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
ord(a1) + count(distinct a1,a2,b)
select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
98 + count(distinct a1,a2,b)
104
explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b;
id select_type table type possible_keys key key_len ref rows Extra
@ -2514,3 +2514,257 @@ a MAX(b)
2 1
DROP TABLE t;
End of 5.1 tests
#
# WL#3220 (Loose index scan for COUNT DISTINCT)
#
CREATE TABLE t1 (a INT, b INT, c INT, KEY (a,b));
INSERT INTO t1 VALUES (1,1,1), (1,2,1), (1,3,1), (1,4,1);
INSERT INTO t1 SELECT a, b + 4, 1 FROM t1;
INSERT INTO t1 SELECT a + 1, b, 1 FROM t1;
CREATE TABLE t2 (a INT, b INT, c INT, d INT, e INT, f INT, KEY (a,b,c));
INSERT INTO t2 VALUES (1,1,1,1,1,1), (1,2,1,1,1,1), (1,3,1,1,1,1),
(1,4,1,1,1,1);
INSERT INTO t2 SELECT a, b + 4, c,d,e,f FROM t2;
INSERT INTO t2 SELECT a + 1, b, c,d,e,f FROM t2;
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT a) FROM t1;
COUNT(DISTINCT a)
2
EXPLAIN SELECT COUNT(DISTINCT a,b) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT a,b) FROM t1;
COUNT(DISTINCT a,b)
16
EXPLAIN SELECT COUNT(DISTINCT b,a) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT b,a) FROM t1;
COUNT(DISTINCT b,a)
16
EXPLAIN SELECT COUNT(DISTINCT b) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL a 10 NULL 16 Using index
SELECT COUNT(DISTINCT b) FROM t1;
COUNT(DISTINCT b)
8
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a;
COUNT(DISTINCT a)
1
1
EXPLAIN SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
COUNT(DISTINCT b)
8
8
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL a 10 NULL 16 Using index; Using filesort
SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b;
COUNT(DISTINCT a)
2
2
2
2
2
2
2
2
EXPLAIN SELECT DISTINCT COUNT(DISTINCT a) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL a 10 NULL 16 Using index
SELECT DISTINCT COUNT(DISTINCT a) FROM t1;
COUNT(DISTINCT a)
2
EXPLAIN SELECT COUNT(DISTINCT a, b + 0) FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL a 10 NULL 16 Using index
SELECT COUNT(DISTINCT a, b + 0) FROM t1;
COUNT(DISTINCT a, b + 0)
16
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10;
COUNT(DISTINCT a)
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 16
SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10;
COUNT(DISTINCT a)
2
EXPLAIN SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by
SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10;
1
1
EXPLAIN SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by
SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1;
1
1
1
EXPLAIN SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1_1 index NULL a 10 NULL 16 Using index; Using temporary; Using filesort
1 SIMPLE t1_2 index NULL a 10 NULL 16 Using index; Using join buffer
SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a;
COUNT(DISTINCT t1_1.a)
1
1
EXPLAIN SELECT COUNT(DISTINCT a), 12 FROM t1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT a), 12 FROM t1;
COUNT(DISTINCT a) 12
2 12
EXPLAIN SELECT COUNT(DISTINCT a, b, c) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT a, b, c) FROM t2;
COUNT(DISTINCT a, b, c)
16
EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2;
COUNT(DISTINCT a) SUM(DISTINCT a) AVG(DISTINCT a)
2 3 1.5000
EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 16
SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2;
COUNT(DISTINCT a) SUM(DISTINCT a) AVG(DISTINCT f)
2 3 1.0000
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2;
COUNT(DISTINCT a, b) COUNT(DISTINCT b, a)
16 16
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 16
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2;
COUNT(DISTINCT a, b) COUNT(DISTINCT b, f)
16 8
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 16
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2;
COUNT(DISTINCT a, b) COUNT(DISTINCT b, d)
16 8
EXPLAIN SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by
SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c;
a c COUNT(DISTINCT c, a, b)
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
2 1 1
2 1 1
2 1 1
2 1 1
2 1 1
2 1 1
2 1 1
2 1 1
2 1 1
EXPLAIN SELECT COUNT(DISTINCT c, a, b) FROM t2
WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range a a 15 NULL 1 Using where; Using index for group-by
SELECT COUNT(DISTINCT c, a, b) FROM t2
WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c;
COUNT(DISTINCT c, a, b)
EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5
GROUP BY b;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ref a a 5 const 1 Using where; Using index
SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5
GROUP BY b;
COUNT(DISTINCT b) SUM(DISTINCT b)
EXPLAIN SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by
SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
a COUNT(DISTINCT b) SUM(DISTINCT b)
2 8 36
2 8 36
EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by
SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
COUNT(DISTINCT b) SUM(DISTINCT b)
8 36
8 36
EXPLAIN SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 16 Using where
SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42;
COUNT(DISTINCT a, b)
0
EXPLAIN SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2
WHERE b = 13 AND c = 42 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 15 NULL 9 Using where; Using index for group-by
SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2
WHERE b = 13 AND c = 42 GROUP BY a;
a COUNT(DISTINCT a) SUM(DISTINCT a)
EXPLAIN SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 10 NULL 9 Using where; Using index for group-by
SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42;
COUNT(DISTINCT a, b) SUM(DISTINCT a)
0 NULL
EXPLAIN SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by
SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a;
SUM(DISTINCT a) MAX(b)
1 8
2 8
EXPLAIN SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by
SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c;
42 * (a + c + COUNT(DISTINCT c, a, b))
126
126
126
126
126
126
126
168
168
168
168
168
168
168
168
168
EXPLAIN SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by
SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a;
(SUM(DISTINCT a) + MAX(b))
9
10
DROP TABLE t1,t2;
# end of WL#3220 tests

View file

@ -570,13 +570,13 @@ explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
explain select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
explain extended select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
explain extended select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a');
select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121');
select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c');
select count(distinct b) from t1 where (a2 >= 'b') and (b = 'a');
select ord(a1) + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
select 98 + count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a');
#
# Queries with expressions in the select clause
@ -1033,3 +1033,124 @@ SELECT a, MAX(b) FROM t WHERE b GROUP BY a;
DROP TABLE t;
--echo End of 5.1 tests
--echo #
--echo # WL#3220 (Loose index scan for COUNT DISTINCT)
--echo #
CREATE TABLE t1 (a INT, b INT, c INT, KEY (a,b));
INSERT INTO t1 VALUES (1,1,1), (1,2,1), (1,3,1), (1,4,1);
INSERT INTO t1 SELECT a, b + 4, 1 FROM t1;
INSERT INTO t1 SELECT a + 1, b, 1 FROM t1;
CREATE TABLE t2 (a INT, b INT, c INT, d INT, e INT, f INT, KEY (a,b,c));
INSERT INTO t2 VALUES (1,1,1,1,1,1), (1,2,1,1,1,1), (1,3,1,1,1,1),
(1,4,1,1,1,1);
INSERT INTO t2 SELECT a, b + 4, c,d,e,f FROM t2;
INSERT INTO t2 SELECT a + 1, b, c,d,e,f FROM t2;
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1;
SELECT COUNT(DISTINCT a) FROM t1;
EXPLAIN SELECT COUNT(DISTINCT a,b) FROM t1;
SELECT COUNT(DISTINCT a,b) FROM t1;
EXPLAIN SELECT COUNT(DISTINCT b,a) FROM t1;
SELECT COUNT(DISTINCT b,a) FROM t1;
EXPLAIN SELECT COUNT(DISTINCT b) FROM t1;
SELECT COUNT(DISTINCT b) FROM t1;
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a;
SELECT COUNT(DISTINCT a) FROM t1 GROUP BY a;
EXPLAIN SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
SELECT COUNT(DISTINCT b) FROM t1 GROUP BY a;
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b;
SELECT COUNT(DISTINCT a) FROM t1 GROUP BY b;
EXPLAIN SELECT DISTINCT COUNT(DISTINCT a) FROM t1;
SELECT DISTINCT COUNT(DISTINCT a) FROM t1;
EXPLAIN SELECT COUNT(DISTINCT a, b + 0) FROM t1;
SELECT COUNT(DISTINCT a, b + 0) FROM t1;
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10;
SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT b) < 10;
EXPLAIN SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10;
SELECT COUNT(DISTINCT a) FROM t1 HAVING COUNT(DISTINCT c) < 10;
EXPLAIN SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10;
SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10;
EXPLAIN SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1;
SELECT 1 FROM t1 GROUP BY a HAVING COUNT(DISTINCT b) > 1;
EXPLAIN SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a;
SELECT COUNT(DISTINCT t1_1.a) FROM t1 t1_1, t1 t1_2 GROUP BY t1_1.a;
EXPLAIN SELECT COUNT(DISTINCT a), 12 FROM t1;
SELECT COUNT(DISTINCT a), 12 FROM t1;
EXPLAIN SELECT COUNT(DISTINCT a, b, c) FROM t2;
SELECT COUNT(DISTINCT a, b, c) FROM t2;
EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2;
SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2;
EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2;
SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT f) FROM t2;
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2;
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2;
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2;
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, f) FROM t2;
EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2;
SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, d) FROM t2;
EXPLAIN SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c;
SELECT a, c, COUNT(DISTINCT c, a, b) FROM t2 GROUP BY a, b, c;
EXPLAIN SELECT COUNT(DISTINCT c, a, b) FROM t2
WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c;
SELECT COUNT(DISTINCT c, a, b) FROM t2
WHERE a > 5 AND b BETWEEN 10 AND 20 GROUP BY a, b, c;
EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5
GROUP BY b;
SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 WHERE a = 5
GROUP BY b;
EXPLAIN SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
SELECT a, COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
EXPLAIN SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
SELECT COUNT(DISTINCT b), SUM(DISTINCT b) FROM t2 GROUP BY a;
EXPLAIN SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42;
SELECT COUNT(DISTINCT a, b) FROM t2 WHERE c = 13 AND d = 42;
EXPLAIN SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2
WHERE b = 13 AND c = 42 GROUP BY a;
SELECT a, COUNT(DISTINCT a), SUM(DISTINCT a) FROM t2
WHERE b = 13 AND c = 42 GROUP BY a;
EXPLAIN SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42;
SELECT COUNT(DISTINCT a, b), SUM(DISTINCT a) FROM t2 WHERE b = 42;
EXPLAIN SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a;
SELECT SUM(DISTINCT a), MAX(b) FROM t2 GROUP BY a;
EXPLAIN SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c;
SELECT 42 * (a + c + COUNT(DISTINCT c, a, b)) FROM t2 GROUP BY a, b, c;
EXPLAIN SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a;
SELECT (SUM(DISTINCT a) + MAX(b)) FROM t2 GROUP BY a;
DROP TABLE t1,t2;
--echo # end of WL#3220 tests

View file

@ -1934,9 +1934,12 @@ public:
virtual bool str_needs_quotes() { return TRUE; }
my_decimal *val_decimal(my_decimal *);
int cmp(const uchar *a, const uchar *b)
{
DBUG_ASSERT(ptr == a);
return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len));
{
DBUG_ASSERT(ptr == a || ptr == b);
if (ptr == a)
return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len));
else
return Field_bit::key_cmp(a, bytes_in_rec+test(bit_len)) * -1;
}
int cmp_binary_offset(uint row_offset)
{ return cmp_offset(row_offset); }

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,87 @@
#include <my_tree.h>
/*
class Item_sum;
class Aggregator_distinct;
class Aggregator_simple;
/**
The abstract base class for the Aggregator_* classes.
It implements the data collection functions (setup/add/clear)
as either pass-through to the real functionality or
as collectors into an Unique (for distinct) structure.
Note that update_field/reset_field are not in that
class, because they're simply not called when
GROUP BY/DISTINCT can be handled with help of index on grouped
fields (quick_group = 0);
*/
class Aggregator : public Sql_alloc
{
friend class Item_sum;
friend class Item_sum_sum;
friend class Item_sum_count;
friend class Item_sum_avg;
/*
All members are protected as this class is not usable outside of an
Item_sum descendant.
*/
protected:
/* the aggregate function class to act on */
Item_sum *item_sum;
/**
When feeding back the data in endup() from Unique/temp table back to
Item_sum::add() methods we must read the data from Unique (and not
recalculate the functions that are given as arguments to the aggregate
function.
This flag is to tell the add() methods to take the data from the Unique
instead by calling the relevant val_..() method
*/
bool use_distinct_values;
public:
Aggregator (Item_sum *arg): item_sum(arg), use_distinct_values(FALSE) {}
virtual ~Aggregator () {} /* Keep gcc happy */
enum Aggregator_type { SIMPLE_AGGREGATOR, DISTINCT_AGGREGATOR };
virtual Aggregator_type Aggrtype() = 0;
/**
Called before adding the first row.
Allocates and sets up the internal aggregation structures used,
e.g. the Unique instance used to calculate distinct.
*/
virtual bool setup(THD *) = 0;
/**
Called when we need to wipe out all the data from the aggregator :
all the values acumulated and all the state.
Cleans up the internal structures and resets them to their initial state.
*/
virtual void clear() = 0;
/**
Called when there's a new value to be aggregated.
Updates the internal state of the aggregator to reflect the new value.
*/
virtual bool add() = 0;
/**
Called when there are no more data and the final value is to be retrieved.
Finalises the state of the aggregator, so the final result can be retrieved.
*/
virtual void endup() = 0;
};
class st_select_lex;
/**
Class Item_sum is the base class used for special expressions that SQL calls
'set functions'. These expressions are formed with the help of aggregate
functions such as SUM, MAX, GROUP_CONCAT etc.
@ -215,13 +295,32 @@
TODO: to catch queries where the limit is exceeded to make the
code clean here.
*/
class st_select_lex;
*/
class Item_sum :public Item_result_field
{
public:
/**
Aggregator class instance. Not set initially. Allocated only after
it is determined if the incoming data are already distinct.
*/
Aggregator *aggr;
/**
Used in making ROLLUP. Set for the ROLLUP copies of the original
Item_sum and passed to create_tmp_field() to cause it to work
over the temp table buffer that is referenced by
Item_result_field::result_field.
*/
bool force_copy_fields;
/**
Indicates how the aggregate function was specified by the parser :
1 if it was written as AGGREGATE(DISTINCT),
0 if it was AGGREGATE()
*/
bool with_distinct;
enum Sumfunctype
{ COUNT_FUNC, COUNT_DISTINCT_FUNC, SUM_FUNC, SUM_DISTINCT_FUNC, AVG_FUNC,
AVG_DISTINCT_FUNC, MIN_FUNC, MAX_FUNC, STD_FUNC,
@ -263,47 +362,28 @@ public:
Item_sum() :quick_group(1), arg_count(0), forced_const(FALSE)
{
mark_as_sum_func();
init_aggregator();
}
Item_sum(Item *a) :quick_group(1), arg_count(1), args(tmp_args),
orig_args(tmp_orig_args), forced_const(FALSE)
{
args[0]=a;
mark_as_sum_func();
init_aggregator();
}
Item_sum( Item *a, Item *b ) :quick_group(1), arg_count(2), args(tmp_args),
orig_args(tmp_orig_args), forced_const(FALSE)
{
args[0]=a; args[1]=b;
mark_as_sum_func();
init_aggregator();
}
Item_sum(List<Item> &list);
//Copy constructor, need to perform subselects with temporary tables
Item_sum(THD *thd, Item_sum *item);
enum Type type() const { return SUM_FUNC_ITEM; }
virtual enum Sumfunctype sum_func () const=0;
/*
This method is similar to add(), but it is called when the current
aggregation group changes. Thus it performs a combination of
clear() and add().
*/
inline bool reset() { clear(); return add(); };
/*
Prepare this item for evaluation of an aggregate value. This is
called by reset() when a group changes, or, for correlated
subqueries, between subquery executions. E.g. for COUNT(), this
method should set count= 0;
*/
virtual void clear()= 0;
/*
This method is called for the next row in the same group. Its
purpose is to aggregate the new value to the previous values in
the group (i.e. since clear() was called last time). For example,
for COUNT(), do count++.
*/
virtual bool add()=0;
inline bool reset() { aggregator_clear(); return aggregator_add(); };
/*
Called when new group is started and results are being saved in
@ -343,11 +423,6 @@ public:
{ return new Item_field(field); }
table_map used_tables() const { return used_tables_cache; }
void update_used_tables ();
void cleanup()
{
Item::cleanup();
forced_const= FALSE;
}
bool is_null() { return null_value; }
void make_const ()
{
@ -359,7 +434,9 @@ public:
virtual void print(String *str, enum_query_type query_type);
void fix_num_length_and_dec();
/*
/**
Mark an aggregate as having no rows.
This function is called by the execution engine to assign 'NO ROWS
FOUND' value to an aggregate item, when the underlying result set
has no rows. Such value, in a general case, may be different from
@ -367,10 +444,15 @@ public:
may be initialized to 0 by clear() and to NULL by
no_rows_in_result().
*/
void no_rows_in_result() { clear(); }
virtual bool setup(THD *thd) {return 0;}
virtual void make_unique() {}
void no_rows_in_result()
{
if (!aggr)
set_aggregator(with_distinct ?
Aggregator::DISTINCT_AGGREGATOR :
Aggregator::SIMPLE_AGGREGATOR);
reset();
}
virtual void make_unique() { force_copy_fields= TRUE; }
Item *get_tmp_table_item(THD *thd);
virtual Field *create_tmp_field(bool group, TABLE *table,
uint convert_blob_length);
@ -381,14 +463,178 @@ public:
st_select_lex *depended_from()
{ return (nest_level == aggr_level ? 0 : aggr_sel); }
Item *get_arg(int i) { return args[i]; }
Item *set_arg(int i, THD *thd, Item *new_val);
Item *get_arg(uint i) { return args[i]; }
Item *set_arg(uint i, THD *thd, Item *new_val);
uint get_arg_count() { return arg_count; }
/* Initialization of distinct related members */
void init_aggregator()
{
aggr= NULL;
with_distinct= FALSE;
force_copy_fields= FALSE;
}
/**
Called to initialize the aggregator.
*/
inline bool aggregator_setup(THD *thd) { return aggr->setup(thd); };
/**
Called to cleanup the aggregator.
*/
inline void aggregator_clear() { aggr->clear(); }
/**
Called to add value to the aggregator.
*/
inline bool aggregator_add() { return aggr->add(); };
/* stores the declared DISTINCT flag (from the parser) */
void set_distinct(bool distinct)
{
with_distinct= distinct;
quick_group= with_distinct ? 0 : 1;
}
/**
Set the type of aggregation : DISTINCT or not.
Called when the final determination is done about the aggregation
type and the object is about to be used.
*/
int set_aggregator(Aggregator::Aggregator_type aggregator);
virtual void clear()= 0;
virtual bool add()= 0;
virtual bool setup(THD *thd) {return 0;}
void cleanup ();
};
class Unique;
/**
The distinct aggregator.
Implements AGGFN (DISTINCT ..)
Collects all the data into an Unique (similarly to what Item_sum_distinct
does currently) and then (if applicable) iterates over the list of
unique values and pumps them back into its object
*/
class Aggregator_distinct : public Aggregator
{
friend class Item_sum_sum;
friend class Item_sum_count;
friend class Item_sum_avg;
protected:
/*
flag to prevent consecutive runs of endup(). Normally in endup there are
expensive calculations (like walking the distinct tree for example)
which we must do only once if there are no data changes.
We can re-use the data for the second and subsequent val_xxx() calls.
endup_done set to TRUE also means that the calculated values for
the aggregate functions are correct and don't need recalculation.
*/
bool endup_done;
/*
Used depending on the type of the aggregate function and the presence of
blob columns in it:
- For COUNT(DISTINCT) and no blob fields this points to a real temporary
table. It's used as a hash table.
- For AVG/SUM(DISTINCT) or COUNT(DISTINCT) with blob fields only the
in-memory data structure of a temporary table is constructed.
It's used by the Field classes to transform data into row format.
*/
TABLE *table;
/*
An array of field lengths on row allocated and used only for
COUNT(DISTINCT) with multiple columns and no blobs. Used in
Aggregator_distinct::composite_key_cmp (called from Unique to compare
nodes
*/
uint32 *field_lengths;
/*
used in conjunction with 'table' to support the access to Field classes
for COUNT(DISTINCT). Needed by copy_fields()/copy_funcs().
*/
TMP_TABLE_PARAM *tmp_table_param;
/*
If there are no blobs in the COUNT(DISTINCT) arguments, we can use a tree,
which is faster than heap table. In that case, we still use the table
to help get things set up, but we insert nothing in it.
For AVG/SUM(DISTINCT) we always use this tree (as it takes a single
argument) to get the distinct rows.
*/
Unique *tree;
/*
The length of the temp table row. Must be a member of the class as it
gets passed down to simple_raw_key_cmp () as a compare function argument
to Unique. simple_raw_key_cmp () is used as a fast comparison function
when the entire row can be binary compared.
*/
uint tree_key_length;
/*
Set to true if the result is known to be always NULL.
If set deactivates creation and usage of the temporary table (in the
'table' member) and the Unique instance (in the 'tree' member) as well as
the calculation of the final value on the first call to
Item_[sum|avg|count]::val_xxx().
*/
bool always_null;
public:
Aggregator_distinct (Item_sum *sum) :
Aggregator(sum), table(NULL), tmp_table_param(NULL), tree(NULL),
always_null(FALSE) {}
virtual ~Aggregator_distinct ();
Aggregator_type Aggrtype() { return DISTINCT_AGGREGATOR; }
bool setup(THD *);
void clear();
bool add();
void endup();
bool unique_walk_function(void *element);
static int composite_key_cmp(void* arg, uchar* key1, uchar* key2);
};
/**
The pass-through aggregator.
Implements AGGFN (DISTINCT ..) by knowing it gets distinct data on input.
So it just pumps them back to the Item_sum descendant class.
*/
class Aggregator_simple : public Aggregator
{
public:
Aggregator_simple (Item_sum *sum) :
Aggregator(sum) {}
Aggregator_type Aggrtype() { return Aggregator::SIMPLE_AGGREGATOR; }
bool setup(THD * thd) { return item_sum->setup(thd); }
void clear() { item_sum->clear(); }
bool add() { return item_sum->add(); }
void endup() {};
};
class Item_sum_num :public Item_sum
{
friend class Aggregator_distinct;
protected:
/*
val_xxx() functions may be called several times during the execution of a
@ -443,9 +689,15 @@ protected:
void fix_length_and_dec();
public:
Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {}
Item_sum_sum(Item *item_par, bool distinct= FALSE) :Item_sum_num(item_par)
{
set_distinct(distinct);
}
Item_sum_sum(THD *thd, Item_sum_sum *item);
enum Sumfunctype sum_func () const {return SUM_FUNC;}
enum Sumfunctype sum_func () const
{
return with_distinct ? SUM_DISTINCT_FUNC : SUM_FUNC;
}
void clear();
bool add();
double val_real();
@ -456,109 +708,50 @@ public:
void reset_field();
void update_field();
void no_rows_in_result() {}
const char *func_name() const { return "sum("; }
const char *func_name() const
{
return with_distinct ? "sum(distinct " : "sum(";
}
Item *copy_or_same(THD* thd);
};
/* Common class for SUM(DISTINCT), AVG(DISTINCT) */
class Unique;
class Item_sum_distinct :public Item_sum_num
{
protected:
/* storage for the summation result */
ulonglong count;
Hybrid_type val;
/* storage for unique elements */
Unique *tree;
TABLE *table;
enum enum_field_types table_field_type;
uint tree_key_length;
protected:
Item_sum_distinct(THD *thd, Item_sum_distinct *item);
public:
Item_sum_distinct(Item *item_par);
~Item_sum_distinct();
bool setup(THD *thd);
void clear();
void cleanup();
bool add();
double val_real();
my_decimal *val_decimal(my_decimal *);
longlong val_int();
String *val_str(String *str);
/* XXX: does it need make_unique? */
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
void reset_field() {} // not used
void update_field() {} // not used
virtual void no_rows_in_result() {}
void fix_length_and_dec();
enum Item_result result_type () const { return val.traits->type(); }
virtual void calculate_val_and_count();
virtual bool unique_walk_function(void *elem);
};
/*
Item_sum_sum_distinct - implementation of SUM(DISTINCT expr).
See also: MySQL manual, chapter 'Adding New Functions To MySQL'
and comments in item_sum.cc.
*/
class Item_sum_sum_distinct :public Item_sum_distinct
{
private:
Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item)
:Item_sum_distinct(thd, item) {}
public:
Item_sum_sum_distinct(Item *item_arg) :Item_sum_distinct(item_arg) {}
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
const char *func_name() const { return "sum(distinct "; }
Item *copy_or_same(THD* thd) { return new Item_sum_sum_distinct(thd, this); }
};
/* Item_sum_avg_distinct - SELECT AVG(DISTINCT expr) FROM ... */
class Item_sum_avg_distinct: public Item_sum_distinct
{
private:
Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original)
:Item_sum_distinct(thd, original) {}
public:
uint prec_increment;
Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {}
void fix_length_and_dec();
virtual void calculate_val_and_count();
enum Sumfunctype sum_func () const { return AVG_DISTINCT_FUNC; }
const char *func_name() const { return "avg(distinct "; }
Item *copy_or_same(THD* thd) { return new Item_sum_avg_distinct(thd, this); }
};
class Item_sum_count :public Item_sum_int
{
longlong count;
friend class Aggregator_distinct;
void clear();
bool add();
void cleanup();
public:
Item_sum_count(Item *item_par)
:Item_sum_int(item_par),count(0)
{}
/**
Constructs an instance for COUNT(DISTINCT)
@param list a list of the arguments to the aggregate function
This constructor is called by the parser only for COUNT (DISTINCT).
*/
Item_sum_count(List<Item> &list)
:Item_sum_int(list),count(0)
{
set_distinct(TRUE);
}
Item_sum_count(THD *thd, Item_sum_count *item)
:Item_sum_int(thd, item), count(item->count)
{}
enum Sumfunctype sum_func () const { return COUNT_FUNC; }
void clear();
enum Sumfunctype sum_func () const
{
return with_distinct ? COUNT_DISTINCT_FUNC : COUNT_FUNC;
}
void no_rows_in_result() { count=0; }
bool add();
void make_const(longlong count_arg)
{
count=count_arg;
@ -566,79 +759,15 @@ class Item_sum_count :public Item_sum_int
}
longlong val_int();
void reset_field();
void cleanup();
void update_field();
const char *func_name() const { return "count("; }
const char *func_name() const
{
return with_distinct ? "count(distinct " : "count(";
}
Item *copy_or_same(THD* thd);
};
class TMP_TABLE_PARAM;
class Item_sum_count_distinct :public Item_sum_int
{
TABLE *table;
uint32 *field_lengths;
TMP_TABLE_PARAM *tmp_table_param;
bool force_copy_fields;
/*
If there are no blobs, we can use a tree, which
is faster than heap table. In that case, we still use the table
to help get things set up, but we insert nothing in it
*/
Unique *tree;
/*
Storage for the value of count between calls to val_int() so val_int()
will not recalculate on each call. Validitiy of the value is stored in
is_evaluated.
*/
longlong count;
/*
Following is 0 normal object and pointer to original one for copy
(to correctly free resources)
*/
Item_sum_count_distinct *original;
uint tree_key_length;
bool always_null; // Set to 1 if the result is always NULL
friend int composite_key_cmp(void* arg, uchar* key1, uchar* key2);
friend int simple_str_key_cmp(void* arg, uchar* key1, uchar* key2);
public:
Item_sum_count_distinct(List<Item> &list)
:Item_sum_int(list), table(0), field_lengths(0), tmp_table_param(0),
force_copy_fields(0), tree(0), count(0),
original(0), always_null(FALSE)
{ quick_group= 0; }
Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item)
:Item_sum_int(thd, item), table(item->table),
field_lengths(item->field_lengths),
tmp_table_param(item->tmp_table_param),
force_copy_fields(0), tree(item->tree), count(item->count),
original(item), tree_key_length(item->tree_key_length),
always_null(item->always_null)
{}
~Item_sum_count_distinct();
void cleanup();
enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
void clear();
bool add();
longlong val_int();
void reset_field() { return ;} // Never called
void update_field() { return ; } // Never called
const char *func_name() const { return "count(distinct "; }
bool setup(THD *thd);
void make_unique();
Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
};
/* Item to get the value of a stored sum function */
class Item_sum_avg;
@ -674,13 +803,18 @@ public:
uint prec_increment;
uint f_precision, f_scale, dec_bin_size;
Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {}
Item_sum_avg(Item *item_par, bool distinct= FALSE)
:Item_sum_sum(item_par, distinct), count(0)
{}
Item_sum_avg(THD *thd, Item_sum_avg *item)
:Item_sum_sum(thd, item), count(item->count),
prec_increment(item->prec_increment) {}
void fix_length_and_dec();
enum Sumfunctype sum_func () const {return AVG_FUNC;}
enum Sumfunctype sum_func () const
{
return with_distinct ? AVG_DISTINCT_FUNC : AVG_FUNC;
}
void clear();
bool add();
double val_real();
@ -693,7 +827,10 @@ public:
Item *result_item(Field *field)
{ return new Item_avg_field(hybrid_type, this); }
void no_rows_in_result() {}
const char *func_name() const { return "avg("; }
const char *func_name() const
{
return with_distinct ? "avg(distinct " : "avg(";
}
Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
void cleanup()

View file

@ -708,7 +708,8 @@ static
TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
double read_time);
static
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree);
TRP_GROUP_MIN_MAX *get_best_group_min_max(PARAM *param, SEL_TREE *tree,
double read_time);
static double get_index_only_read_time(const PARAM* param, ha_rows records,
int keynr);
@ -2049,7 +2050,7 @@ public:
class TRP_GROUP_MIN_MAX : public TABLE_READ_PLAN
{
private:
bool have_min, have_max;
bool have_min, have_max, have_agg_distinct;
KEY_PART_INFO *min_max_arg_part;
uint group_prefix_len;
uint used_key_parts;
@ -2061,11 +2062,13 @@ private:
SEL_TREE *range_tree; /* Represents all range predicates in the query. */
SEL_ARG *index_tree; /* The SEL_ARG sub-tree corresponding to index_info. */
uint param_idx; /* Index of used key in param->key. */
/* Number of records selected by the ranges in index_tree. */
bool is_index_scan; /* Use index_next() instead of random read */
public:
/* Number of records selected by the ranges in index_tree. */
ha_rows quick_prefix_records;
public:
TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg,
TRP_GROUP_MIN_MAX(bool have_min_arg, bool have_max_arg,
bool have_agg_distinct_arg,
KEY_PART_INFO *min_max_arg_part_arg,
uint group_prefix_len_arg, uint used_key_parts_arg,
uint group_key_parts_arg, KEY *index_info_arg,
@ -2074,11 +2077,12 @@ public:
SEL_TREE *tree_arg, SEL_ARG *index_tree_arg,
uint param_idx_arg, ha_rows quick_prefix_records_arg)
: have_min(have_min_arg), have_max(have_max_arg),
have_agg_distinct(have_agg_distinct_arg),
min_max_arg_part(min_max_arg_part_arg),
group_prefix_len(group_prefix_len_arg), used_key_parts(used_key_parts_arg),
group_key_parts(group_key_parts_arg), index_info(index_info_arg),
index(index_arg), key_infix_len(key_infix_len_arg), range_tree(tree_arg),
index_tree(index_tree_arg), param_idx(param_idx_arg),
index_tree(index_tree_arg), param_idx(param_idx_arg), is_index_scan(FALSE),
quick_prefix_records(quick_prefix_records_arg)
{
if (key_infix_len)
@ -2088,6 +2092,7 @@ public:
QUICK_SELECT_I *make_quick(PARAM *param, bool retrieve_full_rows,
MEM_ROOT *parent_alloc);
void use_index_scan() { is_index_scan= TRUE; }
};
@ -2349,7 +2354,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
Try to construct a QUICK_GROUP_MIN_MAX_SELECT.
Notice that it can be constructed no matter if there is a range tree.
*/
group_trp= get_best_group_min_max(&param, tree);
group_trp= get_best_group_min_max(&param, tree, best_read_time);
if (group_trp)
{
param.table->quick_condition_rows= min(group_trp->records,
@ -9048,15 +9053,10 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
double *read_cost, ha_rows *records);
/*
/**
Test if this access method is applicable to a GROUP query with MIN/MAX
functions, and if so, construct a new TRP object.
SYNOPSIS
get_best_group_min_max()
param Parameter from test_quick_select
sel_tree Range tree generated by get_mm_tree
DESCRIPTION
Test whether a query can be computed via a QUICK_GROUP_MIN_MAX_SELECT.
Queries computable via a QUICK_GROUP_MIN_MAX_SELECT must satisfy the
@ -9167,17 +9167,16 @@ cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
- Lift the limitation in condition (B3), that is, make this access method
applicable to ROLLUP queries.
RETURN
If mem_root != NULL
- valid TRP_GROUP_MIN_MAX object if this QUICK class can be used for
the query
- NULL o/w.
If mem_root == NULL
- NULL
@param param Parameter from test_quick_select
@param sel_tree Range tree generated by get_mm_tree
@param read_time Best read time so far (=table/index scan time)
@return table read plan
@retval NULL Loose index scan not applicable or mem_root == NULL
@retval !NULL Loose index scan table read plan
*/
static TRP_GROUP_MIN_MAX *
get_best_group_min_max(PARAM *param, SEL_TREE *tree)
get_best_group_min_max(PARAM *param, SEL_TREE *tree, double read_time)
{
THD *thd= param->thd;
JOIN *join= thd->lex->current_select->join;
@ -9198,25 +9197,33 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
ORDER *tmp_group;
Item *item;
Item_field *item_field;
bool is_agg_distinct;
List<Item_field> agg_distinct_flds;
DBUG_ENTER("get_best_group_min_max");
/* Perform few 'cheap' tests whether this access method is applicable. */
if (!join)
DBUG_RETURN(NULL); /* This is not a select statement. */
if ((join->tables != 1) || /* The query must reference one table. */
((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
(!join->select_distinct)) ||
(join->select_lex->olap == ROLLUP_TYPE)) /* Check (B3) for ROLLUP */
DBUG_RETURN(NULL);
if (table->s->keys == 0) /* There are no indexes to use. */
DBUG_RETURN(NULL);
/* Analyze the query in more detail. */
List_iterator<Item> select_items_it(join->fields_list);
/* Check (SA1,SA4) and store the only MIN/MAX argument - the C attribute.*/
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
DBUG_RETURN(NULL);
List_iterator<Item> select_items_it(join->fields_list);
is_agg_distinct = is_indexed_agg_distinct(join, &agg_distinct_flds);
if ((!join->group_list) && /* Neither GROUP BY nor a DISTINCT query. */
(!join->select_distinct) &&
!is_agg_distinct)
DBUG_RETURN(NULL);
/* Analyze the query in more detail. */
if (join->sum_funcs[0])
{
Item_sum *min_max_item;
@ -9227,6 +9234,10 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
have_min= TRUE;
else if (min_max_item->sum_func() == Item_sum::MAX_FUNC)
have_max= TRUE;
else if (min_max_item->sum_func() == Item_sum::COUNT_DISTINCT_FUNC ||
min_max_item->sum_func() == Item_sum::SUM_DISTINCT_FUNC ||
min_max_item->sum_func() == Item_sum::AVG_DISTINCT_FUNC)
continue;
else
DBUG_RETURN(NULL);
@ -9243,13 +9254,12 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
DBUG_RETURN(NULL);
}
}
/* Check (SA5). */
if (join->select_distinct)
{
while ((item= select_items_it++))
{
if (item->type() != Item::FIELD_ITEM)
if (item->real_item()->type() != Item::FIELD_ITEM)
DBUG_RETURN(NULL);
}
}
@ -9257,7 +9267,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
/* Check (GA4) - that there are no expressions among the group attributes. */
for (tmp_group= join->group_list; tmp_group; tmp_group= tmp_group->next)
{
if ((*tmp_group->item)->type() != Item::FIELD_ITEM)
if ((*tmp_group->item)->real_item()->type() != Item::FIELD_ITEM)
DBUG_RETURN(NULL);
}
@ -9276,6 +9286,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
uint best_param_idx= 0;
const uint pk= param->table->s->primary_key;
uint max_key_part;
SEL_ARG *cur_index_tree= NULL;
ha_rows cur_quick_prefix_records= 0;
uint cur_param_idx=MAX_KEY;
@ -9329,6 +9340,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
}
}
max_key_part= 0;
used_key_parts_map.clear_all();
/*
Check (GA1) for GROUP BY queries.
*/
@ -9352,6 +9365,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
{
cur_group_prefix_len+= cur_part->store_length;
++cur_group_key_parts;
max_key_part= cur_part - cur_index_info->key_part + 1;
used_key_parts_map.set_bit(max_key_part);
}
else
goto next_index;
@ -9365,14 +9380,26 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
Later group_fields_array of ORDER objects is used to convert the query
to a GROUP query.
*/
else if (join->select_distinct)
if ((!join->group_list && join->select_distinct) ||
is_agg_distinct)
{
select_items_it.rewind();
used_key_parts_map.clear_all();
uint max_key_part= 0;
while ((item= select_items_it++))
if (!is_agg_distinct)
{
item_field= (Item_field*) item; /* (SA5) already checked above. */
select_items_it.rewind();
}
List_iterator<Item_field> agg_distinct_flds_it (agg_distinct_flds);
while (NULL != (item = (is_agg_distinct ?
(Item *) agg_distinct_flds_it++ : select_items_it++)))
{
/* (SA5) already checked above. */
item_field= (Item_field*) item->real_item();
DBUG_ASSERT(item->real_item()->type() == Item::FIELD_ITEM);
/* not doing loose index scan for derived tables */
if (!item_field->field)
goto next_index;
/* Find the order of the key part in the index. */
key_part_nr= get_field_keypart(cur_index_info, item_field->field);
/*
@ -9381,7 +9408,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
*/
if (used_key_parts_map.is_set(key_part_nr))
continue;
if (key_part_nr < 1 || key_part_nr > join->fields_list.elements)
if (key_part_nr < 1 ||
(!is_agg_distinct && key_part_nr > join->fields_list.elements))
goto next_index;
cur_part= cur_index_info->key_part + key_part_nr - 1;
cur_group_prefix_len+= cur_part->store_length;
@ -9401,10 +9429,6 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
if (all_parts != cur_parts)
goto next_index;
}
else
{
DBUG_ASSERT(FALSE);
}
/* Check (SA2). */
if (min_max_arg_item)
@ -9558,7 +9582,8 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
/* The query passes all tests, so construct a new TRP object. */
read_plan= new (param->mem_root)
TRP_GROUP_MIN_MAX(have_min, have_max, min_max_arg_part,
TRP_GROUP_MIN_MAX(have_min, have_max, is_agg_distinct,
min_max_arg_part,
group_prefix_len, used_key_parts,
group_key_parts, index_info, index,
key_infix_len,
@ -9572,6 +9597,11 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
read_plan->read_cost= best_read_cost;
read_plan->records= best_records;
if (read_time < best_read_cost && is_agg_distinct)
{
read_plan->read_cost= 0;
read_plan->use_index_scan();
}
DBUG_PRINT("info",
("Returning group min/max plan: cost: %g, records: %lu",
@ -10077,11 +10107,12 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table,
param->thd->lex->current_select->join,
have_min, have_max, min_max_arg_part,
have_min, have_max,
have_agg_distinct, min_max_arg_part,
group_prefix_len, group_key_parts,
used_key_parts, index_info, index,
read_cost, records, key_infix_len,
key_infix, parent_alloc);
key_infix, parent_alloc, is_index_scan);
if (!quick)
DBUG_RETURN(NULL);
@ -10161,6 +10192,9 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
key_infix_len Length of the key infix appended to the group prefix
key_infix Infix of constants from equality predicates
parent_alloc Memory pool for this and quick_prefix_select data
is_index_scan get the next different key not by jumping on it via
index read, but by scanning until the end of the
rows with equal key value.
RETURN
None
@ -10168,20 +10202,22 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
QUICK_GROUP_MIN_MAX_SELECT::
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
bool have_max_arg,
bool have_max_arg, bool have_agg_distinct_arg,
KEY_PART_INFO *min_max_arg_part_arg,
uint group_prefix_len_arg, uint group_key_parts_arg,
uint used_key_parts_arg, KEY *index_info_arg,
uint use_index, double read_cost_arg,
ha_rows records_arg, uint key_infix_len_arg,
uchar *key_infix_arg, MEM_ROOT *parent_alloc)
uchar *key_infix_arg, MEM_ROOT *parent_alloc,
bool is_index_scan_arg)
:join(join_arg), index_info(index_info_arg),
group_prefix_len(group_prefix_len_arg),
group_key_parts(group_key_parts_arg), have_min(have_min_arg),
have_max(have_max_arg), seen_first_key(FALSE),
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg),
key_infix_len(key_infix_len_arg), min_functions_it(NULL),
max_functions_it(NULL)
have_max(have_max_arg), have_agg_distinct(have_agg_distinct_arg),
seen_first_key(FALSE), min_max_arg_part(min_max_arg_part_arg),
key_infix(key_infix_arg), key_infix_len(key_infix_len_arg),
min_functions_it(NULL), max_functions_it(NULL),
is_index_scan(is_index_scan_arg)
{
head= table;
file= head->file;
@ -10744,6 +10780,56 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max()
}
/**
Find the next different key value by skiping all the rows with the same key
value.
Implements a specialized loose index access method for queries
containing aggregate functions with distinct of the form:
SELECT [SUM|COUNT|AVG](DISTINCT a,...) FROM t
This method comes to replace the index scan + Unique class
(distinct selection) for loose index scan that visits all the rows of a
covering index instead of jumping in the begining of each group.
TODO: Placeholder function. To be replaced by a handler API call
@param is_index_scan hint to use index scan instead of random index read
to find the next different value.
@param file table handler
@param key_part group key to compare
@param record row data
@param group_prefix current key prefix data
@param group_prefix_len length of the current key prefix data
@param group_key_parts number of the current key prefix columns
@return status
@retval 0 success
@retval !0 failure
*/
static int index_next_different (bool is_index_scan, handler *file,
KEY_PART_INFO *key_part, uchar * record,
const uchar * group_prefix,
uint group_prefix_len,
uint group_key_parts)
{
if (is_index_scan)
{
int result= 0;
while (!key_cmp (key_part, group_prefix, group_prefix_len))
{
result= file->index_next(record);
if (result)
return(result);
}
return result;
}
else
return file->index_read_map(record, group_prefix,
make_prev_keypart_map(group_key_parts),
HA_READ_AFTER_KEY);
}
/*
Determine the prefix of the next group.
@ -10790,9 +10876,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
else
{
/* Load the first key in this group into record. */
result= file->index_read_map(record, group_prefix,
make_prev_keypart_map(group_key_parts),
HA_READ_AFTER_KEY);
result= index_next_different (is_index_scan, file, index_info->key_part,
record, group_prefix, group_prefix_len,
group_key_parts);
if (result)
DBUG_RETURN(result);
}

View file

@ -616,6 +616,7 @@ private:
uchar *last_prefix; /* Prefix of the last group for detecting EOF. */
bool have_min; /* Specify whether we are computing */
bool have_max; /* a MIN, a MAX, or both. */
bool have_agg_distinct;/* aggregate_function(DISTINCT ...). */
bool seen_first_key; /* Denotes whether the first key was retrieved.*/
KEY_PART_INFO *min_max_arg_part; /* The keypart of the only argument field */
/* of all MIN/MAX functions. */
@ -629,6 +630,11 @@ private:
List<Item_sum> *max_functions;
List_iterator<Item_sum> *min_functions_it;
List_iterator<Item_sum> *max_functions_it;
/*
Use index scan to get the next different key instead of jumping into it
through index read
*/
bool is_index_scan;
public:
/*
The following two members are public to allow easy access from
@ -646,12 +652,13 @@ private:
void update_max_result();
public:
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
bool have_max, KEY_PART_INFO *min_max_arg_part,
bool have_max, bool have_agg_distinct,
KEY_PART_INFO *min_max_arg_part,
uint group_prefix_len, uint group_key_parts,
uint used_key_parts, KEY *index_info, uint
use_index, double read_cost, ha_rows records, uint
key_infix_len, uchar *key_infix, MEM_ROOT
*parent_alloc);
*parent_alloc, bool is_index_scan);
~QUICK_GROUP_MIN_MAX_SELECT();
bool add_range(SEL_ARG *sel_range);
void update_key_stat();
@ -667,6 +674,12 @@ public:
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
bool is_agg_distinct() { return have_agg_distinct; }
virtual void append_loose_scan_type(String *str)
{
if (is_index_scan)
str->append(STRING_WITH_LEN(" (scanning)"));
}
};

View file

@ -355,10 +355,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
const_result= 0;
break;
}
item_sum->set_aggregator (item_sum->with_distinct ?
Aggregator::DISTINCT_AGGREGATOR :
Aggregator::SIMPLE_AGGREGATOR);
if (!count)
{
/* If count == 0, then we know that is_exact_count == TRUE. */
((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */
((Item_sum_min*) item_sum)->aggregator_clear(); /* Set to NULL. */
}
else
((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */
@ -443,10 +446,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
const_result= 0;
break;
}
item_sum->set_aggregator (item_sum->with_distinct ?
Aggregator::DISTINCT_AGGREGATOR :
Aggregator::SIMPLE_AGGREGATOR);
if (!count)
{
/* If count != 1, then we know that is_exact_count == TRUE. */
((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */
((Item_sum_max*) item_sum)->aggregator_clear(); /* Set to NULL. */
}
else
((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */

View file

@ -54,6 +54,7 @@
class Reprepare_observer
{
public:
Reprepare_observer() {}
/**
Check if a change of metadata is OK. In future
the signature of this method may be extended to accept the old

View file

@ -222,6 +222,7 @@ static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
static void copy_sum_funcs(Item_sum **func_ptr, Item_sum **end);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr);
static bool prepare_sum_aggregators(Item_sum **func_ptr, bool need_distinct);
static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table,bool need_order,
@ -1232,7 +1233,11 @@ JOIN::optimize()
if (test_if_subpart(group_list, order) ||
(!group_list && tmp_table_param.sum_func_count))
{
order=0;
if (is_indexed_agg_distinct(this, NULL))
sort_and_group= 0;
}
// Can't use sort on head table if using row cache
if (full_join)
@ -1410,8 +1415,16 @@ JOIN::optimize()
single table queries, thus it is sufficient to test only the first
join_tab element of the plan for its access method.
*/
bool need_distinct= TRUE;
if (join_tab->is_using_loose_index_scan())
{
tmp_table_param.precomputed_group_by= TRUE;
if (join_tab->is_using_agg_loose_index_scan())
{
need_distinct= FALSE;
tmp_table_param.precomputed_group_by= FALSE;
}
}
/* Create a tmp table if distinct or if the sort is too complicated */
if (need_tmp)
@ -1472,6 +1485,7 @@ JOIN::optimize()
HA_POS_ERROR, HA_POS_ERROR, FALSE) ||
alloc_group_fields(this, group_list) ||
make_sum_func_list(all_fields, fields_list, 1) ||
prepare_sum_aggregators(sum_funcs, need_distinct) ||
setup_sum_funcs(thd, sum_funcs))
{
DBUG_RETURN(1);
@ -1481,6 +1495,7 @@ JOIN::optimize()
else
{
if (make_sum_func_list(all_fields, fields_list, 0) ||
prepare_sum_aggregators(sum_funcs, need_distinct) ||
setup_sum_funcs(thd, sum_funcs))
{
DBUG_RETURN(1);
@ -1953,7 +1968,9 @@ JOIN::exec()
}
}
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1, TRUE))
1, TRUE) ||
prepare_sum_aggregators(curr_join->sum_funcs,
!curr_join->join_tab->is_using_agg_loose_index_scan()))
DBUG_VOID_RETURN;
curr_join->group_list= 0;
if (!curr_join->sort_and_group &&
@ -2056,6 +2073,8 @@ JOIN::exec()
if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list,
1, TRUE) ||
prepare_sum_aggregators (curr_join->sum_funcs, !curr_join->join_tab ||
!curr_join->join_tab->is_using_agg_loose_index_scan()) ||
setup_sum_funcs(curr_join->thd, curr_join->sum_funcs) ||
thd->is_fatal_error)
DBUG_VOID_RETURN;
@ -3937,6 +3956,82 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
}
/**
Check for the presence of AGGFN(DISTINCT a) queries that may be subject
to loose index scan.
Check if the query is a subject to AGGFN(DISTINCT) using loose index scan
(QUICK_GROUP_MIN_MAX_SELECT).
Optionally (if out_args is supplied) will push the arguments of
AGGFN(DISTINCT) to the list
@param join the join to check
@param[out] out_args list of aggregate function arguments
@return does the query qualify for indexed AGGFN(DISTINCT)
@retval true it does
@retval false AGGFN(DISTINCT) must apply distinct in it.
*/
bool
is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
{
Item_sum **sum_item_ptr;
bool result= false;
if (join->tables != 1 || /* reference more than 1 table */
join->select_distinct || /* or a DISTINCT */
join->select_lex->olap == ROLLUP_TYPE) /* Check (B3) for ROLLUP */
return false;
if (join->make_sum_func_list(join->all_fields, join->fields_list, 1))
return false;
for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++)
{
Item_sum *sum_item= *sum_item_ptr;
Item *expr;
/* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */
switch (sum_item->sum_func())
{
case Item_sum::MIN_FUNC:
case Item_sum::MAX_FUNC:
continue;
case Item_sum::COUNT_DISTINCT_FUNC:
break;
case Item_sum::AVG_DISTINCT_FUNC:
case Item_sum::SUM_DISTINCT_FUNC:
if (sum_item->get_arg_count() == 1)
break;
/* fall through */
default: return false;
}
/*
We arrive here for every COUNT(DISTINCT),AVG(DISTINCT) or SUM(DISTINCT).
Collect the arguments of the aggregate functions to a list.
We don't worry about duplicates as these will be sorted out later in
get_best_group_min_max
*/
for (uint i= 0; i < sum_item->get_arg_count(); i++)
{
expr= sum_item->get_arg(i);
/* The AGGFN(DISTINCT) arg is not an attribute? */
if (expr->real_item()->type() != Item::FIELD_ITEM)
return false;
/*
If we came to this point the AGGFN(DISTINCT) loose index scan
optimization is applicable
*/
if (out_args)
out_args->push_back((Item_field *) expr);
result= true;
}
}
return result;
}
/**
Discover the indexes that can be used for GROUP BY or DISTINCT queries.
@ -3979,6 +4074,10 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab)
item->walk(&Item::collect_item_field_processor, 0,
(uchar*) &indexed_fields);
}
else if (is_indexed_agg_distinct(join, &indexed_fields))
{
join->sort_and_group= 1;
}
else
return;
@ -10377,6 +10476,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list)
bzero(share, sizeof(*share));
table->field= field;
table->s= share;
table->temp_pool_slot= MY_BIT_NONE;
share->blob_field= blob_field;
share->fields= field_count;
share->blob_ptr_size= portable_sizeof_char_ptr;
@ -14532,7 +14632,7 @@ setup_new_fields(THD *thd, List<Item> &fields,
optimize away 'order by'.
*/
static ORDER *
ORDER *
create_distinct_group(THD *thd, Item **ref_pointer_array,
ORDER *order_list, List<Item> &fields,
List<Item> &all_fields,
@ -15334,7 +15434,22 @@ static bool setup_sum_funcs(THD *thd, Item_sum **func_ptr)
DBUG_ENTER("setup_sum_funcs");
while ((func= *(func_ptr++)))
{
if (func->setup(thd))
if (func->aggregator_setup(thd))
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
}
static bool prepare_sum_aggregators(Item_sum **func_ptr, bool need_distinct)
{
Item_sum *func;
DBUG_ENTER("setup_sum_funcs");
while ((func= *(func_ptr++)))
{
if (func->set_aggregator(need_distinct && func->with_distinct ?
Aggregator::DISTINCT_AGGREGATOR :
Aggregator::SIMPLE_AGGREGATOR))
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
@ -15384,7 +15499,7 @@ init_sum_functions(Item_sum **func_ptr, Item_sum **end_ptr)
/* If rollup, calculate the upper sum levels */
for ( ; *func_ptr ; func_ptr++)
{
if ((*func_ptr)->add())
if ((*func_ptr)->aggregator_add())
return 1;
}
return 0;
@ -15396,7 +15511,7 @@ update_sum_func(Item_sum **func_ptr)
{
Item_sum *func;
for (; (func= (Item_sum*) *func_ptr) ; func_ptr++)
if (func->add())
if (func->aggregator_add())
return 1;
return 0;
}
@ -16313,7 +16428,12 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (key_read)
{
if (quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)
{
QUICK_GROUP_MIN_MAX_SELECT *qgs=
(QUICK_GROUP_MIN_MAX_SELECT *) tab->select->quick;
extra.append(STRING_WITH_LEN("; Using index for group-by"));
qgs->append_loose_scan_type(&extra);
}
else
extra.append(STRING_WITH_LEN("; Using index"));
}

View file

@ -218,6 +218,11 @@ typedef struct st_join_table {
(select->quick->get_type() ==
QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX));
}
bool is_using_agg_loose_index_scan ()
{
return (is_using_loose_index_scan() &&
((QUICK_GROUP_MIN_MAX_SELECT *)select->quick)->is_agg_distinct());
}
} JOIN_TAB;
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
@ -564,6 +569,8 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field,
const char *name, TABLE *table,
Item_field *item, uint convert_blob_length);
bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
/* functions from opt_sum.cc */
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);

View file

@ -8182,7 +8182,7 @@ sum_expr:
}
| AVG_SYM '(' DISTINCT in_sum_expr ')'
{
$$= new (YYTHD->mem_root) Item_sum_avg_distinct($4);
$$= new (YYTHD->mem_root) Item_sum_avg($4, TRUE);
if ($$ == NULL)
MYSQL_YYABORT;
}
@ -8225,7 +8225,7 @@ sum_expr:
{ Select->in_sum_expr--; }
')'
{
$$= new (YYTHD->mem_root) Item_sum_count_distinct(* $5);
$$= new (YYTHD->mem_root) Item_sum_count(* $5);
if ($$ == NULL)
MYSQL_YYABORT;
}
@ -8290,7 +8290,7 @@ sum_expr:
}
| SUM_SYM '(' DISTINCT in_sum_expr ')'
{
$$= new (YYTHD->mem_root) Item_sum_sum_distinct($4);
$$= new (YYTHD->mem_root) Item_sum_sum($4, TRUE);
if ($$ == NULL)
MYSQL_YYABORT;
}