mirror of
https://github.com/MariaDB/server.git
synced 2025-02-02 03:51:50 +01:00
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.1-new
into pylon.mylan:/home/psergey/mysql-5.1-26dec-merge
This commit is contained in:
commit
059aaa8ec8
18 changed files with 2169 additions and 62 deletions
261
mysql-test/r/partition_pruning.result
Normal file
261
mysql-test/r/partition_pruning.result
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
create table t1 ( a int not null) partition by hash(a) partitions 2;
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
explain select * from t1 where a=5 and a=6;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
a int(11) not null
|
||||||
|
) partition by hash (a) partitions 2;
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
explain partitions select * from t1 where a=1;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 p1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t1 where a=2;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t1 where a=1 or a=2;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
create table t2 (
|
||||||
|
a int not null,
|
||||||
|
b int not null
|
||||||
|
) partition by key(a,b) partitions 2;
|
||||||
|
insert into t2 values (1,1),(2,2),(3,3);
|
||||||
|
explain partitions select * from t2 where a=1;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t2 p0,p1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t2 where b=1;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t2 p0,p1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t2 where a=1 and b=1;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t2 p0 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
create table t3 (
|
||||||
|
a int
|
||||||
|
)
|
||||||
|
partition by range (a*1) (
|
||||||
|
partition p0 values less than (10),
|
||||||
|
partition p1 values less than (20)
|
||||||
|
);
|
||||||
|
insert into t3 values (5),(15);
|
||||||
|
explain partitions select * from t3 where a=11;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t3 p1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
explain partitions select * from t3 where a=10;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t3 p1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
explain partitions select * from t3 where a=20;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
explain partitions select * from t3 where a=30;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
create table t4 (a int not null, b int not null) partition by LIST (a+b) (
|
||||||
|
partition p0 values in (12),
|
||||||
|
partition p1 values in (14)
|
||||||
|
);
|
||||||
|
insert into t4 values (10,2), (10,4);
|
||||||
|
explain partitions select * from t4 where (a=10 and b=1) or (a=10 and b=2);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t4 p0 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
explain partitions select * from t4
|
||||||
|
where (a=10 and b=1) or (a=10 and b=2) or (a=10 and b = 3);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t4 p0 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
explain partitions select * from t4 where (a=10 and b=2) or (a=10 and b=3)
|
||||||
|
or (a=10 and b = 4);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t4 p0,p1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
explain partitions select * from t4 where (a=10 and b=1) or a=11;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t4 p0,p1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
explain partitions select * from t4 where (a=10 and b=2) or a=11;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t4 p0,p1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
drop table t1, t2, t3, t4;
|
||||||
|
create table t5 (a int not null, b int not null,
|
||||||
|
c int not null, d int not null)
|
||||||
|
partition by LIST(a+b) subpartition by HASH (c+d) subpartitions 2
|
||||||
|
(
|
||||||
|
partition p0 values in (12),
|
||||||
|
partition p1 values in (14)
|
||||||
|
);
|
||||||
|
insert into t5 values (10,2,0,0), (10,4,0,0), (10,2,0,1), (10,4,0,1);
|
||||||
|
explain partitions select * from t5;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t5 p0_sp0,p0_sp1,p1_sp0,p1_sp1 ALL NULL NULL NULL NULL 4
|
||||||
|
explain partitions select * from t5
|
||||||
|
where (a=10 and b=1) or (a=10 and b=2) or (a=10 and b = 3);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t5 p0_sp0,p0_sp1 ALL NULL NULL NULL NULL 4 Using where
|
||||||
|
explain partitions select * from t5 where (a=10 and b=2) or (a=10 and b=3)
|
||||||
|
or (a=10 and b = 4);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t5 p0_sp0,p0_sp1,p1_sp0,p1_sp1 ALL NULL NULL NULL NULL 4 Using where
|
||||||
|
explain partitions select * from t5 where (c=1 and d=1);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t5 p0_sp0,p1_sp0 ALL NULL NULL NULL NULL 4 Using where
|
||||||
|
explain partitions select * from t5 where (c=2 and d=1);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t5 p0_sp1,p1_sp1 ALL NULL NULL NULL NULL 4 Using where
|
||||||
|
explain partitions select * from t5 where (a=10 and b=2 and c=1 and d=1) or
|
||||||
|
(c=2 and d=1);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t5 p0_sp0,p0_sp1,p1_sp1 ALL NULL NULL NULL NULL 4 Using where
|
||||||
|
explain partitions select * from t5 where (a=10 and b=2 and c=1 and d=1) or
|
||||||
|
(b=2 and c=2 and d=1);
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t5 p0_sp0,p0_sp1,p1_sp1 ALL NULL NULL NULL NULL 4 Using where
|
||||||
|
create table t6 (a int not null) partition by LIST(a) (
|
||||||
|
partition p1 values in (1),
|
||||||
|
partition p3 values in (3),
|
||||||
|
partition p5 values in (5),
|
||||||
|
partition p7 values in (7),
|
||||||
|
partition p9 values in (9)
|
||||||
|
);
|
||||||
|
insert into t6 values (1),(3),(5);
|
||||||
|
explain partitions select * from t6 where a < 1;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
explain partitions select * from t6 where a <= 1;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t6 p1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t6 where a > 9;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
explain partitions select * from t6 where a >= 9;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t6 p9 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t6 where a > 0 and a < 5;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t6 p1,p3 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t6 where a > 5 and a < 12;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t6 p7,p9 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t6 where a > 3 and a < 8 ;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t6 p5,p7 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t6 where a >= 0 and a <= 5;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t6 p1,p3,p5 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t6 where a >= 5 and a <= 12;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t6 p5,p7,p9 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t6 where a >= 3 and a <= 8;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t6 p3,p5,p7 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t6 where a > 3 and a < 5;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
create table t7 (a int not null) partition by RANGE(a) (
|
||||||
|
partition p10 values less than (10),
|
||||||
|
partition p30 values less than (30),
|
||||||
|
partition p50 values less than (50),
|
||||||
|
partition p70 values less than (70),
|
||||||
|
partition p90 values less than (90)
|
||||||
|
);
|
||||||
|
insert into t7 values (10),(30),(50);
|
||||||
|
explain partitions select * from t7 where a < 5;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t7 p10 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t7 where a < 10;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t7 p10 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t7 where a <= 10;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t7 p10,p30 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t7 where a = 10;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t7 p30 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t7 where a < 90;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t7 p10,p30,p50,p70,p90 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t7 where a = 90;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
explain partitions select * from t7 where a > 90;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
explain partitions select * from t7 where a >= 90;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
explain partitions select * from t7 where a > 11 and a < 29;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t7 p30 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
create table t8 (a date not null) partition by RANGE(YEAR(a)) (
|
||||||
|
partition p0 values less than (1980),
|
||||||
|
partition p1 values less than (1990),
|
||||||
|
partition p2 values less than (2000)
|
||||||
|
);
|
||||||
|
insert into t8 values ('1985-05-05'),('1995-05-05');
|
||||||
|
explain partitions select * from t8 where a < '1980-02-02';
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t8 p0,p1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
create table t9 (a date not null) partition by RANGE(TO_DAYS(a)) (
|
||||||
|
partition p0 values less than (732299), -- 2004-12-19
|
||||||
|
partition p1 values less than (732468), -- 2005-06-06
|
||||||
|
partition p2 values less than (732664) -- 2005-12-19
|
||||||
|
);
|
||||||
|
insert into t9 values ('2005-05-05'), ('2005-04-04');
|
||||||
|
explain partitions select * from t9 where a < '2004-12-19';
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t9 p0 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
explain partitions select * from t9 where a <= '2004-12-19';
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t9 p0,p1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
drop table t5,t6,t7,t8,t9;
|
||||||
|
create table t1 (a enum('a','b','c','d') default 'a')
|
||||||
|
partition by hash (ascii(a)) partitions 2;
|
||||||
|
insert into t1 values ('a'),('b'),('c');
|
||||||
|
explain partitions select * from t1 where a='b';
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
drop table t1;
|
||||||
|
create table t1 (
|
||||||
|
a1 int not null
|
||||||
|
)
|
||||||
|
partition by range (a1) (
|
||||||
|
partition p0 values less than (3),
|
||||||
|
partition p1 values less than (6),
|
||||||
|
partition p2 values less than (9)
|
||||||
|
);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
explain partitions select * from t1 where a1 > 3;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 p1,p2 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t1 where a1 >= 3;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 p1,p2 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t1 where a1 < 3 and a1 > 3;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
|
drop table t1;
|
||||||
|
create table t3 (a int, b int)
|
||||||
|
partition by list(a) subpartition by hash(b) subpartitions 4 (
|
||||||
|
partition p0 values in (1),
|
||||||
|
partition p1 values in (2),
|
||||||
|
partition p2 values in (3),
|
||||||
|
partition p3 values in (4)
|
||||||
|
);
|
||||||
|
insert into t3 values (1,1),(2,2),(3,3);
|
||||||
|
explain partitions select * from t3 where a=2 or b=1;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t3 p0_sp1,p1_sp0,p1_sp1,p1_sp2,p1_sp3,p2_sp1,p3_sp1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t3 where a=4 or b=2;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t3 p0_sp2,p1_sp2,p2_sp2,p3_sp0,p3_sp1,p3_sp2,p3_sp3 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
explain partitions select * from t3 where (a=2 or b=1) and (a=4 or b=2) ;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t3 p1_sp2,p3_sp1 ALL NULL NULL NULL NULL 3 Using where
|
||||||
|
drop table t3;
|
||||||
|
create table t1 (a int) partition by hash(a) partitions 2;
|
||||||
|
insert into t1 values (1),(2);
|
||||||
|
explain partitions select * from t1 where a is null;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
explain partitions select * from t1 where a is not null;
|
||||||
|
id select_type table partitions type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 2 Using where
|
||||||
|
drop table t1;
|
|
@ -1,4 +1,4 @@
|
||||||
drop table if exists t1,t2;
|
drop table if exists t1,t2,t3,t4;
|
||||||
drop database if exists client_test_db;
|
drop database if exists client_test_db;
|
||||||
create table t1
|
create table t1
|
||||||
(
|
(
|
||||||
|
|
238
mysql-test/t/partition_pruning.test
Normal file
238
mysql-test/t/partition_pruning.test
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
#
|
||||||
|
# Partition pruning tests. Currently we only detect which partitions to
|
||||||
|
# prune, so the test is EXPLAINs.
|
||||||
|
#
|
||||||
|
-- source include/have_partition.inc
|
||||||
|
|
||||||
|
--disable_warnings
|
||||||
|
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
|
||||||
|
# Check if we can infer from condition on partition fields that
|
||||||
|
# no records will match.
|
||||||
|
create table t1 ( a int not null) partition by hash(a) partitions 2;
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
explain select * from t1 where a=5 and a=6;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# Simple HASH partitioning
|
||||||
|
create table t1 (
|
||||||
|
a int(11) not null
|
||||||
|
) partition by hash (a) partitions 2;
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
|
||||||
|
explain partitions select * from t1 where a=1;
|
||||||
|
explain partitions select * from t1 where a=2;
|
||||||
|
explain partitions select * from t1 where a=1 or a=2;
|
||||||
|
|
||||||
|
# Partitioning over several fields
|
||||||
|
create table t2 (
|
||||||
|
a int not null,
|
||||||
|
b int not null
|
||||||
|
) partition by key(a,b) partitions 2;
|
||||||
|
insert into t2 values (1,1),(2,2),(3,3);
|
||||||
|
|
||||||
|
explain partitions select * from t2 where a=1;
|
||||||
|
explain partitions select * from t2 where b=1;
|
||||||
|
|
||||||
|
explain partitions select * from t2 where a=1 and b=1;
|
||||||
|
|
||||||
|
# RANGE(expr) partitioning
|
||||||
|
create table t3 (
|
||||||
|
a int
|
||||||
|
)
|
||||||
|
partition by range (a*1) (
|
||||||
|
partition p0 values less than (10),
|
||||||
|
partition p1 values less than (20)
|
||||||
|
);
|
||||||
|
insert into t3 values (5),(15);
|
||||||
|
|
||||||
|
explain partitions select * from t3 where a=11;
|
||||||
|
explain partitions select * from t3 where a=10;
|
||||||
|
explain partitions select * from t3 where a=20;
|
||||||
|
|
||||||
|
explain partitions select * from t3 where a=30;
|
||||||
|
|
||||||
|
# LIST(expr) partitioning
|
||||||
|
create table t4 (a int not null, b int not null) partition by LIST (a+b) (
|
||||||
|
partition p0 values in (12),
|
||||||
|
partition p1 values in (14)
|
||||||
|
);
|
||||||
|
insert into t4 values (10,2), (10,4);
|
||||||
|
|
||||||
|
# empty OR one
|
||||||
|
explain partitions select * from t4 where (a=10 and b=1) or (a=10 and b=2);
|
||||||
|
|
||||||
|
# empty OR one OR empty
|
||||||
|
explain partitions select * from t4
|
||||||
|
where (a=10 and b=1) or (a=10 and b=2) or (a=10 and b = 3);
|
||||||
|
|
||||||
|
# one OR empty OR one
|
||||||
|
explain partitions select * from t4 where (a=10 and b=2) or (a=10 and b=3)
|
||||||
|
or (a=10 and b = 4);
|
||||||
|
|
||||||
|
# empty OR full
|
||||||
|
explain partitions select * from t4 where (a=10 and b=1) or a=11;
|
||||||
|
|
||||||
|
# one OR full
|
||||||
|
explain partitions select * from t4 where (a=10 and b=2) or a=11;
|
||||||
|
|
||||||
|
drop table t1, t2, t3, t4;
|
||||||
|
|
||||||
|
# LIST(expr)/HASH subpartitioning.
|
||||||
|
create table t5 (a int not null, b int not null,
|
||||||
|
c int not null, d int not null)
|
||||||
|
partition by LIST(a+b) subpartition by HASH (c+d) subpartitions 2
|
||||||
|
(
|
||||||
|
partition p0 values in (12),
|
||||||
|
partition p1 values in (14)
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into t5 values (10,2,0,0), (10,4,0,0), (10,2,0,1), (10,4,0,1);
|
||||||
|
explain partitions select * from t5;
|
||||||
|
|
||||||
|
# empty OR one OR empty
|
||||||
|
explain partitions select * from t5
|
||||||
|
where (a=10 and b=1) or (a=10 and b=2) or (a=10 and b = 3);
|
||||||
|
|
||||||
|
# one OR empty OR one
|
||||||
|
explain partitions select * from t5 where (a=10 and b=2) or (a=10 and b=3)
|
||||||
|
or (a=10 and b = 4);
|
||||||
|
|
||||||
|
# conditions on subpartitions only
|
||||||
|
explain partitions select * from t5 where (c=1 and d=1);
|
||||||
|
explain partitions select * from t5 where (c=2 and d=1);
|
||||||
|
|
||||||
|
# mixed partition/subpartitions.
|
||||||
|
explain partitions select * from t5 where (a=10 and b=2 and c=1 and d=1) or
|
||||||
|
(c=2 and d=1);
|
||||||
|
|
||||||
|
# same as above
|
||||||
|
explain partitions select * from t5 where (a=10 and b=2 and c=1 and d=1) or
|
||||||
|
(b=2 and c=2 and d=1);
|
||||||
|
|
||||||
|
# LIST(field) partitioning, interval analysis.
|
||||||
|
create table t6 (a int not null) partition by LIST(a) (
|
||||||
|
partition p1 values in (1),
|
||||||
|
partition p3 values in (3),
|
||||||
|
partition p5 values in (5),
|
||||||
|
partition p7 values in (7),
|
||||||
|
partition p9 values in (9)
|
||||||
|
);
|
||||||
|
insert into t6 values (1),(3),(5);
|
||||||
|
|
||||||
|
explain partitions select * from t6 where a < 1;
|
||||||
|
explain partitions select * from t6 where a <= 1;
|
||||||
|
explain partitions select * from t6 where a > 9;
|
||||||
|
explain partitions select * from t6 where a >= 9;
|
||||||
|
|
||||||
|
explain partitions select * from t6 where a > 0 and a < 5;
|
||||||
|
explain partitions select * from t6 where a > 5 and a < 12;
|
||||||
|
explain partitions select * from t6 where a > 3 and a < 8 ;
|
||||||
|
|
||||||
|
explain partitions select * from t6 where a >= 0 and a <= 5;
|
||||||
|
explain partitions select * from t6 where a >= 5 and a <= 12;
|
||||||
|
explain partitions select * from t6 where a >= 3 and a <= 8;
|
||||||
|
|
||||||
|
explain partitions select * from t6 where a > 3 and a < 5;
|
||||||
|
|
||||||
|
# RANGE(field) partitioning, interval analysis.
|
||||||
|
create table t7 (a int not null) partition by RANGE(a) (
|
||||||
|
partition p10 values less than (10),
|
||||||
|
partition p30 values less than (30),
|
||||||
|
partition p50 values less than (50),
|
||||||
|
partition p70 values less than (70),
|
||||||
|
partition p90 values less than (90)
|
||||||
|
);
|
||||||
|
insert into t7 values (10),(30),(50);
|
||||||
|
|
||||||
|
# leftmost intervals
|
||||||
|
explain partitions select * from t7 where a < 5;
|
||||||
|
explain partitions select * from t7 where a < 10;
|
||||||
|
explain partitions select * from t7 where a <= 10;
|
||||||
|
explain partitions select * from t7 where a = 10;
|
||||||
|
|
||||||
|
#rightmost intervals
|
||||||
|
explain partitions select * from t7 where a < 90;
|
||||||
|
explain partitions select * from t7 where a = 90;
|
||||||
|
explain partitions select * from t7 where a > 90;
|
||||||
|
explain partitions select * from t7 where a >= 90;
|
||||||
|
|
||||||
|
# misc intervals
|
||||||
|
explain partitions select * from t7 where a > 11 and a < 29;
|
||||||
|
|
||||||
|
# LIST(monontonic_func) partitioning
|
||||||
|
create table t8 (a date not null) partition by RANGE(YEAR(a)) (
|
||||||
|
partition p0 values less than (1980),
|
||||||
|
partition p1 values less than (1990),
|
||||||
|
partition p2 values less than (2000)
|
||||||
|
);
|
||||||
|
insert into t8 values ('1985-05-05'),('1995-05-05');
|
||||||
|
|
||||||
|
explain partitions select * from t8 where a < '1980-02-02';
|
||||||
|
|
||||||
|
# LIST(strict_monotonic_func) partitioning
|
||||||
|
create table t9 (a date not null) partition by RANGE(TO_DAYS(a)) (
|
||||||
|
partition p0 values less than (732299), -- 2004-12-19
|
||||||
|
partition p1 values less than (732468), -- 2005-06-06
|
||||||
|
partition p2 values less than (732664) -- 2005-12-19
|
||||||
|
);
|
||||||
|
insert into t9 values ('2005-05-05'), ('2005-04-04');
|
||||||
|
|
||||||
|
explain partitions select * from t9 where a < '2004-12-19';
|
||||||
|
explain partitions select * from t9 where a <= '2004-12-19';
|
||||||
|
|
||||||
|
drop table t5,t6,t7,t8,t9;
|
||||||
|
|
||||||
|
# Test the case where we can't create partitioning 'index'
|
||||||
|
create table t1 (a enum('a','b','c','d') default 'a')
|
||||||
|
partition by hash (ascii(a)) partitions 2;
|
||||||
|
insert into t1 values ('a'),('b'),('c');
|
||||||
|
explain partitions select * from t1 where a='b';
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Test cases for bugs found in code review:
|
||||||
|
#
|
||||||
|
create table t1 (
|
||||||
|
a1 int not null
|
||||||
|
)
|
||||||
|
partition by range (a1) (
|
||||||
|
partition p0 values less than (3),
|
||||||
|
partition p1 values less than (6),
|
||||||
|
partition p2 values less than (9)
|
||||||
|
);
|
||||||
|
insert into t1 values (1),(2),(3);
|
||||||
|
explain partitions select * from t1 where a1 > 3;
|
||||||
|
explain partitions select * from t1 where a1 >= 3;
|
||||||
|
|
||||||
|
explain partitions select * from t1 where a1 < 3 and a1 > 3;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
create table t3 (a int, b int)
|
||||||
|
partition by list(a) subpartition by hash(b) subpartitions 4 (
|
||||||
|
partition p0 values in (1),
|
||||||
|
partition p1 values in (2),
|
||||||
|
partition p2 values in (3),
|
||||||
|
partition p3 values in (4)
|
||||||
|
);
|
||||||
|
insert into t3 values (1,1),(2,2),(3,3);
|
||||||
|
|
||||||
|
explain partitions select * from t3 where a=2 or b=1;
|
||||||
|
explain partitions select * from t3 where a=4 or b=2;
|
||||||
|
explain partitions select * from t3 where (a=2 or b=1) and (a=4 or b=2) ;
|
||||||
|
drop table t3;
|
||||||
|
|
||||||
|
# Test for NULLs
|
||||||
|
create table t1 (a int) partition by hash(a) partitions 2;
|
||||||
|
insert into t1 values (1),(2);
|
||||||
|
explain partitions select * from t1 where a is null;
|
||||||
|
|
||||||
|
# this selects both
|
||||||
|
explain partitions select * from t1 where a is not null;
|
||||||
|
drop table t1;
|
||||||
|
|
||||||
|
# No tests for NULLs in RANGE(monotonic_expr()) - they depend on BUG#15447
|
||||||
|
# being fixed.
|
|
@ -2,7 +2,7 @@
|
||||||
# SQL Syntax for Prepared Statements test
|
# SQL Syntax for Prepared Statements test
|
||||||
#
|
#
|
||||||
--disable_warnings
|
--disable_warnings
|
||||||
drop table if exists t1,t2;
|
drop table if exists t1,t2,t3,t4;
|
||||||
|
|
||||||
# Avoid wrong warnings if mysql_client_test fails
|
# Avoid wrong warnings if mysql_client_test fails
|
||||||
drop database if exists client_test_db;
|
drop database if exists client_test_db;
|
||||||
|
|
|
@ -3121,7 +3121,6 @@ void ha_ndbcluster::info(uint flag)
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int ha_ndbcluster::extra(enum ha_extra_function operation)
|
int ha_ndbcluster::extra(enum ha_extra_function operation)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("extra");
|
DBUG_ENTER("extra");
|
||||||
|
@ -3130,6 +3129,8 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
|
||||||
DBUG_PRINT("info", ("HA_EXTRA_RESET"));
|
DBUG_PRINT("info", ("HA_EXTRA_RESET"));
|
||||||
DBUG_PRINT("info", ("Clearing condition stack"));
|
DBUG_PRINT("info", ("Clearing condition stack"));
|
||||||
cond_clear();
|
cond_clear();
|
||||||
|
if (m_part_info)
|
||||||
|
bitmap_clear_all(&m_part_info->used_partitions);
|
||||||
break;
|
break;
|
||||||
case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/
|
case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/
|
||||||
DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY"));
|
DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY"));
|
||||||
|
|
|
@ -2799,6 +2799,8 @@ int ha_partition::reset(void)
|
||||||
handler **file;
|
handler **file;
|
||||||
DBUG_ENTER("ha_partition::reset");
|
DBUG_ENTER("ha_partition::reset");
|
||||||
file= m_file;
|
file= m_file;
|
||||||
|
if (m_part_info)
|
||||||
|
bitmap_clear_all(&m_part_info->used_partitions);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if ((tmp= (*file)->reset()))
|
if ((tmp= (*file)->reset()))
|
||||||
|
|
|
@ -547,19 +547,52 @@ public:
|
||||||
|
|
||||||
List<char> part_field_list;
|
List<char> part_field_list;
|
||||||
List<char> subpart_field_list;
|
List<char> subpart_field_list;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If there is no subpartitioning, use only this func to get partition ids.
|
||||||
|
If there is subpartitioning, use the this func to get partition id when
|
||||||
|
you have both partition and subpartition fields.
|
||||||
|
*/
|
||||||
get_part_id_func get_partition_id;
|
get_part_id_func get_partition_id;
|
||||||
get_part_id_func get_part_partition_id;
|
|
||||||
get_subpart_id_func get_subpartition_id;
|
|
||||||
|
|
||||||
|
/* Get partition id when we don't have subpartition fields */
|
||||||
|
get_part_id_func get_part_partition_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get subpartition id when we have don't have partition fields by we do
|
||||||
|
have subpartition ids.
|
||||||
|
Mikael said that for given constant tuple
|
||||||
|
{subpart_field1, ..., subpart_fieldN} the subpartition id will be the
|
||||||
|
same in all subpartitions
|
||||||
|
*/
|
||||||
|
get_subpart_id_func get_subpartition_id;
|
||||||
|
|
||||||
|
/* NULL-terminated list of fields used in partitioned expression */
|
||||||
Field **part_field_array;
|
Field **part_field_array;
|
||||||
|
/* NULL-terminated list of fields used in subpartitioned expression */
|
||||||
Field **subpart_field_array;
|
Field **subpart_field_array;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Array of all fields used in partition and subpartition expression,
|
||||||
|
without duplicates, NULL-terminated.
|
||||||
|
*/
|
||||||
Field **full_part_field_array;
|
Field **full_part_field_array;
|
||||||
|
|
||||||
Item *part_expr;
|
Item *part_expr;
|
||||||
Item *subpart_expr;
|
Item *subpart_expr;
|
||||||
|
|
||||||
Item *item_free_list;
|
Item *item_free_list;
|
||||||
|
|
||||||
|
/*
|
||||||
|
A bitmap of partitions used by the current query.
|
||||||
|
Usage pattern:
|
||||||
|
* It is guaranteed that all partitions are set to be unused on query start.
|
||||||
|
* Before index/rnd_init(), partition pruning code sets the bits for used
|
||||||
|
partitions.
|
||||||
|
* The handler->extra(HA_EXTRA_RESET) call at query end sets all partitions
|
||||||
|
to be unused.
|
||||||
|
*/
|
||||||
|
MY_BITMAP used_partitions;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
longlong *range_int_array;
|
longlong *range_int_array;
|
||||||
|
@ -760,6 +793,13 @@ void get_full_part_id_from_key(const TABLE *table, byte *buf,
|
||||||
bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
|
bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
|
||||||
uint part_info_len, TABLE *table,
|
uint part_info_len, TABLE *table,
|
||||||
handlerton *default_db_type);
|
handlerton *default_db_type);
|
||||||
|
void make_used_partitions_str(partition_info *part_info, String *parts_str);
|
||||||
|
uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
|
||||||
|
bool left_endpoint,
|
||||||
|
bool include_endpoint);
|
||||||
|
uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
|
||||||
|
bool left_endpoint,
|
||||||
|
bool include_endpoint);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
35
sql/item.h
35
sql/item.h
|
@ -368,6 +368,28 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This enum is used to report information about monotonicity of function
|
||||||
|
represented by Item* tree.
|
||||||
|
Monotonicity is defined only for Item* trees that represent table
|
||||||
|
partitioning expressions (i.e. have no subselects/user vars/PS parameters
|
||||||
|
etc etc). An Item* tree is assumed to have the same monotonicity properties
|
||||||
|
as its correspoinding function F:
|
||||||
|
|
||||||
|
[signed] longlong F(field1, field2, ...) {
|
||||||
|
put values of field_i into table record buffer;
|
||||||
|
return item->val_int();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum monotonicity_info
|
||||||
|
{
|
||||||
|
NON_MONOTONIC, /* none of the below holds */
|
||||||
|
MONOTONIC_INCREASING, /* F() is unary and "x < y" => "F(x) < F(y)" */
|
||||||
|
MONOTONIC_STRICT_INCREASING /* F() is unary and "x < y" => "F(x) <= F(y)" */
|
||||||
|
} enum_monotonicity_info;
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
typedef bool (Item::*Item_processor)(byte *arg);
|
typedef bool (Item::*Item_processor)(byte *arg);
|
||||||
|
@ -466,6 +488,15 @@ public:
|
||||||
virtual Item_result cast_to_int_type() const { return result_type(); }
|
virtual Item_result cast_to_int_type() const { return result_type(); }
|
||||||
virtual enum_field_types field_type() const;
|
virtual enum_field_types field_type() const;
|
||||||
virtual enum Type type() const =0;
|
virtual enum Type type() const =0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Return information about function monotonicity. See comment for
|
||||||
|
enum_monotonicity_info for details. This function can only be called
|
||||||
|
after fix_fields() call.
|
||||||
|
*/
|
||||||
|
virtual enum_monotonicity_info get_monotonicity_info() const
|
||||||
|
{ return NON_MONOTONIC; }
|
||||||
|
|
||||||
/* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */
|
/* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */
|
||||||
/*
|
/*
|
||||||
Return double precision floating point representation of item.
|
Return double precision floating point representation of item.
|
||||||
|
@ -1140,6 +1171,10 @@ public:
|
||||||
{
|
{
|
||||||
return field->type();
|
return field->type();
|
||||||
}
|
}
|
||||||
|
enum_monotonicity_info get_monotonicity_info() const
|
||||||
|
{
|
||||||
|
return MONOTONIC_STRICT_INCREASING;
|
||||||
|
}
|
||||||
Field *get_tmp_table_field() { return result_field; }
|
Field *get_tmp_table_field() { return result_field; }
|
||||||
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
|
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
|
||||||
bool get_date(TIME *ltime,uint fuzzydate);
|
bool get_date(TIME *ltime,uint fuzzydate);
|
||||||
|
|
|
@ -885,6 +885,19 @@ longlong Item_func_to_days::val_int()
|
||||||
return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
|
return (longlong) calc_daynr(ltime.year,ltime.month,ltime.day);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const
|
||||||
|
{
|
||||||
|
if (args[0]->type() == Item::FIELD_ITEM)
|
||||||
|
{
|
||||||
|
if (args[0]->field_type() == MYSQL_TYPE_DATE)
|
||||||
|
return MONOTONIC_STRICT_INCREASING;
|
||||||
|
if (args[0]->field_type() == MYSQL_TYPE_DATETIME)
|
||||||
|
return MONOTONIC_INCREASING;
|
||||||
|
}
|
||||||
|
return NON_MONOTONIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
longlong Item_func_dayofyear::val_int()
|
longlong Item_func_dayofyear::val_int()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 1);
|
DBUG_ASSERT(fixed == 1);
|
||||||
|
@ -1067,6 +1080,14 @@ longlong Item_func_year::val_int()
|
||||||
return (longlong) ltime.year;
|
return (longlong) ltime.year;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum_monotonicity_info Item_func_year::get_monotonicity_info() const
|
||||||
|
{
|
||||||
|
if (args[0]->type() == Item::FIELD_ITEM &&
|
||||||
|
(args[0]->field_type() == MYSQL_TYPE_DATE ||
|
||||||
|
args[0]->field_type() == MYSQL_TYPE_DATETIME))
|
||||||
|
return MONOTONIC_INCREASING;
|
||||||
|
return NON_MONOTONIC;
|
||||||
|
}
|
||||||
|
|
||||||
longlong Item_func_unix_timestamp::val_int()
|
longlong Item_func_unix_timestamp::val_int()
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,6 +65,7 @@ public:
|
||||||
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
|
max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
|
||||||
maybe_null=1;
|
maybe_null=1;
|
||||||
}
|
}
|
||||||
|
enum_monotonicity_info get_monotonicity_info() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,6 +235,7 @@ public:
|
||||||
Item_func_year(Item *a) :Item_int_func(a) {}
|
Item_func_year(Item *a) :Item_int_func(a) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "year"; }
|
const char *func_name() const { return "year"; }
|
||||||
|
enum_monotonicity_info get_monotonicity_info() const;
|
||||||
void fix_length_and_dec()
|
void fix_length_and_dec()
|
||||||
{
|
{
|
||||||
decimals=0;
|
decimals=0;
|
||||||
|
|
1307
sql/opt_range.cc
1307
sql/opt_range.cc
File diff suppressed because it is too large
Load diff
|
@ -249,6 +249,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
struct st_qsel_param;
|
struct st_qsel_param;
|
||||||
|
class PARAM;
|
||||||
class SEL_ARG;
|
class SEL_ARG;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -283,12 +284,12 @@ protected:
|
||||||
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
|
QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
|
||||||
struct st_table_ref *ref,
|
struct st_table_ref *ref,
|
||||||
ha_rows records);
|
ha_rows records);
|
||||||
friend bool get_quick_keys(struct st_qsel_param *param,
|
friend bool get_quick_keys(PARAM *param,
|
||||||
QUICK_RANGE_SELECT *quick,KEY_PART *key,
|
QUICK_RANGE_SELECT *quick,KEY_PART *key,
|
||||||
SEL_ARG *key_tree,
|
SEL_ARG *key_tree,
|
||||||
char *min_key, uint min_key_flag,
|
char *min_key, uint min_key_flag,
|
||||||
char *max_key, uint max_key_flag);
|
char *max_key, uint max_key_flag);
|
||||||
friend QUICK_RANGE_SELECT *get_quick_select(struct st_qsel_param*,uint idx,
|
friend QUICK_RANGE_SELECT *get_quick_select(PARAM*,uint idx,
|
||||||
SEL_ARG *key_tree,
|
SEL_ARG *key_tree,
|
||||||
MEM_ROOT *alloc);
|
MEM_ROOT *alloc);
|
||||||
friend class QUICK_SELECT_DESC;
|
friend class QUICK_SELECT_DESC;
|
||||||
|
@ -718,4 +719,8 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
|
||||||
ha_rows records);
|
ha_rows records);
|
||||||
uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit);
|
uint get_index_for_order(TABLE *table, ORDER *order, ha_rows limit);
|
||||||
|
|
||||||
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
|
bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -755,6 +755,13 @@ int THD::send_explain_fields(select_result *result)
|
||||||
field_list.push_back(new Item_empty_string("select_type", 19, cs));
|
field_list.push_back(new Item_empty_string("select_type", 19, cs));
|
||||||
field_list.push_back(item= new Item_empty_string("table", NAME_LEN, cs));
|
field_list.push_back(item= new Item_empty_string("table", NAME_LEN, cs));
|
||||||
item->maybe_null= 1;
|
item->maybe_null= 1;
|
||||||
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
|
if (lex->describe & DESCRIBE_PARTITIONS)
|
||||||
|
{
|
||||||
|
field_list.push_back(item= new Item_empty_string("partitions", 10, cs));
|
||||||
|
item->maybe_null= 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
field_list.push_back(item= new Item_empty_string("type", 10, cs));
|
field_list.push_back(item= new Item_empty_string("type", 10, cs));
|
||||||
item->maybe_null= 1;
|
item->maybe_null= 1;
|
||||||
field_list.push_back(item=new Item_empty_string("possible_keys",
|
field_list.push_back(item=new Item_empty_string("possible_keys",
|
||||||
|
|
|
@ -103,6 +103,11 @@ enum enum_sql_command {
|
||||||
// describe/explain types
|
// describe/explain types
|
||||||
#define DESCRIBE_NORMAL 1
|
#define DESCRIBE_NORMAL 1
|
||||||
#define DESCRIBE_EXTENDED 2
|
#define DESCRIBE_EXTENDED 2
|
||||||
|
/*
|
||||||
|
This is not #ifdef'ed because we want "EXPLAIN PARTITIONS ..." to produce
|
||||||
|
additional "partitions" column even if partitioning is not compiled in.
|
||||||
|
*/
|
||||||
|
#define DESCRIBE_PARTITIONS 4
|
||||||
|
|
||||||
enum enum_sp_suid_behaviour
|
enum enum_sp_suid_behaviour
|
||||||
{
|
{
|
||||||
|
|
|
@ -2478,17 +2478,96 @@ bool get_partition_id_list(partition_info *part_info,
|
||||||
if (list_value < part_func_value)
|
if (list_value < part_func_value)
|
||||||
min_list_index= list_index + 1;
|
min_list_index= list_index + 1;
|
||||||
else if (list_value > part_func_value)
|
else if (list_value > part_func_value)
|
||||||
|
{
|
||||||
|
if (!list_index)
|
||||||
|
goto notfound;
|
||||||
max_list_index= list_index - 1;
|
max_list_index= list_index - 1;
|
||||||
else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
*part_id= (uint32)list_array[list_index].partition_id;
|
*part_id= (uint32)list_array[list_index].partition_id;
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
notfound:
|
||||||
*part_id= 0;
|
*part_id= 0;
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find the sub-array part_info->list_array that corresponds to given interval
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
get_list_array_idx_for_endpoint()
|
||||||
|
part_info Partitioning info (partitioning type must be LIST)
|
||||||
|
left_endpoint TRUE - the interval is [a; +inf) or (a; +inf)
|
||||||
|
FALSE - the interval is (-inf; a] or (-inf; a)
|
||||||
|
include_endpoint TRUE iff the interval includes the endpoint
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
This function finds the sub-array of part_info->list_array where values of
|
||||||
|
list_array[idx].list_value are contained within the specifed interval.
|
||||||
|
list_array is ordered by list_value, so
|
||||||
|
1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==TRUE), the
|
||||||
|
sought sub-array starts at some index idx and continues till array end.
|
||||||
|
The function returns first number idx, such that
|
||||||
|
list_array[idx].list_value is contained within the passed interval.
|
||||||
|
|
||||||
|
2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==FALSE), the
|
||||||
|
sought sub-array starts at array start and continues till some last
|
||||||
|
index idx.
|
||||||
|
The function returns first number idx, such that
|
||||||
|
list_array[idx].list_value is NOT contained within the passed interval.
|
||||||
|
If all array elements are contained, part_info->no_list_values is
|
||||||
|
returned.
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
The caller will call this function and then will run along the sub-array of
|
||||||
|
list_array to collect partition ids. If the number of list values is
|
||||||
|
significantly higher then number of partitions, this could be slow and
|
||||||
|
we could invent some other approach. The "run over list array" part is
|
||||||
|
already wrapped in a get_next()-like function.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
The edge of corresponding sub-array of part_info->list_array
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
|
||||||
|
bool left_endpoint,
|
||||||
|
bool include_endpoint)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("get_list_array_idx_for_endpoint");
|
||||||
|
LIST_PART_ENTRY *list_array= part_info->list_array;
|
||||||
|
uint list_index;
|
||||||
|
longlong list_value;
|
||||||
|
uint min_list_index= 0, max_list_index= part_info->no_list_values - 1;
|
||||||
|
/* Get the partitioning function value for the endpoint */
|
||||||
|
longlong part_func_value= part_info->part_expr->val_int();
|
||||||
|
while (max_list_index >= min_list_index)
|
||||||
|
{
|
||||||
|
list_index= (max_list_index + min_list_index) >> 1;
|
||||||
|
list_value= list_array[list_index].list_value;
|
||||||
|
if (list_value < part_func_value)
|
||||||
|
min_list_index= list_index + 1;
|
||||||
|
else if (list_value > part_func_value)
|
||||||
|
{
|
||||||
|
if (!list_index)
|
||||||
|
goto notfound;
|
||||||
|
max_list_index= list_index - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBUG_RETURN(list_index + test(left_endpoint ^ include_endpoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notfound:
|
||||||
|
if (list_value < part_func_value)
|
||||||
|
list_index++;
|
||||||
|
DBUG_RETURN(list_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool get_partition_id_range(partition_info *part_info,
|
bool get_partition_id_range(partition_info *part_info,
|
||||||
uint32 *part_id)
|
uint32 *part_id)
|
||||||
{
|
{
|
||||||
|
@ -2517,6 +2596,89 @@ bool get_partition_id_range(partition_info *part_info,
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find the sub-array of part_info->range_int_array that covers given interval
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
get_partition_id_range_for_endpoint()
|
||||||
|
part_info Partitioning info (partitioning type must be RANGE)
|
||||||
|
left_endpoint TRUE - the interval is [a; +inf) or (a; +inf)
|
||||||
|
FALSE - the interval is (-inf; a] or (-inf; a).
|
||||||
|
include_endpoint TRUE <=> the endpoint itself is included in the
|
||||||
|
interval
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
This function finds the sub-array of part_info->range_int_array where the
|
||||||
|
elements have non-empty intersections with the given interval.
|
||||||
|
|
||||||
|
A range_int_array element at index idx represents the interval
|
||||||
|
|
||||||
|
[range_int_array[idx-1], range_int_array[idx]),
|
||||||
|
|
||||||
|
intervals are disjoint and ordered by their right bound, so
|
||||||
|
|
||||||
|
1. For [a; +inf) or (a; +inf)-type intervals (left_endpoint==TRUE), the
|
||||||
|
sought sub-array starts at some index idx and continues till array end.
|
||||||
|
The function returns first number idx, such that the interval
|
||||||
|
represented by range_int_array[idx] has non empty intersection with
|
||||||
|
the passed interval.
|
||||||
|
|
||||||
|
2. For (-inf; a] or (-inf; a)-type intervals (left_endpoint==FALSE), the
|
||||||
|
sought sub-array starts at array start and continues till some last
|
||||||
|
index idx.
|
||||||
|
The function returns first number idx, such that the interval
|
||||||
|
represented by range_int_array[idx] has EMPTY intersection with the
|
||||||
|
passed interval.
|
||||||
|
If the interval represented by the last array element has non-empty
|
||||||
|
intersection with the passed interval, part_info->no_parts is
|
||||||
|
returned.
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
The edge of corresponding part_info->range_int_array sub-array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
|
||||||
|
bool left_endpoint,
|
||||||
|
bool include_endpoint)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("get_partition_id_range_for_endpoint");
|
||||||
|
longlong *range_array= part_info->range_int_array;
|
||||||
|
uint max_partition= part_info->no_parts - 1;
|
||||||
|
uint min_part_id= 0, max_part_id= max_partition, loc_part_id;
|
||||||
|
/* Get the partitioning function value for the endpoint */
|
||||||
|
longlong part_func_value= part_info->part_expr->val_int();
|
||||||
|
while (max_part_id > min_part_id)
|
||||||
|
{
|
||||||
|
loc_part_id= (max_part_id + min_part_id + 1) >> 1;
|
||||||
|
if (range_array[loc_part_id] < part_func_value)
|
||||||
|
min_part_id= loc_part_id + 1;
|
||||||
|
else
|
||||||
|
max_part_id= loc_part_id - 1;
|
||||||
|
}
|
||||||
|
loc_part_id= max_part_id;
|
||||||
|
if (loc_part_id < max_partition &&
|
||||||
|
part_func_value >= range_array[loc_part_id+1])
|
||||||
|
{
|
||||||
|
loc_part_id++;
|
||||||
|
}
|
||||||
|
if (left_endpoint)
|
||||||
|
{
|
||||||
|
if (part_func_value >= range_array[loc_part_id])
|
||||||
|
loc_part_id++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (part_func_value == range_array[loc_part_id])
|
||||||
|
loc_part_id += test(include_endpoint);
|
||||||
|
else if (part_func_value > range_array[loc_part_id])
|
||||||
|
loc_part_id++;
|
||||||
|
loc_part_id++;
|
||||||
|
}
|
||||||
|
DBUG_RETURN(loc_part_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool get_partition_id_hash_nosub(partition_info *part_info,
|
bool get_partition_id_hash_nosub(partition_info *part_info,
|
||||||
uint32 *part_id)
|
uint32 *part_id)
|
||||||
{
|
{
|
||||||
|
@ -3205,10 +3367,16 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
|
||||||
*/
|
*/
|
||||||
uint part_func_len= part_info->part_func_len;
|
uint part_func_len= part_info->part_func_len;
|
||||||
uint subpart_func_len= part_info->subpart_func_len;
|
uint subpart_func_len= part_info->subpart_func_len;
|
||||||
|
uint bitmap_bits= part_info->no_subparts?
|
||||||
|
(part_info->no_subparts* part_info->no_parts):
|
||||||
|
part_info->no_parts;
|
||||||
|
uint bitmap_bytes= bitmap_buffer_size(bitmap_bits);
|
||||||
|
uint32 *bitmap_buf;
|
||||||
char *part_func_string, *subpart_func_string= NULL;
|
char *part_func_string, *subpart_func_string= NULL;
|
||||||
if (!((part_func_string= thd->alloc(part_func_len))) ||
|
if (!((part_func_string= thd->alloc(part_func_len))) ||
|
||||||
(subpart_func_len &&
|
(subpart_func_len &&
|
||||||
!((subpart_func_string= thd->alloc(subpart_func_len)))))
|
!((subpart_func_string= thd->alloc(subpart_func_len)))) ||
|
||||||
|
!((bitmap_buf= (uint32*)thd->alloc(bitmap_bytes))))
|
||||||
{
|
{
|
||||||
my_error(ER_OUTOFMEMORY, MYF(0), part_func_len);
|
my_error(ER_OUTOFMEMORY, MYF(0), part_func_len);
|
||||||
free_items(thd->free_list);
|
free_items(thd->free_list);
|
||||||
|
@ -3221,6 +3389,8 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
|
||||||
subpart_func_len);
|
subpart_func_len);
|
||||||
part_info->part_func_string= part_func_string;
|
part_info->part_func_string= part_func_string;
|
||||||
part_info->subpart_func_string= subpart_func_string;
|
part_info->subpart_func_string= subpart_func_string;
|
||||||
|
|
||||||
|
bitmap_init(&part_info->used_partitions, bitmap_buf, bitmap_bytes*8, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
result= FALSE;
|
result= FALSE;
|
||||||
|
@ -3294,3 +3464,60 @@ void set_key_field_ptr(KEY *key_info, const byte *new_buf,
|
||||||
} while (++i < key_parts);
|
} while (++i < key_parts);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fill the string comma-separated line of used partitions names
|
||||||
|
SYNOPSIS
|
||||||
|
make_used_partitions_str()
|
||||||
|
part_info IN Partitioning info
|
||||||
|
parts_str OUT The string to fill
|
||||||
|
*/
|
||||||
|
|
||||||
|
void make_used_partitions_str(partition_info *part_info, String *parts_str)
|
||||||
|
{
|
||||||
|
parts_str->length(0);
|
||||||
|
partition_element *pe;
|
||||||
|
uint partition_id= 0;
|
||||||
|
List_iterator<partition_element> it(part_info->partitions);
|
||||||
|
|
||||||
|
if (part_info->subpart_type != NOT_A_PARTITION)
|
||||||
|
{
|
||||||
|
partition_element *head_pe;
|
||||||
|
while ((head_pe= it++))
|
||||||
|
{
|
||||||
|
List_iterator<partition_element> it2(head_pe->subpartitions);
|
||||||
|
while ((pe= it2++))
|
||||||
|
{
|
||||||
|
if (bitmap_is_set(&part_info->used_partitions, partition_id))
|
||||||
|
{
|
||||||
|
if (parts_str->length())
|
||||||
|
parts_str->append(',');
|
||||||
|
parts_str->append(head_pe->partition_name,
|
||||||
|
strlen(head_pe->partition_name),
|
||||||
|
system_charset_info);
|
||||||
|
parts_str->append('_');
|
||||||
|
parts_str->append(pe->partition_name,
|
||||||
|
strlen(pe->partition_name),
|
||||||
|
system_charset_info);
|
||||||
|
}
|
||||||
|
partition_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while ((pe= it++))
|
||||||
|
{
|
||||||
|
if (bitmap_is_set(&part_info->used_partitions, partition_id))
|
||||||
|
{
|
||||||
|
if (parts_str->length())
|
||||||
|
parts_str->append(',');
|
||||||
|
parts_str->append(pe->partition_name, strlen(pe->partition_name),
|
||||||
|
system_charset_info);
|
||||||
|
}
|
||||||
|
partition_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -633,6 +633,21 @@ JOIN::optimize()
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
|
{
|
||||||
|
TABLE_LIST *tbl;
|
||||||
|
for (tbl= select_lex->leaf_tables; tbl; tbl= tbl->next_leaf)
|
||||||
|
{
|
||||||
|
if (!tbl->embedding)
|
||||||
|
{
|
||||||
|
Item *prune_cond= tbl->on_expr? tbl->on_expr : conds;
|
||||||
|
tbl->table->no_partitions_used= prune_partitions(thd, tbl->table,
|
||||||
|
prune_cond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Optimize count(*), min() and max() */
|
/* Optimize count(*), min() and max() */
|
||||||
if (tables_list && tmp_table_param.sum_func_count && ! group_list)
|
if (tables_list && tmp_table_param.sum_func_count && ! group_list)
|
||||||
{
|
{
|
||||||
|
@ -2018,7 +2033,11 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
||||||
if (*s->on_expr_ref)
|
if (*s->on_expr_ref)
|
||||||
{
|
{
|
||||||
/* s is the only inner table of an outer join */
|
/* s is the only inner table of an outer join */
|
||||||
if (!table->file->records && !embedding)
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
|
if ((!table->file->records || table->no_partitions_used) && !embedding)
|
||||||
|
#else
|
||||||
|
if (!table->file->records || && !embedding)
|
||||||
|
#endif
|
||||||
{ // Empty table
|
{ // Empty table
|
||||||
s->dependent= 0; // Ignore LEFT JOIN depend.
|
s->dependent= 0; // Ignore LEFT JOIN depend.
|
||||||
set_position(join,const_count++,s,(KEYUSE*) 0);
|
set_position(join,const_count++,s,(KEYUSE*) 0);
|
||||||
|
@ -2045,8 +2064,14 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
||||||
while (embedding);
|
while (embedding);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
if ((table->s->system || table->file->records <= 1) && ! s->dependent &&
|
bool no_partitions_used= table->no_partitions_used;
|
||||||
|
#else
|
||||||
|
const bool no_partitions_used= FALSE;
|
||||||
|
#endif
|
||||||
|
if ((table->s->system || table->file->records <= 1 ||
|
||||||
|
no_partitions_used) &&
|
||||||
|
!s->dependent &&
|
||||||
!(table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
|
!(table->file->table_flags() & HA_NOT_EXACT_COUNT) &&
|
||||||
!table->fulltext_searched)
|
!table->fulltext_searched)
|
||||||
{
|
{
|
||||||
|
@ -13770,6 +13795,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
||||||
strlen(join->select_lex->type), cs));
|
strlen(join->select_lex->type), cs));
|
||||||
for (uint i=0 ; i < 7; i++)
|
for (uint i=0 ; i < 7; i++)
|
||||||
item_list.push_back(item_null);
|
item_list.push_back(item_null);
|
||||||
|
if (join->thd->lex->describe & DESCRIBE_PARTITIONS)
|
||||||
|
item_list.push_back(item_null);
|
||||||
|
|
||||||
item_list.push_back(new Item_string(message,strlen(message),cs));
|
item_list.push_back(new Item_string(message,strlen(message),cs));
|
||||||
if (result->send_data(item_list))
|
if (result->send_data(item_list))
|
||||||
join->error= 1;
|
join->error= 1;
|
||||||
|
@ -13890,7 +13918,28 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
|
||||||
item_list.push_back(new Item_string(table->alias,
|
item_list.push_back(new Item_string(table->alias,
|
||||||
strlen(table->alias),
|
strlen(table->alias),
|
||||||
cs));
|
cs));
|
||||||
/* type */
|
/* "partitions" column */
|
||||||
|
if (join->thd->lex->describe & DESCRIBE_PARTITIONS)
|
||||||
|
{
|
||||||
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
|
partition_info *part_info;
|
||||||
|
if (!table->derived_select_number &&
|
||||||
|
(part_info= table->part_info))
|
||||||
|
{
|
||||||
|
char parts_buff[128];
|
||||||
|
String parts_str(parts_buff,sizeof(parts_buff),cs);
|
||||||
|
make_used_partitions_str(part_info, &parts_str);
|
||||||
|
item_list.push_back(new Item_string(parts_str.ptr(),
|
||||||
|
parts_str.length(), cs));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
item_list.push_back(item_null);
|
||||||
|
#else
|
||||||
|
/* just produce empty column if partitioning is not compiled in */
|
||||||
|
item_list.push_back(item_null);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* "type" column */
|
||||||
item_list.push_back(new Item_string(join_type_str[tab->type],
|
item_list.push_back(new Item_string(join_type_str[tab->type],
|
||||||
strlen(join_type_str[tab->type]),
|
strlen(join_type_str[tab->type]),
|
||||||
cs));
|
cs));
|
||||||
|
|
|
@ -7419,8 +7419,10 @@ describe_command:
|
||||||
opt_extended_describe:
|
opt_extended_describe:
|
||||||
/* empty */ {}
|
/* empty */ {}
|
||||||
| EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
|
| EXTENDED_SYM { Lex->describe|= DESCRIBE_EXTENDED; }
|
||||||
|
| PARTITIONS_SYM { Lex->describe|= DESCRIBE_PARTITIONS; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
opt_describe_column:
|
opt_describe_column:
|
||||||
/* empty */ {}
|
/* empty */ {}
|
||||||
| text_string { Lex->wild= $1; }
|
| text_string { Lex->wild= $1; }
|
||||||
|
|
|
@ -300,6 +300,7 @@ struct st_table {
|
||||||
FILESORT_INFO sort;
|
FILESORT_INFO sort;
|
||||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
partition_info *part_info; /* Partition related information */
|
partition_info *part_info; /* Partition related information */
|
||||||
|
bool no_partitions_used; /* If true, all partitions have been pruned away */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool fill_item_list(List<Item> *item_list) const;
|
bool fill_item_list(List<Item> *item_list) const;
|
||||||
|
|
Loading…
Add table
Reference in a new issue