From 6942c25e733967e4d3da8aaad3b2e9a2832dc33e Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 15 Sep 2009 17:07:52 +0200 Subject: [PATCH 01/27] WL#3352, Introducing Column list partitioning, makes it possible to partition on most data types, makes it possible to prune on multi-field partitioning --- BUILD/build_mccge.sh | 2 +- mysql-test/r/partition_mgm_err.result | 2 +- mysql-test/r/partition_range.result | 94 ++ .../suite/parts/inc/partition_key_32col.inc | 2 +- mysql-test/t/partition_column.test | 209 +++ mysql-test/t/partition_column_prune.test | 71 + mysql-test/t/partition_error.test | 6 +- mysql-test/t/partition_mgm_err.test | 2 +- mysql-test/t/partition_range.test | 76 + mysql-test/t/type_decimal.test | 10 +- sql/ha_partition.h | 3 +- sql/item_create.cc | 22 + sql/item_timefunc.cc | 33 + sql/item_timefunc.h | 18 + sql/lex.h | 1 + sql/opt_range.cc | 288 +++- sql/partition_element.h | 37 +- sql/partition_info.cc | 497 +++++-- sql/partition_info.h | 36 +- sql/share/errmsg.txt | 10 + sql/sql_lex.cc | 1 + sql/sql_lex.h | 3 + sql/sql_partition.cc | 1256 +++++++++++------ sql/sql_partition.h | 12 +- sql/sql_show.cc | 18 +- sql/sql_table.cc | 2 +- sql/sql_yacc.yy | 284 +++- 27 files changed, 2235 insertions(+), 760 deletions(-) create mode 100644 mysql-test/t/partition_column.test create mode 100644 mysql-test/t/partition_column_prune.test diff --git a/BUILD/build_mccge.sh b/BUILD/build_mccge.sh index ad3e728453c..379ca1b2c68 100755 --- a/BUILD/build_mccge.sh +++ b/BUILD/build_mccge.sh @@ -556,7 +556,7 @@ parse_package() package="pro" ;; extended ) - package="" + package="extended" ;; cge ) package="cge" diff --git a/mysql-test/r/partition_mgm_err.result b/mysql-test/r/partition_mgm_err.result index f8403988f47..a13278d724e 100644 --- a/mysql-test/r/partition_mgm_err.result +++ b/mysql-test/r/partition_mgm_err.result @@ -41,7 +41,7 @@ ERROR HY000: Reorganize of range partitions cannot change total ranges except fo ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO (PARTITION x01 VALUES LESS THAN (4), PARTITION x11 VALUES LESS THAN (2)); -ERROR HY000: Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range +ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO (PARTITION x01 VALUES LESS THAN (6), PARTITION x11 VALUES LESS THAN (4)); diff --git a/mysql-test/r/partition_range.result b/mysql-test/r/partition_range.result index e8fc55b759b..fc15665d698 100644 --- a/mysql-test/r/partition_range.result +++ b/mysql-test/r/partition_range.result @@ -1,6 +1,100 @@ drop table if exists t1, t2; create table t1 (a int) partition by range (a) +( partition p0 values less than (NULL), +partition p1 values less than (MAXVALUE)); +ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '), +partition p1 values less than (MAXVALUE))' at line 3 +create table t1 (a datetime not null) +partition by range (TO_SECONDS(a)) +( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')), +partition p1 VALUES LESS THAN (TO_SECONDS('2007-04-01 00:00:00'))); +INSERT INTO t1 VALUES ('2007-03-01 12:00:00'), ('2007-03-07 12:00:00'); +INSERT INTO t1 VALUES ('2007-03-08 12:00:00'), ('2007-03-15 12:00:00'); +explain partitions select * from t1 where a < '2007-03-08 00:00:00'; +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 < '2007-03-08 00:00:01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a <= '2007-03-08 00:00:00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a <= '2007-03-07 23:59:59'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t1 where a < '2007-03-07 23:59:59'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 ALL NULL NULL NULL NULL 4 Using where +drop table t1; +create table t1 (a date) +partition by range(to_seconds(a)) +(partition p0 values less than (to_seconds('2004-01-01')), +partition p1 values less than (to_seconds('2005-01-01'))); +insert into t1 values ('2003-12-30'),('2004-12-31'); +select * from t1; +a +2003-12-30 +2004-12-31 +explain partitions select * from t1 where a <= '2003-12-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 system NULL NULL NULL NULL 1 +select * from t1 where a <= '2003-12-31'; +a +2003-12-30 +explain partitions select * from t1 where a <= '2005-01-01'; +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 +select * from t1 where a <= '2005-01-01'; +a +2003-12-30 +2004-12-31 +drop table t1; +create table t1 (a datetime) +partition by range(to_seconds(a)) +(partition p0 values less than (to_seconds('2004-01-01 12:00:00')), +partition p1 values less than (to_seconds('2005-01-01 12:00:00'))); +insert into t1 values ('2004-01-01 11:59:29'),('2005-01-01 11:59:59'); +select * from t1; +a +2004-01-01 11:59:29 +2005-01-01 11:59:59 +explain partitions select * from t1 where a <= '2004-01-01 11:59.59'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 system NULL NULL NULL NULL 1 +select * from t1 where a <= '2004-01-01 11:59:59'; +a +2004-01-01 11:59:29 +explain partitions select * from t1 where a <= '2005-01-01'; +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 +select * from t1 where a <= '2005-01-01'; +a +2004-01-01 11:59:29 +drop table t1; +create table t1 (a int, b char(20)) +partition by range column_list(a,b) +(partition p0 values less than (1)); +ERROR 42000: Inconsistency in usage of column lists for partitioning near '))' at line 3 +create table t1 (a int, b char(20)) +partition by range(a) +(partition p0 values less than (column_list(1,"b"))); +ERROR HY000: Inconsistency in usage of column lists for partitioning +create table t1 (a int, b char(20)) +partition by range(a) +(partition p0 values less than (column_list(1,"b"))); +ERROR HY000: Inconsistency in usage of column lists for partitioning +create table t1 (a int, b char(20)); +create global index inx on t1 (a,b) +partition by range (a) +(partition p0 values less than (1)); +drop table t1; +create table t1 (a int, b char(20)) +partition by range column_list(b) +(partition p0 values less than (column_list("b"))); +drop table t1; +create table t1 (a int) +partition by range (a) ( partition p0 values less than (maxvalue)); alter table t1 add partition (partition p1 values less than (100000)); ERROR HY000: MAXVALUE can only be used in last partition definition diff --git a/mysql-test/suite/parts/inc/partition_key_32col.inc b/mysql-test/suite/parts/inc/partition_key_32col.inc index 74016d9b556..b0635ca0e9c 100644 --- a/mysql-test/suite/parts/inc/partition_key_32col.inc +++ b/mysql-test/suite/parts/inc/partition_key_32col.inc @@ -1,4 +1,4 @@ ---error ER_TOO_MANY_KEY_PARTS +--error ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR eval create table t1 (a date not null, b varchar(50) not null, c varchar(50) not null, d enum('m', 'w') not null, e int not null, f decimal (18,2) not null, g bigint not null, h tinyint not null, a1 date not null, b1 varchar(50) not null, c1 varchar(50) not null, d1 enum('m', 'w') not null, e1 int not null, f1 decimal (18,2) not null, g1 bigint not null, h1 tinyint not null, a2 date not null, b2 varchar(50) not null, c2 varchar(50) not null, d2 enum('m', 'w') not null, e2 int not null, f2 decimal (18,2) not null, g2 bigint not null, h2 tinyint not null, a3 date not null, b3 varchar(50) not null, c3 varchar(50) not null, d3 enum('m', 'w') not null, e3 int not null, f3 decimal (18,2) not null, g3 bigint not null, h3 tinyint not null, i char(255), primary key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1,a2,b2,c2,d2,e2,f2,g2,h2,a3,b3,c3,d3,e3,f3,g3,h3)) engine=$engine partition by key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1,a2,b2,c2,d2,e2,f2,g2,h2,a3,b3,c3,d3,e3,f3,g3,h3) ( partition pa1 max_rows=20 min_rows=2, diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test new file mode 100644 index 00000000000..b1f5f4abfcf --- /dev/null +++ b/mysql-test/t/partition_column.test @@ -0,0 +1,209 @@ +# +# Tests for the new column list partitioning introduced in second +# version for partitioning. +# +--source include/have_partition.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1 (a int, b char(10), c varchar(25), d datetime) +partition by range column_list(a,b,c,d) +subpartition by hash (to_seconds(d)) +subpartitions 4 +( partition p0 values less than (column_list(1, NULL, MAXVALUE, NULL)), + partition p1 values less than (column_list(1, 'a', MAXVALUE, TO_DAYS('1999-01-01'))), + partition p2 values less than (column_list(1, 'a', MAXVALUE, MAXVALUE)), + partition p3 values less than (column_list(1, MAXVALUE, MAXVALUE, MAXVALUE))); +drop table t1; + +create table t1 (a int, b char(10), c varchar(5), d int) +partition by range column_list(a,b,c) +subpartition by key (c,d) +subpartitions 3 +( partition p0 values less than (column_list(1,'abc','abc')), + partition p1 values less than (column_list(2,'abc','abc')), + partition p2 values less than (column_list(3,'abc','abc')), + partition p3 values less than (column_list(4,'abc','abc'))); + +insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); +insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); +insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); +insert into t1 values (1,'d','e',1),(2,'d','e',2),(3,'d','e',3); +select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) OR + (a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2)))); +drop table t1; + +create table t1 (a int, b varchar(2), c int) +partition by range column_list (a, b, c) +(partition p0 values less than (column_list(1, 'A', 1)), + partition p1 values less than (column_list(1, 'B', 1))); +insert into t1 values (1, 'A', 1); +explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; +select * from t1 where a = 1 AND b <= 'A' and c = 1; +drop table t1; + +create table t1 (a char, b char, c char) +partition by list column_list(a) +( partition p0 values in (column_list('a'))); +insert into t1 (a) values ('a'); +select * from t1 where a = 'a'; +drop table t1; + +--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR +create table t1 (d timestamp) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), + partition p1 values less than (column_list('2040-01-01'))); + +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(null, 10))); +drop table t1; + +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), + partition p1 values less than (column_list('2009-01-01'))); +drop table t1; + +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('1999-01-01')), + partition p1 values less than (column_list('2000-01-01'))); +drop table t1; + +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), + partition p1 values less than (column_list('3000-01-01'))); +drop table t1; + +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p2 values less than (column_list(99,99)), + partition p1 values less than (column_list(99,999))); + +insert into t1 values (99,998); +select * from t1 where b = 998; +drop table t1; + +create table t1 as select to_seconds(null) as to_seconds; +select data_type from information_schema.columns +where column_name='to_seconds'; +drop table t1; + +--error ER_PARSE_ERROR +create table t1 (a int, b int) +partition by list column_list(a,b) +(partition p0 values in (column_list(maxvalue,maxvalue))); +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(maxvalue,maxvalue))); +drop table t1; + +create table t1 (a int) +partition by list column_list(a) +(partition p0 values in (column_list(0))); +select partition_method from information_schema.partitions where table_name='t1'; +drop table t1; + +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list('H23456')), + partition p1 values less than (column_list('M23456'))); +insert into t1 values ('F23456'); +select * from t1; +drop table t1; + +-- error 1054 +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list(H23456)), + partition p1 values less than (column_list(M23456))); + +-- error ER_RANGE_NOT_INCREASING_ERROR +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list(23456)), + partition p1 values less than (column_list(23456))); + +-- error 1064 +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (10)); + +-- error ER_PARTITION_COLUMN_LIST_ERROR +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(1,1,1)); + +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(1, NULL)), + partition p1 values less than (column_list(2, maxvalue)), + partition p2 values less than (column_list(3, 3)), + partition p3 values less than (column_list(10, NULL))); + +-- error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values (10,0); +insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1); +select * from t1; + +alter table t1 +partition by range column_list(b,a) +(partition p0 values less than (column_list(1,2)), + partition p1 values less than (column_list(3,3)), + partition p2 values less than (column_list(9,5))); +explain partitions select * from t1 where b < 2; +select * from t1 where b < 2; +explain partitions select * from t1 where b < 4; +select * from t1 where b < 4; + +alter table t1 reorganize partition p1 into +(partition p11 values less than (column_list(2,2)), + partition p12 values less than (column_list(3,3))); + +-- error ER_REORG_OUTSIDE_RANGE +alter table t1 reorganize partition p0 into +(partition p01 values less than (column_list(0,3)), + partition p02 values less than (column_list(1,1))); + +-- error ER_PARTITION_COLUMN_LIST_ERROR +alter table t1 reorganize partition p2 into +(partition p2 values less than(column_list(9,6,1))); + +-- error ER_PARTITION_COLUMN_LIST_ERROR +alter table t1 reorganize partition p2 into +(partition p2 values less than (10)); + +alter table t1 reorganize partition p2 into +(partition p21 values less than (column_list(4,7)), + partition p22 values less than (column_list(9,5))); +explain partitions select * from t1 where b < 4; +select * from t1 where b < 4; +drop table t1; + +#create table t1 (a int, b int) +#partition by range column_list(a,b) +#(partition p0 values less than (column_list(99,99)), +# partition p1 values less than (column_list(99,maxvalue))); +#drop table t1; + +create table t1 (a int, b int) +partition by list column_list(a,b) +subpartition by hash (b) +subpartitions 2 +(partition p0 values in (column_list(0,0), column_list(1,1)), + partition p1 values in (column_list(1000,1000))); +insert into t1 values (1000,1000); +#select * from t1 where a = 0 and b = 0; +drop table t1; + +create table t1 (a char, b char, c char) +partition by range column_list(a,b,c) +( partition p0 values less than (column_list('a','b','c'))); +alter table t1 add partition +(partition p1 values less than (column_list('b','c','d'))); +drop table t1; diff --git a/mysql-test/t/partition_column_prune.test b/mysql-test/t/partition_column_prune.test new file mode 100644 index 00000000000..52267a66b65 --- /dev/null +++ b/mysql-test/t/partition_column_prune.test @@ -0,0 +1,71 @@ +# +# Partition pruning tests for new COLUMN LIST feature +# +-- source include/have_partition.inc + +--disable_warnings +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +--enable_warnings + +create table t1 (a char, b char, c char) +partition by range column_list(a,b,c) +( partition p0 values less than (column_list('a','b','c'))); +insert into t1 values ('a', NULL, 'd'); +explain partitions select * from t1 where a = 'a' AND c = 'd'; +select * from t1 where a = 'a' AND c = 'd'; +drop table t1; + +## COLUMN_LIST partition pruning tests +create table t1 (a int not null) partition by range column_list(a) ( + partition p0 values less than (column_list(10)), + partition p1 values less than (column_list(20)), + partition p2 values less than (column_list(30)), + partition p3 values less than (column_list(40)), + partition p4 values less than (column_list(50)), + partition p5 values less than (column_list(60)), + partition p6 values less than (column_list(70)) +); +insert into t1 values (5),(15),(25),(35),(45),(55),(65); +insert into t1 values (5),(15),(25),(35),(45),(55),(65); + +create table t2 (a int not null) partition by range(a) ( + partition p0 values less than (10), + partition p1 values less than (20), + partition p2 values less than (30), + partition p3 values less than (40), + partition p4 values less than (50), + partition p5 values less than (60), + partition p6 values less than (70) +); +insert into t2 values (5),(15),(25),(35),(45),(55),(65); +insert into t2 values (5),(15),(25),(35),(45),(55),(65); + +explain partitions select * from t1 where a > 35 and a < 45; +explain partitions select * from t2 where a > 35 and a < 45; + +drop table t1, t2; + +create table t1 (a int not null, b int not null ) +partition by range column_list(a,b) ( + partition p01 values less than (column_list(2,10)), + partition p02 values less than (column_list(2,20)), + partition p03 values less than (column_list(2,30)), + + partition p11 values less than (column_list(4,10)), + partition p12 values less than (column_list(4,20)), + partition p13 values less than (column_list(4,30)), + + partition p21 values less than (column_list(6,10)), + partition p22 values less than (column_list(6,20)), + partition p23 values less than (column_list(6,30)) +); + +insert into t1 values (2,5), (2,15), (2,25), + (4,5), (4,15), (4,25), (6,5), (6,15), (6,25); +insert into t1 select * from t1; + +explain partitions select * from t1 where a=2; +explain partitions select * from t1 where a=4; +explain partitions select * from t1 where a=2 and b < 22; + +drop table t1; diff --git a/mysql-test/t/partition_error.test b/mysql-test/t/partition_error.test index 49632f95dfb..1e76945ca46 100644 --- a/mysql-test/t/partition_error.test +++ b/mysql-test/t/partition_error.test @@ -180,7 +180,7 @@ partitions 3 (partition x1, partition x2); # -# Partition by key specified 3 partitions but only defined 2 => error +# Partition by hash, random function # --error 1064 CREATE TABLE t1 ( @@ -193,7 +193,7 @@ partitions 2 (partition x1, partition x2); # -# Partition by key specified 3 partitions but only defined 2 => error +# Partition by range, random function # --error 1064 CREATE TABLE t1 ( @@ -206,7 +206,7 @@ partitions 2 (partition x1 values less than (0), partition x2 values less than (2)); # -# Partition by key specified 3 partitions but only defined 2 => error +# Partition by list, random function # --error 1064 CREATE TABLE t1 ( diff --git a/mysql-test/t/partition_mgm_err.test b/mysql-test/t/partition_mgm_err.test index 0f8b8d3cd90..f921fa8ebca 100644 --- a/mysql-test/t/partition_mgm_err.test +++ b/mysql-test/t/partition_mgm_err.test @@ -61,7 +61,7 @@ ALTER TABLE t1 REORGANIZE PARTITION x0, x1, x1 INTO ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO (PARTITION x01 VALUES LESS THAN (5)); ---error ER_REORG_OUTSIDE_RANGE +--error ER_RANGE_NOT_INCREASING_ERROR ALTER TABLE t1 REORGANIZE PARTITION x0,x1 INTO (PARTITION x01 VALUES LESS THAN (4), PARTITION x11 VALUES LESS THAN (2)); diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test index c02d9049f2e..c14dfd1822d 100644 --- a/mysql-test/t/partition_range.test +++ b/mysql-test/t/partition_range.test @@ -9,6 +9,82 @@ drop table if exists t1, t2; --enable_warnings +--error ER_PARSE_ERROR +create table t1 (a int) +partition by range (a) +( partition p0 values less than (NULL), + partition p1 values less than (MAXVALUE)); +# +# Merge fix of bug#27927 for TO_SECONDS function +# +create table t1 (a datetime not null) +partition by range (TO_SECONDS(a)) +( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')), + partition p1 VALUES LESS THAN (TO_SECONDS('2007-04-01 00:00:00'))); +INSERT INTO t1 VALUES ('2007-03-01 12:00:00'), ('2007-03-07 12:00:00'); +INSERT INTO t1 VALUES ('2007-03-08 12:00:00'), ('2007-03-15 12:00:00'); +explain partitions select * from t1 where a < '2007-03-08 00:00:00'; +explain partitions select * from t1 where a < '2007-03-08 00:00:01'; +explain partitions select * from t1 where a <= '2007-03-08 00:00:00'; +explain partitions select * from t1 where a <= '2007-03-07 23:59:59'; +explain partitions select * from t1 where a < '2007-03-07 23:59:59'; +drop table t1; +# +# New test cases for new function to_seconds +# +create table t1 (a date) +partition by range(to_seconds(a)) +(partition p0 values less than (to_seconds('2004-01-01')), + partition p1 values less than (to_seconds('2005-01-01'))); +insert into t1 values ('2003-12-30'),('2004-12-31'); +select * from t1; +explain partitions select * from t1 where a <= '2003-12-31'; +select * from t1 where a <= '2003-12-31'; +explain partitions select * from t1 where a <= '2005-01-01'; +select * from t1 where a <= '2005-01-01'; +drop table t1; + +create table t1 (a datetime) +partition by range(to_seconds(a)) +(partition p0 values less than (to_seconds('2004-01-01 12:00:00')), + partition p1 values less than (to_seconds('2005-01-01 12:00:00'))); +insert into t1 values ('2004-01-01 11:59:29'),('2005-01-01 11:59:59'); +select * from t1; +explain partitions select * from t1 where a <= '2004-01-01 11:59.59'; +select * from t1 where a <= '2004-01-01 11:59:59'; +explain partitions select * from t1 where a <= '2005-01-01'; +select * from t1 where a <= '2005-01-01'; +drop table t1; + +# +# Adding new test cases for column list variant for partitioning +# +--error 1064 +create table t1 (a int, b char(20)) +partition by range column_list(a,b) +(partition p0 values less than (1)); + +--error ER_PARTITION_COLUMN_LIST_ERROR +create table t1 (a int, b char(20)) +partition by range(a) +(partition p0 values less than (column_list(1,"b"))); + +--error ER_PARTITION_COLUMN_LIST_ERROR +create table t1 (a int, b char(20)) +partition by range(a) +(partition p0 values less than (column_list(1,"b"))); + +create table t1 (a int, b char(20)); +create global index inx on t1 (a,b) +partition by range (a) +(partition p0 values less than (1)); +drop table t1; + +create table t1 (a int, b char(20)) +partition by range column_list(b) +(partition p0 values less than (column_list("b"))); +drop table t1; + # # BUG 33429: Succeeds in adding partition when maxvalue on last partition # diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 8a81908296f..dfe36ed0905 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -8,13 +8,13 @@ SET SQL_WARNINGS=1; CREATE TABLE t1 ( id int(11) NOT NULL auto_increment, datatype_id int(11) DEFAULT '0' NOT NULL, - minvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL, - maxvalue decimal(20,10) DEFAULT '0.0000000000' NOT NULL, + min_value decimal(20,10) DEFAULT '0.0000000000' NOT NULL, + max_value decimal(20,10) DEFAULT '0.0000000000' NOT NULL, valuename varchar(20), forecolor int(11), backcolor int(11), PRIMARY KEY (id), - UNIQUE datatype_id (datatype_id, minvalue, maxvalue) + UNIQUE datatype_id (datatype_id, min_value, max_value) ); INSERT INTO t1 VALUES ( '1', '4', '0.0000000000', '0.0000000000', 'Ei saja', '0', '16776960'); INSERT INTO t1 VALUES ( '2', '4', '1.0000000000', '1.0000000000', 'Sajab', '16777215', '255'); @@ -148,8 +148,8 @@ INSERT INTO t1 VALUES ( '139', '21', '326.0000000000', '326.0000000000', 'Lumine INSERT INTO t1 VALUES ( '143', '16', '-4.9000000000', '-0.1000000000', '', NULL, '15774720'); INSERT INTO t1 VALUES ( '145', '15', '0.0000000000', '1.9000000000', '', '0', '16769024'); INSERT INTO t1 VALUES ( '146', '16', '0.0000000000', '1.9000000000', '', '0', '16769024'); -select * from t1 where minvalue<=1 and maxvalue>=-1 and datatype_id=16; -select * from t1 where minvalue<=-1 and maxvalue>=-1 and datatype_id=16; +select * from t1 where min_value<=1 and max_value>=-1 and datatype_id=16; +select * from t1 where min_value<=-1 and max_value>=-1 and datatype_id=16; drop table t1; # diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 8a81a759e2a..cc6558f2db0 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -19,7 +19,8 @@ enum partition_keywords { - PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR + PKW_HASH= 0, PKW_RANGE, PKW_LIST, PKW_KEY, PKW_MAXVALUE, PKW_LINEAR, + PKW_COLUMNS }; /* diff --git a/sql/item_create.cc b/sql/item_create.cc index bf359b10caa..3adc0112ff8 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -2052,6 +2052,18 @@ protected: virtual ~Create_func_to_days() {} }; +class Create_func_to_seconds : public Create_func_arg1 +{ +public: + virtual Item* create(THD *thd, Item *arg1); + + static Create_func_to_seconds s_singleton; + +protected: + Create_func_to_seconds() {} + virtual ~Create_func_to_seconds() {} +}; + #ifdef HAVE_SPATIAL class Create_func_touches : public Create_func_arg2 @@ -4480,6 +4492,15 @@ Create_func_to_days::create(THD *thd, Item *arg1) } +Create_func_to_seconds Create_func_to_seconds::s_singleton; + +Item* +Create_func_to_seconds::create(THD *thd, Item *arg1) +{ + return new (thd->mem_root) Item_func_to_seconds(arg1); +} + + #ifdef HAVE_SPATIAL Create_func_touches Create_func_touches::s_singleton; @@ -4917,6 +4938,7 @@ static Native_func_registry func_array[] = { { C_STRING_WITH_LEN("TIME_TO_SEC") }, BUILDER(Create_func_time_to_sec)}, { { C_STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)}, { { C_STRING_WITH_LEN("TO_DAYS") }, BUILDER(Create_func_to_days)}, + { { C_STRING_WITH_LEN("TO_SECONDS") }, BUILDER(Create_func_to_seconds)}, { { C_STRING_WITH_LEN("UCASE") }, BUILDER(Create_func_ucase)}, { { C_STRING_WITH_LEN("UNCOMPRESS") }, BUILDER(Create_func_uncompress)}, { { C_STRING_WITH_LEN("UNCOMPRESSED_LENGTH") }, BUILDER(Create_func_uncompressed_length)}, diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d79b0b02998..bad9b85b2b6 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -941,6 +941,27 @@ longlong Item_func_to_days::val_int() } +longlong Item_func_to_seconds::val_int_endpoint(bool left_endp, + bool *incl_endp) +{ + longlong res= val_int(); + return null_value ? LONGLONG_MIN : res; +} + +longlong Item_func_to_seconds::val_int() +{ + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + longlong seconds; + longlong days; + if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) + return 0; + seconds=ltime.hour*3600L+ltime.minute*60+ltime.second; + seconds=ltime.neg ? -seconds : seconds; + days= (longlong) calc_daynr(ltime.year,ltime.month,ltime.day); + return (seconds + days * (24L * 3600L)); +} + /* Get information about this Item tree monotonicity @@ -967,6 +988,18 @@ enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const return NON_MONOTONIC; } +enum_monotonicity_info Item_func_to_seconds::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_to_days::val_int_endpoint(bool left_endp, bool *incl_endp) { diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 9e3c2e8c89f..fd42ec307db 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -73,6 +73,24 @@ public: }; +class Item_func_to_seconds :public Item_int_func +{ +public: + Item_func_to_seconds(Item *a) :Item_int_func(a) {} + longlong val_int(); + const char *func_name() const { return "to_seconds"; } + void fix_length_and_dec() + { + decimals=0; + max_length=6*MY_CHARSET_BIN_MB_MAXLEN; + maybe_null=1; + } + enum_monotonicity_info get_monotonicity_info() const; + longlong val_int_endpoint(bool left_endp, bool *incl_endp); + bool check_partition_func_processor(uchar *bool_arg) { return FALSE;} +}; + + class Item_func_dayofmonth :public Item_int_func { public: diff --git a/sql/lex.h b/sql/lex.h index 0a85824f6f7..c42ece86993 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -113,6 +113,7 @@ static SYMBOL symbols[] = { { "COLLATION", SYM(COLLATION_SYM)}, { "COLUMN", SYM(COLUMN_SYM)}, { "COLUMNS", SYM(COLUMNS)}, + { "COLUMN_LIST", SYM(COLUMN_LIST_SYM)}, { "COMMENT", SYM(COMMENT_SYM)}, { "COMMIT", SYM(COMMIT_SYM)}, { "COMMITTED", SYM(COMMITTED_SYM)}, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 47067c03a85..e226b51fc66 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -438,35 +438,55 @@ public: return 0; } - /* returns a number of keypart values appended to the key buffer */ - int store_min_key(KEY_PART *key, uchar **range_key, uint *range_key_flag) + /* + Returns a number of keypart values appended to the key buffer + for min key and max key. This function is used by both Range + Analysis and Partition pruning. For partition pruning we have + to ensure that we don't store also subpartition fields. Thus + we have to stop at the last partition part and not step into + the subpartition fields. For Range Analysis we set last_part + to MAX_KEY which we should never reach. + */ + int store_min_key(KEY_PART *key, + uchar **range_key, + uint *range_key_flag, + uint last_part) { SEL_ARG *key_tree= first(); uint res= key_tree->store_min(key[key_tree->part].store_length, range_key, *range_key_flag); *range_key_flag|= key_tree->min_flag; if (key_tree->next_key_part && + key_tree->part != last_part && key_tree->next_key_part->part == key_tree->part+1 && !(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) - res+= key_tree->next_key_part->store_min_key(key, range_key, - range_key_flag); + res+= key_tree->next_key_part->store_min_key(key, + range_key, + range_key_flag, + last_part); return res; } /* returns a number of keypart values appended to the key buffer */ - int store_max_key(KEY_PART *key, uchar **range_key, uint *range_key_flag) + int store_max_key(KEY_PART *key, + uchar **range_key, + uint *range_key_flag, + uint last_part) { SEL_ARG *key_tree= last(); uint res=key_tree->store_max(key[key_tree->part].store_length, range_key, *range_key_flag); (*range_key_flag)|= key_tree->max_flag; if (key_tree->next_key_part && + key_tree->part != last_part && key_tree->next_key_part->part == key_tree->part+1 && !(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) && key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) - res+= key_tree->next_key_part->store_max_key(key, range_key, - range_key_flag); + res+= key_tree->next_key_part->store_max_key(key, + range_key, + range_key_flag, + last_part); return res; } @@ -634,6 +654,12 @@ public: using_real_indexes==TRUE */ uint real_keynr[MAX_KEY]; + + /* Used to store 'current key tuples', in both range analysis and + * partitioning (list) analysis*/ + uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], + max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; + /* Number of SEL_ARG objects allocated by SEL_ARG::clone_tree operations */ uint alloced_sel_args; }; @@ -645,8 +671,6 @@ public: longlong baseflag; uint max_key_part, range_count; - uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], - max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; bool quick; // Don't calulate possible keys uint fields_bitmap_size; @@ -2599,6 +2623,8 @@ typedef struct st_part_prune_param /* Same as above for subpartitioning */ my_bool *is_subpart_keypart; + my_bool ignore_part_fields; /* Ignore rest of partioning fields */ + /*************************************************************** Following fields form find_used_partitions() recursion context: **************************************************************/ @@ -2614,6 +2640,11 @@ typedef struct st_part_prune_param /* Initialized bitmap of no_subparts size */ MY_BITMAP subparts_bitmap; + + uchar *cur_min_key; + uchar *cur_max_key; + + uint cur_min_flag, cur_max_flag; } PART_PRUNE_PARAM; static bool create_partition_index_description(PART_PRUNE_PARAM *prune_par); @@ -2731,6 +2762,11 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond) prune_param.arg_stack_end= prune_param.arg_stack; prune_param.cur_part_fields= 0; prune_param.cur_subpart_fields= 0; + + prune_param.cur_min_key= prune_param.range_param.min_key; + prune_param.cur_max_key= prune_param.range_param.max_key; + prune_param.cur_min_flag= prune_param.cur_max_flag= 0; + init_all_partitions_iterator(part_info, &prune_param.part_iter); if (!tree->keys[0] || (-1 == (res= find_used_partitions(&prune_param, tree->keys[0])))) @@ -2967,6 +3003,11 @@ int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, SEL_IMERGE *imerge) ppar->arg_stack_end= ppar->arg_stack; ppar->cur_part_fields= 0; ppar->cur_subpart_fields= 0; + + ppar->cur_min_key= ppar->range_param.min_key; + ppar->cur_max_key= ppar->range_param.max_key; + ppar->cur_min_flag= ppar->cur_max_flag= 0; + init_all_partitions_iterator(ppar->part_info, &ppar->part_iter); SEL_ARG *key_tree= (*ptree)->keys[0]; if (!key_tree || (-1 == (res |= find_used_partitions(ppar, key_tree)))) @@ -3091,8 +3132,12 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) { int res, left_res=0, right_res=0; int partno= (int)key_tree->part; - bool pushed= FALSE; bool set_full_part_if_bad_ret= FALSE; + bool ignore_part_fields= ppar->ignore_part_fields; + bool did_set_ignore_part_fields= FALSE; + + if (check_stack_overrun(ppar->range_param.thd, 3*STACK_MIN_SIZE, NULL)) + return -1; if (key_tree->left != &null_element) { @@ -3100,35 +3145,153 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) return -1; } + /* Push SEL_ARG's to stack to enable looking backwards as well */ + ppar->cur_part_fields+= ppar->is_part_keypart[partno]; + ppar->cur_subpart_fields+= ppar->is_subpart_keypart[partno]; + *(ppar->arg_stack_end++)= key_tree; + if (key_tree->type == SEL_ARG::KEY_RANGE) { - if (partno == 0 && (NULL != ppar->part_info->get_part_iter_for_interval)) + if (ppar->part_info->get_part_iter_for_interval && + key_tree->part <= ppar->last_part_partno) { - /* - Partitioning is done by RANGE|INTERVAL(monotonic_expr(fieldX)), and - we got "const1 CMP fieldX CMP const2" interval <-- psergey-todo: change + if (ignore_part_fields) + { + /* + We come here when a condition on the first partitioning + fields led to evaluating the partitioning condition + (due to finding a condition of the type a < const or + b > const). Thus we must ignore the rest of the + partitioning fields but we still want to analyse the + subpartitioning fields. + */ + if (key_tree->next_key_part) + res= find_used_partitions(ppar, key_tree->next_key_part); + else + res= -1; + goto pop_and_go_right; + } + /* Collect left and right bound, their lengths and flags */ + uchar *min_key= ppar->cur_min_key; + uchar *max_key= ppar->cur_max_key; + uchar *tmp_min_key= min_key; + uchar *tmp_max_key= max_key; + key_tree->store_min(ppar->key[key_tree->part].store_length, + &tmp_min_key, ppar->cur_min_flag); + key_tree->store_max(ppar->key[key_tree->part].store_length, + &tmp_max_key, ppar->cur_max_flag); + uint flag; + if (key_tree->next_key_part && + key_tree->next_key_part->part == key_tree->part+1 && + key_tree->next_key_part->part <= ppar->last_part_partno && + key_tree->next_key_part->type == SEL_ARG::KEY_RANGE) + { + /* + There are more key parts for partition pruning to handle + This mainly happens when the condition is an equality + condition. + */ + if ((tmp_min_key - min_key) == (tmp_max_key - max_key) && + (memcmp(min_key, max_key, (uint)(tmp_max_key - max_key)) == 0) && + !key_tree->min_flag && !key_tree->max_flag) + { + /* Set 'parameters' */ + ppar->cur_min_key= tmp_min_key; + ppar->cur_max_key= tmp_max_key; + uint save_min_flag= ppar->cur_min_flag; + uint save_max_flag= ppar->cur_max_flag; + + ppar->cur_min_flag|= key_tree->min_flag; + ppar->cur_max_flag|= key_tree->max_flag; + + res= find_used_partitions(ppar, key_tree->next_key_part); + + /* Restore 'parameters' back */ + ppar->cur_min_key= min_key; + ppar->cur_max_key= max_key; + + ppar->cur_min_flag= save_min_flag; + ppar->cur_max_flag= save_max_flag; + goto pop_and_go_right; + } + /* We have arrived at the last field in the partition pruning */ + uint tmp_min_flag= key_tree->min_flag, + tmp_max_flag= key_tree->max_flag; + if (!tmp_min_flag) + key_tree->next_key_part->store_min_key(ppar->key, + &tmp_min_key, + &tmp_min_flag, + ppar->last_part_partno); + if (!tmp_max_flag) + key_tree->next_key_part->store_max_key(ppar->key, + &tmp_max_key, + &tmp_max_flag, + ppar->last_part_partno); + flag= tmp_min_flag | tmp_max_flag; + } + else + flag= key_tree->min_flag | key_tree->max_flag; + + if (tmp_min_key != ppar->range_param.min_key) + flag&= ~NO_MIN_RANGE; + else + flag|= NO_MIN_RANGE; + if (tmp_max_key != ppar->range_param.max_key) + flag&= ~NO_MAX_RANGE; + else + flag|= NO_MAX_RANGE; + + /* + We need to call the interval mapper if we have a condition which + makes sense to prune on. In the example of a COLUMN_LIST on a and + b it makes sense if we have a condition on a, or conditions on + both a and b. If we only have conditions on b it might make sense + but this is a harder case we will solve later. For the harder case + this clause then turns into use of all partitions and thus we + simply set res= -1 as if the mapper had returned that. */ - DBUG_EXECUTE("info", dbug_print_segment_range(key_tree, - ppar->range_param. - key_parts);); - res= ppar->part_info-> - get_part_iter_for_interval(ppar->part_info, - FALSE, - key_tree->min_value, - key_tree->max_value, - key_tree->min_flag | key_tree->max_flag, - &ppar->part_iter); - if (!res) - goto go_right; /* res==0 --> no satisfying partitions */ + if (ppar->arg_stack[0]->part == 0) + { + uint32 i; + uint32 store_length_array[MAX_KEY]; + uint32 num_keys= ppar->part_fields; + + for (i= 0; i < num_keys; i++) + store_length_array[i]= ppar->key[i].store_length; + res= ppar->part_info-> + get_part_iter_for_interval(ppar->part_info, + FALSE, + store_length_array, + ppar->range_param.min_key, + ppar->range_param.max_key, + tmp_min_key - ppar->range_param.min_key, + tmp_max_key - ppar->range_param.max_key, + flag, + &ppar->part_iter); + if (!res) + goto pop_and_go_right; /* res==0 --> no satisfying partitions */ + } + else + res= -1; + if (res == -1) { - //get a full range iterator + /* get a full range iterator */ init_all_partitions_iterator(ppar->part_info, &ppar->part_iter); } /* Save our intent to mark full partition as used if we will not be able to obtain further limits on subpartitions */ + if (partno < ppar->last_part_partno) + { + /* + We need to ignore the rest of the partitioning fields in all + evaluations after this + */ + did_set_ignore_part_fields= TRUE; + ppar->ignore_part_fields= TRUE; + } set_full_part_if_bad_ret= TRUE; goto process_next_key_part; } @@ -3143,13 +3306,16 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) res= ppar->part_info-> get_subpart_iter_for_interval(ppar->part_info, TRUE, + NULL, /* Currently not used here */ key_tree->min_value, key_tree->max_value, - key_tree->min_flag | key_tree->max_flag, + 0, 0, /* Those are ignored here */ + key_tree->min_flag | + key_tree->max_flag, &subpart_iter); DBUG_ASSERT(res); /* We can't get "no satisfying subpartitions" */ if (res == -1) - return -1; /* all subpartitions satisfy */ + goto pop_and_go_right; /* all subpartitions satisfy */ uint32 subpart_id; bitmap_clear_all(&ppar->subparts_bitmap); @@ -3167,18 +3333,14 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) bitmap_set_bit(&ppar->part_info->used_partitions, part_id * ppar->part_info->no_subparts + i); } - goto go_right; + goto pop_and_go_right; } if (key_tree->is_singlepoint()) { - pushed= TRUE; - ppar->cur_part_fields+= ppar->is_part_keypart[partno]; - ppar->cur_subpart_fields+= ppar->is_subpart_keypart[partno]; - *(ppar->arg_stack_end++) = key_tree; - if (partno == ppar->last_part_partno && - ppar->cur_part_fields == ppar->part_fields) + ppar->cur_part_fields == ppar->part_fields && + ppar->part_info->get_part_iter_for_interval == NULL) { /* Ok, we've got "fieldN<=>constN"-type SEL_ARGs for all partitioning @@ -3245,7 +3407,10 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) able to infer any suitable condition, so bail out. */ if (partno >= ppar->last_part_partno) - return -1; + { + res= -1; + goto pop_and_go_right; + } } } @@ -3254,7 +3419,17 @@ process_next_key_part: res= find_used_partitions(ppar, key_tree->next_key_part); else res= -1; - + + if (did_set_ignore_part_fields) + { + /* + We have returned from processing all key trees linked to our next + key part. We are ready to be moving down (using right pointers) and + this tree is a new evaluation requiring its own decision on whether + to ignore partitioning fields. + */ + ppar->ignore_part_fields= FALSE; + } if (set_full_part_if_bad_ret) { if (res == -1) @@ -3277,18 +3452,14 @@ process_next_key_part: init_all_partitions_iterator(ppar->part_info, &ppar->part_iter); } - if (pushed) - { pop_and_go_right: - /* Pop this key part info off the "stack" */ - ppar->arg_stack_end--; - ppar->cur_part_fields-= ppar->is_part_keypart[partno]; - ppar->cur_subpart_fields-= ppar->is_subpart_keypart[partno]; - } + /* Pop this key part info off the "stack" */ + ppar->arg_stack_end--; + ppar->cur_part_fields-= ppar->is_part_keypart[partno]; + ppar->cur_subpart_fields-= ppar->is_subpart_keypart[partno]; if (res == -1) return -1; -go_right: if (key_tree->right != &null_element) { if (-1 == (right_res= find_used_partitions(ppar,key_tree->right))) @@ -3377,6 +3548,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) uint total_parts= used_part_fields + used_subpart_fields; + ppar->ignore_part_fields= FALSE; ppar->part_fields= used_part_fields; ppar->last_part_partno= (int)used_part_fields - 1; @@ -7477,12 +7649,16 @@ check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree, tmp_max_flag=key_tree->max_flag; if (!tmp_min_flag) tmp_min_keypart+= - key_tree->next_key_part->store_min_key(param->key[idx], &tmp_min_key, - &tmp_min_flag); + key_tree->next_key_part->store_min_key(param->key[idx], + &tmp_min_key, + &tmp_min_flag, + MAX_KEY); if (!tmp_max_flag) tmp_max_keypart+= - key_tree->next_key_part->store_max_key(param->key[idx], &tmp_max_key, - &tmp_max_flag); + key_tree->next_key_part->store_max_key(param->key[idx], + &tmp_max_key, + &tmp_max_flag, + MAX_KEY); min_key_length= (uint) (tmp_min_key - param->min_key); max_key_length= (uint) (tmp_max_key - param->max_key); } @@ -7752,11 +7928,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key, { uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag; if (!tmp_min_flag) - min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key, - &tmp_min_flag); + min_part+= key_tree->next_key_part->store_min_key(key, + &tmp_min_key, + &tmp_min_flag, + MAX_KEY); if (!tmp_max_flag) - max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key, - &tmp_max_flag); + max_part+= key_tree->next_key_part->store_max_key(key, + &tmp_max_key, + &tmp_max_flag, + MAX_KEY); flag=tmp_min_flag | tmp_max_flag; } } diff --git a/sql/partition_element.h b/sql/partition_element.h index 905bc38165b..d749681fe9b 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyright (C) 2006-2009 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,6 +35,35 @@ enum partition_state { PART_IS_ADDED= 8 }; +/* + This struct is used to keep track of column expressions as part + of the COLUMNS concept in conjunction with RANGE and LIST partitioning. + The value can be either of MINVALUE, MAXVALUE and an expression that + must be constant and evaluate to the same type as the column it + represents. + + The data in this fixed in two steps. The parser will only fill in whether + it is a max_value or provide an expression. Filling in + column_value, part_info, partition_id, null_value is done by the + function fix_column_value_function. However the item tree needs + fixed also before writing it into the frm file (in add_column_list_values). + To distinguish between those two variants, fixed= 1 after the + fixing in add_column_list_values and fixed= 2 otherwise. This is + since the fixing in add_column_list_values isn't a complete fixing. +*/ + +typedef struct p_column_list_val +{ + void* column_value; + Item* item_expression; + partition_info *part_info; + uint partition_id; + bool max_value; + bool null_value; + char fixed; +} part_column_list_val; + + /* This struct is used to contain the value of an element in the VALUES IN struct. It needs to keep knowledge of @@ -47,6 +76,7 @@ typedef struct p_elem_val longlong value; bool null_value; bool unsigned_flag; + part_column_list_val *col_val_array; } part_elem_value; struct st_ddl_log_memory_entry; @@ -68,8 +98,9 @@ public: enum partition_state part_state; uint16 nodegroup_id; bool has_null_value; - bool signed_flag;/* Indicate whether this partition uses signed constants */ - bool max_value; /* Indicate whether this partition uses MAXVALUE */ + /* signed_flag and max_value only relevant for subpartitions */ + bool signed_flag; + bool max_value; partition_element() : part_max_rows(0), part_min_rows(0), range_value(0), diff --git a/sql/partition_info.cc b/sql/partition_info.cc index e2027d3571e..bb7c7c2be0f 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -591,6 +591,7 @@ error: SYNOPSIS check_range_constants() + thd Thread object RETURN VALUE TRUE An error occurred during creation of range constants @@ -603,76 +604,112 @@ error: called for RANGE PARTITIONed tables. */ -bool partition_info::check_range_constants() +bool partition_info::check_range_constants(THD *thd) { partition_element* part_def; - longlong current_largest; - longlong part_range_value; bool first= TRUE; uint i; List_iterator it(partitions); - bool result= TRUE; - bool signed_flag= !part_expr->unsigned_flag; + int result= TRUE; DBUG_ENTER("partition_info::check_range_constants"); - DBUG_PRINT("enter", ("INT_RESULT with %d parts", no_parts)); + DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", no_parts, + column_list)); - LINT_INIT(current_largest); - - part_result_type= INT_RESULT; - range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong)); - if (unlikely(range_int_array == NULL)) + if (column_list) { - mem_alloc_error(no_parts * sizeof(longlong)); - goto end; - } - i= 0; - do - { - part_def= it++; - if ((i != (no_parts - 1)) || !defined_max_value) + part_column_list_val* loc_range_col_array; + part_column_list_val *current_largest_col_val; + uint no_column_values= part_field_list.elements; + uint size_entries= sizeof(part_column_list_val) * no_column_values; + range_col_array= (part_column_list_val*)sql_calloc(no_parts * + size_entries); + LINT_INIT(current_largest_col_val); + if (unlikely(range_col_array == NULL)) { - part_range_value= part_def->range_value; - if (!signed_flag) - part_range_value-= 0x8000000000000000ULL; + mem_alloc_error(no_parts * sizeof(longlong)); + goto end; } - else - part_range_value= LONGLONG_MAX; - if (first) + loc_range_col_array= range_col_array; + i= 0; + do { - current_largest= part_range_value; - range_int_array[0]= part_range_value; - first= FALSE; - } - else - { - if (likely(current_largest < part_range_value)) + part_def= it++; { - current_largest= part_range_value; - range_int_array[i]= part_range_value; + List_iterator list_val_it(part_def->list_val_list); + part_elem_value *range_val= list_val_it++; + part_column_list_val *col_val= range_val->col_val_array; + + if (fix_column_value_functions(thd, col_val, i)) + goto end; + memcpy(loc_range_col_array, (const void*)col_val, size_entries); + loc_range_col_array+= no_column_values; + if (!first) + { + if (compare_column_values((const void*)current_largest_col_val, + (const void*)col_val) >= 0) + goto range_not_increasing_error; + } + current_largest_col_val= col_val; } - else if (defined_max_value && - current_largest == part_range_value && - part_range_value == LONGLONG_MAX && - i == (no_parts - 1)) + first= FALSE; + } while (++i < no_parts); + } + else + { + longlong current_largest; + longlong part_range_value; + bool signed_flag= !part_expr->unsigned_flag; + + LINT_INIT(current_largest); + + part_result_type= INT_RESULT; + range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong)); + if (unlikely(range_int_array == NULL)) + { + mem_alloc_error(no_parts * sizeof(longlong)); + goto end; + } + i= 0; + do + { + part_def= it++; + if ((i != (no_parts - 1)) || !defined_max_value) { - range_int_array[i]= part_range_value; + part_range_value= part_def->range_value; + if (!signed_flag) + part_range_value-= 0x8000000000000000ULL; } else + part_range_value= LONGLONG_MAX; + + if (!first) { - my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0)); - goto end; + if (unlikely(current_largest > part_range_value) || + (unlikely(current_largest == part_range_value) && + (part_range_value < LONGLONG_MAX || + i != (no_parts - 1) || + !defined_max_value))) + goto range_not_increasing_error; } - } - } while (++i < no_parts); + range_int_array[i]= part_range_value; + current_largest= part_range_value; + first= FALSE; + } while (++i < no_parts); + } result= FALSE; end: DBUG_RETURN(result); + +range_not_increasing_error: + my_error(ER_RANGE_NOT_INCREASING_ERROR, MYF(0)); + goto end; } /* Support routines for check_list_constants used by qsort to sort the - constant list expressions. One routine for unsigned and one for signed. + constant list expressions. One routine for integers and one for + column lists. SYNOPSIS list_part_cmp() @@ -697,6 +734,133 @@ int partition_info::list_part_cmp(const void* a, const void* b) return 0; } + /* + Compare two lists of column values in RANGE/LIST partitioning + SYNOPSIS + compare_column_values() + first First column list argument + second Second column list argument + RETURN VALUES + 0 Equal + -1 First argument is smaller + +1 First argument is larger +*/ + +int partition_info::compare_column_values(const void *first_arg, + const void *second_arg) +{ + const part_column_list_val *first= (part_column_list_val*)first_arg; + const part_column_list_val *second= (part_column_list_val*)second_arg; + partition_info *part_info= first->part_info; + Field **field; + + for (field= part_info->part_field_array; *field; + field++, first++, second++) + { + if (first->max_value || second->max_value) + { + if (first->max_value && second->max_value) + continue; + if (second->max_value) + return -1; + else + return +1; + } + if (first->null_value || second->null_value) + { + if (first->null_value && second->null_value) + continue; + if (second->null_value) + return +1; + else + return -1; + } + int res= (*field)->cmp((const uchar*)first->column_value, + (const uchar*)second->column_value); + if (res) + return res; + } + return 0; +} + +/* + Evaluate VALUES functions for column list values + SYNOPSIS + fix_column_value_functions() + thd Thread object + col_val List of column values + part_id Partition id we are fixing + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Fix column VALUES and store in memory array adapted to the data type +*/ + +bool partition_info::fix_column_value_functions(THD *thd, + part_column_list_val *col_val, + uint part_id) +{ + uint no_columns= part_field_list.elements; + Name_resolution_context *context= &thd->lex->current_select->context; + TABLE_LIST *save_list= context->table_list; + bool result= FALSE; + uint i; + const char *save_where= thd->where; + DBUG_ENTER("partition_info::fix_column_value_functions"); + if (col_val->fixed > 1) + { + DBUG_RETURN(FALSE); + } + context->table_list= 0; + thd->where= "partition function"; + for (i= 0; i < no_columns; col_val++, i++) + { + Item *column_item= col_val->item_expression; + Field *field= part_field_array[i]; + col_val->part_info= this; + col_val->partition_id= part_id; + if (col_val->max_value) + col_val->column_value= NULL; + else + { + if (!col_val->fixed && + (column_item->fix_fields(thd, (Item**)0) || + (!column_item->const_item()))) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + result= TRUE; + goto end; + } + col_val->null_value= column_item->null_value; + col_val->column_value= NULL; + if (!col_val->null_value) + { + uchar *val_ptr; + uint len= field->pack_length(); + if (column_item->save_in_field(field, TRUE)) + { + my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); + result= TRUE; + goto end; + } + if (!(val_ptr= (uchar*) sql_calloc(len))) + { + mem_alloc_error(len); + result= TRUE; + goto end; + } + col_val->column_value= val_ptr; + memcpy(val_ptr, field->ptr, len); + } + } + col_val->fixed= 2; + } +end: + thd->where= save_where; + context->table_list= save_list; + DBUG_RETURN(result); +} /* This routine allocates an array for all list constants to achieve a fast @@ -706,6 +870,7 @@ int partition_info::list_part_cmp(const void* a, const void* b) SYNOPSIS check_list_constants() + thd Thread object RETURN VALUE TRUE An error occurred during creation of list constants @@ -718,15 +883,18 @@ int partition_info::list_part_cmp(const void* a, const void* b) called for LIST PARTITIONed tables. */ -bool partition_info::check_list_constants() +bool partition_info::check_list_constants(THD *thd) { - uint i; + uint i, size_entries, no_column_values; uint list_index= 0; part_elem_value *list_value; bool result= TRUE; - longlong curr_value, prev_value, type_add, calc_value; + longlong type_add, calc_value; + void *curr_value, *prev_value; partition_element* part_def; bool found_null= FALSE; + int (*compare_func)(const void *, const void*); + void *ptr; List_iterator list_func_it(partitions); DBUG_ENTER("partition_info::check_list_constants"); @@ -767,48 +935,86 @@ bool partition_info::check_list_constants() no_list_values++; } while (++i < no_parts); list_func_it.rewind(); - list_array= (LIST_PART_ENTRY*)sql_alloc((no_list_values+1) * - sizeof(LIST_PART_ENTRY)); - if (unlikely(list_array == NULL)) + no_column_values= part_field_list.elements; + size_entries= column_list ? + (no_column_values * sizeof(part_column_list_val)) : + sizeof(LIST_PART_ENTRY); + ptr= sql_calloc((no_list_values+1) * size_entries); + if (unlikely(ptr == NULL)) { - mem_alloc_error(no_list_values * sizeof(LIST_PART_ENTRY)); + mem_alloc_error(no_list_values * size_entries); goto end; } - - i= 0; - /* - Fix to be able to reuse signed sort functions also for unsigned - partition functions. - */ - type_add= (longlong)(part_expr->unsigned_flag ? + if (column_list) + { + part_column_list_val *loc_list_col_array; + loc_list_col_array= (part_column_list_val*)ptr; + list_col_array= (part_column_list_val*)ptr; + compare_func= compare_column_values; + i= 0; + /* + Fix to be able to reuse signed sort functions also for unsigned + partition functions. + */ + do + { + part_def= list_func_it++; + List_iterator list_val_it2(part_def->list_val_list); + while ((list_value= list_val_it2++)) + { + part_column_list_val *col_val= list_value->col_val_array; + if (unlikely(fix_column_value_functions(thd, col_val, i))) + { + DBUG_RETURN(TRUE); + } + memcpy(loc_list_col_array, (const void*)col_val, size_entries); + loc_list_col_array+= no_column_values; + } + } while (++i < no_parts); + } + else + { + compare_func= list_part_cmp; + list_array= (LIST_PART_ENTRY*)ptr; + i= 0; + /* + Fix to be able to reuse signed sort functions also for unsigned + partition functions. + */ + type_add= (longlong)(part_expr->unsigned_flag ? 0x8000000000000000ULL : 0ULL); - do - { - part_def= list_func_it++; - List_iterator list_val_it2(part_def->list_val_list); - while ((list_value= list_val_it2++)) + do { - calc_value= list_value->value - type_add; - list_array[list_index].list_value= calc_value; - list_array[list_index++].partition_id= i; - } - } while (++i < no_parts); - + part_def= list_func_it++; + List_iterator list_val_it2(part_def->list_val_list); + while ((list_value= list_val_it2++)) + { + calc_value= list_value->value - type_add; + list_array[list_index].list_value= calc_value; + list_array[list_index++].partition_id= i; + } + } while (++i < no_parts); + } if (fixed && no_list_values) { bool first= TRUE; + /* + list_array and list_col_array are unions, so this works for both + variants of LIST partitioning. + */ my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), &list_part_cmp); - + i= 0; LINT_INIT(prev_value); do { DBUG_ASSERT(i < no_list_values); - curr_value= list_array[i].list_value; - if (likely(first || prev_value != curr_value)) + curr_value= column_list ? (void*)&list_col_array[no_column_values * i] : + (void*)&list_array[i]; + if (likely(first || compare_func(curr_value, prev_value))) { prev_value= curr_value; first= FALSE; @@ -831,10 +1037,11 @@ end: SYNOPSIS check_partition_info() + thd Thread object + eng_type Return value for used engine in partitions file A reference to a handler of the table info Create info - engine_type Return value for used engine in partitions - check_partition_function Should we check the partition function + add_or_reorg_part Is it ALTER TABLE ADD/REORGANIZE command RETURN VALUE TRUE Error, something went wrong @@ -850,7 +1057,7 @@ end: bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, handler *file, HA_CREATE_INFO *info, - bool check_partition_function) + bool add_or_reorg_part) { handlerton *table_engine= default_engine_type; uint i, tot_partitions; @@ -861,11 +1068,11 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, DBUG_PRINT("info", ("default table_engine = %s", ha_resolve_storage_engine_name(table_engine))); - if (check_partition_function) + if (!add_or_reorg_part) { int err= 0; - if (part_type != HASH_PARTITION || !list_of_part_fields) + if (!list_of_part_fields) { DBUG_ASSERT(part_expr); err= part_expr->walk(&Item::check_partition_func_processor, 0, @@ -1064,10 +1271,12 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, list constants. */ - if (fixed) + if (add_or_reorg_part) { - if (unlikely((part_type == RANGE_PARTITION && check_range_constants()) || - (part_type == LIST_PARTITION && check_list_constants()))) + if (unlikely((part_type == RANGE_PARTITION && + check_range_constants(thd)) || + (part_type == LIST_PARTITION && + check_list_constants(thd)))) goto end; } result= FALSE; @@ -1098,20 +1307,96 @@ void partition_info::print_no_partition_found(TABLE *table) if (check_single_table_access(current_thd, SELECT_ACL, &table_list, TRUE)) + { my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE, ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), MYF(0)); + } else { - my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); - if (part_expr->null_value) - buf_ptr= (char*)"NULL"; + if (column_list) + buf_ptr= (char*)"from column_list"; else - longlong2str(err_value, buf, - part_expr->unsigned_flag ? 10 : -10); + { + my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); + if (part_expr->null_value) + buf_ptr= (char*)"NULL"; + else + longlong2str(err_value, buf, + part_expr->unsigned_flag ? 10 : -10); + dbug_tmp_restore_column_map(table->read_set, old_map); + } my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr); - dbug_tmp_restore_column_map(table->read_set, old_map); } } + + +/* + Create a new column value in current list + SYNOPSIS + add_column_value() + RETURN + >0 A part_column_list_val object which have been + inserted into its list + 0 Memory allocation failure +*/ + +part_column_list_val *partition_info::add_column_value() +{ + uint max_val= num_columns ? num_columns : MAX_REF_PARTS; + DBUG_ENTER("add_column_value"); + DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u", + num_columns, curr_list_object, max_val)); + if (curr_list_object < max_val) + { + DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]); + } + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(NULL); +} + + +/* + Set fields related to partition expression + SYNOPSIS + set_part_expr() + start_token Start of partition function string + item_ptr Pointer to item tree + end_token End of partition function string + is_subpart Subpartition indicator + RETURN VALUES + TRUE Memory allocation error + FALSE Success +*/ + +bool partition_info::set_part_expr(char *start_token, Item *item_ptr, + char *end_token, bool is_subpart) +{ + uint expr_len= end_token - start_token; + char *func_string= (char*) sql_memdup(start_token, expr_len); + + if (!func_string) + { + mem_alloc_error(expr_len); + return TRUE; + } + if (is_subpart) + { + list_of_subpart_fields= FALSE; + subpart_expr= item_ptr; + subpart_func_string= func_string; + subpart_func_len= expr_len; + } + else + { + list_of_part_fields= FALSE; + part_expr= item_ptr; + part_func_string= func_string; + part_func_len= expr_len; + } + return FALSE; +} + + /* Set up buffers and arrays for fields requiring preparation SYNOPSIS @@ -1223,46 +1508,6 @@ bool partition_info::set_up_charset_field_preps() } subpart_charset_field_array[i]= NULL; } - if (tot_fields) - { - uint k; - size= tot_fields*sizeof(char**); - if (!(char_ptrs= (uchar**)sql_calloc(size))) - goto error; - full_part_field_buffers= char_ptrs; - if (!(char_ptrs= (uchar**)sql_calloc(size))) - goto error; - restore_full_part_field_ptrs= char_ptrs; - size= (tot_fields + 1) * sizeof(char**); - if (!(char_ptrs= (uchar**)sql_calloc(size))) - goto error; - full_part_charset_field_array= (Field**)char_ptrs; - for (i= 0; i < tot_part_fields; i++) - { - full_part_charset_field_array[i]= part_charset_field_array[i]; - full_part_field_buffers[i]= part_field_buffers[i]; - } - k= tot_part_fields; - for (i= 0; i < tot_subpart_fields; i++) - { - uint j; - bool found= FALSE; - field= subpart_charset_field_array[i]; - - for (j= 0; j < tot_part_fields; j++) - { - if (field == part_charset_field_array[i]) - found= TRUE; - } - if (!found) - { - full_part_charset_field_array[k]= subpart_charset_field_array[i]; - full_part_field_buffers[k]= subpart_field_buffers[i]; - k++; - } - } - full_part_charset_field_array[k]= NULL; - } DBUG_RETURN(FALSE); error: mem_alloc_error(size); diff --git a/sql/partition_info.h b/sql/partition_info.h index 415f955d5d4..f232e761946 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -19,6 +19,8 @@ #include "partition_element.h" +#define MAX_STR_SIZE_PF 512 + class partition_info; /* Some function typedefs */ @@ -64,10 +66,9 @@ public: /* When we have various string fields we might need some preparation before and clean-up after calling the get_part_id_func's. We need - one such method for get_partition_id and one for - get_part_partition_id and one for get_subpartition_id. + one such method for get_part_partition_id and one for + get_subpartition_id. */ - get_part_id_func get_partition_id_charset; get_part_id_func get_part_partition_id_charset; get_subpart_id_func get_subpartition_id_charset; @@ -81,7 +82,6 @@ public: without duplicates, NULL-terminated. */ Field **full_part_field_array; - Field **full_part_charset_field_array; /* Set of all fields used in partition and subpartition expression. Required for testing of partition fields in write_set when @@ -97,10 +97,8 @@ public: */ uchar **part_field_buffers; uchar **subpart_field_buffers; - uchar **full_part_field_buffers; uchar **restore_part_field_ptrs; uchar **restore_subpart_field_ptrs; - uchar **restore_full_part_field_ptrs; Item *part_expr; Item *subpart_expr; @@ -124,6 +122,8 @@ public: union { longlong *range_int_array; LIST_PART_ENTRY *list_array; + part_column_list_val *range_col_array; + part_column_list_val *list_col_array; }; /******************************************** @@ -154,6 +154,10 @@ public: partition_element *curr_part_elem; partition_element *current_partition; + part_elem_value *curr_list_val; + uint curr_list_object; + uint num_columns; + /* These key_map's are used for Partitioning to enable quick decisions on whether we can derive more information about which partition to @@ -205,7 +209,7 @@ public: bool is_auto_partitioned; bool from_openfrm; bool has_null_value; - + bool column_list; partition_info() : get_partition_id(NULL), get_part_partition_id(NULL), @@ -214,11 +218,8 @@ public: part_charset_field_array(NULL), subpart_charset_field_array(NULL), full_part_field_array(NULL), - full_part_charset_field_array(NULL), part_field_buffers(NULL), subpart_field_buffers(NULL), - full_part_field_buffers(NULL), restore_part_field_ptrs(NULL), restore_subpart_field_ptrs(NULL), - restore_full_part_field_ptrs(NULL), part_expr(NULL), subpart_expr(NULL), item_free_list(NULL), first_log_entry(NULL), exec_log_entry(NULL), frm_log_entry(NULL), list_array(NULL), err_value(0), @@ -226,6 +227,7 @@ public: part_func_string(NULL), subpart_func_string(NULL), part_state(NULL), curr_part_elem(NULL), current_partition(NULL), + curr_list_object(0), num_columns(0), default_engine_type(NULL), part_result_type(INT_RESULT), part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), @@ -241,7 +243,7 @@ public: list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), linear_hash_ind(FALSE), fixed(FALSE), is_auto_partitioned(FALSE), from_openfrm(FALSE), - has_null_value(FALSE) + has_null_value(FALSE), column_list(FALSE) { all_fields_in_PF.clear_all(); all_fields_in_PPF.clear_all(); @@ -271,16 +273,19 @@ public: uint start_no); char *has_unique_names(); bool check_engine_mix(handlerton *engine_type, bool default_engine); - bool check_range_constants(); - bool check_list_constants(); + bool check_range_constants(THD *thd); + bool check_list_constants(THD *thd); bool check_partition_info(THD *thd, handlerton **eng_type, handler *file, HA_CREATE_INFO *info, bool check_partition_function); void print_no_partition_found(TABLE *table); + part_column_list_val *add_column_value(); + bool set_part_expr(char *start_token, Item *item_ptr, + char *end_token, bool is_subpart); + static int compare_column_values(const void *a, const void *b); bool set_up_charset_field_preps(); private: static int list_part_cmp(const void* a, const void* b); - static int list_part_cmp_unsigned(const void* a, const void* b); bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info, uint start_no); bool set_up_default_subpartitions(handler *file, HA_CREATE_INFO *info); @@ -288,6 +293,9 @@ private: uint start_no); char *create_subpartition_name(uint subpart_no, const char *part_name); bool has_unique_name(partition_element *element); + bool fix_column_value_functions(THD *thd, + part_column_list_val *col_val, + uint part_id); }; uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5531ee71620..514dc06728d 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6180,6 +6180,16 @@ ER_TOO_LONG_FIELD_COMMENT ER_FUNC_INEXISTENT_NAME_COLLISION 42000 eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual" +ER_GLOBAL_PARTITION_INDEX_ERROR + eng "Partitioning of indexes only supported for global indexes" +ER_PARTITION_COLUMN_LIST_ERROR + eng "Inconsistency in usage of column lists for partitioning" +ER_WRONG_TYPE_COLUMN_VALUE_ERROR + eng "Partition column values of incorrect type" +ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR + eng "Too many fields in '%s'" +ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR + eng "Cannot use MAXVALUE as value in List partitioning" # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # mysql_priv.h with the new maximal additional length for explain_filename. diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2adbc44eb12..61f243ece1c 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -323,6 +323,7 @@ void lex_start(THD *thd) lex->select_lex.select_number= 1; lex->length=0; lex->part_info= 0; + lex->global_flag= 0; lex->select_lex.in_sum_expr=0; lex->select_lex.ftfunc_list_alloc.empty(); lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 76fd5354c51..d714e3d0441 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1565,6 +1565,9 @@ typedef struct st_lex : public Query_tables_list /* Partition info structure filled in by PARTITION BY parse part */ partition_info *part_info; + /* Flag to index a global index created */ + bool global_flag; + /* The definer of the object being created (view, trigger, stored routine). I.e. the value of DEFINER clause. diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 61766e5c509..9684e842d40 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -18,16 +18,29 @@ to partitioning introduced in MySQL version 5.1. It contains functionality used by all handlers that support partitioning, such as the partitioning handler itself and the NDB handler. + (Much of the code in this file has been split into partition_info.cc and + the header files partition_info.h + partition_element.h + sql_partition.h) - The first version was written by Mikael Ronstrom. + The first version was written by Mikael Ronstrom 2004-2006. + Various parts of the optimizer code was written by Sergey Petrunia. + Code have been maintained by Mattias Jonsson. + The second version was written by Mikael Ronstrom 2006-2007 with some + final fixes for partition pruning in 2008-2009 with assistance from Sergey + Petrunia and Mattias Jonsson. - This version supports RANGE partitioning, LIST partitioning, HASH + The first version supports RANGE partitioning, LIST partitioning, HASH partitioning and composite partitioning (hereafter called subpartitioning) where each RANGE/LIST partitioning is HASH partitioned. The hash function can either be supplied by the user or by only a list of fields (also called KEY partitioning), where the MySQL server will use an internal hash function. There are quite a few defaults that can be used as well. + + The second version introduces a new variant of RANGE and LIST partitioning + which is often referred to as column lists in the code variables. This + enables a user to specify a set of columns and their concatenated value + as the partition value. By comparing the concatenation of these values + the proper partition can be choosen. */ /* Some general useful functions */ @@ -50,9 +63,11 @@ const LEX_STRING partition_keywords[]= { C_STRING_WITH_LEN("LIST") }, { C_STRING_WITH_LEN("KEY") }, { C_STRING_WITH_LEN("MAXVALUE") }, - { C_STRING_WITH_LEN("LINEAR ") } + { C_STRING_WITH_LEN("LINEAR ") }, + { C_STRING_WITH_LEN(" COLUMN_LIST") } }; static const char *part_str= "PARTITION"; +static const char *subpart_str= "SUBPARTITION"; static const char *sub_str= "SUB"; static const char *by_str= "BY"; static const char *space_str= " "; @@ -61,26 +76,23 @@ static const char *end_paren_str= ")"; static const char *begin_paren_str= "("; static const char *comma_str= ","; -static int get_part_id_charset_func_all(partition_info *part_info, - uint32 *part_id, - longlong *func_value); +int get_partition_id_list_col(partition_info *part_info, + uint32 *part_id, + longlong *func_value); +int get_partition_id_list(partition_info *part_info, + uint32 *part_id, + longlong *func_value); +int get_partition_id_range_col(partition_info *part_info, + uint32 *part_id, + longlong *func_value); +int get_partition_id_range(partition_info *part_info, + uint32 *part_id, + longlong *func_value); static int get_part_id_charset_func_part(partition_info *part_info, uint32 *part_id, longlong *func_value); static int get_part_id_charset_func_subpart(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -static int get_part_part_id_charset_func(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -static int get_subpart_id_charset_func(partition_info *part_info, - uint32 *part_id); -int get_partition_id_list(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_range(partition_info *part_info, - uint32 *part_id, - longlong *func_value); + uint32 *part_id); int get_partition_id_hash_nosub(partition_info *part_info, uint32 *part_id, longlong *func_value); @@ -93,30 +105,9 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info, int get_partition_id_linear_key_nosub(partition_info *part_info, uint32 *part_id, longlong *func_value); -int get_partition_id_range_sub_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_range_sub_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_range_sub_linear_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_range_sub_linear_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_list_sub_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_list_sub_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_list_sub_linear_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value); -int get_partition_id_list_sub_linear_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value); +int get_partition_id_with_sub(partition_info *part_info, + uint32 *part_id, + longlong *func_value); int get_partition_id_hash_sub(partition_info *part_info, uint32 *part_id); int get_partition_id_key_sub(partition_info *part_info, @@ -134,14 +125,29 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter); uint32 get_next_partition_id_list(PARTITION_ITERATOR* part_iter); int get_part_iter_for_interval_via_mapping(partition_info *part_info, bool is_subpart, + uint32 *store_length_array, uchar *min_value, uchar *max_value, + uint min_len, uint max_len, uint flags, PARTITION_ITERATOR *part_iter); +int get_part_iter_for_interval_cols_via_map(partition_info *part_info, + bool is_subpart, + uint32 *store_length_array, + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, + uint flags, + PARTITION_ITERATOR *part_iter); int get_part_iter_for_interval_via_walking(partition_info *part_info, bool is_subpart, + uint32 *store_length_array, uchar *min_value, uchar *max_value, + uint min_len, uint max_len, uint flags, PARTITION_ITERATOR *part_iter); +static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec); +static int cmp_rec_and_tuple_prune(part_column_list_val *val, + uint32 n_vals_in_rec, + bool tail_is_min); #ifdef WITH_PARTITION_STORAGE_ENGINE /* @@ -161,7 +167,7 @@ bool is_name_in_list(char *name, List list_names) { List_iterator names_it(list_names); - uint no_names= list_names.elements; + uint num_names= list_names.elements; uint i= 0; do @@ -169,7 +175,7 @@ bool is_name_in_list(char *name, char *list_name= names_it++; if (!(my_strcasecmp(system_charset_info, name, list_name))) return TRUE; - } while (++i < no_names); + } while (++i < num_names); return FALSE; } @@ -451,6 +457,7 @@ static bool set_up_field_array(TABLE *table, uint no_fields= 0; uint size_field_array; uint i= 0; + uint inx; partition_info *part_info= table->part_info; int result= FALSE; DBUG_ENTER("set_up_field_array"); @@ -461,6 +468,16 @@ static bool set_up_field_array(TABLE *table, if (field->flags & GET_FIXED_FIELDS_FLAG) no_fields++; } + if (no_fields > MAX_REF_PARTS) + { + char *ptr; + if (is_sub_part) + ptr= (char*)"subpartition function"; + else + ptr= (char*)"partition function"; + my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), ptr); + DBUG_RETURN(TRUE); + } if (no_fields == 0) { /* @@ -470,7 +487,7 @@ static bool set_up_field_array(TABLE *table, DBUG_RETURN(result); } size_field_array= (no_fields+1)*sizeof(Field*); - field_array= (Field**)sql_alloc(size_field_array); + field_array= (Field**)sql_calloc(size_field_array); if (unlikely(!field_array)) { mem_alloc_error(size_field_array); @@ -485,7 +502,30 @@ static bool set_up_field_array(TABLE *table, field->flags|= FIELD_IN_PART_FUNC_FLAG; if (likely(!result)) { - field_array[i++]= field; + if (!is_sub_part && part_info->column_list) + { + List_iterator it(part_info->part_field_list); + char *field_name; + + DBUG_ASSERT(no_fields == part_info->part_field_list.elements); + inx= 0; + do + { + field_name= it++; + if (!strcmp(field_name, field->field_name)) + break; + } while (++inx < no_fields); + if (inx == no_fields) + { + mem_alloc_error(1); + result= TRUE; + continue; + } + } + else + inx= i; + field_array[inx]= field; + i++; /* We check that the fields are proper. It is required for each @@ -564,7 +604,7 @@ static bool create_full_part_field_array(THD *thd, TABLE *table, no_part_fields++; } size_field_array= (no_part_fields+1)*sizeof(Field*); - field_array= (Field**)sql_alloc(size_field_array); + field_array= (Field**)sql_calloc(size_field_array); if (unlikely(!field_array)) { mem_alloc_error(size_field_array); @@ -776,7 +816,7 @@ static bool handle_list_of_fields(List_iterator it, goto end; } } - if (is_list_empty) + if (is_list_empty && part_info->part_type == HASH_PARTITION) { uint primary_key= table->s->primary_key; if (primary_key != MAX_KEY) @@ -868,7 +908,6 @@ int check_signed_flag(partition_info *part_info) table The table object part_info Reference to partitioning data structure is_sub_part Is the table subpartitioned as well - is_field_to_be_setup Flag if we are to set-up field arrays RETURN VALUE TRUE An error occurred, something was wrong with the @@ -891,8 +930,8 @@ int check_signed_flag(partition_info *part_info) on the field object. */ -bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, - bool is_sub_part, bool is_field_to_be_setup) +static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, + bool is_sub_part) { partition_info *part_info= table->part_info; uint dir_length, home_dir_length; @@ -985,8 +1024,7 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, if (unlikely(error)) { DBUG_PRINT("info", ("Field in partition function not part of table")); - if (is_field_to_be_setup) - clear_field_flag(table); + clear_field_flag(table); goto end; } thd->where= save_where; @@ -998,9 +1036,7 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, } if ((!is_sub_part) && (error= check_signed_flag(part_info))) goto end; - result= FALSE; - if (is_field_to_be_setup) - result= set_up_field_array(table, is_sub_part); + result= set_up_field_array(table, is_sub_part); if (!is_sub_part) part_info->fixed= TRUE; end: @@ -1283,64 +1319,47 @@ static void set_up_partition_func_pointers(partition_info *part_info) if (part_info->is_sub_partitioned()) { + part_info->get_partition_id= get_partition_id_with_sub; if (part_info->part_type == RANGE_PARTITION) { - part_info->get_part_partition_id= get_partition_id_range; + if (part_info->column_list) + part_info->get_part_partition_id= get_partition_id_range_col; + else + part_info->get_part_partition_id= get_partition_id_range; if (part_info->list_of_subpart_fields) { if (part_info->linear_hash_ind) - { - part_info->get_partition_id= get_partition_id_range_sub_linear_key; part_info->get_subpartition_id= get_partition_id_linear_key_sub; - } else - { - part_info->get_partition_id= get_partition_id_range_sub_key; part_info->get_subpartition_id= get_partition_id_key_sub; - } } else { if (part_info->linear_hash_ind) - { - part_info->get_partition_id= get_partition_id_range_sub_linear_hash; part_info->get_subpartition_id= get_partition_id_linear_hash_sub; - } else - { - part_info->get_partition_id= get_partition_id_range_sub_hash; part_info->get_subpartition_id= get_partition_id_hash_sub; - } } } else /* LIST Partitioning */ { - part_info->get_part_partition_id= get_partition_id_list; + if (part_info->column_list) + part_info->get_part_partition_id= get_partition_id_list_col; + else + part_info->get_part_partition_id= get_partition_id_list; if (part_info->list_of_subpart_fields) { if (part_info->linear_hash_ind) - { - part_info->get_partition_id= get_partition_id_list_sub_linear_key; part_info->get_subpartition_id= get_partition_id_linear_key_sub; - } else - { - part_info->get_partition_id= get_partition_id_list_sub_key; part_info->get_subpartition_id= get_partition_id_key_sub; - } } else { if (part_info->linear_hash_ind) - { - part_info->get_partition_id= get_partition_id_list_sub_linear_hash; part_info->get_subpartition_id= get_partition_id_linear_hash_sub; - } else - { - part_info->get_partition_id= get_partition_id_list_sub_hash; part_info->get_subpartition_id= get_partition_id_hash_sub; - } } } } @@ -1349,9 +1368,19 @@ static void set_up_partition_func_pointers(partition_info *part_info) part_info->get_part_partition_id= NULL; part_info->get_subpartition_id= NULL; if (part_info->part_type == RANGE_PARTITION) - part_info->get_partition_id= get_partition_id_range; + { + if (part_info->column_list) + part_info->get_partition_id= get_partition_id_range_col; + else + part_info->get_partition_id= get_partition_id_range; + } else if (part_info->part_type == LIST_PARTITION) - part_info->get_partition_id= get_partition_id_list; + { + if (part_info->column_list) + part_info->get_partition_id= get_partition_id_list_col; + else + part_info->get_partition_id= get_partition_id_list; + } else /* HASH partitioning */ { if (part_info->list_of_part_fields) @@ -1370,32 +1399,37 @@ static void set_up_partition_func_pointers(partition_info *part_info) } } } - if (part_info->full_part_charset_field_array) + /* + We need special functions to handle character sets since they require copy + of field pointers and restore afterwards. For subpartitioned tables we do + the copy and restore individually on the part and subpart parts. For non- + subpartitioned tables we use the same functions as used for the parts part + of subpartioning. + Thus for subpartitioned tables the get_partition_id is always + get_partition_id_with_sub, even when character sets exists. + */ + if (part_info->part_charset_field_array) { - DBUG_ASSERT(part_info->get_partition_id); - part_info->get_partition_id_charset= part_info->get_partition_id; - if (part_info->part_charset_field_array && - part_info->subpart_charset_field_array) - part_info->get_partition_id= get_part_id_charset_func_all; - else if (part_info->part_charset_field_array) - part_info->get_partition_id= get_part_id_charset_func_part; + if (part_info->is_sub_partitioned()) + { + DBUG_ASSERT(part_info->get_part_partition_id); + part_info->get_part_partition_id_charset= + part_info->get_part_partition_id; + part_info->get_part_partition_id= get_part_id_charset_func_part; + } else - part_info->get_partition_id= get_part_id_charset_func_subpart; - } - if (part_info->part_charset_field_array && - part_info->is_sub_partitioned()) - { - DBUG_ASSERT(part_info->get_part_partition_id); - part_info->get_part_partition_id_charset= - part_info->get_part_partition_id; - part_info->get_part_partition_id= get_part_part_id_charset_func; + { + DBUG_ASSERT(part_info->get_partition_id); + part_info->get_part_partition_id_charset= part_info->get_partition_id; + part_info->get_partition_id= get_part_id_charset_func_part; + } } if (part_info->subpart_charset_field_array) { DBUG_ASSERT(part_info->get_subpartition_id); part_info->get_subpartition_id_charset= part_info->get_subpartition_id; - part_info->get_subpartition_id= get_subpart_id_charset_func; + part_info->get_subpartition_id= get_part_id_charset_func_subpart; } DBUG_VOID_RETURN; } @@ -1603,12 +1637,12 @@ bool fix_partition_func(THD *thd, TABLE *table, else { if (unlikely(fix_fields_part_func(thd, part_info->subpart_expr, - table, TRUE, TRUE))) + table, TRUE))) goto end; if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT)) { my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), - "SUBPARTITION"); + subpart_str); goto end; } } @@ -1631,7 +1665,7 @@ bool fix_partition_func(THD *thd, TABLE *table, else { if (unlikely(fix_fields_part_func(thd, part_info->part_expr, - table, FALSE, TRUE))) + table, FALSE))) goto end; if (unlikely(part_info->part_expr->result_type() != INT_RESULT)) { @@ -1644,19 +1678,28 @@ bool fix_partition_func(THD *thd, TABLE *table, else { const char *error_str; - if (unlikely(fix_fields_part_func(thd, part_info->part_expr, - table, FALSE, TRUE))) - goto end; + if (part_info->column_list) + { + List_iterator it(part_info->part_field_list); + if (unlikely(handle_list_of_fields(it, table, part_info, FALSE))) + goto end; + } + else + { + if (unlikely(fix_fields_part_func(thd, part_info->part_expr, + table, FALSE))) + goto end; + } if (part_info->part_type == RANGE_PARTITION) { error_str= partition_keywords[PKW_RANGE].str; - if (unlikely(part_info->check_range_constants())) + if (unlikely(part_info->check_range_constants(thd))) goto end; } else if (part_info->part_type == LIST_PARTITION) { error_str= partition_keywords[PKW_LIST].str; - if (unlikely(part_info->check_list_constants())) + if (unlikely(part_info->check_list_constants(thd))) goto end; } else @@ -1670,7 +1713,8 @@ bool fix_partition_func(THD *thd, TABLE *table, my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str); goto end; } - if (unlikely(part_info->part_expr->result_type() != INT_RESULT)) + if (unlikely(!part_info->column_list && + part_info->part_expr->result_type() != INT_RESULT)) { my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str); goto end; @@ -1723,9 +1767,9 @@ end: static int add_write(File fptr, const char *buf, uint len) { - uint len_written= my_write(fptr, (const uchar*)buf, len, MYF(0)); + uint ret_code= my_write(fptr, (const uchar*)buf, len, MYF(MY_FNABP)); - if (likely(len == len_written)) + if (likely(ret_code == 0)) return 0; else return 1; @@ -1774,14 +1818,8 @@ static int add_begin_parenthesis(File fptr) static int add_part_key_word(File fptr, const char *key_string) { int err= add_string(fptr, key_string); - err+= add_space(fptr); - return err + add_begin_parenthesis(fptr); -} - -static int add_hash(File fptr) -{ - return add_part_key_word(fptr, partition_keywords[PKW_HASH].str); + return err; } static int add_partition(File fptr) @@ -1812,15 +1850,15 @@ static int add_subpartition_by(File fptr) return err + add_partition_by(fptr); } -static int add_key_partition(File fptr, List field_list) +static int add_part_field_list(File fptr, List field_list) { uint i, no_fields; - int err; + int err= 0; List_iterator part_it(field_list); - err= add_part_key_word(fptr, partition_keywords[PKW_KEY].str); no_fields= field_list.elements; i= 0; + err+= add_begin_parenthesis(fptr); while (i < no_fields) { const char *field_str= part_it++; @@ -1836,6 +1874,7 @@ static int add_key_partition(File fptr, List field_list) err+= add_comma(fptr); i++; } + err+= add_end_parenthesis(fptr); return err; } @@ -1945,24 +1984,88 @@ static int add_partition_options(File fptr, partition_element *p_elem) return err + add_engine(fptr,p_elem->engine_type); } -static int add_partition_values(File fptr, partition_info *part_info, partition_element *p_elem) +static int add_column_list_values(File fptr, partition_info *part_info, + part_elem_value *list_value) +{ + int err= 0; + uint i; + uint no_elements= part_info->part_field_list.elements; + err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); + err+= add_begin_parenthesis(fptr); + for (i= 0; i < no_elements; i++) + { + part_column_list_val *col_val= &list_value->col_val_array[i]; + if (col_val->max_value) + err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str); + else if (col_val->null_value) + err+= add_string(fptr, "NULL"); + else + { + char buffer[MAX_STR_SIZE_PF]; + String str(buffer, sizeof(buffer), &my_charset_bin); + Item *item_expr= col_val->item_expression; + if (!col_val->fixed && + (item_expr->fix_fields(current_thd, (Item**)0) || + (!item_expr->const_item()))) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + return 1; + } + col_val->fixed= 1; + if (item_expr->null_value) + err+= add_string(fptr, "NULL"); + else + { + String *res= item_expr->val_str(&str); + if (!res) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + return 1; + } + if (item_expr->result_type() == STRING_RESULT) + err+= add_string(fptr,"'"); + err+= add_string_object(fptr, res); + if (item_expr->result_type() == STRING_RESULT) + err+= add_string(fptr,"'"); + } + } + if (i != (no_elements - 1)) + err+= add_string(fptr, comma_str); + } + err+= add_end_parenthesis(fptr); + return err; +} + +static int add_partition_values(File fptr, partition_info *part_info, + partition_element *p_elem) { int err= 0; if (part_info->part_type == RANGE_PARTITION) { err+= add_string(fptr, " VALUES LESS THAN "); - if (!p_elem->max_value) + if (part_info->column_list) { + List_iterator list_val_it(p_elem->list_val_list); + part_elem_value *list_value= list_val_it++; err+= add_begin_parenthesis(fptr); - if (p_elem->signed_flag) - err+= add_int(fptr, p_elem->range_value); - else - err+= add_uint(fptr, p_elem->range_value); + err+= add_column_list_values(fptr, part_info, list_value); err+= add_end_parenthesis(fptr); } else - err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str); + { + if (!p_elem->max_value) + { + err+= add_begin_parenthesis(fptr); + if (p_elem->signed_flag) + err+= add_int(fptr, p_elem->range_value); + else + err+= add_uint(fptr, p_elem->range_value); + err+= add_end_parenthesis(fptr); + } + else + err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str); + } } else if (part_info->part_type == LIST_PARTITION) { @@ -1987,10 +2090,15 @@ static int add_partition_values(File fptr, partition_info *part_info, partition_ { part_elem_value *list_value= list_val_it++; - if (!list_value->unsigned_flag) - err+= add_int(fptr, list_value->value); + if (part_info->column_list) + err+= add_column_list_values(fptr, part_info, list_value); else - err+= add_uint(fptr, list_value->value); + { + if (!list_value->unsigned_flag) + err+= add_int(fptr, list_value->value); + else + err+= add_uint(fptr, list_value->value); + } if (i != (no_items-1)) err+= add_comma(fptr); } while (++i < no_items); @@ -2073,9 +2181,12 @@ char *generate_partition_syntax(partition_info *part_info, if (part_info->linear_hash_ind) err+= add_string(fptr, partition_keywords[PKW_LINEAR].str); if (part_info->list_of_part_fields) - err+= add_key_partition(fptr, part_info->part_field_list); + { + err+= add_part_key_word(fptr, partition_keywords[PKW_KEY].str); + err+= add_part_field_list(fptr, part_info->part_field_list); + } else - err+= add_hash(fptr); + err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str); break; default: DBUG_ASSERT(0); @@ -2085,9 +2196,17 @@ char *generate_partition_syntax(partition_info *part_info, DBUG_RETURN(NULL); } if (part_info->part_expr) + { + err+= add_begin_parenthesis(fptr); err+= add_string_len(fptr, part_info->part_func_string, part_info->part_func_len); - err+= add_end_parenthesis(fptr); + err+= add_end_parenthesis(fptr); + } + else if (part_info->column_list) + { + err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); + err+= add_part_field_list(fptr, part_info->part_field_list); + } if ((!part_info->use_default_no_partitions) && part_info->use_default_partitions) { @@ -2103,13 +2222,19 @@ char *generate_partition_syntax(partition_info *part_info, if (part_info->linear_hash_ind) err+= add_string(fptr, partition_keywords[PKW_LINEAR].str); if (part_info->list_of_subpart_fields) - err+= add_key_partition(fptr, part_info->subpart_field_list); + { + add_part_key_word(fptr, partition_keywords[PKW_KEY].str); + add_part_field_list(fptr, part_info->subpart_field_list); + } else - err+= add_hash(fptr); + err+= add_part_key_word(fptr, partition_keywords[PKW_HASH].str); if (part_info->subpart_expr) + { + err+= add_begin_parenthesis(fptr); err+= add_string_len(fptr, part_info->subpart_func_string, part_info->subpart_func_len); - err+= add_end_parenthesis(fptr); + err+= add_end_parenthesis(fptr); + } if ((!part_info->use_default_no_subpartitions) && part_info->use_default_subpartitions) { @@ -2446,7 +2571,7 @@ static uint32 get_part_id_linear_key(partition_info *part_info, uint no_parts, longlong *func_value) { - DBUG_ENTER("get_partition_id_linear_key"); + DBUG_ENTER("get_part_id_linear_key"); *func_value= calculate_key_value(field_array); DBUG_RETURN(get_part_id_from_linear_hash(*func_value, @@ -2537,6 +2662,44 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr) return; } +/* + This function is used to calculate the partition id where all partition + fields have been prepared to point to a record where the partition field + values are bound. + + SYNOPSIS + get_partition_id() + part_info A reference to the partition_info struct where all the + desired information is given + out:part_id The partition id is returned through this pointer + out: func_value Value of partition function (longlong) + + RETURN VALUE + part_id Partition id of partition that would contain + row with given values of PF-fields + HA_ERR_NO_PARTITION_FOUND The fields of the partition function didn't + fit into any partition and thus the values of + the PF-fields are not allowed. + + DESCRIPTION + A routine used from write_row, update_row and delete_row from any + handler supporting partitioning. It is also a support routine for + get_partition_set used to find the set of partitions needed to scan + for a certain index scan or full table scan. + + It is actually 9 different variants of this function which are called + through a function pointer. + + get_partition_id_list + get_partition_id_list_col + get_partition_id_range + get_partition_id_range_col + get_partition_id_hash_nosub + get_partition_id_key_nosub + get_partition_id_linear_hash_nosub + get_partition_id_linear_key_nosub + get_partition_id_with_sub +*/ /* This function is used to calculate the main partition to use in the case of @@ -2558,67 +2721,26 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr) DESCRIPTION - It is actually 6 different variants of this function which are called + It is actually 8 different variants of this function which are called through a function pointer. get_partition_id_list + get_partition_id_list_col get_partition_id_range + get_partition_id_range_col get_partition_id_hash_nosub get_partition_id_key_nosub - get_partition_id_linear_hash_nosub + get_partition_id_linhash_nosub get_partition_id_linear_key_nosub */ -static int get_part_id_charset_func_subpart(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - int res; - copy_to_part_field_buffers(part_info->subpart_charset_field_array, - part_info->subpart_field_buffers, - part_info->restore_subpart_field_ptrs); - res= part_info->get_partition_id_charset(part_info, part_id, func_value); - restore_part_field_pointers(part_info->subpart_charset_field_array, - part_info->restore_subpart_field_ptrs); - return res; -} - - static int get_part_id_charset_func_part(partition_info *part_info, uint32 *part_id, longlong *func_value) { int res; - copy_to_part_field_buffers(part_info->part_charset_field_array, - part_info->part_field_buffers, - part_info->restore_part_field_ptrs); - res= part_info->get_partition_id_charset(part_info, part_id, func_value); - restore_part_field_pointers(part_info->part_charset_field_array, - part_info->restore_part_field_ptrs); - return res; -} + DBUG_ENTER("get_part_id_charset_func_part"); - -static int get_part_id_charset_func_all(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - int res; - copy_to_part_field_buffers(part_info->full_part_field_array, - part_info->full_part_field_buffers, - part_info->restore_full_part_field_ptrs); - res= part_info->get_partition_id_charset(part_info, part_id, func_value); - restore_part_field_pointers(part_info->full_part_field_array, - part_info->restore_full_part_field_ptrs); - return res; -} - - -static int get_part_part_id_charset_func(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - int res; copy_to_part_field_buffers(part_info->part_charset_field_array, part_info->part_field_buffers, part_info->restore_part_field_ptrs); @@ -2626,21 +2748,58 @@ static int get_part_part_id_charset_func(partition_info *part_info, part_id, func_value); restore_part_field_pointers(part_info->part_charset_field_array, part_info->restore_part_field_ptrs); - return res; + DBUG_RETURN(res); } -static int get_subpart_id_charset_func(partition_info *part_info, - uint32 *part_id) +static int get_part_id_charset_func_subpart(partition_info *part_info, + uint32 *part_id) { int res; + DBUG_ENTER("get_part_id_charset_func_subpart"); + copy_to_part_field_buffers(part_info->subpart_charset_field_array, part_info->subpart_field_buffers, part_info->restore_subpart_field_ptrs); res= part_info->get_subpartition_id_charset(part_info, part_id); restore_part_field_pointers(part_info->subpart_charset_field_array, part_info->restore_subpart_field_ptrs); - return res; + DBUG_RETURN(res); +} + +int get_partition_id_list_col(partition_info *part_info, + uint32 *part_id, + longlong *func_value) +{ + part_column_list_val *list_col_array= part_info->list_col_array; + uint no_columns= part_info->part_field_list.elements; + int list_index, cmp; + int min_list_index= 0; + int max_list_index= part_info->no_list_values - 1; + DBUG_ENTER("get_partition_id_list_col"); + + while (max_list_index >= min_list_index) + { + list_index= (max_list_index + min_list_index) >> 1; + cmp= cmp_rec_and_tuple(list_col_array + list_index*no_columns, + no_columns); + if (cmp > 0) + min_list_index= list_index + 1; + else if (cmp < 0) + { + if (!list_index) + goto notfound; + max_list_index= list_index - 1; + } + else + { + *part_id= (uint32)list_col_array[list_index].partition_id; + DBUG_RETURN(0); + } + } +notfound: + *part_id= 0; + DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); } @@ -2735,6 +2894,44 @@ notfound: The edge of corresponding sub-array of part_info->list_array */ +uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info, + bool left_endpoint, + bool include_endpoint, + uint32 nparts) +{ + part_column_list_val *list_col_array= part_info->list_col_array; + uint no_columns= part_info->part_field_list.elements; + int list_index, cmp; + uint min_list_index= 0; + uint max_list_index= part_info->no_list_values - 1; + bool tailf= !(left_endpoint ^ include_endpoint); + DBUG_ENTER("get_partition_id_cols_list_for_endpoint"); + + do + { + list_index= (max_list_index + min_list_index) >> 1; + cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*no_columns, + nparts, tailf); + if (cmp > 0) + min_list_index= list_index + 1; + else if (cmp < 0) + { + if (!list_index) + goto notfound; + max_list_index= list_index - 1; + } + else + { + DBUG_RETURN(list_index + test(left_endpoint ^ include_endpoint)); + } + } while (max_list_index >= min_list_index); +notfound: + if (cmp > 0) + list_index++; + DBUG_RETURN(list_index); +} + + uint32 get_list_array_idx_for_endpoint_charset(partition_info *part_info, bool left_endpoint, bool include_endpoint) @@ -2795,6 +2992,44 @@ notfound: } +int get_partition_id_range_col(partition_info *part_info, + uint32 *part_id, + longlong *func_value) +{ + part_column_list_val *range_col_array= part_info->range_col_array; + uint no_columns= part_info->part_field_list.elements; + uint max_partition= part_info->no_parts - 1; + uint min_part_id= 0; + uint max_part_id= max_partition; + uint loc_part_id; + DBUG_ENTER("get_partition_id_range_col"); + + while (max_part_id > min_part_id) + { + loc_part_id= (max_part_id + min_part_id + 1) >> 1; + if (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, + no_columns) >= 0) + 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) + if (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, + no_columns) >= 0) + loc_part_id++; + *part_id= (uint32)loc_part_id; + if (loc_part_id == max_partition && + (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, + no_columns) >= 0)) + DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); + + DBUG_PRINT("exit",("partition: %d", *part_id)); + DBUG_RETURN(0); + return 0; +} + + int get_partition_id_range(partition_info *part_info, uint32 *part_id, longlong *func_value) @@ -2995,8 +3230,8 @@ int get_partition_id_key_nosub(partition_info *part_info, int get_partition_id_linear_key_nosub(partition_info *part_info, - uint32 *part_id, - longlong *func_value) + uint32 *part_id, + longlong *func_value) { *part_id= get_part_id_linear_key(part_info, part_info->part_field_array, @@ -3005,215 +3240,27 @@ int get_partition_id_linear_key_nosub(partition_info *part_info, } -int get_partition_id_range_sub_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value) +int get_partition_id_with_sub(partition_info *part_info, + uint32 *part_id, + longlong *func_value) { uint32 loc_part_id, sub_part_id; uint no_subparts; - longlong local_func_value; int error; - DBUG_ENTER("get_partition_id_range_sub_hash"); - LINT_INIT(loc_part_id); - LINT_INIT(sub_part_id); + DBUG_ENTER("get_partition_id_with_sub"); - if (unlikely((error= get_partition_id_range(part_info, &loc_part_id, - func_value)))) + if (unlikely((error= part_info->get_part_partition_id(part_info, + &loc_part_id, + func_value)))) { DBUG_RETURN(error); } no_subparts= part_info->no_subparts; - if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr, - &sub_part_id, &local_func_value)))) + if (unlikely((error= part_info->get_subpartition_id(part_info, + &sub_part_id)))) { DBUG_RETURN(error); - } - - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_range_sub_linear_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_range_sub_linear_hash"); - LINT_INIT(loc_part_id); - LINT_INIT(sub_part_id); - - if (unlikely((error= get_partition_id_range(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts, - part_info->subpart_expr, - &sub_part_id, - &local_func_value)))) - { - DBUG_RETURN(error); - } - - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_range_sub_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_range_sub_key"); - LINT_INIT(loc_part_id); - - if (unlikely((error= get_partition_id_range(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - sub_part_id= get_part_id_key(part_info->subpart_field_array, - no_subparts, &local_func_value); - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_range_sub_linear_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_range_sub_linear_key"); - LINT_INIT(loc_part_id); - - if (unlikely((error= get_partition_id_range(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - sub_part_id= get_part_id_linear_key(part_info, - part_info->subpart_field_array, - no_subparts, &local_func_value); - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_list_sub_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_list_sub_hash"); - LINT_INIT(sub_part_id); - - if (unlikely((error= get_partition_id_list(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - if (unlikely((error= get_part_id_hash(no_subparts, part_info->subpart_expr, - &sub_part_id, &local_func_value)))) - { - DBUG_RETURN(error); - } - - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_list_sub_linear_hash(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_list_sub_linear_hash"); - LINT_INIT(sub_part_id); - - if (unlikely((error= get_partition_id_list(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - if (unlikely((error= get_part_id_linear_hash(part_info, no_subparts, - part_info->subpart_expr, - &sub_part_id, - &local_func_value)))) - { - DBUG_RETURN(error); - } - - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_list_sub_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_range_sub_key"); - - if (unlikely((error= get_partition_id_list(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - sub_part_id= get_part_id_key(part_info->subpart_field_array, - no_subparts, &local_func_value); - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); - DBUG_RETURN(0); -} - - -int get_partition_id_list_sub_linear_key(partition_info *part_info, - uint32 *part_id, - longlong *func_value) -{ - uint32 loc_part_id, sub_part_id; - uint no_subparts; - longlong local_func_value; - int error; - DBUG_ENTER("get_partition_id_list_sub_linear_key"); - - if (unlikely((error= get_partition_id_list(part_info, &loc_part_id, - func_value)))) - { - DBUG_RETURN(error); - } - no_subparts= part_info->no_subparts; - sub_part_id= get_part_id_linear_key(part_info, - part_info->subpart_field_array, - no_subparts, &local_func_value); + } *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); DBUG_RETURN(0); } @@ -4226,6 +4273,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, partition_info *tab_part_info= table->part_info; partition_info *alt_part_info= thd->work_part_info; uint flags= 0; + bool is_last_partition_reorged; + part_elem_value *tab_max_elem_val= NULL; + part_elem_value *alt_max_elem_val= NULL; + longlong tab_max_range= 0, alt_max_range= 0; + if (!tab_part_info) { my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); @@ -4280,34 +4332,43 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, ((flags & (HA_FAST_CHANGE_PARTITION | HA_PARTITION_ONE_PHASE)) != 0); DBUG_PRINT("info", ("*fast_alter_partition: %d flags: 0x%x", *fast_alter_partition, flags)); - if (((alter_info->flags & ALTER_ADD_PARTITION) || - (alter_info->flags & ALTER_REORGANIZE_PARTITION)) && - (thd->work_part_info->part_type != tab_part_info->part_type) && - (thd->work_part_info->part_type != NOT_A_PARTITION)) + if ((alter_info->flags & ALTER_ADD_PARTITION) || + (alter_info->flags & ALTER_REORGANIZE_PARTITION)) { - if (thd->work_part_info->part_type == RANGE_PARTITION) + if ((tab_part_info->column_list && + alt_part_info->num_columns != tab_part_info->num_columns) || + (!tab_part_info->column_list && alt_part_info->num_columns)) { - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); } - else if (thd->work_part_info->part_type == LIST_PARTITION) + if ((thd->work_part_info->part_type != tab_part_info->part_type) && + (thd->work_part_info->part_type != NOT_A_PARTITION)) { - DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION); - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "LIST", "IN"); + if (thd->work_part_info->part_type == RANGE_PARTITION) + { + my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN"); + } + else if (thd->work_part_info->part_type == LIST_PARTITION) + { + DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION); + my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "LIST", "IN"); + } + else if (tab_part_info->part_type == RANGE_PARTITION) + { + my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN"); + } + else + { + DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION); + my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), + "LIST", "IN"); + } + DBUG_RETURN(TRUE); } - else if (tab_part_info->part_type == RANGE_PARTITION) - { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); - } - else - { - DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION); - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "LIST", "IN"); - } - DBUG_RETURN(TRUE); } if (alter_info->flags & ALTER_ADD_PARTITION) { @@ -4747,7 +4808,6 @@ state of p1. */ uint no_parts_reorged= alter_info->partition_names.elements; uint no_parts_new= thd->work_part_info->partitions.elements; - partition_info *alt_part_info= thd->work_part_info; uint check_total_partitions; tab_part_info->is_auto_partitioned= FALSE; @@ -4827,9 +4887,7 @@ the generated partition syntax in a correct manner. uint part_count= 0; bool found_first= FALSE; bool found_last= FALSE; - bool is_last_partition_reorged; uint drop_count= 0; - longlong tab_max_range= 0, alt_max_range= 0; do { partition_element *part_elem= tab_it++; @@ -4839,7 +4897,13 @@ the generated partition syntax in a correct manner. { is_last_partition_reorged= TRUE; drop_count++; - tab_max_range= part_elem->range_value; + if (tab_part_info->column_list) + { + List_iterator p(part_elem->list_val_list); + tab_max_elem_val= p++; + } + else + tab_max_range= part_elem->range_value; if (*fast_alter_partition && tab_part_info->temp_partitions.push_back(part_elem)) { @@ -4851,13 +4915,21 @@ the generated partition syntax in a correct manner. if (!found_first) { uint alt_part_count= 0; - found_first= TRUE; + partition_element *alt_part_elem; List_iterator alt_it(alt_part_info->partitions); + found_first= TRUE; do { - partition_element *alt_part_elem= alt_it++; - alt_max_range= alt_part_elem->range_value; + alt_part_elem= alt_it++; + if (tab_part_info->column_list) + { + List_iterator p(alt_part_elem->list_val_list); + alt_max_elem_val= p++; + } + else + alt_max_range= alt_part_elem->range_value; + if (*fast_alter_partition) alt_part_elem->part_state= PART_TO_BE_ADDED; if (alt_part_count == 0) @@ -4885,25 +4957,6 @@ the generated partition syntax in a correct manner. my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE"); DBUG_RETURN(TRUE); } - if (tab_part_info->part_type == RANGE_PARTITION && - ((is_last_partition_reorged && - alt_max_range < tab_max_range) || - (!is_last_partition_reorged && - alt_max_range != tab_max_range))) - { - /* - For range partitioning the total resulting range before and - after the change must be the same except in one case. This is - when the last partition is reorganised, in this case it is - acceptable to increase the total range. - The reason is that it is not allowed to have "holes" in the - middle of the ranges and thus we should not allow to reorganise - to create "holes". Also we should not allow using REORGANIZE - to drop data. - */ - my_error(ER_REORG_OUTSIDE_RANGE, MYF(0)); - DBUG_RETURN(TRUE); - } tab_part_info->no_parts= check_total_partitions; } } @@ -4923,10 +4976,42 @@ the generated partition syntax in a correct manner. tab_part_info->use_default_no_subpartitions= FALSE; } if (tab_part_info->check_partition_info(thd, (handlerton**)NULL, - table->file, ULL(0), FALSE)) + table->file, ULL(0), TRUE)) { DBUG_RETURN(TRUE); } + /* + The check below needs to be performed after check_partition_info + since this function "fixes" the item trees of the new partitions + to reorganize into + */ + if (alter_info->flags == ALTER_REORGANIZE_PARTITION && + tab_part_info->part_type == RANGE_PARTITION && + ((is_last_partition_reorged && + (tab_part_info->column_list ? + (tab_part_info->compare_column_values( + alt_max_elem_val->col_val_array, + tab_max_elem_val->col_val_array) < 0) : + alt_max_range < tab_max_range)) || + (!is_last_partition_reorged && + (tab_part_info->column_list ? + (tab_part_info->compare_column_values( + alt_max_elem_val->col_val_array, + tab_max_elem_val->col_val_array) != 0) : + alt_max_range != tab_max_range)))) + { + /* + For range partitioning the total resulting range before and + after the change must be the same except in one case. This is + when the last partition is reorganised, in this case it is + acceptable to increase the total range. + The reason is that it is not allowed to have "holes" in the + middle of the ranges and thus we should not allow to reorganise + to create "holes". + */ + my_error(ER_REORG_OUTSIDE_RANGE, MYF(0)); + DBUG_RETURN(TRUE); + } } } else @@ -6565,16 +6650,19 @@ void make_used_partitions_str(partition_info *part_info, String *parts_str) IMPLEMENTATION There are two available interval analyzer functions: (1) get_part_iter_for_interval_via_mapping - (2) get_part_iter_for_interval_via_walking + (2) get_part_iter_for_interval_cols_via_map + (3) get_part_iter_for_interval_via_walking They both have limited applicability: (1) is applicable for "PARTITION BY (func(t.field))", where func is a monotonic function. - - (2) is applicable for + + (2) is applicable for "PARTITION BY COLUMN_LIST (field_list) + + (3) is applicable for "[SUB]PARTITION BY (any_func(t.integer_field))" - If both are applicable, (1) is preferred over (2). + If both (1) and (3) are applicable, (1) is preferred over (3). This function sets part_info::get_part_iter_for_interval according to this criteria, and also sets some auxilary fields that the function @@ -6594,10 +6682,19 @@ static void set_up_range_analysis_info(partition_info *part_info) switch (part_info->part_type) { case RANGE_PARTITION: case LIST_PARTITION: - if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC) + if (!part_info->column_list) + { + if (part_info->part_expr->get_monotonicity_info() != NON_MONOTONIC) + { + part_info->get_part_iter_for_interval= + get_part_iter_for_interval_via_mapping; + goto setup_subparts; + } + } + else { part_info->get_part_iter_for_interval= - get_part_iter_for_interval_via_mapping; + get_part_iter_for_interval_cols_via_map; goto setup_subparts; } default: @@ -6648,9 +6745,104 @@ setup_subparts: } +/* TODO Commenting those functions */ +uint32 store_tuple_to_record(Field **pfield, + uint32 *store_length_array, + uchar *value, + uchar *value_end) +{ + // see store_key_image_to_rec + uint32 nparts= 0; + uchar *loc_value; + while (value < value_end) + { + loc_value= value; + if ((*pfield)->real_maybe_null()) + { + if (*loc_value) + { + (*pfield)->set_null(); + } + (*pfield)->set_notnull(); + loc_value++; + } + uint len= (*pfield)->pack_length(); + (*pfield)->set_key_image(loc_value, len); + value+= *store_length_array; + store_length_array++; + nparts++; + pfield++; + } + return nparts; +} + +/* + RANGE(columns) partitioning: compare value bound and probe tuple. + + The value bound always is a full tuple (but may include MIN_VALUE and + MAX_VALUE special values). + + The probe tuple may be a prefix of partitioning tuple. The tail_is_min + parameter specifies whether the suffix components should be assumed to + hold MIN_VALUE or MAX_VALUE +*/ + +static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec) +{ + partition_info *part_info= val->part_info; + Field **field= part_info->part_field_array; + Field **fields_end= field + nvals_in_rec; + int res; + + for (; field != fields_end; field++, val++) + { + if (val->max_value) + return -1; + if ((*field)->is_null()) + { + if (val->null_value) + continue; + return -1; + } + if (val->null_value) + return +1; + res= (*field)->cmp((const uchar*)val->column_value); + if (res) + return res; + } + return 0; +} + + +static int cmp_rec_and_tuple_prune(part_column_list_val *val, + uint32 n_vals_in_rec, + bool tail_is_min) +{ + int cmp; + Field **field; + partition_info *part_info; + if ((cmp= cmp_rec_and_tuple(val, n_vals_in_rec))) + return cmp; + part_info= val->part_info; + field= part_info->part_field_array + n_vals_in_rec; + for (; *field; field++, val++) + { + if (tail_is_min) + return -1; + if (!tail_is_min && !val->max_value) + return +1; + } + return 0; +} + + typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint, bool include_endpoint); +typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint, + bool include_endpoint, + uint32 no_parts); + /* Partitioning Interval Analysis: Initialize the iterator for "mapping" case @@ -6686,17 +6878,132 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint, -1 - All partitions would match (iterator not initialized) */ +uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, + bool left_endpoint, + bool include_endpoint, + uint32 nparts) +{ + uint max_partition= part_info->no_parts - 1; + uint min_part_id= 0, max_part_id= max_partition, loc_part_id; + part_column_list_val *range_col_array= part_info->range_col_array; + uint no_columns= part_info->part_field_list.elements; + bool tailf= !(left_endpoint ^ include_endpoint); + DBUG_ENTER("get_partition_id_cols_range_for_endpoint"); + + /* Get the partitioning function value for the endpoint */ + while (max_part_id > min_part_id) + { + loc_part_id= (max_part_id + min_part_id + 1) >> 1; + if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*no_columns, + nparts, tailf) >= 0) + 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 && + cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*no_columns, + nparts, tailf) >= 0 + ) + { + loc_part_id++; + } + if (left_endpoint) + { + if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*no_columns, + nparts, tailf) >= 0) + loc_part_id++; + } + else + { + if (loc_part_id < max_partition) + { + int res= cmp_rec_and_tuple_prune(range_col_array + + loc_part_id * no_columns, + nparts, tailf); + if (!res) + loc_part_id += test(include_endpoint); + else if (res > 0) + loc_part_id++; + } + loc_part_id++; + } + DBUG_RETURN(loc_part_id); +} + + +int get_part_iter_for_interval_cols_via_map(partition_info *part_info, + bool is_subpart, + uint32 *store_length_array, + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, + uint flags, + PARTITION_ITERATOR *part_iter) +{ + uint32 nparts; + get_col_endpoint_func get_col_endpoint; + DBUG_ENTER("get_part_iter_for_interval_cols_via_map"); + + if (part_info->part_type == RANGE_PARTITION) + { + get_col_endpoint= get_partition_id_cols_range_for_endpoint; + part_iter->get_next= get_next_partition_id_range; + } + else + { + get_col_endpoint= get_partition_id_cols_list_for_endpoint; + part_iter->get_next= get_next_partition_id_list; + part_iter->part_info= part_info; + } + if (flags & NO_MIN_RANGE) + part_iter->part_nums.start= part_iter->part_nums.cur= 0; + else + { + // Copy from min_value to record + nparts= store_tuple_to_record(part_info->part_field_array, + store_length_array, + min_value, + min_value + min_len); + part_iter->part_nums.start= part_iter->part_nums.cur= + get_col_endpoint(part_info, TRUE, !(flags & NEAR_MIN), + nparts); + } + if (flags & NO_MAX_RANGE) + part_iter->part_nums.end= part_info->no_parts; + else + { + // Copy from max_value to record + nparts= store_tuple_to_record(part_info->part_field_array, + store_length_array, + max_value, + max_value + max_len); + part_iter->part_nums.end= get_col_endpoint(part_info, FALSE, + !(flags & NEAR_MAX), + nparts); + } + if (part_iter->part_nums.start == part_iter->part_nums.end) + DBUG_RETURN(0); + DBUG_RETURN(1); +} + + int get_part_iter_for_interval_via_mapping(partition_info *part_info, bool is_subpart, + uint32 *store_length_array, /* ignored */ uchar *min_value, uchar *max_value, + uint min_len, uint max_len, /* ignored */ uint flags, PARTITION_ITERATOR *part_iter) { - DBUG_ASSERT(!is_subpart); Field *field= part_info->part_field_array[0]; uint32 max_endpoint_val; get_endpoint_func get_endpoint; uint field_len= field->pack_length_in_rec(); + DBUG_ENTER("get_part_iter_for_interval_via_mapping"); + DBUG_ASSERT(!is_subpart); + (void) store_length_array; + (void)min_len; + (void)max_len; part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; if (part_info->part_type == RANGE_PARTITION) @@ -6728,7 +7035,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, part_iter->part_nums.start= part_iter->part_nums.end= 0; part_iter->part_nums.cur= 0; part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE; - return -1; + DBUG_RETURN(-1); } } else @@ -6747,7 +7054,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, { /* The right bound is X <= NULL, i.e. it is a "X IS NULL" interval */ part_iter->part_nums.end= 0; - return 1; + DBUG_RETURN(1); } } else @@ -6767,7 +7074,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp); part_iter->part_nums.cur= part_iter->part_nums.start; if (part_iter->part_nums.start == max_endpoint_val) - return 0; /* No partitions */ + DBUG_RETURN(0); /* No partitions */ } } @@ -6781,9 +7088,9 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, part_iter->part_nums.end= get_endpoint(part_info, 0, include_endp); if (part_iter->part_nums.start >= part_iter->part_nums.end && !part_iter->ret_null_part) - return 0; /* No partitions */ + DBUG_RETURN(0); /* No partitions */ } - return 1; /* Ok, iterator initialized */ + DBUG_RETURN(1); /* Ok, iterator initialized */ } @@ -6841,14 +7148,21 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, */ int get_part_iter_for_interval_via_walking(partition_info *part_info, - bool is_subpart, - uchar *min_value, uchar *max_value, - uint flags, - PARTITION_ITERATOR *part_iter) + bool is_subpart, + uint32 *store_length_array, /* ignored */ + uchar *min_value, uchar *max_value, + uint min_len, uint max_len, /* ignored */ + uint flags, + PARTITION_ITERATOR *part_iter) { Field *field; uint total_parts; partition_iter_func get_next_func; + DBUG_ENTER("get_part_iter_for_interval_via_walking"); + (void)store_length_array; + (void)min_len; + (void)max_len; + if (is_subpart) { field= part_info->subpart_field_array[0]; @@ -6878,7 +7192,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, if (!part_info->get_subpartition_id(part_info, &part_id)) { init_single_partition_iterator(part_id, part_iter); - return 1; /* Ok, iterator initialized */ + DBUG_RETURN(1); /* Ok, iterator initialized */ } } else @@ -6891,10 +7205,10 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, if (!res) { init_single_partition_iterator(part_id, part_iter); - return 1; /* Ok, iterator initialized */ + DBUG_RETURN(1); /* Ok, iterator initialized */ } } - return 0; /* No partitions match */ + DBUG_RETURN(0); /* No partitions match */ } if ((field->real_maybe_null() && @@ -6902,7 +7216,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, (!(flags & NO_MAX_RANGE) && *max_value))) || // X total_parts || n_values > MAX_RANGE_TO_WALK) - return -1; + DBUG_RETURN(-1); part_iter->field_vals.start= part_iter->field_vals.cur= a; part_iter->field_vals.end= b; part_iter->part_info= part_info; part_iter->get_next= get_next_func; - return 1; + DBUG_RETURN(1); } @@ -6976,8 +7290,9 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) DESCRIPTION This implementation of PARTITION_ITERATOR::get_next() is special for - LIST partitioning: it enumerates partition ids in - part_info->list_array[i] where i runs over [min_idx, max_idx] interval. + LIST partitioning: it enumerates partition ids in + part_info->list_array[i] (list_col_array[i] for COLUMN_LIST LIST + partitioning) where i runs over [min_idx, max_idx] interval. The function conforms to partition_iter_func type. RETURN @@ -6999,8 +7314,13 @@ uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) return NOT_A_PARTITION_ID; } else - return part_iter->part_info->list_array[part_iter-> - part_nums.cur++].partition_id; + { + partition_info *part_info= part_iter->part_info; + uint32 num_part= part_iter->part_nums.cur++; + return part_info->column_list ? + part_info->list_col_array[num_part].partition_id : + part_info->list_array[num_part].partition_id; + } } diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 282e24f1853..7902cc77877 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -173,9 +173,12 @@ typedef struct st_partition_iter SYNOPSIS get_partitions_in_range_iter() part_info Partitioning info - is_subpart + is_subpart + store_length_array Length of fields packed in opt_range_key format min_val Left edge, field value in opt_range_key format. - max_val Right edge, field value in opt_range_key format. + max_val Right edge, field value in opt_range_key format. + min_len Length of minimum value + max_len Length of maximum value flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE, NO_MAX_RANGE. part_iter Iterator structure to be initialized @@ -191,8 +194,9 @@ typedef struct st_partition_iter The set of partitions is returned by initializing an iterator in *part_iter NOTES - There are currently two functions of this type: + There are currently three functions of this type: - get_part_iter_for_interval_via_walking + - get_part_iter_for_interval_cols_via_map - get_part_iter_for_interval_via_mapping RETURN @@ -203,7 +207,9 @@ typedef struct st_partition_iter typedef int (*get_partitions_in_range_iter)(partition_info *part_info, bool is_subpart, + uint32 *store_length_array, uchar *min_val, uchar *max_val, + uint min_len, uint max_len, uint flags, PARTITION_ITERATOR *part_iter); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 5c2c351652b..3aef62dfb31 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4869,12 +4869,18 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, /* Partition method*/ switch (part_info->part_type) { case RANGE_PARTITION: - table->field[7]->store(partition_keywords[PKW_RANGE].str, - partition_keywords[PKW_RANGE].length, cs); - break; case LIST_PARTITION: - table->field[7]->store(partition_keywords[PKW_LIST].str, - partition_keywords[PKW_LIST].length, cs); + tmp_res.length(0); + if (part_info->part_type == RANGE_PARTITION) + tmp_res.append(partition_keywords[PKW_RANGE].str, + partition_keywords[PKW_RANGE].length); + else + tmp_res.append(partition_keywords[PKW_LIST].str, + partition_keywords[PKW_LIST].length); + if (part_info->column_list) + tmp_res.append(partition_keywords[PKW_COLUMNS].str, + partition_keywords[PKW_COLUMNS].length); + table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs); break; case HASH_PARTITION: tmp_res.length(0); @@ -6484,7 +6490,7 @@ ST_FIELD_INFO partitions_fields_info[]= (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE}, {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE}, - {"PARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, + {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE}, {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 81d00f46000..fce51c7e3da 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3664,7 +3664,7 @@ bool mysql_create_table_no_lock(THD *thd, ha_resolve_storage_engine_name(part_info->default_engine_type), ha_resolve_storage_engine_name(create_info->db_type))); if (part_info->check_partition_info(thd, &engine_type, file, - create_info, TRUE)) + create_info, FALSE)) goto err; part_info->default_engine_type= engine_type; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4ed9946a334..0e0e3ec6bd3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -515,10 +515,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 169 shift/reduce conflicts. + Currently there are 168 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 169 +%expect 168 /* Comments for TOKENS. @@ -603,6 +603,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token COLLATE_SYM /* SQL-2003-R */ %token COLLATION_SYM /* SQL-2003-N */ %token COLUMNS +%token COLUMN_LIST_SYM %token COLUMN_SYM /* SQL-2003-R */ %token COMMENT_SYM %token COMMITTED_SYM /* SQL-2003-N */ @@ -1156,6 +1157,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_natural_language_mode opt_query_expansion opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt + opt_global %type ulong_num real_ulong_num merge_insert_types @@ -1298,6 +1300,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail install uninstall partition_entry binlog_base64_event init_key_options key_options key_opts key_opt key_using_alg + part_column_list part_column_expr_list part_column_expr_item + part_column_list_value server_def server_options_list server_option definer_opt no_definer definer END_OF_INPUT @@ -1691,12 +1695,12 @@ create: $5->table.str); } } - | CREATE opt_unique_or_fulltext INDEX_SYM ident key_alg ON + | CREATE opt_global opt_unique_or_fulltext INDEX_SYM ident key_alg ON table_ident { LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_INDEX; - if (!lex->current_select->add_table_to_list(lex->thd, $7, + if (!lex->current_select->add_table_to_list(lex->thd, $8, NULL, TL_OPTION_UPDATING)) MYSQL_YYABORT; @@ -1704,6 +1708,7 @@ create: lex->alter_info.flags= ALTER_ADD_INDEX; lex->col_list.empty(); lex->change=NullS; + lex->global_flag= $2; } '(' key_list ')' key_options { @@ -1714,13 +1719,22 @@ create: my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } - key= new Key($2, $4.str, &lex->key_create_info, 0, + key= new Key($3, $5.str, &lex->key_create_info, 0, lex->col_list); if (key == NULL) MYSQL_YYABORT; lex->alter_info.key_list.push_back(key); lex->col_list.empty(); } + opt_partitioning + { + LEX *lex= Lex; + if (!lex->global_flag && lex->part_info) + { + my_error(ER_GLOBAL_PARTITION_INDEX_ERROR, MYF(0)); + YYABORT; + } + } | CREATE DATABASE opt_if_not_exists ident { Lex->create_info.default_table_charset= NULL; @@ -3802,19 +3816,21 @@ partition: part_type_def: opt_linear KEY_SYM '(' part_field_list ')' { - LEX *lex= Lex; - lex->part_info->list_of_part_fields= TRUE; - lex->part_info->part_type= HASH_PARTITION; + partition_info *part_info= Lex->part_info; + part_info->list_of_part_fields= TRUE; + part_info->part_type= HASH_PARTITION; } | opt_linear HASH_SYM { Lex->part_info->part_type= HASH_PARTITION; } part_func {} - | RANGE_SYM + | RANGE_SYM part_func { Lex->part_info->part_type= RANGE_PARTITION; } - part_func {} - | LIST_SYM + | RANGE_SYM part_column_list + { Lex->part_info->part_type= RANGE_PARTITION; } + | LIST_SYM part_func + { Lex->part_info->part_type= LIST_PARTITION; } + | LIST_SYM part_column_list { Lex->part_info->part_type= LIST_PARTITION; } - part_func {} ; opt_linear: @@ -3836,41 +3852,45 @@ part_field_item_list: part_field_item: ident { - if (Lex->part_info->part_field_list.push_back($1.str)) + partition_info *part_info= Lex->part_info; + part_info->num_columns++; + if (part_info->part_field_list.push_back($1.str)) { mem_alloc_error(1); MYSQL_YYABORT; } + if (part_info->num_columns > MAX_REF_PARTS) + { + my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of partition fields"); + MYSQL_YYABORT; + } } ; +part_column_list: + COLUMN_LIST_SYM '(' part_field_list ')' + { + partition_info *part_info= Lex->part_info; + part_info->column_list= TRUE; + part_info->list_of_part_fields= TRUE; + } + ; + + part_func: '(' remember_name part_func_expr remember_end ')' { - LEX *lex= Lex; - uint expr_len= (uint)($4 - $2) - 1; - lex->part_info->list_of_part_fields= FALSE; - lex->part_info->part_expr= $3; - char *func_string= (char*) sql_memdup($2+1, expr_len); - if (func_string == NULL) - MYSQL_YYABORT; - lex->part_info->part_func_string= func_string; - lex->part_info->part_func_len= expr_len; + if (Lex->part_info->set_part_expr($2+1, $3, $4, FALSE)) + { MYSQL_YYABORT; } } ; sub_part_func: '(' remember_name part_func_expr remember_end ')' { - LEX *lex= Lex; - uint expr_len= (uint)($4 - $2) - 1; - lex->part_info->list_of_subpart_fields= FALSE; - lex->part_info->subpart_expr= $3; - char *func_string= (char*) sql_memdup($2+1, expr_len); - if (func_string == NULL) - MYSQL_YYABORT; - lex->part_info->subpart_func_string= func_string; - lex->part_info->subpart_func_len= expr_len; + if (Lex->part_info->set_part_expr($2+1, $3, $4, TRUE)) + { MYSQL_YYABORT; } } ; @@ -3880,15 +3900,15 @@ opt_no_parts: | PARTITIONS_SYM real_ulong_num { uint no_parts= $2; - LEX *lex= Lex; + partition_info *part_info= Lex->part_info; if (no_parts == 0) { my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions"); MYSQL_YYABORT; } - lex->part_info->no_parts= no_parts; - lex->part_info->use_default_no_partitions= FALSE; + part_info->no_parts= no_parts; + part_info->use_default_no_partitions= FALSE; } ; @@ -3900,9 +3920,9 @@ opt_sub_part: | SUBPARTITION_SYM BY opt_linear KEY_SYM '(' sub_part_field_list ')' { - LEX *lex= Lex; - lex->part_info->subpart_type= HASH_PARTITION; - lex->part_info->list_of_subpart_fields= TRUE; + partition_info *part_info= Lex->part_info; + part_info->subpart_type= HASH_PARTITION; + part_info->list_of_subpart_fields= TRUE; } opt_no_subparts {} ; @@ -3915,11 +3935,18 @@ sub_part_field_list: sub_part_field_item: ident { - if (Lex->part_info->subpart_field_list.push_back($1.str)) + partition_info *part_info= Lex->part_info; + if (part_info->subpart_field_list.push_back($1.str)) { mem_alloc_error(1); MYSQL_YYABORT; } + if (part_info->subpart_field_list.elements > MAX_REF_PARTS) + { + my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), + "list of subpartition fields"); + MYSQL_YYABORT; + } } ; @@ -3960,8 +3987,7 @@ part_defs: {} | '(' part_def_list ')' { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; uint count_curr_parts= part_info->partitions.elements; if (part_info->no_parts != 0) { @@ -3988,8 +4014,7 @@ part_def_list: part_definition: PARTITION_SYM { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; partition_element *p_elem= new partition_element(); if (!p_elem || part_info->partitions.push_back(p_elem)) @@ -4013,8 +4038,7 @@ part_definition: part_name: ident { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; partition_element *p_elem= part_info->curr_part_elem; p_elem->partition_name= $1.str; } @@ -4024,15 +4048,16 @@ opt_part_values: /* empty */ { LEX *lex= Lex; + partition_info *part_info= lex->part_info; if (! lex->is_partition_management()) { - if (lex->part_info->part_type == RANGE_PARTITION) + if (part_info->part_type == RANGE_PARTITION) { my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN"); MYSQL_YYABORT; } - if (lex->part_info->part_type == LIST_PARTITION) + if (part_info->part_type == LIST_PARTITION) { my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), "LIST", "IN"); @@ -4040,14 +4065,15 @@ opt_part_values: } } else - lex->part_info->part_type= HASH_PARTITION; + part_info->part_type= HASH_PARTITION; } | VALUES LESS_SYM THAN_SYM part_func_max { LEX *lex= Lex; + partition_info *part_info= lex->part_info; if (! lex->is_partition_management()) { - if (Lex->part_info->part_type != RANGE_PARTITION) + if (part_info->part_type != RANGE_PARTITION) { my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "RANGE", "LESS THAN"); @@ -4055,14 +4081,15 @@ opt_part_values: } } else - lex->part_info->part_type= RANGE_PARTITION; + part_info->part_type= RANGE_PARTITION; } | VALUES IN_SYM '(' part_list_func ')' { LEX *lex= Lex; + partition_info *part_info= lex->part_info; if (! lex->is_partition_management()) { - if (Lex->part_info->part_type != LIST_PARTITION) + if (part_info->part_type != LIST_PARTITION) { my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), "LIST", "IN"); @@ -4070,36 +4097,139 @@ opt_part_values: } } else - lex->part_info->part_type= LIST_PARTITION; + part_info->part_type= LIST_PARTITION; + } + ; + +part_column_expr_list: + part_column_expr_item {} + | part_column_expr_list ',' part_column_expr_item {} + ; + +part_column_expr_item: + MAX_VALUE_SYM + { + partition_info *part_info= Lex->part_info; + part_column_list_val *col_val; + if (part_info->part_type == LIST_PARTITION) + { + my_parse_error(ER(ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR)); + MYSQL_YYABORT; + } + if (!(col_val= part_info->add_column_value())) + { + MYSQL_YYABORT; + } + col_val->max_value= TRUE; + } + | bit_expr + { + part_column_list_val *col_val; + LEX *lex= Lex; + if (!lex->safe_to_cache_query) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + MYSQL_YYABORT; + } + if (!(col_val= lex->part_info->add_column_value())) + { + MYSQL_YYABORT; + } + col_val->item_expression= $1; + col_val->part_info= NULL; + } + ; + +part_column_list_value: + COLUMN_LIST_SYM + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + uint num_columns; + partition_element *p_elem= part_info->curr_part_elem; + part_column_list_val *col_val_array; + part_elem_value *list_val; + + if (!part_info->column_list && + !lex->is_partition_management()) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + MYSQL_YYABORT; + } + if (!(list_val= + (part_elem_value*)sql_calloc(sizeof(part_elem_value))) || + p_elem->list_val_list.push_back(list_val)) + { + mem_alloc_error(sizeof(part_elem_value)); + MYSQL_YYABORT; + } + if (part_info->num_columns) + num_columns= part_info->num_columns; + else + num_columns= MAX_REF_PARTS; + if (!(col_val_array= + (part_column_list_val*)sql_calloc(num_columns * + sizeof(part_column_list_val)))) + { + mem_alloc_error(num_columns * sizeof(part_elem_value)); + MYSQL_YYABORT; + } + list_val->col_val_array= col_val_array; + part_info->curr_list_val= list_val; + part_info->curr_list_object= 0; + } + '(' part_column_expr_list ')' + { + partition_info *part_info= Lex->part_info; + uint num_columns= part_info->num_columns; + if (num_columns && num_columns != part_info->curr_list_object) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + MYSQL_YYABORT; + } + part_info->num_columns= part_info->curr_list_object; } ; part_func_max: max_value_sym { - LEX *lex= Lex; - if (lex->part_info->defined_max_value) + partition_info *part_info= Lex->part_info; + if (part_info->defined_max_value) { my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR)); MYSQL_YYABORT; } - lex->part_info->defined_max_value= TRUE; - lex->part_info->curr_part_elem->max_value= TRUE; - lex->part_info->curr_part_elem->range_value= LONGLONG_MAX; + if (part_info->column_list) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } + part_info->defined_max_value= TRUE; + part_info->curr_part_elem->max_value= TRUE; + part_info->curr_part_elem->range_value= LONGLONG_MAX; } | part_range_func { - if (Lex->part_info->defined_max_value) + partition_info *part_info= Lex->part_info; + if (part_info->defined_max_value) { my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR)); MYSQL_YYABORT; } - if (Lex->part_info->curr_part_elem->has_null_value) + if (part_info->curr_part_elem->has_null_value) { my_parse_error(ER(ER_NULL_IN_VALUES_LESS_THAN)); MYSQL_YYABORT; } + if (part_info->column_list) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } } + | '(' part_column_list_value ')' + {} ; max_value_sym: @@ -4136,7 +4266,13 @@ part_list_item: mem_alloc_error(sizeof(part_elem_value)); MYSQL_YYABORT; } + if (part_info->column_list) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } } + | part_column_list_value ; part_bit_expr: @@ -4145,6 +4281,7 @@ part_bit_expr: Item *part_expr= $1; THD *thd= YYTHD; LEX *lex= thd->lex; + partition_info *part_info= lex->part_info; Name_resolution_context *context= &lex->current_select->context; TABLE_LIST *save_list= context->table_list; const char *save_where= thd->where; @@ -4181,12 +4318,12 @@ part_bit_expr: value_ptr->unsigned_flag= FALSE; if ((value_ptr->null_value= part_expr->null_value)) { - if (Lex->part_info->curr_part_elem->has_null_value) + if (part_info->curr_part_elem->has_null_value) { my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); MYSQL_YYABORT; } - Lex->part_info->curr_part_elem->has_null_value= TRUE; + part_info->curr_part_elem->has_null_value= TRUE; } else if (part_expr->result_type() != INT_RESULT) { @@ -4200,8 +4337,9 @@ part_bit_expr: opt_sub_partition: /* empty */ { - if (Lex->part_info->no_subparts != 0 && - !Lex->part_info->use_default_subpartitions) + partition_info *part_info= Lex->part_info; + if (part_info->no_subparts != 0 && + !part_info->use_default_subpartitions) { /* We come here when we have defined subpartitions on the first @@ -4213,8 +4351,7 @@ opt_sub_partition: } | '(' sub_part_list ')' { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; if (part_info->no_subparts != 0) { if (part_info->no_subparts != @@ -4245,8 +4382,7 @@ sub_part_list: sub_part_definition: SUBPARTITION_SYM { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; + partition_info *part_info= Lex->part_info; partition_element *curr_part= part_info->current_partition; partition_element *sub_p_elem= new partition_element(curr_part); if (part_info->use_default_subpartitions && @@ -4300,9 +4436,9 @@ opt_part_option: { Lex->part_info->curr_part_elem->tablespace_name= $3.str; } | opt_storage ENGINE_SYM opt_equal storage_engines { - LEX *lex= Lex; - lex->part_info->curr_part_elem->engine_type= $4; - lex->part_info->default_engine_type= $4; + partition_info *part_info= Lex->part_info; + part_info->curr_part_elem->engine_type= $4; + part_info->default_engine_type= $4; } | NODEGROUP_SYM opt_equal real_ulong_num { Lex->part_info->curr_part_elem->nodegroup_id= (uint16) $3; } @@ -4318,6 +4454,11 @@ opt_part_option: { Lex->part_info->curr_part_elem->part_comment= $3.str; } ; +opt_global: + /* empty */ { $$= FALSE;} + | GLOBAL_SYM { $$= TRUE; } + ; + /* End of partition parser part */ @@ -5786,8 +5927,8 @@ reorg_parts_rule: } INTO '(' part_def_list ')' { - LEX *lex= Lex; - lex->part_info->no_parts= lex->part_info->partitions.elements; + partition_info *part_info= Lex->part_info; + part_info->no_parts= part_info->partitions.elements; } ; @@ -11529,7 +11670,6 @@ keyword_sp: | MAX_SIZE_SYM {} | MAX_UPDATES_PER_HOUR {} | MAX_USER_CONNECTIONS_SYM {} - | MAX_VALUE_SYM {} | MEDIUM_SYM {} | MEMORY_SYM {} | MERGE_SYM {} From 3b29941f5df7ba95685da159344bc2632c12f1ac Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 15 Sep 2009 17:27:10 +0200 Subject: [PATCH 02/27] Forgot to add result files for WL#3352 new test cases --- mysql-test/r/partition_column.result | 213 +++++++++++++++++++++ mysql-test/r/partition_column_prune.result | 66 +++++++ 2 files changed, 279 insertions(+) create mode 100644 mysql-test/r/partition_column.result create mode 100644 mysql-test/r/partition_column_prune.result diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result new file mode 100644 index 00000000000..5c6464b271d --- /dev/null +++ b/mysql-test/r/partition_column.result @@ -0,0 +1,213 @@ +drop table if exists t1; +create table t1 (a int, b char(10), c varchar(25), d datetime) +partition by range column_list(a,b,c,d) +subpartition by hash (to_seconds(d)) +subpartitions 4 +( partition p0 values less than (column_list(1, NULL, MAXVALUE, NULL)), +partition p1 values less than (column_list(1, 'a', MAXVALUE, TO_DAYS('1999-01-01'))), +partition p2 values less than (column_list(1, 'a', MAXVALUE, MAXVALUE)), +partition p3 values less than (column_list(1, MAXVALUE, MAXVALUE, MAXVALUE))); +drop table t1; +create table t1 (a int, b char(10), c varchar(5), d int) +partition by range column_list(a,b,c) +subpartition by key (c,d) +subpartitions 3 +( partition p0 values less than (column_list(1,'abc','abc')), +partition p1 values less than (column_list(2,'abc','abc')), +partition p2 values less than (column_list(3,'abc','abc')), +partition p3 values less than (column_list(4,'abc','abc'))); +insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); +insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); +insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); +insert into t1 values (1,'d','e',1),(2,'d','e',2),(3,'d','e',3); +select * from t1 where (a = 1 AND b < 'd' AND (c = 'b' OR (c = 'c' AND d = 1)) OR +(a = 1 AND b >= 'a' AND (c = 'c' OR (c = 'd' AND d = 2)))); +a b c d +1 a b 1 +1 b c 1 +drop table t1; +create table t1 (a int, b varchar(2), c int) +partition by range column_list (a, b, c) +(partition p0 values less than (column_list(1, 'A', 1)), +partition p1 values less than (column_list(1, 'B', 1))); +insert into t1 values (1, 'A', 1); +explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1 system NULL NULL NULL NULL 1 +select * from t1 where a = 1 AND b <= 'A' and c = 1; +a b c +1 A 1 +drop table t1; +create table t1 (a char, b char, c char) +partition by list column_list(a) +( partition p0 values in (column_list('a'))); +insert into t1 (a) values ('a'); +select * from t1 where a = 'a'; +a b c +a NULL NULL +drop table t1; +create table t1 (d timestamp) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), +partition p1 values less than (column_list('2040-01-01'))); +ERROR HY000: Partition column values of incorrect type +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(null, 10))); +drop table t1; +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), +partition p1 values less than (column_list('2009-01-01'))); +drop table t1; +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('1999-01-01')), +partition p1 values less than (column_list('2000-01-01'))); +drop table t1; +create table t1 (d date) +partition by range column_list(d) +( partition p0 values less than (column_list('2000-01-01')), +partition p1 values less than (column_list('3000-01-01'))); +drop table t1; +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p2 values less than (column_list(99,99)), +partition p1 values less than (column_list(99,999))); +insert into t1 values (99,998); +select * from t1 where b = 998; +a b +99 998 +drop table t1; +create table t1 as select to_seconds(null) as to_seconds; +select data_type from information_schema.columns +where column_name='to_seconds'; +data_type +int +drop table t1; +create table t1 (a int, b int) +partition by list column_list(a,b) +(partition p0 values in (column_list(maxvalue,maxvalue))); +ERROR 42000: Cannot use MAXVALUE as value in List partitioning near 'maxvalue,maxvalue)))' at line 3 +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(maxvalue,maxvalue))); +drop table t1; +create table t1 (a int) +partition by list column_list(a) +(partition p0 values in (column_list(0))); +select partition_method from information_schema.partitions where table_name='t1'; +partition_method +LIST COLUMN_LIST +drop table t1; +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list('H23456')), +partition p1 values less than (column_list('M23456'))); +insert into t1 values ('F23456'); +select * from t1; +a +F23456 +drop table t1; +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list(H23456)), +partition p1 values less than (column_list(M23456))); +ERROR 42S22: Unknown column 'H23456' in 'field list' +create table t1 (a char(6)) +partition by range column_list(a) +(partition p0 values less than (column_list(23456)), +partition p1 values less than (column_list(23456))); +ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (10)); +ERROR 42000: Inconsistency in usage of column lists for partitioning near '))' at line 3 +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(1,1,1)); +ERROR HY000: Inconsistency in usage of column lists for partitioning +create table t1 (a int, b int) +partition by range column_list(a,b) +(partition p0 values less than (column_list(1, NULL)), +partition p1 values less than (column_list(2, maxvalue)), +partition p2 values less than (column_list(3, 3)), +partition p3 values less than (column_list(10, NULL))); +insert into t1 values (10,0); +ERROR HY000: Table has no partition for value from column_list +insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1); +select * from t1; +a b +0 1 +1 1 +2 1 +3 1 +3 4 +4 9 +9 1 +alter table t1 +partition by range column_list(b,a) +(partition p0 values less than (column_list(1,2)), +partition p1 values less than (column_list(3,3)), +partition p2 values less than (column_list(9,5))); +explain partitions select * from t1 where b < 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 7 Using where +select * from t1 where b < 2; +a b +0 1 +1 1 +2 1 +3 1 +9 1 +explain partitions select * from t1 where b < 4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p1,p2 ALL NULL NULL NULL NULL 7 Using where +select * from t1 where b < 4; +a b +0 1 +1 1 +2 1 +3 1 +9 1 +alter table t1 reorganize partition p1 into +(partition p11 values less than (column_list(2,2)), +partition p12 values less than (column_list(3,3))); +alter table t1 reorganize partition p0 into +(partition p01 values less than (column_list(0,3)), +partition p02 values less than (column_list(1,1))); +ERROR HY000: Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range +alter table t1 reorganize partition p2 into +(partition p2 values less than(column_list(9,6,1))); +ERROR HY000: Inconsistency in usage of column lists for partitioning +alter table t1 reorganize partition p2 into +(partition p2 values less than (10)); +ERROR HY000: Inconsistency in usage of column lists for partitioning +alter table t1 reorganize partition p2 into +(partition p21 values less than (column_list(4,7)), +partition p22 values less than (column_list(9,5))); +explain partitions select * from t1 where b < 4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0,p11,p12,p21 ALL NULL NULL NULL NULL 7 Using where +select * from t1 where b < 4; +a b +0 1 +1 1 +2 1 +3 1 +9 1 +drop table t1; +create table t1 (a int, b int) +partition by list column_list(a,b) +subpartition by hash (b) +subpartitions 2 +(partition p0 values in (column_list(0,0), column_list(1,1)), +partition p1 values in (column_list(1000,1000))); +insert into t1 values (1000,1000); +drop table t1; +create table t1 (a char, b char, c char) +partition by range column_list(a,b,c) +( partition p0 values less than (column_list('a','b','c'))); +alter table t1 add partition +(partition p1 values less than (column_list('b','c','d'))); +drop table t1; diff --git a/mysql-test/r/partition_column_prune.result b/mysql-test/r/partition_column_prune.result new file mode 100644 index 00000000000..8f7a8f85d05 --- /dev/null +++ b/mysql-test/r/partition_column_prune.result @@ -0,0 +1,66 @@ +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +create table t1 (a char, b char, c char) +partition by range column_list(a,b,c) +( partition p0 values less than (column_list('a','b','c'))); +insert into t1 values ('a', NULL, 'd'); +explain partitions select * from t1 where a = 'a' AND c = 'd'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0 system NULL NULL NULL NULL 1 +select * from t1 where a = 'a' AND c = 'd'; +a b c +a NULL d +drop table t1; +create table t1 (a int not null) partition by range column_list(a) ( +partition p0 values less than (column_list(10)), +partition p1 values less than (column_list(20)), +partition p2 values less than (column_list(30)), +partition p3 values less than (column_list(40)), +partition p4 values less than (column_list(50)), +partition p5 values less than (column_list(60)), +partition p6 values less than (column_list(70)) +); +insert into t1 values (5),(15),(25),(35),(45),(55),(65); +insert into t1 values (5),(15),(25),(35),(45),(55),(65); +create table t2 (a int not null) partition by range(a) ( +partition p0 values less than (10), +partition p1 values less than (20), +partition p2 values less than (30), +partition p3 values less than (40), +partition p4 values less than (50), +partition p5 values less than (60), +partition p6 values less than (70) +); +insert into t2 values (5),(15),(25),(35),(45),(55),(65); +insert into t2 values (5),(15),(25),(35),(45),(55),(65); +explain partitions select * from t1 where a > 35 and a < 45; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p3,p4 ALL NULL NULL NULL NULL 4 Using where +explain partitions select * from t2 where a > 35 and a < 45; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t2 p3,p4 ALL NULL NULL NULL NULL 4 Using where +drop table t1, t2; +create table t1 (a int not null, b int not null ) +partition by range column_list(a,b) ( +partition p01 values less than (column_list(2,10)), +partition p02 values less than (column_list(2,20)), +partition p03 values less than (column_list(2,30)), +partition p11 values less than (column_list(4,10)), +partition p12 values less than (column_list(4,20)), +partition p13 values less than (column_list(4,30)), +partition p21 values less than (column_list(6,10)), +partition p22 values less than (column_list(6,20)), +partition p23 values less than (column_list(6,30)) +); +insert into t1 values (2,5), (2,15), (2,25), +(4,5), (4,15), (4,25), (6,5), (6,15), (6,25); +insert into t1 select * from t1; +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 p01,p02,p03,p11 ALL NULL NULL NULL NULL 13 Using where +explain partitions select * from t1 where a=4; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p11,p12,p13,p21 ALL NULL NULL NULL NULL 16 Using where +explain partitions select * from t1 where a=2 and b < 22; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p01,p02,p03 ALL NULL NULL NULL NULL 16 Using where +drop table t1; From dc97402c11e7b19d1358772e94d34ce5b4496fc6 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 1 Oct 2009 15:04:42 +0200 Subject: [PATCH 03/27] Changed all no_ to num_ to avoid strange names like no_list_values which is not expected to be number of list values, rather a boolea indicating no list values --- mysql-test/r/partition_column.result | 29 ++ mysql-test/t/partition_column.test | 32 ++ sql/ha_partition.cc | 134 ++++---- sql/ha_partition.h | 6 +- sql/opt_range.cc | 20 +- sql/partition_info.cc | 145 ++++----- sql/partition_info.h | 32 +- sql/sql_lex.cc | 2 +- sql/sql_lex.h | 6 +- sql/sql_partition.cc | 467 +++++++++++++-------------- sql/sql_partition.h | 2 +- sql/sql_table.cc | 22 +- sql/sql_yacc.yy | 53 ++- 13 files changed, 500 insertions(+), 450 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 5c6464b271d..0aaa4e78f68 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,33 @@ drop table if exists t1; +create table t1 (a int) +partition by list (a) +( partition p0 values in (1), +partition p1 values in (1)); +ERROR HY000: Multiple definition of same constant in list partitioning +create table t1 (a int) +partition by list (a) +( partition p0 values in (2, 1), +partition p1 values in (4, NULL, 3)); +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +insert into t1 values (4); +insert into t1 values (NULL); +insert into t1 values (5); +ERROR HY000: Table has no partition for value 5 +drop table t1; +create table t1 (a int) +partition by list column_list(a) +( partition p0 values in (column_list(2), column_list(1)), +partition p1 values in (column_list(4), column_list(NULL), column_list(3))); +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +insert into t1 values (4); +insert into t1 values (NULL); +insert into t1 values (5); +ERROR HY000: Table has no partition for value from column_list +drop table t1; create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index b1f5f4abfcf..f551b58119e 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,38 @@ drop table if exists t1; --enable_warnings +--error ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR +create table t1 (a int) +partition by list (a) +( partition p0 values in (1), + partition p1 values in (1)); + +create table t1 (a int) +partition by list (a) +( partition p0 values in (2, 1), + partition p1 values in (4, NULL, 3)); +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +insert into t1 values (4); +insert into t1 values (NULL); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values (5); +drop table t1; + +create table t1 (a int) +partition by list column_list(a) +( partition p0 values in (column_list(2), column_list(1)), + partition p1 values in (column_list(4), column_list(NULL), column_list(3))); +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +insert into t1 values (4); +insert into t1 values (NULL); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +insert into t1 values (5); +drop table t1; + create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ac8c46ec4e3..1b7165dd590 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -244,7 +244,7 @@ void ha_partition::init_handler_variables() /* this allows blackhole to work properly */ - m_no_locks= 0; + m_num_locks= 0; #ifdef DONT_HAVE_TO_BE_INITALIZED m_start_key.flag= 0; @@ -579,8 +579,8 @@ int ha_partition::drop_partitions(const char *path) { List_iterator part_it(m_part_info->partitions); char part_name_buff[FN_REFLEN]; - uint no_parts= m_part_info->partitions.elements; - uint no_subparts= m_part_info->no_subparts; + uint num_parts= m_part_info->partitions.elements; + uint num_subparts= m_part_info->num_subparts; uint i= 0; uint name_variant; int ret_error; @@ -610,7 +610,7 @@ int ha_partition::drop_partitions(const char *path) do { partition_element *sub_elem= sub_it++; - part= i * no_subparts + j; + part= i * num_subparts + j; create_subpartition_name(part_name_buff, path, part_elem->partition_name, sub_elem->partition_name, name_variant); @@ -620,7 +620,7 @@ int ha_partition::drop_partitions(const char *path) error= ret_error; if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) error= 1; - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -639,7 +639,7 @@ int ha_partition::drop_partitions(const char *path) else part_elem->part_state= PART_IS_DROPPED; } - } while (++i < no_parts); + } while (++i < num_parts); VOID(sync_ddl_log()); DBUG_RETURN(error); } @@ -670,9 +670,9 @@ int ha_partition::rename_partitions(const char *path) List_iterator temp_it(m_part_info->temp_partitions); char part_name_buff[FN_REFLEN]; char norm_name_buff[FN_REFLEN]; - uint no_parts= m_part_info->partitions.elements; + uint num_parts= m_part_info->partitions.elements; uint part_count= 0; - uint no_subparts= m_part_info->no_subparts; + uint num_subparts= m_part_info->num_subparts; uint i= 0; uint j= 0; int error= 0; @@ -720,7 +720,7 @@ int ha_partition::rename_partitions(const char *path) error= 1; else sub_elem->log_entry= NULL; /* Indicate success */ - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -776,7 +776,7 @@ int ha_partition::rename_partitions(const char *path) do { sub_elem= sub_it++; - part= i * no_subparts + j; + part= i * num_subparts + j; create_subpartition_name(norm_name_buff, path, part_elem->partition_name, sub_elem->partition_name, @@ -805,7 +805,7 @@ int ha_partition::rename_partitions(const char *path) error= 1; else sub_elem->log_entry= NULL; - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -837,7 +837,7 @@ int ha_partition::rename_partitions(const char *path) part_elem->log_entry= NULL; } } - } while (++i < no_parts); + } while (++i < num_parts); VOID(sync_ddl_log()); DBUG_RETURN(error); } @@ -1047,8 +1047,8 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, uint flag) { List_iterator part_it(m_part_info->partitions); - uint no_parts= m_part_info->no_parts; - uint no_subparts= m_part_info->no_subparts; + uint num_parts= m_part_info->num_parts; + uint num_subparts= m_part_info->num_subparts; uint i= 0; int error; DBUG_ENTER("ha_partition::handle_opt_partitions"); @@ -1072,7 +1072,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, do { sub_elem= subpart_it++; - part= i * no_subparts + j; + part= i * num_subparts + j; DBUG_PRINT("info", ("Optimize subpartition %u (%s)", part, sub_elem->partition_name)); #ifdef NOT_USED @@ -1096,7 +1096,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, } DBUG_RETURN(error); } - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -1124,7 +1124,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, } } } - } while (++i < no_parts); + } while (++i < num_parts); DBUG_RETURN(FALSE); } @@ -1328,10 +1328,10 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, List_iterator part_it(m_part_info->partitions); List_iterator t_it(m_part_info->temp_partitions); char part_name_buff[FN_REFLEN]; - uint no_parts= m_part_info->partitions.elements; - uint no_subparts= m_part_info->no_subparts; + uint num_parts= m_part_info->partitions.elements; + uint num_subparts= m_part_info->num_subparts; uint i= 0; - uint no_remain_partitions, part_count, orig_count; + uint num_remain_partitions, part_count, orig_count; handler **new_file_array; int error= 1; bool first; @@ -1347,7 +1347,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_name_buff))); m_reorged_parts= 0; if (!m_part_info->is_sub_partitioned()) - no_subparts= 1; + num_subparts= 1; /* Step 1: @@ -1356,7 +1356,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, */ if (temp_partitions) { - m_reorged_parts= temp_partitions * no_subparts; + m_reorged_parts= temp_partitions * num_subparts; } else { @@ -1366,9 +1366,9 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, if (part_elem->part_state == PART_CHANGED || part_elem->part_state == PART_REORGED_DROPPED) { - m_reorged_parts+= no_subparts; + m_reorged_parts+= num_subparts; } - } while (++i < no_parts); + } while (++i < num_parts); } if (m_reorged_parts && !(m_reorged_file= (handler**)sql_calloc(sizeof(handler*)* @@ -1383,10 +1383,10 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, Calculate number of partitions after change and allocate space for their handler references. */ - no_remain_partitions= 0; + num_remain_partitions= 0; if (temp_partitions) { - no_remain_partitions= no_parts * no_subparts; + num_remain_partitions= num_parts * num_subparts; } else { @@ -1399,17 +1399,17 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->part_state == PART_TO_BE_ADDED || part_elem->part_state == PART_CHANGED) { - no_remain_partitions+= no_subparts; + num_remain_partitions+= num_subparts; } - } while (++i < no_parts); + } while (++i < num_parts); } if (!(new_file_array= (handler**)sql_calloc(sizeof(handler*)* - (2*(no_remain_partitions + 1))))) + (2*(num_remain_partitions + 1))))) { - mem_alloc_error(sizeof(handler*)*2*(no_remain_partitions+1)); + mem_alloc_error(sizeof(handler*)*2*(num_remain_partitions+1)); DBUG_RETURN(ER_OUTOFMEMORY); } - m_added_file= &new_file_array[no_remain_partitions + 1]; + m_added_file= &new_file_array[num_remain_partitions + 1]; /* Step 3: @@ -1428,9 +1428,9 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->part_state == PART_REORGED_DROPPED) { memcpy((void*)&m_reorged_file[part_count], - (void*)&m_file[i*no_subparts], - sizeof(handler*)*no_subparts); - part_count+= no_subparts; + (void*)&m_file[i*num_subparts], + sizeof(handler*)*num_subparts); + part_count+= num_subparts; } else if (first && temp_partitions && part_elem->part_state == PART_TO_BE_ADDED) @@ -1445,11 +1445,11 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, ones used to be. */ first= FALSE; - DBUG_ASSERT(((i*no_subparts) + m_reorged_parts) <= m_file_tot_parts); - memcpy((void*)m_reorged_file, &m_file[i*no_subparts], + DBUG_ASSERT(((i*num_subparts) + m_reorged_parts) <= m_file_tot_parts); + memcpy((void*)m_reorged_file, &m_file[i*num_subparts], sizeof(handler*)*m_reorged_parts); } - } while (++i < no_parts); + } while (++i < num_parts); } /* @@ -1467,11 +1467,11 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, partition_element *part_elem= part_it++; if (part_elem->part_state == PART_NORMAL) { - DBUG_ASSERT(orig_count + no_subparts <= m_file_tot_parts); + DBUG_ASSERT(orig_count + num_subparts <= m_file_tot_parts); memcpy((void*)&new_file_array[part_count], (void*)&m_file[orig_count], - sizeof(handler*)*no_subparts); - part_count+= no_subparts; - orig_count+= no_subparts; + sizeof(handler*)*num_subparts); + part_count+= num_subparts; + orig_count+= num_subparts; } else if (part_elem->part_state == PART_CHANGED || part_elem->part_state == PART_TO_BE_ADDED) @@ -1487,16 +1487,16 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, mem_alloc_error(sizeof(handler)); DBUG_RETURN(ER_OUTOFMEMORY); } - } while (++j < no_subparts); + } while (++j < num_subparts); if (part_elem->part_state == PART_CHANGED) - orig_count+= no_subparts; + orig_count+= num_subparts; else if (temp_partitions && first) { - orig_count+= (no_subparts * temp_partitions); + orig_count+= (num_subparts * temp_partitions); first= FALSE; } } - } while (++i < no_parts); + } while (++i < num_parts); first= FALSE; /* Step 5: @@ -1533,7 +1533,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->partition_name, sub_elem->partition_name, name_variant); - part= i * no_subparts + j; + part= i * num_subparts + j; DBUG_PRINT("info", ("Add subpartition %s", part_name_buff)); if ((error= prepare_new_partition(table, create_info, new_file_array[part], @@ -1544,7 +1544,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, DBUG_RETURN(error); } m_added_file[part_count++]= new_file_array[part]; - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -1563,7 +1563,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, m_added_file[part_count++]= new_file_array[i]; } } - } while (++i < no_parts); + } while (++i < num_parts); /* Step 6: @@ -1580,7 +1580,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info, part_elem->part_state= PART_IS_CHANGED; else if (part_elem->part_state == PART_REORGED_DROPPED) part_elem->part_state= PART_TO_BE_DROPPED; - } while (++i < no_parts); + } while (++i < num_parts); for (i= 0; i < temp_partitions; i++) { partition_element *part_elem= t_it++; @@ -1621,9 +1621,9 @@ int ha_partition::copy_partitions(ulonglong * const copied, if (m_part_info->linear_hash_ind) { if (m_part_info->part_type == HASH_PARTITION) - set_linear_hash_mask(m_part_info, m_part_info->no_parts); + set_linear_hash_mask(m_part_info, m_part_info->num_parts); else - set_linear_hash_mask(m_part_info, m_part_info->no_subparts); + set_linear_hash_mask(m_part_info, m_part_info->num_subparts); } while (reorg_part < m_reorged_parts) @@ -1902,7 +1902,7 @@ partition_element *ha_partition::find_partition_element(uint part_id) uint curr_part_id= 0; List_iterator_fast part_it(m_part_info->partitions); - for (i= 0; i < m_part_info->no_parts; i++) + for (i= 0; i < m_part_info->num_parts; i++) { partition_element *part_elem; part_elem= part_it++; @@ -1910,7 +1910,7 @@ partition_element *ha_partition::find_partition_element(uint part_id) { uint j; List_iterator_fast sub_it(part_elem->subpartitions); - for (j= 0; j < m_part_info->no_subparts; j++) + for (j= 0; j < m_part_info->num_subparts; j++) { part_elem= sub_it++; if (part_id == curr_part_id++) @@ -2031,7 +2031,7 @@ bool ha_partition::create_handler_file(const char *name) { partition_element *part_elem, *subpart_elem; uint i, j, part_name_len, subpart_name_len; - uint tot_partition_words, tot_name_len, no_parts; + uint tot_partition_words, tot_name_len, num_parts; uint tot_parts= 0; uint tot_len_words, tot_len_byte, chksum, tot_name_words; char *name_buffer_ptr; @@ -2044,11 +2044,11 @@ bool ha_partition::create_handler_file(const char *name) List_iterator_fast part_it(m_part_info->partitions); DBUG_ENTER("create_handler_file"); - no_parts= m_part_info->partitions.elements; - DBUG_PRINT("info", ("table name = %s, no_parts = %u", name, - no_parts)); + num_parts= m_part_info->partitions.elements; + DBUG_PRINT("info", ("table name = %s, num_parts = %u", name, + num_parts)); tot_name_len= 0; - for (i= 0; i < no_parts; i++) + for (i= 0; i < num_parts; i++) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && @@ -2066,7 +2066,7 @@ bool ha_partition::create_handler_file(const char *name) else { List_iterator_fast sub_it(part_elem->subpartitions); - for (j= 0; j < m_part_info->no_subparts; j++) + for (j= 0; j < m_part_info->num_subparts; j++) { subpart_elem= sub_it++; tablename_to_filename(subpart_elem->partition_name, @@ -2100,7 +2100,7 @@ bool ha_partition::create_handler_file(const char *name) engine_array= (file_buffer + 12); name_buffer_ptr= (char*) (file_buffer + ((4 + tot_partition_words) * 4)); part_it.rewind(); - for (i= 0; i < no_parts; i++) + for (i= 0; i < num_parts; i++) { part_elem= part_it++; if (part_elem->part_state != PART_NORMAL && @@ -2118,7 +2118,7 @@ bool ha_partition::create_handler_file(const char *name) else { List_iterator_fast sub_it(part_elem->subpartitions); - for (j= 0; j < m_part_info->no_subparts; j++) + for (j= 0; j < m_part_info->num_subparts; j++) { subpart_elem= sub_it++; tablename_to_filename(part_elem->partition_name, part_name, @@ -2254,7 +2254,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root) } m_file_tot_parts= m_tot_parts; bzero((char*) m_file, alloc_len); - DBUG_ASSERT(m_part_info->no_parts > 0); + DBUG_ASSERT(m_part_info->num_parts > 0); i= 0; part_count= 0; @@ -2267,7 +2267,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root) part_elem= part_it++; if (m_is_sub_partitioned) { - for (j= 0; j < m_part_info->no_subparts; j++) + for (j= 0; j < m_part_info->num_subparts; j++) { if (!(m_file[part_count++]= get_new_handler(table_share, mem_root, part_elem->engine_type))) @@ -2284,7 +2284,7 @@ bool ha_partition::new_handlers_from_part_info(MEM_ROOT *mem_root) DBUG_PRINT("info", ("engine_type: %u", (uint) ha_legacy_type(part_elem->engine_type))); } - } while (++i < m_part_info->no_parts); + } while (++i < m_part_info->num_parts); if (part_elem->engine_type == myisam_hton) { DBUG_PRINT("info", ("MyISAM")); @@ -2480,7 +2480,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) if ((error= (*file)->ha_open(table, (const char*) name_buff, mode, test_if_locked))) goto err_handler; - m_no_locks+= (*file)->lock_count(); + m_num_locks+= (*file)->lock_count(); name_buffer_ptr+= strlen(name_buffer_ptr) + 1; set_if_bigger(ref_length, ((*file)->ref_length)); /* @@ -2820,8 +2820,8 @@ int ha_partition::start_stmt(THD *thd, thr_lock_type lock_type) uint ha_partition::lock_count() const { DBUG_ENTER("ha_partition::lock_count"); - DBUG_PRINT("info", ("m_no_locks %d", m_no_locks)); - DBUG_RETURN(m_no_locks); + DBUG_PRINT("info", ("m_num_locks %d", m_num_locks)); + DBUG_RETURN(m_num_locks); } diff --git a/sql/ha_partition.h b/sql/ha_partition.h index cc6558f2db0..3a09c1d2ea3 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -112,7 +112,7 @@ private: uint m_reorged_parts; // Number of reorganised parts uint m_tot_parts; // Total number of partitions; - uint m_no_locks; // For engines like ha_blackhole, which needs no locks + uint m_num_locks; // For engines like ha_blackhole, which needs no locks uint m_last_part; // Last file that we update,write,read int m_lock_type; // Remembers type of last // external_lock @@ -239,10 +239,10 @@ public: size_t pack_frm_len); virtual int drop_partitions(const char *path); virtual int rename_partitions(const char *path); - bool get_no_parts(const char *name, uint *no_parts) + bool get_no_parts(const char *name, uint *num_parts) { DBUG_ENTER("ha_partition::get_no_parts"); - *no_parts= m_tot_parts; + *num_parts= m_tot_parts; DBUG_RETURN(0); } virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index e226b51fc66..801045a8f6d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2638,7 +2638,7 @@ typedef struct st_part_prune_param /* Iterator to be used to obtain the "current" set of used partitions */ PARTITION_ITERATOR part_iter; - /* Initialized bitmap of no_subparts size */ + /* Initialized bitmap of num_subparts size */ MY_BITMAP subparts_bitmap; uchar *cur_min_key; @@ -2904,8 +2904,8 @@ static void mark_full_partition_used_no_parts(partition_info* part_info, static void mark_full_partition_used_with_parts(partition_info *part_info, uint32 part_id) { - uint32 start= part_id * part_info->no_subparts; - uint32 end= start + part_info->no_subparts; + uint32 start= part_id * part_info->num_subparts; + uint32 end= start + part_info->num_subparts; DBUG_ENTER("mark_full_partition_used_with_parts"); for (; start != end; start++) @@ -3328,10 +3328,10 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) != NOT_A_PARTITION_ID) { - for (uint i= 0; i < ppar->part_info->no_subparts; i++) + for (uint i= 0; i < ppar->part_info->num_subparts; i++) if (bitmap_is_set(&ppar->subparts_bitmap, i)) bitmap_set_bit(&ppar->part_info->used_partitions, - part_id * ppar->part_info->no_subparts + i); + part_id * ppar->part_info->num_subparts + i); } goto pop_and_go_right; } @@ -3393,7 +3393,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) NOT_A_PARTITION_ID) { bitmap_set_bit(&part_info->used_partitions, - part_id * part_info->no_subparts + subpart_id); + part_id * part_info->num_subparts + subpart_id); } res= 1; /* Some partitions were marked as used */ goto pop_and_go_right; @@ -3541,10 +3541,10 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) uint used_part_fields, used_subpart_fields; used_part_fields= fields_ok_for_partition_index(part_info->part_field_array) ? - part_info->no_part_fields : 0; + part_info->num_part_fields : 0; used_subpart_fields= fields_ok_for_partition_index(part_info->subpart_field_array)? - part_info->no_subpart_fields : 0; + part_info->num_subpart_fields : 0; uint total_parts= used_part_fields + used_subpart_fields; @@ -3583,10 +3583,10 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) if (ppar->subpart_fields) { my_bitmap_map *buf; - uint32 bufsize= bitmap_buffer_size(ppar->part_info->no_subparts); + uint32 bufsize= bitmap_buffer_size(ppar->part_info->num_subparts); if (!(buf= (my_bitmap_map*) alloc_root(alloc, bufsize))) return TRUE; - bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->no_subparts, + bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts, FALSE); } range_par->key_parts= key_part; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index bb7c7c2be0f..aaa6d0d3767 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -75,7 +75,7 @@ partition_info *partition_info::get_clone() SYNOPSIS create_default_partition_names() part_no Partition number for subparts - no_parts Number of partitions + num_parts Number of partitions start_no Starting partition number subpart Is it subpartitions @@ -91,10 +91,10 @@ partition_info *partition_info::get_clone() #define MAX_PART_NAME_SIZE 8 char *partition_info::create_default_partition_names(uint part_no, - uint no_parts_arg, + uint num_parts_arg, uint start_no) { - char *ptr= (char*) sql_calloc(no_parts_arg*MAX_PART_NAME_SIZE); + char *ptr= (char*) sql_calloc(num_parts_arg*MAX_PART_NAME_SIZE); char *move_ptr= ptr; uint i= 0; DBUG_ENTER("create_default_partition_names"); @@ -105,11 +105,11 @@ char *partition_info::create_default_partition_names(uint part_no, { my_sprintf(move_ptr, (move_ptr,"p%u", (start_no + i))); move_ptr+=MAX_PART_NAME_SIZE; - } while (++i < no_parts_arg); + } while (++i < num_parts_arg); } else { - mem_alloc_error(no_parts_arg*MAX_PART_NAME_SIZE); + mem_alloc_error(num_parts_arg*MAX_PART_NAME_SIZE); } DBUG_RETURN(ptr); } @@ -189,19 +189,19 @@ bool partition_info::set_up_default_partitions(handler *file, goto end; } - if ((no_parts == 0) && - ((no_parts= file->get_default_no_partitions(info)) == 0)) + if ((num_parts == 0) && + ((num_parts= file->get_default_no_partitions(info)) == 0)) { my_error(ER_PARTITION_NOT_DEFINED_ERROR, MYF(0), "partitions"); goto end; } - if (unlikely(no_parts > MAX_PARTITIONS)) + if (unlikely(num_parts > MAX_PARTITIONS)) { my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); goto end; } - if (unlikely((!(default_name= create_default_partition_names(0, no_parts, + if (unlikely((!(default_name= create_default_partition_names(0, num_parts, start_no))))) goto end; i= 0; @@ -220,7 +220,7 @@ bool partition_info::set_up_default_partitions(handler *file, mem_alloc_error(sizeof(partition_element)); goto end; } - } while (++i < no_parts); + } while (++i < num_parts); result= FALSE; end: DBUG_RETURN(result); @@ -259,9 +259,9 @@ bool partition_info::set_up_default_subpartitions(handler *file, List_iterator part_it(partitions); DBUG_ENTER("partition_info::set_up_default_subpartitions"); - if (no_subparts == 0) - no_subparts= file->get_default_no_partitions(info); - if (unlikely((no_parts * no_subparts) > MAX_PARTITIONS)) + if (num_subparts == 0) + num_subparts= file->get_default_no_partitions(info); + if (unlikely((num_parts * num_subparts) > MAX_PARTITIONS)) { my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); goto end; @@ -288,8 +288,8 @@ bool partition_info::set_up_default_subpartitions(handler *file, mem_alloc_error(sizeof(partition_element)); goto end; } - } while (++j < no_subparts); - } while (++i < no_parts); + } while (++j < num_subparts); + } while (++i < num_parts); result= FALSE; end: DBUG_RETURN(result); @@ -520,12 +520,12 @@ bool partition_info::check_engine_mix(handlerton *engine_type, { handlerton *old_engine_type= engine_type; bool first= TRUE; - uint no_parts= partitions.elements; + uint num_parts= partitions.elements; DBUG_ENTER("partition_info::check_engine_mix"); DBUG_PRINT("info", ("in: engine_type = %s, table_engine_set = %u", ha_resolve_storage_engine_name(engine_type), table_engine_set)); - if (no_parts) + if (num_parts) { List_iterator part_it(partitions); uint i= 0; @@ -538,7 +538,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, if (is_sub_partitioned() && part_elem->subpartitions.elements) { - uint no_subparts= part_elem->subpartitions.elements; + uint num_subparts= part_elem->subpartitions.elements; uint j= 0; List_iterator sub_it(part_elem->subpartitions); do @@ -550,7 +550,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, if (check_engine_condition(sub_elem, table_engine_set, &engine_type, &first)) goto error; - } while (++j < no_subparts); + } while (++j < num_subparts); /* ensure that the partition also has correct engine */ if (check_engine_condition(part_elem, table_engine_set, &engine_type, &first)) @@ -559,7 +559,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, else if (check_engine_condition(part_elem, table_engine_set, &engine_type, &first)) goto error; - } while (++i < no_parts); + } while (++i < num_parts); } DBUG_PRINT("info", ("engine_type = %s", ha_resolve_storage_engine_name(engine_type))); @@ -612,21 +612,21 @@ bool partition_info::check_range_constants(THD *thd) List_iterator it(partitions); int result= TRUE; DBUG_ENTER("partition_info::check_range_constants"); - DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", no_parts, + DBUG_PRINT("enter", ("RANGE with %d parts, column_list = %u", num_parts, column_list)); if (column_list) { part_column_list_val* loc_range_col_array; part_column_list_val *current_largest_col_val; - uint no_column_values= part_field_list.elements; - uint size_entries= sizeof(part_column_list_val) * no_column_values; - range_col_array= (part_column_list_val*)sql_calloc(no_parts * + uint num_column_values= part_field_list.elements; + uint size_entries= sizeof(part_column_list_val) * num_column_values; + range_col_array= (part_column_list_val*)sql_calloc(num_parts * size_entries); LINT_INIT(current_largest_col_val); if (unlikely(range_col_array == NULL)) { - mem_alloc_error(no_parts * sizeof(longlong)); + mem_alloc_error(num_parts * sizeof(longlong)); goto end; } loc_range_col_array= range_col_array; @@ -642,7 +642,7 @@ bool partition_info::check_range_constants(THD *thd) if (fix_column_value_functions(thd, col_val, i)) goto end; memcpy(loc_range_col_array, (const void*)col_val, size_entries); - loc_range_col_array+= no_column_values; + loc_range_col_array+= num_column_values; if (!first) { if (compare_column_values((const void*)current_largest_col_val, @@ -652,7 +652,7 @@ bool partition_info::check_range_constants(THD *thd) current_largest_col_val= col_val; } first= FALSE; - } while (++i < no_parts); + } while (++i < num_parts); } else { @@ -663,17 +663,17 @@ bool partition_info::check_range_constants(THD *thd) LINT_INIT(current_largest); part_result_type= INT_RESULT; - range_int_array= (longlong*)sql_alloc(no_parts * sizeof(longlong)); + range_int_array= (longlong*)sql_alloc(num_parts * sizeof(longlong)); if (unlikely(range_int_array == NULL)) { - mem_alloc_error(no_parts * sizeof(longlong)); + mem_alloc_error(num_parts * sizeof(longlong)); goto end; } i= 0; do { part_def= it++; - if ((i != (no_parts - 1)) || !defined_max_value) + if ((i != (num_parts - 1)) || !defined_max_value) { part_range_value= part_def->range_value; if (!signed_flag) @@ -687,14 +687,14 @@ bool partition_info::check_range_constants(THD *thd) if (unlikely(current_largest > part_range_value) || (unlikely(current_largest == part_range_value) && (part_range_value < LONGLONG_MAX || - i != (no_parts - 1) || + i != (num_parts - 1) || !defined_max_value))) goto range_not_increasing_error; } range_int_array[i]= part_range_value; current_largest= part_range_value; first= FALSE; - } while (++i < no_parts); + } while (++i < num_parts); } result= FALSE; end: @@ -801,7 +801,7 @@ bool partition_info::fix_column_value_functions(THD *thd, part_column_list_val *col_val, uint part_id) { - uint no_columns= part_field_list.elements; + uint num_columns= part_field_list.elements; Name_resolution_context *context= &thd->lex->current_select->context; TABLE_LIST *save_list= context->table_list; bool result= FALSE; @@ -814,7 +814,7 @@ bool partition_info::fix_column_value_functions(THD *thd, } context->table_list= 0; thd->where= "partition function"; - for (i= 0; i < no_columns; col_val++, i++) + for (i= 0; i < num_columns; col_val++, i++) { Item *column_item= col_val->item_expression; Field *field= part_field_array[i]; @@ -885,7 +885,7 @@ end: bool partition_info::check_list_constants(THD *thd) { - uint i, size_entries, no_column_values; + uint i, size_entries, num_column_values; uint list_index= 0; part_elem_value *list_value; bool result= TRUE; @@ -899,7 +899,7 @@ bool partition_info::check_list_constants(THD *thd) DBUG_ENTER("partition_info::check_list_constants"); part_result_type= INT_RESULT; - no_list_values= 0; + num_list_values= 0; /* We begin by calculating the number of list values that have been defined in the first step. @@ -932,17 +932,17 @@ bool partition_info::check_list_constants(THD *thd) } List_iterator list_val_it1(part_def->list_val_list); while (list_val_it1++) - no_list_values++; - } while (++i < no_parts); + num_list_values++; + } while (++i < num_parts); list_func_it.rewind(); - no_column_values= part_field_list.elements; + num_column_values= part_field_list.elements; size_entries= column_list ? - (no_column_values * sizeof(part_column_list_val)) : + (num_column_values * sizeof(part_column_list_val)) : sizeof(LIST_PART_ENTRY); - ptr= sql_calloc((no_list_values+1) * size_entries); + ptr= sql_calloc((num_list_values+1) * size_entries); if (unlikely(ptr == NULL)) { - mem_alloc_error(no_list_values * size_entries); + mem_alloc_error(num_list_values * size_entries); goto end; } if (column_list) @@ -952,10 +952,6 @@ bool partition_info::check_list_constants(THD *thd) list_col_array= (part_column_list_val*)ptr; compare_func= compare_column_values; i= 0; - /* - Fix to be able to reuse signed sort functions also for unsigned - partition functions. - */ do { part_def= list_func_it++; @@ -968,9 +964,9 @@ bool partition_info::check_list_constants(THD *thd) DBUG_RETURN(TRUE); } memcpy(loc_list_col_array, (const void*)col_val, size_entries); - loc_list_col_array+= no_column_values; + loc_list_col_array+= num_column_values; } - } while (++i < no_parts); + } while (++i < num_parts); } else { @@ -995,24 +991,24 @@ bool partition_info::check_list_constants(THD *thd) list_array[list_index].list_value= calc_value; list_array[list_index++].partition_id= i; } - } while (++i < no_parts); + } while (++i < num_parts); } - if (fixed && no_list_values) + if (fixed && num_list_values) { bool first= TRUE; /* list_array and list_col_array are unions, so this works for both variants of LIST partitioning. */ - my_qsort((void*)list_array, no_list_values, sizeof(LIST_PART_ENTRY), + my_qsort((void*)list_array, num_list_values, sizeof(LIST_PART_ENTRY), &list_part_cmp); i= 0; LINT_INIT(prev_value); do { - DBUG_ASSERT(i < no_list_values); - curr_value= column_list ? (void*)&list_col_array[no_column_values * i] : + DBUG_ASSERT(i < num_list_values); + curr_value= column_list ? (void*)&list_col_array[num_column_values * i] : (void*)&list_array[i]; if (likely(first || compare_func(curr_value, prev_value))) { @@ -1024,7 +1020,7 @@ bool partition_info::check_list_constants(THD *thd) my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); goto end; } - } while (++i < no_list_values); + } while (++i < num_list_values); } result= FALSE; end: @@ -1088,7 +1084,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } } if (unlikely(!is_sub_partitioned() && - !(use_default_subpartitions && use_default_no_subpartitions))) + !(use_default_subpartitions && use_default_num_subpartitions))) { my_error(ER_SUBPARTITION_ERROR, MYF(0)); goto end; @@ -1154,8 +1150,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, i= 0; { List_iterator part_it(partitions); - uint no_parts_not_set= 0; - uint prev_no_subparts_not_set= no_subparts + 1; + uint num_parts_not_set= 0; + uint prev_num_subparts_not_set= num_subparts + 1; do { partition_element *part_elem= part_it++; @@ -1177,7 +1173,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, { if (part_elem->engine_type == NULL) { - no_parts_not_set++; + num_parts_not_set++; part_elem->engine_type= default_engine_type; } if (check_table_name(part_elem->partition_name, @@ -1192,7 +1188,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, else { uint j= 0; - uint no_subparts_not_set= 0; + uint num_subparts_not_set= 0; List_iterator sub_it(part_elem->subpartitions); partition_element *sub_elem; do @@ -1211,44 +1207,45 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, else { sub_elem->engine_type= default_engine_type; - no_subparts_not_set++; + num_subparts_not_set++; } } DBUG_PRINT("info", ("part = %d sub = %d engine = %s", i, j, ha_resolve_storage_engine_name(sub_elem->engine_type))); - } while (++j < no_subparts); + } while (++j < num_subparts); - if (prev_no_subparts_not_set == (no_subparts + 1) && - (no_subparts_not_set == 0 || no_subparts_not_set == no_subparts)) - prev_no_subparts_not_set= no_subparts_not_set; + if (prev_num_subparts_not_set == (num_subparts + 1) && + (num_subparts_not_set == 0 || + num_subparts_not_set == num_subparts)) + prev_num_subparts_not_set= num_subparts_not_set; if (!table_engine_set && - prev_no_subparts_not_set != no_subparts_not_set) + prev_num_subparts_not_set != num_subparts_not_set) { - DBUG_PRINT("info", ("no_subparts_not_set = %u no_subparts = %u", - no_subparts_not_set, no_subparts)); + DBUG_PRINT("info", ("num_subparts_not_set = %u num_subparts = %u", + num_subparts_not_set, num_subparts)); my_error(ER_MIX_HANDLER_ERROR, MYF(0)); goto end; } if (part_elem->engine_type == NULL) { - if (no_subparts_not_set == 0) + if (num_subparts_not_set == 0) part_elem->engine_type= sub_elem->engine_type; else { - no_parts_not_set++; + num_parts_not_set++; part_elem->engine_type= default_engine_type; } } } - } while (++i < no_parts); + } while (++i < num_parts); if (!table_engine_set && - no_parts_not_set != 0 && - no_parts_not_set != no_parts) + num_parts_not_set != 0 && + num_parts_not_set != num_parts) { - DBUG_PRINT("info", ("no_parts_not_set = %u no_parts = %u", - no_parts_not_set, no_subparts)); + DBUG_PRINT("info", ("num_parts_not_set = %u num_parts = %u", + num_parts_not_set, num_subparts)); my_error(ER_MIX_HANDLER_ERROR, MYF(0)); goto end; } diff --git a/sql/partition_info.h b/sql/partition_info.h index f232e761946..1f2b6b6a95e 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -176,17 +176,17 @@ public: uint part_func_len; uint subpart_func_len; - uint no_parts; - uint no_subparts; + uint num_parts; + uint num_subparts; uint count_curr_subparts; uint part_error_code; - uint no_list_values; + uint num_list_values; - uint no_part_fields; - uint no_subpart_fields; - uint no_full_part_fields; + uint num_part_fields; + uint num_subpart_fields; + uint num_full_part_fields; uint has_null_part_id; /* @@ -197,9 +197,9 @@ public: uint16 linear_hash_mask; bool use_default_partitions; - bool use_default_no_partitions; + bool use_default_num_partitions; bool use_default_subpartitions; - bool use_default_no_subpartitions; + bool use_default_num_subpartitions; bool default_partitions_setup; bool defined_max_value; bool list_of_part_fields; @@ -233,12 +233,12 @@ public: part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), part_info_len(0), part_state_len(0), part_func_len(0), subpart_func_len(0), - no_parts(0), no_subparts(0), + num_parts(0), num_subparts(0), count_curr_subparts(0), part_error_code(0), - no_list_values(0), no_part_fields(0), no_subpart_fields(0), - no_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0), - use_default_partitions(TRUE), use_default_no_partitions(TRUE), - use_default_subpartitions(TRUE), use_default_no_subpartitions(TRUE), + num_list_values(0), num_part_fields(0), num_subpart_fields(0), + num_full_part_fields(0), has_null_part_id(0), linear_hash_mask(0), + use_default_partitions(TRUE), use_default_num_partitions(TRUE), + use_default_subpartitions(TRUE), use_default_num_subpartitions(TRUE), default_partitions_setup(FALSE), defined_max_value(FALSE), list_of_part_fields(FALSE), list_of_subpart_fields(FALSE), linear_hash_ind(FALSE), fixed(FALSE), @@ -266,7 +266,7 @@ public: /* Returns the total number of partitions on the leaf level */ uint get_tot_partitions() { - return no_parts * (is_sub_partitioned() ? no_subparts : 1); + return num_parts * (is_sub_partitioned() ? num_subparts : 1); } bool set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info, @@ -289,7 +289,7 @@ private: bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info, uint start_no); bool set_up_default_subpartitions(handler *file, HA_CREATE_INFO *info); - char *create_default_partition_names(uint part_no, uint no_parts, + char *create_default_partition_names(uint part_no, uint num_parts, uint start_no); char *create_subpartition_name(uint subpart_no, const char *part_name); bool has_unique_name(partition_element *element); @@ -317,6 +317,6 @@ void init_all_partitions_iterator(partition_info *part_info, PARTITION_ITERATOR *part_iter) { part_iter->part_nums.start= part_iter->part_nums.cur= 0; - part_iter->part_nums.end= part_info->no_parts; + part_iter->part_nums.end= part_info->num_parts; part_iter->get_next= get_next_partition_id_range; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 61f243ece1c..703a97a6565 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1498,7 +1498,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root) keys_onoff(rhs.keys_onoff), tablespace_op(rhs.tablespace_op), partition_names(rhs.partition_names, mem_root), - no_parts(rhs.no_parts), + num_parts(rhs.num_parts), change_level(rhs.change_level), datetime_field(rhs.datetime_field), error_if_not_empty(rhs.error_if_not_empty) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d714e3d0441..3d638689700 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -893,7 +893,7 @@ public: enum enum_enable_or_disable keys_onoff; enum tablespace_op_type tablespace_op; List partition_names; - uint no_parts; + uint num_parts; enum_alter_table_change_level change_level; Create_field *datetime_field; bool error_if_not_empty; @@ -903,7 +903,7 @@ public: flags(0), keys_onoff(LEAVE_AS_IS), tablespace_op(NO_TABLESPACE_OP), - no_parts(0), + num_parts(0), change_level(ALTER_TABLE_METADATA_ONLY), datetime_field(NULL), error_if_not_empty(FALSE) @@ -918,7 +918,7 @@ public: flags= 0; keys_onoff= LEAVE_AS_IS; tablespace_op= NO_TABLESPACE_OP; - no_parts= 0; + num_parts= 0; partition_names.empty(); change_level= ALTER_TABLE_METADATA_ONLY; datetime_field= 0; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 9684e842d40..9a9618108e5 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -202,26 +202,26 @@ bool partition_default_handling(TABLE *table, partition_info *part_info, { DBUG_ENTER("partition_default_handling"); - if (part_info->use_default_no_partitions) + if (part_info->use_default_num_partitions) { if (!is_create_table_ind && - table->file->get_no_parts(normalized_path, &part_info->no_parts)) + table->file->get_no_parts(normalized_path, &part_info->num_parts)) { DBUG_RETURN(TRUE); } } else if (part_info->is_sub_partitioned() && - part_info->use_default_no_subpartitions) + part_info->use_default_num_subpartitions) { - uint no_parts; + uint num_parts; if (!is_create_table_ind && - (table->file->get_no_parts(normalized_path, &no_parts))) + (table->file->get_no_parts(normalized_path, &num_parts))) { DBUG_RETURN(TRUE); } - DBUG_ASSERT(part_info->no_parts > 0); - part_info->no_subparts= no_parts / part_info->no_parts; - DBUG_ASSERT((no_parts % part_info->no_parts) == 0); + DBUG_ASSERT(part_info->num_parts > 0); + part_info->num_subparts= num_parts / part_info->num_parts; + DBUG_ASSERT((num_parts % part_info->num_parts) == 0); } part_info->set_up_defaults_for_partitioning(table->file, (ulonglong)0, (uint)0); @@ -254,8 +254,8 @@ bool check_reorganise_list(partition_info *new_part_info, List list_part_names) { uint new_count, old_count; - uint no_new_parts= new_part_info->partitions.elements; - uint no_old_parts= old_part_info->partitions.elements; + uint num_new_parts= new_part_info->partitions.elements; + uint num_old_parts= old_part_info->partitions.elements; List_iterator new_parts_it(new_part_info->partitions); bool same_part_info= (new_part_info == old_part_info); DBUG_ENTER("check_reorganise_list"); @@ -278,8 +278,8 @@ bool check_reorganise_list(partition_info *new_part_info, if (!is_name_in_list(old_name, list_part_names)) DBUG_RETURN(TRUE); } - } while (old_count < no_old_parts); - } while (new_count < no_new_parts); + } while (old_count < num_old_parts); + } while (new_count < num_new_parts); DBUG_RETURN(FALSE); } @@ -454,7 +454,7 @@ static bool set_up_field_array(TABLE *table, bool is_sub_part) { Field **ptr, *field, **field_array; - uint no_fields= 0; + uint num_fields= 0; uint size_field_array; uint i= 0; uint inx; @@ -466,9 +466,9 @@ static bool set_up_field_array(TABLE *table, while ((field= *(ptr++))) { if (field->flags & GET_FIXED_FIELDS_FLAG) - no_fields++; + num_fields++; } - if (no_fields > MAX_REF_PARTS) + if (num_fields > MAX_REF_PARTS) { char *ptr; if (is_sub_part) @@ -478,7 +478,7 @@ static bool set_up_field_array(TABLE *table, my_error(ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR, MYF(0), ptr); DBUG_RETURN(TRUE); } - if (no_fields == 0) + if (num_fields == 0) { /* We are using hidden key as partitioning field @@ -486,7 +486,7 @@ static bool set_up_field_array(TABLE *table, DBUG_ASSERT(!is_sub_part); DBUG_RETURN(result); } - size_field_array= (no_fields+1)*sizeof(Field*); + size_field_array= (num_fields+1)*sizeof(Field*); field_array= (Field**)sql_calloc(size_field_array); if (unlikely(!field_array)) { @@ -507,15 +507,15 @@ static bool set_up_field_array(TABLE *table, List_iterator it(part_info->part_field_list); char *field_name; - DBUG_ASSERT(no_fields == part_info->part_field_list.elements); + DBUG_ASSERT(num_fields == part_info->part_field_list.elements); inx= 0; do { field_name= it++; if (!strcmp(field_name, field->field_name)) break; - } while (++inx < no_fields); - if (inx == no_fields) + } while (++inx < num_fields); + if (inx == num_fields) { mem_alloc_error(1); result= TRUE; @@ -543,16 +543,16 @@ static bool set_up_field_array(TABLE *table, } } } - field_array[no_fields]= 0; + field_array[num_fields]= 0; if (!is_sub_part) { part_info->part_field_array= field_array; - part_info->no_part_fields= no_fields; + part_info->num_part_fields= num_fields; } else { part_info->subpart_field_array= field_array; - part_info->no_subpart_fields= no_fields; + part_info->num_subpart_fields= num_fields; } DBUG_RETURN(result); } @@ -591,19 +591,19 @@ static bool create_full_part_field_array(THD *thd, TABLE *table, if (!part_info->is_sub_partitioned()) { part_info->full_part_field_array= part_info->part_field_array; - part_info->no_full_part_fields= part_info->no_part_fields; + part_info->num_full_part_fields= part_info->num_part_fields; } else { Field *field, **field_array; - uint no_part_fields=0, size_field_array; + uint num_part_fields=0, size_field_array; ptr= table->field; while ((field= *(ptr++))) { if (field->flags & FIELD_IN_PART_FUNC_FLAG) - no_part_fields++; + num_part_fields++; } - size_field_array= (no_part_fields+1)*sizeof(Field*); + size_field_array= (num_part_fields+1)*sizeof(Field*); field_array= (Field**)sql_calloc(size_field_array); if (unlikely(!field_array)) { @@ -611,16 +611,16 @@ static bool create_full_part_field_array(THD *thd, TABLE *table, result= TRUE; goto end; } - no_part_fields= 0; + num_part_fields= 0; ptr= table->field; while ((field= *(ptr++))) { if (field->flags & FIELD_IN_PART_FUNC_FLAG) - field_array[no_part_fields++]= field; + field_array[num_part_fields++]= field; } - field_array[no_part_fields]=0; + field_array[num_part_fields]=0; part_info->full_part_field_array= field_array; - part_info->no_full_part_fields= no_part_fields; + part_info->num_full_part_fields= num_part_fields; } /* @@ -821,11 +821,11 @@ static bool handle_list_of_fields(List_iterator it, uint primary_key= table->s->primary_key; if (primary_key != MAX_KEY) { - uint no_key_parts= table->key_info[primary_key].key_parts, i; + uint num_key_parts= table->key_info[primary_key].key_parts, i; /* In the case of an empty list we use primary key as partition key. */ - for (i= 0; i < no_key_parts; i++) + for (i= 0; i < num_key_parts; i++) { Field *field= table->key_info[primary_key].key_part[i].field; field->flags|= GET_FIXED_FIELDS_FLAG; @@ -889,7 +889,7 @@ int check_signed_flag(partition_info *part_info) error= ER_PARTITION_CONST_DOMAIN_ERROR; break; } - } while (++i < part_info->no_parts); + } while (++i < part_info->num_parts); } return error; } @@ -946,13 +946,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, bool save_use_only_table_context; DBUG_ENTER("fix_fields_part_func"); - if (part_info->fixed) - { - if (!(is_sub_part || (error= check_signed_flag(part_info)))) - result= FALSE; - goto end; - } - /* Set-up the TABLE_LIST object to be a list with a single table Set the object to zero to create NULL pointers and set alias @@ -1217,9 +1210,9 @@ void check_range_capable_PF(TABLE *table) static bool set_up_partition_bitmap(THD *thd, partition_info *part_info) { uint32 *bitmap_buf; - uint bitmap_bits= part_info->no_subparts? - (part_info->no_subparts* part_info->no_parts): - part_info->no_parts; + uint bitmap_bits= part_info->num_subparts? + (part_info->num_subparts* part_info->num_parts): + part_info->num_parts; uint bitmap_bytes= bitmap_buffer_size(bitmap_bits); DBUG_ENTER("set_up_partition_bitmap"); @@ -1437,22 +1430,22 @@ static void set_up_partition_func_pointers(partition_info *part_info) /* For linear hashing we need a mask which is on the form 2**n - 1 where - 2**n >= no_parts. Thus if no_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7. + 2**n >= num_parts. Thus if num_parts is 6 then mask is 2**3 - 1 = 8 - 1 = 7. SYNOPSIS set_linear_hash_mask() part_info Reference to partitioning data structure - no_parts Number of parts in linear hash partitioning + num_parts Number of parts in linear hash partitioning RETURN VALUE NONE */ -void set_linear_hash_mask(partition_info *part_info, uint no_parts) +void set_linear_hash_mask(partition_info *part_info, uint num_parts) { uint mask; - for (mask= 1; mask < no_parts; mask<<=1) + for (mask= 1; mask < num_parts; mask<<=1) ; part_info->linear_hash_mask= mask - 1; } @@ -1466,7 +1459,7 @@ void set_linear_hash_mask(partition_info *part_info, uint no_parts) get_part_id_from_linear_hash() hash_value Hash value calculated by HASH function or KEY function mask Mask calculated previously by set_linear_hash_mask - no_parts Number of partitions in HASH partitioned part + num_parts Number of partitions in HASH partitioned part RETURN VALUE part_id The calculated partition identity (starting at 0) @@ -1479,11 +1472,11 @@ void set_linear_hash_mask(partition_info *part_info, uint no_parts) */ static uint32 get_part_id_from_linear_hash(longlong hash_value, uint mask, - uint no_parts) + uint num_parts) { uint32 part_id= (uint32)(hash_value & mask); - if (part_id >= no_parts) + if (part_id >= num_parts) { uint new_mask= ((mask + 1) >> 1) - 1; part_id= (uint32)(hash_value & new_mask); @@ -1627,7 +1620,7 @@ bool fix_partition_func(THD *thd, TABLE *table, function is correct. */ if (part_info->linear_hash_ind) - set_linear_hash_mask(part_info, part_info->no_subparts); + set_linear_hash_mask(part_info, part_info->num_subparts); if (part_info->list_of_subpart_fields) { List_iterator it(part_info->subpart_field_list); @@ -1655,7 +1648,7 @@ bool fix_partition_func(THD *thd, TABLE *table, if (part_info->part_type == HASH_PARTITION) { if (part_info->linear_hash_ind) - set_linear_hash_mask(part_info, part_info->no_parts); + set_linear_hash_mask(part_info, part_info->num_parts); if (part_info->list_of_part_fields) { List_iterator it(part_info->part_field_list); @@ -1708,7 +1701,7 @@ bool fix_partition_func(THD *thd, TABLE *table, my_error(ER_INCONSISTENT_PARTITION_INFO_ERROR, MYF(0)); goto end; } - if (unlikely(part_info->no_parts < 1)) + if (unlikely(part_info->num_parts < 1)) { my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_str); goto end; @@ -1852,14 +1845,14 @@ static int add_subpartition_by(File fptr) static int add_part_field_list(File fptr, List field_list) { - uint i, no_fields; + uint i, num_fields; int err= 0; List_iterator part_it(field_list); - no_fields= field_list.elements; + num_fields= field_list.elements; i= 0; err+= add_begin_parenthesis(fptr); - while (i < no_fields) + while (i < num_fields) { const char *field_str= part_it++; String field_string("", 0, system_charset_info); @@ -1870,7 +1863,7 @@ static int add_part_field_list(File fptr, List field_list) strlen(field_str)); thd->options= save_options; err+= add_string_object(fptr, &field_string); - if (i != (no_fields-1)) + if (i != (num_fields-1)) err+= add_comma(fptr); i++; } @@ -1989,10 +1982,10 @@ static int add_column_list_values(File fptr, partition_info *part_info, { int err= 0; uint i; - uint no_elements= part_info->part_field_list.elements; + uint num_elements= part_info->part_field_list.elements; err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); err+= add_begin_parenthesis(fptr); - for (i= 0; i < no_elements; i++) + for (i= 0; i < num_elements; i++) { part_column_list_val *col_val= &list_value->col_val_array[i]; if (col_val->max_value) @@ -2029,7 +2022,7 @@ static int add_column_list_values(File fptr, partition_info *part_info, err+= add_string(fptr,"'"); } } - if (i != (no_elements - 1)) + if (i != (num_elements - 1)) err+= add_string(fptr, comma_str); } err+= add_end_parenthesis(fptr); @@ -2072,13 +2065,13 @@ static int add_partition_values(File fptr, partition_info *part_info, uint i; List_iterator list_val_it(p_elem->list_val_list); err+= add_string(fptr, " VALUES IN "); - uint no_items= p_elem->list_val_list.elements; + uint num_items= p_elem->list_val_list.elements; err+= add_begin_parenthesis(fptr); if (p_elem->has_null_value) { err+= add_string(fptr, "NULL"); - if (no_items == 0) + if (num_items == 0) { err+= add_end_parenthesis(fptr); goto end; @@ -2099,9 +2092,9 @@ static int add_partition_values(File fptr, partition_info *part_info, else err+= add_uint(fptr, list_value->value); } - if (i != (no_items-1)) + if (i != (num_items-1)) err+= add_comma(fptr); - } while (++i < no_items); + } while (++i < num_items); err+= add_end_parenthesis(fptr); } end: @@ -2150,7 +2143,7 @@ char *generate_partition_syntax(partition_info *part_info, bool use_sql_alloc, bool show_partition_options) { - uint i,j, tot_no_parts, no_subparts; + uint i,j, tot_num_parts, num_subparts; partition_element *part_elem; ulonglong buffer_length; char path[FN_REFLEN]; @@ -2207,12 +2200,12 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); err+= add_part_field_list(fptr, part_info->part_field_list); } - if ((!part_info->use_default_no_partitions) && + if ((!part_info->use_default_num_partitions) && part_info->use_default_partitions) { err+= add_string(fptr, "\n"); err+= add_string(fptr, "PARTITIONS "); - err+= add_int(fptr, part_info->no_parts); + err+= add_int(fptr, part_info->num_parts); } if (part_info->is_sub_partitioned()) { @@ -2235,16 +2228,16 @@ char *generate_partition_syntax(partition_info *part_info, part_info->subpart_func_len); err+= add_end_parenthesis(fptr); } - if ((!part_info->use_default_no_subpartitions) && + if ((!part_info->use_default_num_subpartitions) && part_info->use_default_subpartitions) { err+= add_string(fptr, "\n"); err+= add_string(fptr, "SUBPARTITIONS "); - err+= add_int(fptr, part_info->no_subparts); + err+= add_int(fptr, part_info->num_subparts); } } - tot_no_parts= part_info->partitions.elements; - no_subparts= part_info->no_subparts; + tot_num_parts= part_info->partitions.elements; + num_subparts= part_info->num_subparts; if (!part_info->use_default_partitions) { @@ -2288,7 +2281,7 @@ char *generate_partition_syntax(partition_info *part_info, err+= add_name_string(fptr, part_elem->partition_name); if (show_partition_options) err+= add_partition_options(fptr, part_elem); - if (j != (no_subparts-1)) + if (j != (num_subparts-1)) { err+= add_comma(fptr); err+= add_string(fptr, "\n"); @@ -2297,12 +2290,12 @@ char *generate_partition_syntax(partition_info *part_info, } else err+= add_end_parenthesis(fptr); - } while (++j < no_subparts); + } while (++j < num_subparts); } } - if (i == (tot_no_parts-1)) + if (i == (tot_num_parts-1)) err+= add_end_parenthesis(fptr); - } while (++i < tot_no_parts); + } while (++i < tot_num_parts); } if (err) goto close_file; @@ -2449,14 +2442,14 @@ static uint32 calculate_key_value(Field **field_array) get_part_id_for_sub() loc_part_id Local partition id sub_part_id Subpartition id - no_subparts Number of subparts + num_subparts Number of subparts */ inline static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id, - uint no_subparts) + uint num_subparts) { - return (uint32)((loc_part_id * no_subparts) + sub_part_id); + return (uint32)((loc_part_id * num_subparts) + sub_part_id); } @@ -2465,7 +2458,7 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id, SYNOPSIS get_part_id_hash() - no_parts Number of hash partitions + num_parts Number of hash partitions part_expr Item tree of hash function out:part_id The returned partition id out:func_value Value of hash function @@ -2475,7 +2468,7 @@ static uint32 get_part_id_for_sub(uint32 loc_part_id, uint32 sub_part_id, FALSE Success */ -static int get_part_id_hash(uint no_parts, +static int get_part_id_hash(uint num_parts, Item *part_expr, uint32 *part_id, longlong *func_value) @@ -2486,7 +2479,7 @@ static int get_part_id_hash(uint no_parts, if (part_val_int(part_expr, func_value)) DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); - int_hash_id= *func_value % no_parts; + int_hash_id= *func_value % num_parts; *part_id= int_hash_id < 0 ? (uint32) -int_hash_id : (uint32) int_hash_id; DBUG_RETURN(FALSE); @@ -2500,7 +2493,7 @@ static int get_part_id_hash(uint no_parts, get_part_id_linear_hash() part_info A reference to the partition_info struct where all the desired information is given - no_parts Number of hash partitions + num_parts Number of hash partitions part_expr Item tree of hash function out:part_id The returned partition id out:func_value Value of hash function @@ -2511,7 +2504,7 @@ static int get_part_id_hash(uint no_parts, */ static int get_part_id_linear_hash(partition_info *part_info, - uint no_parts, + uint num_parts, Item *part_expr, uint32 *part_id, longlong *func_value) @@ -2523,7 +2516,7 @@ static int get_part_id_linear_hash(partition_info *part_info, *part_id= get_part_id_from_linear_hash(*func_value, part_info->linear_hash_mask, - no_parts); + num_parts); DBUG_RETURN(FALSE); } @@ -2534,7 +2527,7 @@ static int get_part_id_linear_hash(partition_info *part_info, SYNOPSIS get_part_id_key() field_array Array of fields for PARTTION KEY - no_parts Number of KEY partitions + num_parts Number of KEY partitions RETURN VALUE Calculated partition id @@ -2542,12 +2535,12 @@ static int get_part_id_linear_hash(partition_info *part_info, inline static uint32 get_part_id_key(Field **field_array, - uint no_parts, + uint num_parts, longlong *func_value) { DBUG_ENTER("get_part_id_key"); *func_value= calculate_key_value(field_array); - DBUG_RETURN((uint32) (*func_value % no_parts)); + DBUG_RETURN((uint32) (*func_value % num_parts)); } @@ -2559,7 +2552,7 @@ static uint32 get_part_id_key(Field **field_array, part_info A reference to the partition_info struct where all the desired information is given field_array Array of fields for PARTTION KEY - no_parts Number of KEY partitions + num_parts Number of KEY partitions RETURN VALUE Calculated partition id @@ -2568,7 +2561,7 @@ static uint32 get_part_id_key(Field **field_array, inline static uint32 get_part_id_linear_key(partition_info *part_info, Field **field_array, - uint no_parts, + uint num_parts, longlong *func_value) { DBUG_ENTER("get_part_id_linear_key"); @@ -2576,7 +2569,7 @@ static uint32 get_part_id_linear_key(partition_info *part_info, *func_value= calculate_key_value(field_array); DBUG_RETURN(get_part_id_from_linear_hash(*func_value, part_info->linear_hash_mask, - no_parts)); + num_parts)); } /* @@ -2772,17 +2765,17 @@ int get_partition_id_list_col(partition_info *part_info, longlong *func_value) { part_column_list_val *list_col_array= part_info->list_col_array; - uint no_columns= part_info->part_field_list.elements; + uint num_columns= part_info->part_field_list.elements; int list_index, cmp; int min_list_index= 0; - int max_list_index= part_info->no_list_values - 1; + int max_list_index= part_info->num_list_values - 1; DBUG_ENTER("get_partition_id_list_col"); while (max_list_index >= min_list_index) { list_index= (max_list_index + min_list_index) >> 1; - cmp= cmp_rec_and_tuple(list_col_array + list_index*no_columns, - no_columns); + cmp= cmp_rec_and_tuple(list_col_array + list_index*num_columns, + num_columns); if (cmp > 0) min_list_index= list_index + 1; else if (cmp < 0) @@ -2810,7 +2803,7 @@ int get_partition_id_list(partition_info *part_info, LIST_PART_ENTRY *list_array= part_info->list_array; int list_index; int min_list_index= 0; - int max_list_index= part_info->no_list_values - 1; + int max_list_index= part_info->num_list_values - 1; longlong part_func_value; int error= part_val_int(part_info->part_expr, &part_func_value); longlong list_value; @@ -2880,7 +2873,7 @@ notfound: 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 + If all array elements are contained, part_info->num_list_values is returned. NOTE @@ -2900,17 +2893,17 @@ uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info, uint32 nparts) { part_column_list_val *list_col_array= part_info->list_col_array; - uint no_columns= part_info->part_field_list.elements; + uint num_columns= part_info->part_field_list.elements; int list_index, cmp; uint min_list_index= 0; - uint max_list_index= part_info->no_list_values - 1; + uint max_list_index= part_info->num_list_values - 1; bool tailf= !(left_endpoint ^ include_endpoint); DBUG_ENTER("get_partition_id_cols_list_for_endpoint"); do { list_index= (max_list_index + min_list_index) >> 1; - cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*no_columns, + cmp= cmp_rec_and_tuple_prune(list_col_array + list_index*num_columns, nparts, tailf); if (cmp > 0) min_list_index= list_index + 1; @@ -2953,7 +2946,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, { LIST_PART_ENTRY *list_array= part_info->list_array; uint list_index; - uint min_list_index= 0, max_list_index= part_info->no_list_values - 1; + uint min_list_index= 0, max_list_index= part_info->num_list_values - 1; longlong list_value; /* Get the partitioning function value for the endpoint */ longlong part_func_value= @@ -2967,7 +2960,7 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, } if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; - DBUG_ASSERT(part_info->no_list_values); + DBUG_ASSERT(part_info->num_list_values); do { list_index= (max_list_index + min_list_index) >> 1; @@ -2997,8 +2990,8 @@ int get_partition_id_range_col(partition_info *part_info, longlong *func_value) { part_column_list_val *range_col_array= part_info->range_col_array; - uint no_columns= part_info->part_field_list.elements; - uint max_partition= part_info->no_parts - 1; + uint num_columns= part_info->part_field_list.elements; + uint max_partition= part_info->num_parts - 1; uint min_part_id= 0; uint max_part_id= max_partition; uint loc_part_id; @@ -3007,21 +3000,21 @@ int get_partition_id_range_col(partition_info *part_info, while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id + 1) >> 1; - if (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, - no_columns) >= 0) + if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns, + num_columns) >= 0) 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) - if (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, - no_columns) >= 0) + if (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns, + num_columns) >= 0) loc_part_id++; *part_id= (uint32)loc_part_id; if (loc_part_id == max_partition && - (cmp_rec_and_tuple(range_col_array + loc_part_id*no_columns, - no_columns) >= 0)) + (cmp_rec_and_tuple(range_col_array + loc_part_id*num_columns, + num_columns) >= 0)) DBUG_RETURN(HA_ERR_NO_PARTITION_FOUND); DBUG_PRINT("exit",("partition: %d", *part_id)); @@ -3035,7 +3028,7 @@ int get_partition_id_range(partition_info *part_info, longlong *func_value) { longlong *range_array= part_info->range_int_array; - uint max_partition= part_info->no_parts - 1; + uint max_partition= part_info->num_parts - 1; uint min_part_id= 0; uint max_part_id= max_partition; uint loc_part_id; @@ -3112,7 +3105,7 @@ int get_partition_id_range(partition_info *part_info, 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 + intersection with the passed interval, part_info->num_parts is returned. RETURN @@ -3140,7 +3133,7 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, bool include_endpoint) { longlong *range_array= part_info->range_int_array; - uint max_partition= part_info->no_parts - 1; + uint max_partition= part_info->num_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= @@ -3205,7 +3198,7 @@ int get_partition_id_hash_nosub(partition_info *part_info, uint32 *part_id, longlong *func_value) { - return get_part_id_hash(part_info->no_parts, part_info->part_expr, + return get_part_id_hash(part_info->num_parts, part_info->part_expr, part_id, func_value); } @@ -3214,7 +3207,7 @@ int get_partition_id_linear_hash_nosub(partition_info *part_info, uint32 *part_id, longlong *func_value) { - return get_part_id_linear_hash(part_info, part_info->no_parts, + return get_part_id_linear_hash(part_info, part_info->num_parts, part_info->part_expr, part_id, func_value); } @@ -3224,7 +3217,7 @@ int get_partition_id_key_nosub(partition_info *part_info, longlong *func_value) { *part_id= get_part_id_key(part_info->part_field_array, - part_info->no_parts, func_value); + part_info->num_parts, func_value); return 0; } @@ -3235,7 +3228,7 @@ int get_partition_id_linear_key_nosub(partition_info *part_info, { *part_id= get_part_id_linear_key(part_info, part_info->part_field_array, - part_info->no_parts, func_value); + part_info->num_parts, func_value); return 0; } @@ -3245,7 +3238,7 @@ int get_partition_id_with_sub(partition_info *part_info, longlong *func_value) { uint32 loc_part_id, sub_part_id; - uint no_subparts; + uint num_subparts; int error; DBUG_ENTER("get_partition_id_with_sub"); @@ -3255,13 +3248,13 @@ int get_partition_id_with_sub(partition_info *part_info, { DBUG_RETURN(error); } - no_subparts= part_info->no_subparts; + num_subparts= part_info->num_subparts; if (unlikely((error= part_info->get_subpartition_id(part_info, &sub_part_id)))) { DBUG_RETURN(error); } - *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, no_subparts); + *part_id= get_part_id_for_sub(loc_part_id, sub_part_id, num_subparts); DBUG_RETURN(0); } @@ -3294,7 +3287,7 @@ int get_partition_id_hash_sub(partition_info *part_info, uint32 *part_id) { longlong func_value; - return get_part_id_hash(part_info->no_subparts, part_info->subpart_expr, + return get_part_id_hash(part_info->num_subparts, part_info->subpart_expr, part_id, &func_value); } @@ -3303,7 +3296,7 @@ int get_partition_id_linear_hash_sub(partition_info *part_info, uint32 *part_id) { longlong func_value; - return get_part_id_linear_hash(part_info, part_info->no_subparts, + return get_part_id_linear_hash(part_info, part_info->num_subparts, part_info->subpart_expr, part_id, &func_value); } @@ -3314,7 +3307,7 @@ int get_partition_id_key_sub(partition_info *part_info, { longlong func_value; *part_id= get_part_id_key(part_info->subpart_field_array, - part_info->no_subparts, &func_value); + part_info->num_subparts, &func_value); return FALSE; } @@ -3325,7 +3318,7 @@ int get_partition_id_linear_key_sub(partition_info *part_info, longlong func_value; *part_id= get_part_id_linear_key(part_info, part_info->subpart_field_array, - part_info->no_subparts, &func_value); + part_info->num_subparts, &func_value); return FALSE; } @@ -3624,16 +3617,16 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, const key_range *key_spec, part_id_range *part_spec) { partition_info *part_info= table->part_info; - uint no_parts= part_info->get_tot_partitions(); + uint num_parts= part_info->get_tot_partitions(); uint i, part_id; - uint sub_part= no_parts; - uint32 part_part= no_parts; + uint sub_part= num_parts; + uint32 part_part= num_parts; KEY *key_info= NULL; bool found_part_field= FALSE; DBUG_ENTER("get_partition_set"); part_spec->start_part= 0; - part_spec->end_part= no_parts - 1; + part_spec->end_part= num_parts - 1; if ((index < MAX_KEY) && key_spec->flag == (uint)HA_READ_KEY_EXACT && part_info->some_fields_in_PF.is_set(index)) @@ -3670,7 +3663,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, { if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part)) { - part_spec->start_part= no_parts; + part_spec->start_part= num_parts; DBUG_VOID_RETURN; } } @@ -3684,7 +3677,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, allowed values. Thus it is certain that the result of this scan will be empty. */ - part_spec->start_part= no_parts; + part_spec->start_part= num_parts; DBUG_VOID_RETURN; } } @@ -3722,7 +3715,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, { if (get_sub_part_id_from_key(table, buf, key_info, key_spec, &sub_part)) { - part_spec->start_part= no_parts; + part_spec->start_part= num_parts; clear_indicator_in_key_fields(key_info); DBUG_VOID_RETURN; } @@ -3731,7 +3724,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, { if (get_part_id_from_key(table,buf,key_info,key_spec,&part_part)) { - part_spec->start_part= no_parts; + part_spec->start_part= num_parts; clear_indicator_in_key_fields(key_info); DBUG_VOID_RETURN; } @@ -3752,29 +3745,29 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, nothing or we have discovered a range of partitions with possible holes in it. We need a bitvector to further the work here. */ - if (!(part_part == no_parts && sub_part == no_parts)) + if (!(part_part == num_parts && sub_part == num_parts)) { /* We can only arrive here if we are using subpartitioning. */ - if (part_part != no_parts) + if (part_part != num_parts) { /* We know the top partition and need to scan all underlying subpartitions. This is a range without holes. */ - DBUG_ASSERT(sub_part == no_parts); - part_spec->start_part= part_part * part_info->no_subparts; - part_spec->end_part= part_spec->start_part+part_info->no_subparts - 1; + DBUG_ASSERT(sub_part == num_parts); + part_spec->start_part= part_part * part_info->num_subparts; + part_spec->end_part= part_spec->start_part+part_info->num_subparts - 1; } else { - DBUG_ASSERT(sub_part != no_parts); + DBUG_ASSERT(sub_part != num_parts); part_spec->start_part= sub_part; part_spec->end_part=sub_part+ - (part_info->no_subparts*(part_info->no_parts-1)); - for (i= 0, part_id= sub_part; i < part_info->no_parts; - i++, part_id+= part_info->no_subparts) + (part_info->num_subparts*(part_info->num_parts-1)); + for (i= 0, part_id= sub_part; i < part_info->num_parts; + i++, part_id+= part_info->num_subparts) ; //Set bit part_id in bit array } } @@ -4038,9 +4031,9 @@ set_engine_all_partitions(partition_info *part_info, partition_element *sub_elem= sub_it++; sub_elem->engine_type= engine_type; - } while (++j < part_info->no_subparts); + } while (++j < part_info->num_subparts); } - } while (++i < part_info->no_parts); + } while (++i < part_info->num_parts); } /* SYNOPSIS @@ -4185,7 +4178,7 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info, enum partition_state part_state) { uint part_count= 0; - uint no_parts_found= 0; + uint num_parts_found= 0; List_iterator part_it(tab_part_info->partitions); do @@ -4200,13 +4193,13 @@ uint set_part_state(Alter_info *alter_info, partition_info *tab_part_info, I.e mark the partition as a partition to be "changed" by analyzing/optimizing/rebuilding/checking/repairing */ - no_parts_found++; + num_parts_found++; part_elem->part_state= part_state; DBUG_PRINT("info", ("Setting part_state to %u for partition %s", part_state, part_elem->partition_name)); } - } while (++part_count < tab_part_info->no_parts); - return no_parts_found; + } while (++part_count < tab_part_info->num_parts); + return num_parts_found; } @@ -4287,13 +4280,13 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, { uint new_part_no, curr_part_no; if (tab_part_info->part_type != HASH_PARTITION || - tab_part_info->use_default_no_partitions) + tab_part_info->use_default_num_partitions) { my_error(ER_REORG_NO_PARAM_ERROR, MYF(0)); DBUG_RETURN(TRUE); } new_part_no= table->file->get_default_no_partitions(create_info); - curr_part_no= tab_part_info->no_parts; + curr_part_no= tab_part_info->num_parts; if (new_part_no == curr_part_no) { /* @@ -4311,7 +4304,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, setting the flag for no default number of partitions */ alter_info->flags|= ALTER_ADD_PARTITION; - thd->work_part_info->no_parts= new_part_no - curr_part_no; + thd->work_part_info->num_parts= new_part_no - curr_part_no; } else { @@ -4320,7 +4313,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, without setting the flag for no default number of partitions */ alter_info->flags|= ALTER_COALESCE_PARTITION; - alter_info->no_parts= curr_part_no - new_part_no; + alter_info->num_parts= curr_part_no - new_part_no; } } if (!(flags= table->file->alter_table_flags(alter_info->flags))) @@ -4378,9 +4371,9 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, partitioning scheme as currently set-up. Partitions are always added at the end in ADD PARTITION. */ - uint no_new_partitions= alt_part_info->no_parts; - uint no_orig_partitions= tab_part_info->no_parts; - uint check_total_partitions= no_new_partitions + no_orig_partitions; + uint num_new_partitions= alt_part_info->num_parts; + uint num_orig_partitions= tab_part_info->num_parts; + uint check_total_partitions= num_new_partitions + num_orig_partitions; uint new_total_partitions= check_total_partitions; /* We allow quite a lot of values to be supplied by defaults, however we @@ -4397,22 +4390,22 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0)); DBUG_RETURN(TRUE); } - if (no_new_partitions == 0) + if (num_new_partitions == 0) { my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0)); DBUG_RETURN(TRUE); } if (tab_part_info->is_sub_partitioned()) { - if (alt_part_info->no_subparts == 0) - alt_part_info->no_subparts= tab_part_info->no_subparts; - else if (alt_part_info->no_subparts != tab_part_info->no_subparts) + if (alt_part_info->num_subparts == 0) + alt_part_info->num_subparts= tab_part_info->num_subparts; + else if (alt_part_info->num_subparts != tab_part_info->num_subparts) { my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0)); DBUG_RETURN(TRUE); } check_total_partitions= new_total_partitions* - alt_part_info->no_subparts; + alt_part_info->num_subparts; } if (check_total_partitions > MAX_PARTITIONS) { @@ -4422,8 +4415,8 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, alt_part_info->part_type= tab_part_info->part_type; alt_part_info->subpart_type= tab_part_info->subpart_type; if (alt_part_info->set_up_defaults_for_partitioning(table->file, - ULL(0), - tab_part_info->no_parts)) + ULL(0), + tab_part_info->num_parts)) { DBUG_RETURN(TRUE); } @@ -4498,7 +4491,7 @@ that are reorganised. uint lower_2n= upper_2n >> 1; bool all_parts= TRUE; if (tab_part_info->linear_hash_ind && - no_new_partitions < upper_2n) + num_new_partitions < upper_2n) { /* An analysis of which parts needs reorganisation shows that it is @@ -4507,7 +4500,7 @@ that are reorganised. onwards it starts again from partition 0 and goes on until it reaches p(upper_2n - 1). If the last new partition reaches beyond upper_2n - 1 then the first interval will end with - p(lower_2n - 1) and start with p(no_orig_partitions - lower_2n). + p(lower_2n - 1) and start with p(num_orig_partitions - lower_2n). If lower_2n partitions are added then p0 to p(lower_2n - 1) will be reorganised which means that the two interval becomes one interval at this point. Thus only when adding less than @@ -4535,7 +4528,7 @@ that are reorganised. to TRUE. In this case we don't get into this if-part at all. */ all_parts= FALSE; - if (no_new_partitions >= lower_2n) + if (num_new_partitions >= lower_2n) { /* In this case there is only one interval since the two intervals @@ -4551,8 +4544,8 @@ that are reorganised. Also in this case there is only one interval since we are not going over a 2**n boundary */ - start_part= no_orig_partitions - lower_2n; - end_part= start_part + (no_new_partitions - 1); + start_part= num_orig_partitions - lower_2n; + end_part= start_part + (num_new_partitions - 1); } else { @@ -4561,7 +4554,7 @@ that are reorganised. new parts that would ensure that the intervals become overlapping. */ - start_part= no_orig_partitions - lower_2n; + start_part= num_orig_partitions - lower_2n; end_part= upper_2n - 1; start_sec_part= 0; end_sec_part= new_total_partitions - (upper_2n + 1); @@ -4578,7 +4571,7 @@ that are reorganised. { p_elem->part_state= PART_CHANGED; } - } while (++part_no < no_orig_partitions); + } while (++part_no < num_orig_partitions); } /* Need to concatenate the lists here to make it possible to check the @@ -4601,8 +4594,8 @@ that are reorganised. mem_alloc_error(1); DBUG_RETURN(TRUE); } - } while (++part_count < no_new_partitions); - tab_part_info->no_parts+= no_new_partitions; + } while (++part_count < num_new_partitions); + tab_part_info->num_parts+= num_new_partitions; } /* If we specify partitions explicitly we don't use defaults anymore. @@ -4617,7 +4610,7 @@ that are reorganised. DBUG_PRINT("info", ("part_info: 0x%lx", (long) tab_part_info)); tab_part_info->use_default_partitions= FALSE; } - tab_part_info->use_default_no_partitions= FALSE; + tab_part_info->use_default_num_partitions= FALSE; tab_part_info->is_auto_partitioned= FALSE; } } @@ -4631,8 +4624,8 @@ that are reorganised. command to drop the partition failed in the middle. */ uint part_count= 0; - uint no_parts_dropped= alter_info->partition_names.elements; - uint no_parts_found= 0; + uint num_parts_dropped= alter_info->partition_names.elements; + uint num_parts_found= 0; List_iterator part_it(tab_part_info->partitions); tab_part_info->is_auto_partitioned= FALSE; @@ -4642,7 +4635,7 @@ that are reorganised. my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP"); DBUG_RETURN(TRUE); } - if (no_parts_dropped >= tab_part_info->no_parts) + if (num_parts_dropped >= tab_part_info->num_parts) { my_error(ER_DROP_LAST_PARTITION, MYF(0)); DBUG_RETURN(TRUE); @@ -4656,11 +4649,11 @@ that are reorganised. /* Set state to indicate that the partition is to be dropped. */ - no_parts_found++; + num_parts_found++; part_elem->part_state= PART_TO_BE_DROPPED; } - } while (++part_count < tab_part_info->no_parts); - if (no_parts_found != no_parts_dropped) + } while (++part_count < tab_part_info->num_parts); + if (num_parts_found != num_parts_dropped) { my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "DROP"); DBUG_RETURN(TRUE); @@ -4670,14 +4663,14 @@ that are reorganised. my_error(ER_ROW_IS_REFERENCED, MYF(0)); DBUG_RETURN(TRUE); } - tab_part_info->no_parts-= no_parts_dropped; + tab_part_info->num_parts-= num_parts_dropped; } else if (alter_info->flags & ALTER_REBUILD_PARTITION) { - uint no_parts_found; - uint no_parts_opt= alter_info->partition_names.elements; - no_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED); - if (no_parts_found != no_parts_opt && + uint num_parts_found; + uint num_parts_opt= alter_info->partition_names.elements; + num_parts_found= set_part_state(alter_info, tab_part_info, PART_CHANGED); + if (num_parts_found != num_parts_opt && (!(alter_info->flags & ALTER_ALL_PARTITION))) { my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REBUILD"); @@ -4691,20 +4684,20 @@ that are reorganised. } else if (alter_info->flags & ALTER_COALESCE_PARTITION) { - uint no_parts_coalesced= alter_info->no_parts; - uint no_parts_remain= tab_part_info->no_parts - no_parts_coalesced; + uint num_parts_coalesced= alter_info->num_parts; + uint num_parts_remain= tab_part_info->num_parts - num_parts_coalesced; List_iterator part_it(tab_part_info->partitions); if (tab_part_info->part_type != HASH_PARTITION) { my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0)); DBUG_RETURN(TRUE); } - if (no_parts_coalesced == 0) + if (num_parts_coalesced == 0) { my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0)); DBUG_RETURN(TRUE); } - if (no_parts_coalesced >= tab_part_info->no_parts) + if (num_parts_coalesced >= tab_part_info->num_parts) { my_error(ER_DROP_LAST_PARTITION, MYF(0)); DBUG_RETURN(TRUE); @@ -4752,21 +4745,21 @@ state of p1. uint upper_2n= tab_part_info->linear_hash_mask + 1; uint lower_2n= upper_2n >> 1; all_parts= FALSE; - if (no_parts_coalesced >= lower_2n) + if (num_parts_coalesced >= lower_2n) { all_parts= TRUE; } - else if (no_parts_remain >= lower_2n) + else if (num_parts_remain >= lower_2n) { - end_part= tab_part_info->no_parts - (lower_2n + 1); - start_part= no_parts_remain - lower_2n; + end_part= tab_part_info->num_parts - (lower_2n + 1); + start_part= num_parts_remain - lower_2n; } else { start_part= 0; - end_part= tab_part_info->no_parts - (lower_2n + 1); + end_part= tab_part_info->num_parts - (lower_2n + 1); end_sec_part= (lower_2n >> 1) - 1; - start_sec_part= end_sec_part - (lower_2n - (no_parts_remain + 1)); + start_sec_part= end_sec_part - (lower_2n - (num_parts_remain + 1)); } } do @@ -4777,19 +4770,19 @@ state of p1. (part_count >= start_part && part_count <= end_part) || (part_count >= start_sec_part && part_count <= end_sec_part))) p_elem->part_state= PART_CHANGED; - if (++part_count > no_parts_remain) + if (++part_count > num_parts_remain) { if (*fast_alter_partition) p_elem->part_state= PART_REORGED_DROPPED; else part_it.remove(); } - } while (part_count < tab_part_info->no_parts); - tab_part_info->no_parts= no_parts_remain; + } while (part_count < tab_part_info->num_parts); + tab_part_info->num_parts= num_parts_remain; } if (!(alter_info->flags & ALTER_TABLE_REORG)) { - tab_part_info->use_default_no_partitions= FALSE; + tab_part_info->use_default_num_partitions= FALSE; tab_part_info->is_auto_partitioned= FALSE; } } @@ -4806,32 +4799,32 @@ state of p1. range as those changed from. This command can be used on RANGE and LIST partitions. */ - uint no_parts_reorged= alter_info->partition_names.elements; - uint no_parts_new= thd->work_part_info->partitions.elements; + uint num_parts_reorged= alter_info->partition_names.elements; + uint num_parts_new= thd->work_part_info->partitions.elements; uint check_total_partitions; tab_part_info->is_auto_partitioned= FALSE; - if (no_parts_reorged > tab_part_info->no_parts) + if (num_parts_reorged > tab_part_info->num_parts) { my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0)); DBUG_RETURN(TRUE); } if (!(tab_part_info->part_type == RANGE_PARTITION || tab_part_info->part_type == LIST_PARTITION) && - (no_parts_new != no_parts_reorged)) + (num_parts_new != num_parts_reorged)) { my_error(ER_REORG_HASH_ONLY_ON_SAME_NO, MYF(0)); DBUG_RETURN(TRUE); } if (tab_part_info->is_sub_partitioned() && - alt_part_info->no_subparts && - alt_part_info->no_subparts != tab_part_info->no_subparts) + alt_part_info->num_subparts && + alt_part_info->num_subparts != tab_part_info->num_subparts) { my_error(ER_PARTITION_WRONG_NO_SUBPART_ERROR, MYF(0)); DBUG_RETURN(TRUE); } - check_total_partitions= tab_part_info->no_parts + no_parts_new; - check_total_partitions-= no_parts_reorged; + check_total_partitions= tab_part_info->num_parts + num_parts_new; + check_total_partitions-= num_parts_reorged; if (check_total_partitions > MAX_PARTITIONS) { my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); @@ -4839,7 +4832,7 @@ state of p1. } alt_part_info->part_type= tab_part_info->part_type; alt_part_info->subpart_type= tab_part_info->subpart_type; - alt_part_info->no_subparts= tab_part_info->no_subparts; + alt_part_info->num_subparts= tab_part_info->num_subparts; DBUG_ASSERT(!alt_part_info->use_default_partitions); if (alt_part_info->set_up_defaults_for_partitioning(table->file, ULL(0), @@ -4936,7 +4929,7 @@ the generated partition syntax in a correct manner. tab_it.replace(alt_part_elem); else tab_it.after(alt_part_elem); - } while (++alt_part_count < no_parts_new); + } while (++alt_part_count < num_parts_new); } else if (found_last) { @@ -4951,13 +4944,13 @@ the generated partition syntax in a correct manner. if (found_first) found_last= TRUE; } - } while (++part_count < tab_part_info->no_parts); - if (drop_count != no_parts_reorged) + } while (++part_count < tab_part_info->num_parts); + if (drop_count != num_parts_reorged) { my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0), "REORGANIZE"); DBUG_RETURN(TRUE); } - tab_part_info->no_parts= check_total_partitions; + tab_part_info->num_parts= check_total_partitions; } } else @@ -4973,7 +4966,7 @@ the generated partition syntax in a correct manner. !alt_part_info->use_default_subpartitions) { tab_part_info->use_default_subpartitions= FALSE; - tab_part_info->use_default_no_subpartitions= FALSE; + tab_part_info->use_default_num_subpartitions= FALSE; } if (tab_part_info->check_partition_info(thd, (handlerton**)NULL, table->file, ULL(0), TRUE)) @@ -5285,8 +5278,8 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) part_it.remove(); remove_count++; } - } while (++i < part_info->no_parts); - part_info->no_parts-= remove_count; + } while (++i < part_info->num_parts); + part_info->num_parts-= remove_count; DBUG_RETURN(FALSE); } @@ -5408,7 +5401,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, char normal_path[FN_REFLEN]; List_iterator part_it(part_info->partitions); uint temp_partitions= part_info->temp_partitions.elements; - uint no_elements= part_info->partitions.elements; + uint num_elements= part_info->partitions.elements; uint i= 0; DBUG_ENTER("write_log_changed_partitions"); @@ -5421,7 +5414,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, if (part_info->is_sub_partitioned()) { List_iterator sub_it(part_elem->subpartitions); - uint no_subparts= part_info->no_subparts; + uint num_subparts= part_info->num_subparts; uint j= 0; do { @@ -5450,7 +5443,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, *next_entry= log_entry->entry_pos; sub_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -5478,7 +5471,7 @@ static bool write_log_changed_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, insert_part_info_log_entry_list(part_info, log_entry); } } - } while (++i < no_elements); + } while (++i < num_elements); DBUG_RETURN(FALSE); } @@ -5504,14 +5497,14 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, char tmp_path[FN_LEN]; List_iterator part_it(part_info->partitions); List_iterator temp_it(part_info->temp_partitions); - uint no_temp_partitions= part_info->temp_partitions.elements; - uint no_elements= part_info->partitions.elements; + uint num_temp_partitions= part_info->temp_partitions.elements; + uint num_elements= part_info->partitions.elements; DBUG_ENTER("write_log_dropped_partitions"); ddl_log_entry.action_type= DDL_LOG_DELETE_ACTION; if (temp_list) - no_elements= no_temp_partitions; - while (no_elements--) + num_elements= num_temp_partitions; + while (num_elements--) { partition_element *part_elem; if (temp_list) @@ -5525,14 +5518,14 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, uint name_variant; if (part_elem->part_state == PART_CHANGED || (part_elem->part_state == PART_TO_BE_ADDED && - no_temp_partitions)) + num_temp_partitions)) name_variant= TEMP_PART_NAME; else name_variant= NORMAL_PART_NAME; if (part_info->is_sub_partitioned()) { List_iterator sub_it(part_elem->subpartitions); - uint no_subparts= part_info->no_subparts; + uint num_subparts= part_info->num_subparts; uint j= 0; do { @@ -5552,7 +5545,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, *next_entry= log_entry->entry_pos; sub_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); - } while (++j < no_subparts); + } while (++j < num_subparts); } else { @@ -6705,7 +6698,7 @@ static void set_up_range_analysis_info(partition_info *part_info) Check if get_part_iter_for_interval_via_walking() can be used for partitioning */ - if (part_info->no_part_fields == 1) + if (part_info->num_part_fields == 1) { Field *field= part_info->part_field_array[0]; switch (field->type()) { @@ -6727,7 +6720,7 @@ setup_subparts: Check if get_part_iter_for_interval_via_walking() can be used for subpartitioning */ - if (part_info->no_subpart_fields == 1) + if (part_info->num_subpart_fields == 1) { Field *field= part_info->subpart_field_array[0]; switch (field->type()) { @@ -6841,7 +6834,7 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint, typedef uint32 (*get_col_endpoint_func)(partition_info*, bool left_endpoint, bool include_endpoint, - uint32 no_parts); + uint32 num_parts); /* Partitioning Interval Analysis: Initialize the iterator for "mapping" case @@ -6883,10 +6876,10 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, bool include_endpoint, uint32 nparts) { - uint max_partition= part_info->no_parts - 1; + uint max_partition= part_info->num_parts - 1; uint min_part_id= 0, max_part_id= max_partition, loc_part_id; part_column_list_val *range_col_array= part_info->range_col_array; - uint no_columns= part_info->part_field_list.elements; + uint num_columns= part_info->part_field_list.elements; bool tailf= !(left_endpoint ^ include_endpoint); DBUG_ENTER("get_partition_id_cols_range_for_endpoint"); @@ -6894,7 +6887,7 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, while (max_part_id > min_part_id) { loc_part_id= (max_part_id + min_part_id + 1) >> 1; - if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*no_columns, + if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns, nparts, tailf) >= 0) min_part_id= loc_part_id + 1; else @@ -6902,7 +6895,7 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, } loc_part_id= max_part_id; if (loc_part_id < max_partition && - cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*no_columns, + cmp_rec_and_tuple_prune(range_col_array + (loc_part_id+1)*num_columns, nparts, tailf) >= 0 ) { @@ -6910,7 +6903,7 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, } if (left_endpoint) { - if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*no_columns, + if (cmp_rec_and_tuple_prune(range_col_array + loc_part_id*num_columns, nparts, tailf) >= 0) loc_part_id++; } @@ -6919,7 +6912,7 @@ uint32 get_partition_id_cols_range_for_endpoint(partition_info *part_info, if (loc_part_id < max_partition) { int res= cmp_rec_and_tuple_prune(range_col_array + - loc_part_id * no_columns, + loc_part_id * num_columns, nparts, tailf); if (!res) loc_part_id += test(include_endpoint); @@ -6969,7 +6962,7 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, nparts); } if (flags & NO_MAX_RANGE) - part_iter->part_nums.end= part_info->no_parts; + part_iter->part_nums.end= part_info->num_parts; else { // Copy from max_value to record @@ -7012,7 +7005,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, get_endpoint= get_partition_id_range_for_endpoint_charset; else get_endpoint= get_partition_id_range_for_endpoint; - max_endpoint_val= part_info->no_parts; + max_endpoint_val= part_info->num_parts; part_iter->get_next= get_next_partition_id_range; } else if (part_info->part_type == LIST_PARTITION) @@ -7022,7 +7015,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, get_endpoint= get_list_array_idx_for_endpoint_charset; else get_endpoint= get_list_array_idx_for_endpoint; - max_endpoint_val= part_info->no_list_values; + max_endpoint_val= part_info->num_list_values; part_iter->get_next= get_next_partition_id_list; part_iter->part_info= part_info; if (max_endpoint_val == 0) @@ -7166,13 +7159,13 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, if (is_subpart) { field= part_info->subpart_field_array[0]; - total_parts= part_info->no_subparts; + total_parts= part_info->num_subparts; get_next_func= get_next_subpartition_via_walking; } else { field= part_info->part_field_array[0]; - total_parts= part_info->no_parts; + total_parts= part_info->num_parts; get_next_func= get_next_partition_via_walking; } diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 7902cc77877..8fce2ebe6d1 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -65,7 +65,7 @@ int get_part_for_delete(const uchar *buf, const uchar *rec0, void prune_partition_set(const TABLE *table, part_id_range *part_spec); bool check_partition_info(partition_info *part_info,handlerton **eng_type, TABLE *table, handler *file, HA_CREATE_INFO *info); -void set_linear_hash_mask(partition_info *part_info, uint no_parts); +void set_linear_hash_mask(partition_info *part_info, uint num_parts); bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind); char *generate_partition_syntax(partition_info *part_info, uint *buf_length, bool use_sql_alloc, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index fce51c7e3da..efc75db8e02 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3700,9 +3700,9 @@ bool mysql_create_table_no_lock(THD *thd, creates a proper .par file. The current part_info object is only used to create the frm-file and .par-file. */ - if (part_info->use_default_no_partitions && - part_info->no_parts && - (int)part_info->no_parts != + if (part_info->use_default_num_partitions && + part_info->num_parts && + (int)part_info->num_parts != file->get_default_no_partitions(create_info)) { uint i; @@ -3713,13 +3713,13 @@ bool mysql_create_table_no_lock(THD *thd, (part_it++)->part_state= PART_TO_BE_DROPPED; } else if (part_info->is_sub_partitioned() && - part_info->use_default_no_subpartitions && - part_info->no_subparts && - (int)part_info->no_subparts != + part_info->use_default_num_subpartitions && + part_info->num_subparts && + (int)part_info->num_subparts != file->get_default_no_partitions(create_info)) { DBUG_ASSERT(thd->lex->sql_command != SQLCOM_CREATE_TABLE); - part_info->no_subparts= file->get_default_no_partitions(create_info); + part_info->num_subparts= file->get_default_no_partitions(create_info); } } else if (create_info->db_type != engine_type) @@ -4531,11 +4531,11 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); DBUG_RETURN(TRUE); } - uint no_parts_found; - uint no_parts_opt= alter_info->partition_names.elements; - no_parts_found= set_part_state(alter_info, table->table->part_info, + uint num_parts_found; + uint num_parts_opt= alter_info->partition_names.elements; + num_parts_found= set_part_state(alter_info, table->table->part_info, PART_CHANGED); - if (no_parts_found != no_parts_opt && + if (num_parts_found != num_parts_opt && (!(alter_info->flags & ALTER_ALL_PARTITION))) { char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0e0e3ec6bd3..0610350b38f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3810,7 +3810,7 @@ partition_entry: ; partition: - BY part_type_def opt_no_parts opt_sub_part part_defs + BY part_type_def opt_num_parts opt_sub_part part_defs ; part_type_def: @@ -3895,20 +3895,20 @@ sub_part_func: ; -opt_no_parts: +opt_num_parts: /* empty */ {} | PARTITIONS_SYM real_ulong_num { - uint no_parts= $2; + uint num_parts= $2; partition_info *part_info= Lex->part_info; - if (no_parts == 0) + if (num_parts == 0) { my_error(ER_NO_PARTS_ERROR, MYF(0), "partitions"); MYSQL_YYABORT; } - part_info->no_parts= no_parts; - part_info->use_default_no_partitions= FALSE; + part_info->num_parts= num_parts; + part_info->use_default_num_partitions= FALSE; } ; @@ -3916,7 +3916,7 @@ opt_sub_part: /* empty */ {} | SUBPARTITION_SYM BY opt_linear HASH_SYM sub_part_func { Lex->part_info->subpart_type= HASH_PARTITION; } - opt_no_subparts {} + opt_num_subparts {} | SUBPARTITION_SYM BY opt_linear KEY_SYM '(' sub_part_field_list ')' { @@ -3924,7 +3924,7 @@ opt_sub_part: part_info->subpart_type= HASH_PARTITION; part_info->list_of_subpart_fields= TRUE; } - opt_no_subparts {} + opt_num_subparts {} ; sub_part_field_list: @@ -3966,19 +3966,19 @@ part_func_expr: } ; -opt_no_subparts: +opt_num_subparts: /* empty */ {} | SUBPARTITIONS_SYM real_ulong_num { - uint no_parts= $2; + uint num_parts= $2; LEX *lex= Lex; - if (no_parts == 0) + if (num_parts == 0) { my_error(ER_NO_PARTS_ERROR, MYF(0), "subpartitions"); MYSQL_YYABORT; } - lex->part_info->no_subparts= no_parts; - lex->part_info->use_default_no_subpartitions= FALSE; + lex->part_info->num_subparts= num_parts; + lex->part_info->use_default_num_subpartitions= FALSE; } ; @@ -3989,9 +3989,9 @@ part_defs: { partition_info *part_info= Lex->part_info; uint count_curr_parts= part_info->partitions.elements; - if (part_info->no_parts != 0) + if (part_info->num_parts != 0) { - if (part_info->no_parts != + if (part_info->num_parts != count_curr_parts) { my_parse_error(ER(ER_PARTITION_WRONG_NO_PART_ERROR)); @@ -4000,7 +4000,7 @@ part_defs: } else if (count_curr_parts > 0) { - part_info->no_parts= count_curr_parts; + part_info->num_parts= count_curr_parts; } part_info->count_curr_subparts= 0; } @@ -4026,7 +4026,7 @@ part_definition: part_info->curr_part_elem= p_elem; part_info->current_partition= p_elem; part_info->use_default_partitions= FALSE; - part_info->use_default_no_partitions= FALSE; + part_info->use_default_num_partitions= FALSE; } part_name opt_part_values @@ -4338,7 +4338,7 @@ opt_sub_partition: /* empty */ { partition_info *part_info= Lex->part_info; - if (part_info->no_subparts != 0 && + if (part_info->num_subparts != 0 && !part_info->use_default_subpartitions) { /* @@ -4352,9 +4352,9 @@ opt_sub_partition: | '(' sub_part_list ')' { partition_info *part_info= Lex->part_info; - if (part_info->no_subparts != 0) + if (part_info->num_subparts != 0) { - if (part_info->no_subparts != + if (part_info->num_subparts != part_info->count_curr_subparts) { my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR)); @@ -4368,7 +4368,7 @@ opt_sub_partition: my_parse_error(ER(ER_PARTITION_WRONG_NO_SUBPART_ERROR)); MYSQL_YYABORT; } - part_info->no_subparts= part_info->count_curr_subparts; + part_info->num_subparts= part_info->count_curr_subparts; } part_info->count_curr_subparts= 0; } @@ -4410,7 +4410,7 @@ sub_part_definition: } part_info->curr_part_elem= sub_p_elem; part_info->use_default_subpartitions= FALSE; - part_info->use_default_no_subpartitions= FALSE; + part_info->use_default_num_subpartitions= FALSE; part_info->count_curr_subparts++; } sub_name opt_part_options {} @@ -5850,7 +5850,7 @@ alter_commands: LEX *lex= Lex; lex->alter_info.flags|= ALTER_COALESCE_PARTITION; lex->no_write_to_binlog= $3; - lex->alter_info.no_parts= $4; + lex->alter_info.num_parts= $4; } | reorg_partition_rule ; @@ -5892,12 +5892,11 @@ add_part_extra: | '(' part_def_list ')' { LEX *lex= Lex; - lex->part_info->no_parts= lex->part_info->partitions.elements; + lex->part_info->num_parts= lex->part_info->partitions.elements; } | PARTITIONS_SYM real_ulong_num { - LEX *lex= Lex; - lex->part_info->no_parts= $2; + Lex->part_info->num_parts= $2; } ; @@ -5928,7 +5927,7 @@ reorg_parts_rule: INTO '(' part_def_list ')' { partition_info *part_info= Lex->part_info; - part_info->no_parts= part_info->partitions.elements; + part_info->num_parts= part_info->partitions.elements; } ; From 66ea81cdb1f6499d8661d6f0c0750218bcb326c5 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 1 Oct 2009 15:09:20 +0200 Subject: [PATCH 04/27] BUG#47752, missed to sort values in list partitioning --- sql/partition_info.cc | 7 ++++--- sql/sql_partition.cc | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index aaa6d0d3767..0540c094ccc 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -993,15 +993,16 @@ bool partition_info::check_list_constants(THD *thd) } } while (++i < num_parts); } - if (fixed && num_list_values) + DBUG_ASSERT(fixed); + if (num_list_values) { bool first= TRUE; /* list_array and list_col_array are unions, so this works for both variants of LIST partitioning. */ - my_qsort((void*)list_array, num_list_values, sizeof(LIST_PART_ENTRY), - &list_part_cmp); + my_qsort((void*)list_array, num_list_values, size_entries, + compare_func); i= 0; LINT_INIT(prev_value); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 9a9618108e5..05b3822ce43 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1030,8 +1030,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, if ((!is_sub_part) && (error= check_signed_flag(part_info))) goto end; result= set_up_field_array(table, is_sub_part); - if (!is_sub_part) - part_info->fixed= TRUE; end: table->get_fields_in_item_tree= FALSE; table->map= 0; //Restore old value @@ -1667,6 +1665,7 @@ bool fix_partition_func(THD *thd, TABLE *table, } part_info->part_result_type= INT_RESULT; } + part_info->fixed= TRUE; } else { @@ -1683,6 +1682,7 @@ bool fix_partition_func(THD *thd, TABLE *table, table, FALSE))) goto end; } + part_info->fixed= TRUE; if (part_info->part_type == RANGE_PARTITION) { error_str= partition_keywords[PKW_RANGE].str; From 4d624635c58520e933f54e1e25b68c9c42e19816 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 1 Oct 2009 16:50:11 +0200 Subject: [PATCH 05/27] Added more test cases --- mysql-test/r/partition_column.result | 40 ++++++++++++++++++++++++++++ mysql-test/t/partition_column.test | 19 +++++++++++++ 2 files changed, 59 insertions(+) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 0aaa4e78f68..66308321a95 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,36 @@ drop table if exists t1; +create table t1 (a int, b int) +partition by list column_list(a,b) +( partition p0 values in (column_list(1, NULL), column_list(2, NULL), +column_list(NULL, NULL)), +partition p1 values in (column_list(1,1), column_list(2,2)), +partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +insert into t1 values (3, NULL); +insert into t1 values (NULL, 1); +insert into t1 values (NULL, NULL); +insert into t1 values (1, NULL); +insert into t1 values (2, NULL); +insert into t1 values (1,1); +insert into t1 values (2,2); +select * from t1 where a = 1; +a b +1 NULL +1 1 +select * from t1 where a = 2; +a b +2 NULL +2 2 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a,b) +(PARTITION p0 VALUES IN ( COLUMN_LIST(1,NULL), COLUMN_LIST(2,NULL), COLUMN_LIST(NULL,NULL)) ENGINE = MyISAM, + PARTITION p1 VALUES IN ( COLUMN_LIST(1,1), COLUMN_LIST(2,2)) ENGINE = MyISAM, + PARTITION p2 VALUES IN ( COLUMN_LIST(3,NULL), COLUMN_LIST(NULL,1)) ENGINE = MyISAM) */ +drop table t1; create table t1 (a int) partition by list (a) ( partition p0 values in (1), @@ -27,6 +59,14 @@ insert into t1 values (4); insert into t1 values (NULL); insert into t1 values (5); ERROR HY000: Table has no partition for value from column_list +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a) +(PARTITION p0 VALUES IN ( COLUMN_LIST(2), COLUMN_LIST(1)) ENGINE = MyISAM, + PARTITION p1 VALUES IN ( COLUMN_LIST(4), COLUMN_LIST(NULL), COLUMN_LIST(3)) ENGINE = MyISAM) */ drop table t1; create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index f551b58119e..ff625acdb1d 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,24 @@ drop table if exists t1; --enable_warnings +create table t1 (a int, b int) +partition by list column_list(a,b) +( partition p0 values in (column_list(1, NULL), column_list(2, NULL), + column_list(NULL, NULL)), + partition p1 values in (column_list(1,1), column_list(2,2)), + partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +insert into t1 values (3, NULL); +insert into t1 values (NULL, 1); +insert into t1 values (NULL, NULL); +insert into t1 values (1, NULL); +insert into t1 values (2, NULL); +insert into t1 values (1,1); +insert into t1 values (2,2); +select * from t1 where a = 1; +select * from t1 where a = 2; +show create table t1; +drop table t1; + --error ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR create table t1 (a int) partition by list (a) @@ -38,6 +56,7 @@ insert into t1 values (4); insert into t1 values (NULL); --error ER_NO_PARTITION_FOR_GIVEN_VALUE insert into t1 values (5); +show create table t1; drop table t1; create table t1 (a int, b char(10), c varchar(25), d datetime) From d0627362adee94d0cac63426a045365f8d8109fd Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 1 Oct 2009 17:15:50 +0200 Subject: [PATCH 06/27] Fixed no_ to num_ change for NDB handler --- sql/ha_ndbcluster.cc | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 264e5649ea9..0aea0128819 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -9781,7 +9781,7 @@ void ha_ndbcluster::set_auto_partitions(partition_info *part_info) int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) { NDBTAB *tab= (NDBTAB*)tab_ref; - int32 *range_data= (int32*)my_malloc(part_info->no_parts*sizeof(int32), + int32 *range_data= (int32*)my_malloc(part_info->num_parts*sizeof(int32), MYF(0)); uint i; int error= 0; @@ -9790,17 +9790,17 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) if (!range_data) { - mem_alloc_error(part_info->no_parts*sizeof(int32)); + mem_alloc_error(part_info->num_parts*sizeof(int32)); DBUG_RETURN(1); } - for (i= 0; i < part_info->no_parts; i++) + for (i= 0; i < part_info->num_parts; i++) { longlong range_val= part_info->range_int_array[i]; if (unsigned_flag) range_val-= 0x8000000000000000ULL; if (range_val < INT_MIN32 || range_val >= INT_MAX32) { - if ((i != part_info->no_parts - 1) || + if ((i != part_info->num_parts - 1) || (range_val != LONGLONG_MAX)) { my_error(ER_LIMITED_PART_RANGE, MYF(0), "NDB"); @@ -9811,7 +9811,7 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) } range_data[i]= (int32)range_val; } - tab->setRangeListData(range_data, sizeof(int32)*part_info->no_parts); + tab->setRangeListData(range_data, sizeof(int32)*part_info->num_parts); error: my_free((char*)range_data, MYF(0)); DBUG_RETURN(error); @@ -9820,7 +9820,7 @@ error: int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) { NDBTAB *tab= (NDBTAB*)tab_ref; - int32 *list_data= (int32*)my_malloc(part_info->no_list_values * 2 + int32 *list_data= (int32*)my_malloc(part_info->num_list_values * 2 * sizeof(int32), MYF(0)); uint32 *part_id, i; int error= 0; @@ -9829,10 +9829,10 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) if (!list_data) { - mem_alloc_error(part_info->no_list_values*2*sizeof(int32)); + mem_alloc_error(part_info->num_list_values*2*sizeof(int32)); DBUG_RETURN(1); } - for (i= 0; i < part_info->no_list_values; i++) + for (i= 0; i < part_info->num_list_values; i++) { LIST_PART_ENTRY *list_entry= &part_info->list_array[i]; longlong list_val= list_entry->list_value; @@ -9848,7 +9848,7 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) part_id= (uint32*)&list_data[2*i+1]; *part_id= list_entry->partition_id; } - tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->no_list_values); + tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->num_list_values); error: my_free((char*)list_data, MYF(0)); DBUG_RETURN(error); @@ -9970,11 +9970,11 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info, ng= 0; ts_names[fd_index]= part_elem->tablespace_name; frag_data[fd_index++]= ng; - } while (++j < part_info->no_subparts); + } while (++j < part_info->num_subparts); } first= FALSE; - } while (++i < part_info->no_parts); - tab->setDefaultNoPartitionsFlag(part_info->use_default_no_partitions); + } while (++i < part_info->num_parts); + tab->setDefaultNoPartitionsFlag(part_info->use_default_num_partitions); tab->setLinearFlag(part_info->linear_hash_ind); { ha_rows max_rows= table_share->max_rows; @@ -10368,7 +10368,7 @@ ndberror2: } -bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts) +bool ha_ndbcluster::get_no_parts(const char *name, uint *num_parts) { Ndb *ndb; NDBDICT *dict; @@ -10390,7 +10390,7 @@ bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts) Ndb_table_guard ndbtab_g(dict= ndb->getDictionary(), m_tabname); if (!ndbtab_g.get_table()) ERR_BREAK(dict->getNdbError(), err); - *no_parts= ndbtab_g.get_table()->getFragmentCount(); + *num_parts= ndbtab_g.get_table()->getFragmentCount(); DBUG_RETURN(FALSE); } From f1437d6afdc53fce49867781b14675003b4a32c3 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 2 Oct 2009 11:31:05 +0200 Subject: [PATCH 07/27] BUG#47754, used number of parts instead of number of list values as end part for list partitioning in column list partitioning --- mysql-test/r/partition_column.result | 9 +++++++++ mysql-test/t/partition_column.test | 5 +++++ sql/sql_partition.cc | 10 +++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 66308321a95..43538cb7c69 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -20,6 +20,15 @@ select * from t1 where a = 2; a b 2 NULL 2 2 +select * from t1 where a > 8; +a b +select * from t1 where a not between 8 and 8; +a b +2 NULL +2 2 +3 NULL +1 NULL +1 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index ff625acdb1d..4edb03405b5 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -14,6 +14,9 @@ partition by list column_list(a,b) column_list(NULL, NULL)), partition p1 values in (column_list(1,1), column_list(2,2)), partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +# +# BUG#47754 Crash when selecting using NOT BETWEEN for column list partitioning +# insert into t1 values (3, NULL); insert into t1 values (NULL, 1); insert into t1 values (NULL, NULL); @@ -23,6 +26,8 @@ insert into t1 values (1,1); insert into t1 values (2,2); select * from t1 where a = 1; select * from t1 where a = 2; +select * from t1 where a > 8; +select * from t1 where a not between 8 and 8; show create table t1; drop table t1; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 05b3822ce43..898cf8f07cd 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6962,7 +6962,15 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, nparts); } if (flags & NO_MAX_RANGE) - part_iter->part_nums.end= part_info->num_parts; + { + if (part_info->part_type == RANGE_PARTITION) + part_iter->part_nums.end= part_info->num_parts; + else /* LIST_PARTITION */ + { + DBUG_ASSERT(part_info->part_type == LIST_PARTITION); + part_iter->part_nums.end= part_info->num_list_values; + } + } else { // Copy from max_value to record From 01072e22fe7cc5e7a53e9ea0a065ba22027d52bf Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Mon, 5 Oct 2009 16:10:18 +0200 Subject: [PATCH 08/27] BUG#47776, Fixed character set handling, used wrong length, eventually also found that didn't need to convert to my_strnxfrm-format for column list partitioned tables, also column list partitioned tables can use multi-byte character sets in partition fields as well as where strxfrm multiplies the number of bytes in the string --- mysql-test/r/partition_innodb.result | 24 ++++++++++++++++++++ mysql-test/t/partition_innodb.test | 30 ++++++++++++++++++++++++ sql/sql_partition.cc | 34 +++++++++++++++++----------- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index af277e5ce40..fb991ef5fcc 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -1,4 +1,28 @@ drop table if exists t1; +create table t1 (a varchar(5)) +engine=memory +partition by range column_list(a) +( partition p0 values less than (column_list('m')), +partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; +create table t1 (a varchar(5)) +engine=myisam +partition by range column_list(a) +( partition p0 values less than (column_list('m')), +partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; +create table t1 (a varchar(5)) +engine=innodb +partition by range column_list(a) +( partition p0 values less than (column_list('m')), +partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; CREATE TABLE t1 (id INT PRIMARY KEY, data INT) ENGINE = InnoDB PARTITION BY RANGE(id) ( PARTITION p0 VALUES LESS THAN (5), diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index c6bf0af0b6f..a8758525342 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -5,6 +5,36 @@ drop table if exists t1; --enable_warnings +# +# BUG#47776, Failed to update for MEMORY engine, crash for InnoDB and success for MyISAM +# +create table t1 (a varchar(5)) +engine=memory +partition by range column_list(a) +( partition p0 values less than (column_list('m')), + partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; + +create table t1 (a varchar(5)) +engine=myisam +partition by range column_list(a) +( partition p0 values less than (column_list('m')), + partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; + +create table t1 (a varchar(5)) +engine=innodb +partition by range column_list(a) +( partition p0 values less than (column_list('m')), + partition p1 values less than (column_list('za'))); +insert into t1 values ('j'); +update t1 set a = 'z' where (a >= 'j'); +drop table t1; + # # Bug#40595: Non-matching rows not released with READ-COMMITTED on tables # with partitions diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 898cf8f07cd..5e7fdb6c981 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1404,15 +1404,21 @@ static void set_up_partition_func_pointers(partition_info *part_info) if (part_info->is_sub_partitioned()) { DBUG_ASSERT(part_info->get_part_partition_id); - part_info->get_part_partition_id_charset= - part_info->get_part_partition_id; - part_info->get_part_partition_id= get_part_id_charset_func_part; + if (!part_info->column_list) + { + part_info->get_part_partition_id= + part_info->get_part_partition_id_charset; + part_info->get_part_partition_id= get_part_id_charset_func_part; + } } else { DBUG_ASSERT(part_info->get_partition_id); - part_info->get_part_partition_id_charset= part_info->get_partition_id; - part_info->get_partition_id= get_part_id_charset_func_part; + if (!part_info->column_list) + { + part_info->get_part_partition_id_charset= part_info->get_partition_id; + part_info->get_part_partition_id= get_part_id_charset_func_part; + } } } if (part_info->subpart_charset_field_array) @@ -1715,7 +1721,8 @@ bool fix_partition_func(THD *thd, TABLE *table, } if (((part_info->part_type != HASH_PARTITION || part_info->list_of_part_fields == FALSE) && - check_part_func_fields(part_info->part_field_array, TRUE)) || + (!part_info->column_list && + check_part_func_fields(part_info->part_field_array, TRUE))) || (part_info->list_of_part_fields == FALSE && part_info->is_sub_partitioned() && check_part_func_fields(part_info->subpart_field_array, TRUE))) @@ -2603,7 +2610,8 @@ static void copy_to_part_field_buffers(Field **ptr, if (!field->maybe_null() || !field->is_null()) { CHARSET_INFO *cs= ((Field_str*)field)->charset(); - uint len= field->pack_length(); + uint max_len= field->pack_length(); + uint data_len= field->data_length(); uchar *field_buf= *field_bufs; /* We only use the field buffer for VARCHAR and CHAR strings @@ -2615,17 +2623,17 @@ static void copy_to_part_field_buffers(Field **ptr, if (field->type() == MYSQL_TYPE_VARCHAR) { uint len_bytes= ((Field_varstring*)field)->length_bytes; - my_strnxfrm(cs, field_buf + len_bytes, (len - len_bytes), - field->ptr + len_bytes, field->field_length); + my_strnxfrm(cs, field_buf + len_bytes, max_len, + field->ptr + len_bytes, data_len); if (len_bytes == 1) - *field_buf= (uchar) field->field_length; + *field_buf= (uchar) data_len; else - int2store(field_buf, field->field_length); + int2store(field_buf, data_len); } else { - my_strnxfrm(cs, field_buf, len, - field->ptr, field->field_length); + my_strnxfrm(cs, field_buf, max_len, + field->ptr, max_len); } field->ptr= field_buf; } From c6e67a9b04289ccf78f5f11485c34875ddf8ad89 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 6 Oct 2009 16:22:15 +0200 Subject: [PATCH 09/27] BUG#47838, NULL values in ranges was dropped due to missing else part in store_tuple_to_record --- mysql-test/r/partition_column.result | 12 ++++++++++++ mysql-test/t/partition_column.test | 27 +++++++++++++++++++++++++++ sql/sql_partition.cc | 11 +++++++---- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 43538cb7c69..f5b5b49de56 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,16 @@ drop table if exists t1; +create table t1 (a int signed) +partition by list column_list(a) +( partition p0 values in (column_list(1), column_list(3), column_list(5), +column_list(7), column_list(9), column_list(NULL)), +partition p1 values in (column_list(2), column_list(4), column_list(6), +column_list(8), column_list(0))); +insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8); +select * from t1 where a <= 1; +a +1 +0 +drop table t1; create table t1 (a int, b int) partition by list column_list(a,b) ( partition p0 values in (column_list(1, NULL), column_list(2, NULL), diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index 4edb03405b5..5eef85b4fa2 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,33 @@ drop table if exists t1; --enable_warnings +# +# BUG#47838, List partitioning have problems with <= and >= +# +create table t1 (a int signed) +partition by list (a) +( partition p0 values in (1, 3, 5, 7, 9, NULL), + partition p1 values in (2, 4, 6, 8, 0)); +insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8); +select * from t1 where NULL <= a; +select * from t1 where a is null; +explain partitions select * from t1 where a is null; +select * from t1 where a <= 1; +drop table t1; + +create table t1 (a int signed) +partition by list column_list(a) +( partition p0 values in (column_list(1), column_list(3), column_list(5), + column_list(7), column_list(9), column_list(NULL)), + partition p1 values in (column_list(2), column_list(4), column_list(6), + column_list(8), column_list(0))); +insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8); +select * from t1 where a <= NULL; +select * from t1 where a is null; +explain partitions select * from t1 where a is null; +select * from t1 where a <= 1; +drop table t1; + create table t1 (a int, b int) partition by list column_list(a,b) ( partition p0 values in (column_list(1, NULL), column_list(2, NULL), diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 5e7fdb6c981..52e28311ead 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6761,10 +6761,9 @@ uint32 store_tuple_to_record(Field **pfield, if ((*pfield)->real_maybe_null()) { if (*loc_value) - { (*pfield)->set_null(); - } - (*pfield)->set_notnull(); + else + (*pfield)->set_notnull(); loc_value++; } uint len= (*pfield)->pack_length(); @@ -6950,12 +6949,16 @@ int get_part_iter_for_interval_cols_via_map(partition_info *part_info, get_col_endpoint= get_partition_id_cols_range_for_endpoint; part_iter->get_next= get_next_partition_id_range; } - else + else if (part_info->part_type == LIST_PARTITION) { get_col_endpoint= get_partition_id_cols_list_for_endpoint; part_iter->get_next= get_next_partition_id_list; part_iter->part_info= part_info; + DBUG_ASSERT(part_info->num_list_values); } + else + assert(0); + if (flags & NO_MIN_RANGE) part_iter->part_nums.start= part_iter->part_nums.cur= 0; else From 2ef1c756db41b003f6e634104f9024cdb4f2b982 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 6 Oct 2009 16:22:54 +0200 Subject: [PATCH 10/27] BUG#47838, NULL values in ranges was dropped due to missing else part in store_tuple_to_record, added more tests --- mysql-test/r/partition_column.result | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index f5b5b49de56..621a127f310 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,11 +1,37 @@ drop table if exists t1; create table t1 (a int signed) +partition by list (a) +( partition p0 values in (1, 3, 5, 7, 9, NULL), +partition p1 values in (2, 4, 6, 8, 0)); +insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8); +select * from t1 where NULL <= a; +a +select * from t1 where a is null; +a +NULL +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 10 Using where +select * from t1 where a <= 1; +a +1 +0 +drop table t1; +create table t1 (a int signed) partition by list column_list(a) ( partition p0 values in (column_list(1), column_list(3), column_list(5), column_list(7), column_list(9), column_list(NULL)), partition p1 values in (column_list(2), column_list(4), column_list(6), column_list(8), column_list(0))); insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8); +select * from t1 where a <= NULL; +a +select * from t1 where a is null; +a +NULL +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 select * from t1 where a <= 1; a 1 From 576dd76aa81787f71e038efd9e00713b7a44b3c5 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Tue, 6 Oct 2009 17:01:59 +0200 Subject: [PATCH 11/27] BUG#47837, Duplicate field names were allowed in both column list partitioning and key partitioning, added check to give error in this case --- mysql-test/r/partition_column.result | 7 ++++ mysql-test/t/partition_column.test | 11 +++++++ sql/partition_info.cc | 49 ++++++++++++++++++++++++++++ sql/partition_info.h | 1 + sql/share/errmsg.txt | 2 ++ 5 files changed, 70 insertions(+) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 621a127f310..fb7f815fd98 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,11 @@ drop table if exists t1; +create table t1 (a int, b int) +partition by key (a,a); +ERROR HY000: Duplicate partition field name a +create table t1 (a int, b int) +partition by list column_list(a,a) +( partition p values in (column_list(1,1))); +ERROR HY000: Duplicate partition field name a create table t1 (a int signed) partition by list (a) ( partition p0 values in (1, 3, 5, 7, 9, NULL), diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index 5eef85b4fa2..1c7e8d59895 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,17 @@ drop table if exists t1; --enable_warnings +# +# BUG#47837, Crash when two same fields in column list processing +# +--error ER_SAME_NAME_PARTITION_FIELD +create table t1 (a int, b int) +partition by key (a,a); +--error ER_SAME_NAME_PARTITION_FIELD +create table t1 (a int, b int) +partition by list column_list(a,a) +( partition p values in (column_list(1,1))); + # # BUG#47838, List partitioning have problems with <= and >= # diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 0540c094ccc..ef212fce28d 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -333,6 +333,49 @@ bool partition_info::set_up_defaults_for_partitioning(handler *file, } +/* + Support routine for check_partition_info + + SYNOPSIS + has_unique_fields + no parameters + + RETURN VALUE + Erroneus field name Error, there are two fields with same name + NULL Ok, no field defined twice + + DESCRIPTION + Check that the user haven't defined the same field twice in + key or column list partitioning. +*/ +char* partition_info::has_unique_fields() +{ + char *field_name_outer, *field_name_inner; + List_iterator it_outer(part_field_list); + uint num_fields= part_field_list.elements; + uint i,j; + DBUG_ENTER("partition_info::has_unique_fields"); + + for (i= 0; i < num_fields; i++) + { + field_name_outer= it_outer++; + List_iterator it_inner(part_field_list); + for (j= 0; j < num_fields; j++) + { + field_name_inner= it_inner++; + if (i == j) + continue; + if (!(my_strcasecmp(system_charset_info, + field_name_outer, + field_name_inner))) + { + DBUG_RETURN(field_name_outer); + } + } + } + DBUG_RETURN(NULL); +} + /* A support function to check if a partition element's name is unique @@ -1143,6 +1186,12 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } } + if (part_field_list.elements > 0 && + (same_name= has_unique_fields())) + { + my_error(ER_SAME_NAME_PARTITION_FIELD, MYF(0), same_name); + goto end; + } if ((same_name= has_unique_names())) { my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name); diff --git a/sql/partition_info.h b/sql/partition_info.h index 1f2b6b6a95e..6e197198807 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -271,6 +271,7 @@ public: bool set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info, uint start_no); + char *has_unique_fields(); char *has_unique_names(); bool check_engine_mix(handlerton *engine_type, bool default_engine); bool check_range_constants(THD *thd); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 514dc06728d..3d228f58360 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5822,6 +5822,8 @@ ER_SAME_NAME_PARTITION eng "Duplicate partition name %-.192s" ger "Doppelter Partitionsname: %-.192s" swe "Duplicerat partitionsnamn %-.192s" +ER_SAME_NAME_PARTITION_FIELD + eng "Duplicate partition field name %-.192s" ER_NO_BINLOG_ERROR eng "It is not allowed to shut off binlog on this command" ger "Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten" From c90669c4d423ba46f09aadde5ff6662e8a63a1c0 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 16 Oct 2009 16:16:06 +0200 Subject: [PATCH 12/27] Fixed removal of column_list keyword for VALUES part, retained for PARTITION BY RANGE/LIST COLUMN_LIST, not entirely working yet --- mysql-test/r/partition_innodb.result | 12 +- mysql-test/r/partition_range.result | 10 +- mysql-test/t/partition_column.test | 131 +++--- mysql-test/t/partition_innodb.test | 12 +- mysql-test/t/partition_range.test | 10 +- sql/partition_element.h | 1 + sql/partition_info.cc | 615 ++++++++++++++++++++++----- sql/partition_info.h | 15 +- sql/share/errmsg.txt | 8 +- sql/sql_partition.cc | 28 +- sql/sql_yacc.yy | 350 ++++++--------- 11 files changed, 765 insertions(+), 427 deletions(-) diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result index fb991ef5fcc..89cf8709b90 100644 --- a/mysql-test/r/partition_innodb.result +++ b/mysql-test/r/partition_innodb.result @@ -2,24 +2,24 @@ drop table if exists t1; create table t1 (a varchar(5)) engine=memory partition by range column_list(a) -( partition p0 values less than (column_list('m')), -partition p1 values less than (column_list('za'))); +( partition p0 values less than ('m'), +partition p1 values less than ('za')); insert into t1 values ('j'); update t1 set a = 'z' where (a >= 'j'); drop table t1; create table t1 (a varchar(5)) engine=myisam partition by range column_list(a) -( partition p0 values less than (column_list('m')), -partition p1 values less than (column_list('za'))); +( partition p0 values less than ('m'), +partition p1 values less than ('za')); insert into t1 values ('j'); update t1 set a = 'z' where (a >= 'j'); drop table t1; create table t1 (a varchar(5)) engine=innodb partition by range column_list(a) -( partition p0 values less than (column_list('m')), -partition p1 values less than (column_list('za'))); +( partition p0 values less than ('m'), +partition p1 values less than ('za')); insert into t1 values ('j'); update t1 set a = 'z' where (a >= 'j'); drop table t1; diff --git a/mysql-test/r/partition_range.result b/mysql-test/r/partition_range.result index fc15665d698..00ada13ed13 100644 --- a/mysql-test/r/partition_range.result +++ b/mysql-test/r/partition_range.result @@ -78,12 +78,12 @@ partition by range column_list(a,b) ERROR 42000: Inconsistency in usage of column lists for partitioning near '))' at line 3 create table t1 (a int, b char(20)) partition by range(a) -(partition p0 values less than (column_list(1,"b"))); -ERROR HY000: Inconsistency in usage of column lists for partitioning +(partition p0 values less than (1,"b")); +ERROR HY000: Cannot have more than one value for this type of RANGE partitioning create table t1 (a int, b char(20)) partition by range(a) -(partition p0 values less than (column_list(1,"b"))); -ERROR HY000: Inconsistency in usage of column lists for partitioning +(partition p0 values less than (1,"b")); +ERROR HY000: Cannot have more than one value for this type of RANGE partitioning create table t1 (a int, b char(20)); create global index inx on t1 (a,b) partition by range (a) @@ -91,7 +91,7 @@ partition by range (a) drop table t1; create table t1 (a int, b char(20)) partition by range column_list(b) -(partition p0 values less than (column_list("b"))); +(partition p0 values less than ("b")); drop table t1; create table t1 (a int) partition by range (a) diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index 1c7e8d59895..edce77e2233 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -17,7 +17,7 @@ partition by key (a,a); --error ER_SAME_NAME_PARTITION_FIELD create table t1 (a int, b int) partition by list column_list(a,a) -( partition p values in (column_list(1,1))); +( partition p values in ((1,1))); # # BUG#47838, List partitioning have problems with <= and >= @@ -35,10 +35,8 @@ drop table t1; create table t1 (a int signed) partition by list column_list(a) -( partition p0 values in (column_list(1), column_list(3), column_list(5), - column_list(7), column_list(9), column_list(NULL)), - partition p1 values in (column_list(2), column_list(4), column_list(6), - column_list(8), column_list(0))); +( partition p0 values in (1, 3, 5, 7, 9, NULL), + partition p1 values in (2, 4, 6, 8, 0)); insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8); select * from t1 where a <= NULL; select * from t1 where a is null; @@ -48,10 +46,9 @@ drop table t1; create table t1 (a int, b int) partition by list column_list(a,b) -( partition p0 values in (column_list(1, NULL), column_list(2, NULL), - column_list(NULL, NULL)), - partition p1 values in (column_list(1,1), column_list(2,2)), - partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +( partition p0 values in ((1, NULL), (2, NULL), (NULL, NULL)), + partition p1 values in ((1,1), (2,2)), + partition p2 values in ((3, NULL), (NULL, 1))); # # BUG#47754 Crash when selecting using NOT BETWEEN for column list partitioning # @@ -88,10 +85,16 @@ insert into t1 values (NULL); insert into t1 values (5); drop table t1; +--error ER_PARSE_ERROR create table t1 (a int) partition by list column_list(a) -( partition p0 values in (column_list(2), column_list(1)), - partition p1 values in (column_list(4), column_list(NULL), column_list(3))); +( partition p0 values in (2, 1), + partition p1 values in ((4), (NULL), (3))); + +create table t1 (a int) +partition by list column_list(a) +( partition p0 values in (2, 1), + partition p1 values in (4, NULL, 3)); insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -106,20 +109,20 @@ create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) subpartitions 4 -( partition p0 values less than (column_list(1, NULL, MAXVALUE, NULL)), - partition p1 values less than (column_list(1, 'a', MAXVALUE, TO_DAYS('1999-01-01'))), - partition p2 values less than (column_list(1, 'a', MAXVALUE, MAXVALUE)), - partition p3 values less than (column_list(1, MAXVALUE, MAXVALUE, MAXVALUE))); +( partition p0 values less than (1, NULL, MAXVALUE, NULL), + partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), + partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), + partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); drop table t1; create table t1 (a int, b char(10), c varchar(5), d int) partition by range column_list(a,b,c) subpartition by key (c,d) subpartitions 3 -( partition p0 values less than (column_list(1,'abc','abc')), - partition p1 values less than (column_list(2,'abc','abc')), - partition p2 values less than (column_list(3,'abc','abc')), - partition p3 values less than (column_list(4,'abc','abc'))); +( partition p0 values less than (1,'abc','abc'), + partition p1 values less than (2,'abc','abc'), + partition p2 values less than (3,'abc','abc'), + partition p3 values less than (4,'abc','abc')); insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); @@ -131,8 +134,8 @@ drop table t1; create table t1 (a int, b varchar(2), c int) partition by range column_list (a, b, c) -(partition p0 values less than (column_list(1, 'A', 1)), - partition p1 values less than (column_list(1, 'B', 1))); +(partition p0 values less than (1, 'A', 1), + partition p1 values less than (1, 'B', 1)); insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; select * from t1 where a = 1 AND b <= 'A' and c = 1; @@ -140,7 +143,7 @@ drop table t1; create table t1 (a char, b char, c char) partition by list column_list(a) -( partition p0 values in (column_list('a'))); +( partition p0 values in ('a')); insert into t1 (a) values ('a'); select * from t1 where a = 'a'; drop table t1; @@ -148,36 +151,36 @@ drop table t1; --error ER_WRONG_TYPE_COLUMN_VALUE_ERROR create table t1 (d timestamp) partition by range column_list(d) -( partition p0 values less than (column_list('2000-01-01')), - partition p1 values less than (column_list('2040-01-01'))); +( partition p0 values less than ('2000-01-01'), + partition p1 values less than ('2040-01-01')); create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (column_list(null, 10))); +(partition p0 values less than (null, 10)); drop table t1; create table t1 (d date) partition by range column_list(d) -( partition p0 values less than (column_list('2000-01-01')), - partition p1 values less than (column_list('2009-01-01'))); +( partition p0 values less than ('2000-01-01'), + partition p1 values less than ('2009-01-01')); drop table t1; create table t1 (d date) partition by range column_list(d) -( partition p0 values less than (column_list('1999-01-01')), - partition p1 values less than (column_list('2000-01-01'))); +( partition p0 values less than ('1999-01-01'), + partition p1 values less than ('2000-01-01')); drop table t1; create table t1 (d date) partition by range column_list(d) -( partition p0 values less than (column_list('2000-01-01')), - partition p1 values less than (column_list('3000-01-01'))); +( partition p0 values less than ('2000-01-01'), + partition p1 values less than ('3000-01-01')); drop table t1; create table t1 (a int, b int) partition by range column_list(a,b) -(partition p2 values less than (column_list(99,99)), - partition p1 values less than (column_list(99,999))); +(partition p2 values less than (99,99), + partition p1 values less than (99,999)); insert into t1 values (99,998); select * from t1 where b = 998; @@ -191,22 +194,22 @@ drop table t1; --error ER_PARSE_ERROR create table t1 (a int, b int) partition by list column_list(a,b) -(partition p0 values in (column_list(maxvalue,maxvalue))); +(partition p0 values in ((maxvalue,maxvalue))); create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (column_list(maxvalue,maxvalue))); +(partition p0 values less than (maxvalue,maxvalue)); drop table t1; create table t1 (a int) partition by list column_list(a) -(partition p0 values in (column_list(0))); +(partition p0 values in (0)); select partition_method from information_schema.partitions where table_name='t1'; drop table t1; create table t1 (a char(6)) partition by range column_list(a) -(partition p0 values less than (column_list('H23456')), - partition p1 values less than (column_list('M23456'))); +(partition p0 values less than ('H23456'), + partition p1 values less than ('M23456')); insert into t1 values ('F23456'); select * from t1; drop table t1; @@ -214,14 +217,14 @@ drop table t1; -- error 1054 create table t1 (a char(6)) partition by range column_list(a) -(partition p0 values less than (column_list(H23456)), - partition p1 values less than (column_list(M23456))); +(partition p0 values less than (H23456), + partition p1 values less than (M23456)); -- error ER_RANGE_NOT_INCREASING_ERROR create table t1 (a char(6)) partition by range column_list(a) -(partition p0 values less than (column_list(23456)), - partition p1 values less than (column_list(23456))); +(partition p0 values less than (23456), + partition p1 values less than (23456)); -- error 1064 create table t1 (a int, b int) @@ -231,14 +234,14 @@ partition by range column_list(a,b) -- error ER_PARTITION_COLUMN_LIST_ERROR create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (column_list(1,1,1)); +(partition p0 values less than (1,1,1); create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (column_list(1, NULL)), - partition p1 values less than (column_list(2, maxvalue)), - partition p2 values less than (column_list(3, 3)), - partition p3 values less than (column_list(10, NULL))); +(partition p0 values less than (1, NULL), + partition p1 values less than (2, maxvalue), + partition p2 values less than (3, 3), + partition p3 values less than (10, NULL)); -- error ER_NO_PARTITION_FOR_GIVEN_VALUE insert into t1 values (10,0); @@ -247,57 +250,51 @@ select * from t1; alter table t1 partition by range column_list(b,a) -(partition p0 values less than (column_list(1,2)), - partition p1 values less than (column_list(3,3)), - partition p2 values less than (column_list(9,5))); +(partition p0 values less than (1,2), + partition p1 values less than (3,3), + partition p2 values less than (9,5)); explain partitions select * from t1 where b < 2; select * from t1 where b < 2; explain partitions select * from t1 where b < 4; select * from t1 where b < 4; alter table t1 reorganize partition p1 into -(partition p11 values less than (column_list(2,2)), - partition p12 values less than (column_list(3,3))); +(partition p11 values less than (2,2), + partition p12 values less than (3,3)); -- error ER_REORG_OUTSIDE_RANGE alter table t1 reorganize partition p0 into -(partition p01 values less than (column_list(0,3)), - partition p02 values less than (column_list(1,1))); +(partition p01 values less than (0,3), + partition p02 values less than (1,1)); -- error ER_PARTITION_COLUMN_LIST_ERROR alter table t1 reorganize partition p2 into -(partition p2 values less than(column_list(9,6,1))); +(partition p2 values less than(9,6,1)); -- error ER_PARTITION_COLUMN_LIST_ERROR alter table t1 reorganize partition p2 into (partition p2 values less than (10)); alter table t1 reorganize partition p2 into -(partition p21 values less than (column_list(4,7)), - partition p22 values less than (column_list(9,5))); +(partition p21 values less than (4,7), + partition p22 values less than (9,5)); explain partitions select * from t1 where b < 4; select * from t1 where b < 4; drop table t1; -#create table t1 (a int, b int) -#partition by range column_list(a,b) -#(partition p0 values less than (column_list(99,99)), -# partition p1 values less than (column_list(99,maxvalue))); -#drop table t1; - create table t1 (a int, b int) partition by list column_list(a,b) subpartition by hash (b) subpartitions 2 -(partition p0 values in (column_list(0,0), column_list(1,1)), - partition p1 values in (column_list(1000,1000))); +(partition p0 values in ((0,0), (1,1)), + partition p1 values in ((1000,1000))); insert into t1 values (1000,1000); #select * from t1 where a = 0 and b = 0; drop table t1; create table t1 (a char, b char, c char) partition by range column_list(a,b,c) -( partition p0 values less than (column_list('a','b','c'))); +( partition p0 values less than ('a','b','c')); alter table t1 add partition -(partition p1 values less than (column_list('b','c','d'))); +(partition p1 values less than ('b','c','d')); drop table t1; diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test index a8758525342..629792a7153 100644 --- a/mysql-test/t/partition_innodb.test +++ b/mysql-test/t/partition_innodb.test @@ -11,8 +11,8 @@ drop table if exists t1; create table t1 (a varchar(5)) engine=memory partition by range column_list(a) -( partition p0 values less than (column_list('m')), - partition p1 values less than (column_list('za'))); +( partition p0 values less than ('m'), + partition p1 values less than ('za')); insert into t1 values ('j'); update t1 set a = 'z' where (a >= 'j'); drop table t1; @@ -20,8 +20,8 @@ drop table t1; create table t1 (a varchar(5)) engine=myisam partition by range column_list(a) -( partition p0 values less than (column_list('m')), - partition p1 values less than (column_list('za'))); +( partition p0 values less than ('m'), + partition p1 values less than ('za')); insert into t1 values ('j'); update t1 set a = 'z' where (a >= 'j'); drop table t1; @@ -29,8 +29,8 @@ drop table t1; create table t1 (a varchar(5)) engine=innodb partition by range column_list(a) -( partition p0 values less than (column_list('m')), - partition p1 values less than (column_list('za'))); +( partition p0 values less than ('m'), + partition p1 values less than ('za')); insert into t1 values ('j'); update t1 set a = 'z' where (a >= 'j'); drop table t1; diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test index c14dfd1822d..76571861188 100644 --- a/mysql-test/t/partition_range.test +++ b/mysql-test/t/partition_range.test @@ -64,15 +64,15 @@ create table t1 (a int, b char(20)) partition by range column_list(a,b) (partition p0 values less than (1)); ---error ER_PARTITION_COLUMN_LIST_ERROR +--error ER_TOO_MANY_VALUES_ERROR create table t1 (a int, b char(20)) partition by range(a) -(partition p0 values less than (column_list(1,"b"))); +(partition p0 values less than (1,"b")); ---error ER_PARTITION_COLUMN_LIST_ERROR +--error ER_TOO_MANY_VALUES_ERROR create table t1 (a int, b char(20)) partition by range(a) -(partition p0 values less than (column_list(1,"b"))); +(partition p0 values less than (1,"b")); create table t1 (a int, b char(20)); create global index inx on t1 (a,b) @@ -82,7 +82,7 @@ drop table t1; create table t1 (a int, b char(20)) partition by range column_list(b) -(partition p0 values less than (column_list("b"))); +(partition p0 values less than ("b")); drop table t1; # diff --git a/sql/partition_element.h b/sql/partition_element.h index d749681fe9b..5cb3b41fa2e 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -74,6 +74,7 @@ typedef struct p_column_list_val typedef struct p_elem_val { longlong value; + uint added_items; bool null_value; bool unsigned_flag; part_column_list_val *col_val_array; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ef212fce28d..430d5b81640 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyrght (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -682,7 +682,7 @@ bool partition_info::check_range_constants(THD *thd) part_elem_value *range_val= list_val_it++; part_column_list_val *col_val= range_val->col_val_array; - if (fix_column_value_functions(thd, col_val, i)) + if (fix_column_value_functions(thd, range_val, i)) goto end; memcpy(loc_range_col_array, (const void*)col_val, size_entries); loc_range_col_array+= num_column_values; @@ -826,85 +826,6 @@ int partition_info::compare_column_values(const void *first_arg, return 0; } -/* - Evaluate VALUES functions for column list values - SYNOPSIS - fix_column_value_functions() - thd Thread object - col_val List of column values - part_id Partition id we are fixing - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Fix column VALUES and store in memory array adapted to the data type -*/ - -bool partition_info::fix_column_value_functions(THD *thd, - part_column_list_val *col_val, - uint part_id) -{ - uint num_columns= part_field_list.elements; - Name_resolution_context *context= &thd->lex->current_select->context; - TABLE_LIST *save_list= context->table_list; - bool result= FALSE; - uint i; - const char *save_where= thd->where; - DBUG_ENTER("partition_info::fix_column_value_functions"); - if (col_val->fixed > 1) - { - DBUG_RETURN(FALSE); - } - context->table_list= 0; - thd->where= "partition function"; - for (i= 0; i < num_columns; col_val++, i++) - { - Item *column_item= col_val->item_expression; - Field *field= part_field_array[i]; - col_val->part_info= this; - col_val->partition_id= part_id; - if (col_val->max_value) - col_val->column_value= NULL; - else - { - if (!col_val->fixed && - (column_item->fix_fields(thd, (Item**)0) || - (!column_item->const_item()))) - { - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); - result= TRUE; - goto end; - } - col_val->null_value= column_item->null_value; - col_val->column_value= NULL; - if (!col_val->null_value) - { - uchar *val_ptr; - uint len= field->pack_length(); - if (column_item->save_in_field(field, TRUE)) - { - my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); - result= TRUE; - goto end; - } - if (!(val_ptr= (uchar*) sql_calloc(len))) - { - mem_alloc_error(len); - result= TRUE; - goto end; - } - col_val->column_value= val_ptr; - memcpy(val_ptr, field->ptr, len); - } - } - col_val->fixed= 2; - } -end: - thd->where= save_where; - context->table_list= save_list; - DBUG_RETURN(result); -} - /* This routine allocates an array for all list constants to achieve a fast check what partition a certain value belongs to. At the same time it does @@ -1002,7 +923,7 @@ bool partition_info::check_list_constants(THD *thd) while ((list_value= list_val_it2++)) { part_column_list_val *col_val= list_value->col_val_array; - if (unlikely(fix_column_value_functions(thd, col_val, i))) + if (unlikely(fix_column_value_functions(thd, list_value, i))) { DBUG_RETURN(TRUE); } @@ -1126,6 +1047,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); goto end; } + if (fix_parser_data(thd)) + goto end; } if (unlikely(!is_sub_partitioned() && !(use_default_subpartitions && use_default_num_subpartitions))) @@ -1377,31 +1300,6 @@ void partition_info::print_no_partition_found(TABLE *table) } -/* - Create a new column value in current list - SYNOPSIS - add_column_value() - RETURN - >0 A part_column_list_val object which have been - inserted into its list - 0 Memory allocation failure -*/ - -part_column_list_val *partition_info::add_column_value() -{ - uint max_val= num_columns ? num_columns : MAX_REF_PARTS; - DBUG_ENTER("add_column_value"); - DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u", - num_columns, curr_list_object, max_val)); - if (curr_list_object < max_val) - { - DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]); - } - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); - DBUG_RETURN(NULL); -} - - /* Set fields related to partition expression SYNOPSIS @@ -1616,4 +1514,507 @@ id_err: } +/* + Create a new column value in current list with maxvalue + Called from parser + + SYNOPSIS + add_max_value() + RETURN + TRUE Error + FALSE Success +*/ + +int partition_info::add_max_value() +{ + DBUG_ENTER("partition_info::add_max_value"); + + part_column_list_val *col_val; + if (!(col_val= add_column_value())) + { + DBUG_RETURN(TRUE); + } + col_val->max_value= TRUE; + DBUG_RETURN(FALSE); +} + +/* + Create a new column value in current list + Called from parser + + SYNOPSIS + add_column_value() + RETURN + >0 A part_column_list_val object which have been + inserted into its list + 0 Memory allocation failure +*/ + +part_column_list_val *partition_info::add_column_value() +{ + uint max_val= num_columns ? num_columns : MAX_REF_PARTS; + DBUG_ENTER("add_column_value"); + DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u", + num_columns, curr_list_object, max_val)); + if (curr_list_object < max_val) + { + curr_list_val->added_items++; + DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]); + } + if (!num_columns && part_type == LIST_PARTITION) + { + /* + We're trying to add more than MAX_REF_PARTS, this can happen + in ALTER TABLE using List partitions where the first partition + uses VALUES IN (1,2,3...,17) where the number of fields in + the list is more than MAX_REF_PARTS, in this case we know + that the number of columns must be 1 and we thus reorganize + into the structure used for 1 column. After this we call + ourselves recursively which should always succeed. + */ + if (!reorganize_into_single_field_col_val()) + { + DBUG_RETURN(add_column_value()); + } + DBUG_RETURN(NULL); + } + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(NULL); +} + + +/* + Add a column value in VALUES LESS THAN or VALUES IN + (Called from parser) + + SYNOPSIS + add_column_list_value() + lex Parser's lex object + item Item object representing column value + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +bool partition_info::add_column_list_value(Item *item) +{ + part_column_list_val *col_val; + DBUG_ENTER("partition_info::add_column_list_value"); + + if (part_type == LIST_PARTITION && + num_columns == 1U) + { + if (init_column_part()) + { + DBUG_RETURN(TRUE); + } + } + if (!(col_val= add_column_value())) + { + DBUG_RETURN(TRUE); + } + col_val->item_expression= item; + col_val->part_info= NULL; + DBUG_RETURN(FALSE); +} + +/* + Initialise part_info object for receiving a set of column values + for a partition, called when parser reaches VALUES LESS THAN or + VALUES IN. + + SYNOPSIS + init_column_part() + lex Parser's lex object + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +bool partition_info::init_column_part() +{ + partition_element *p_elem= curr_part_elem; + part_column_list_val *col_val_array; + part_elem_value *list_val; + uint loc_num_columns; + DBUG_ENTER("partition_info::init_column_part"); + + if (!(list_val= + (part_elem_value*)sql_calloc(sizeof(part_elem_value))) || + p_elem->list_val_list.push_back(list_val)) + { + mem_alloc_error(sizeof(part_elem_value)); + DBUG_RETURN(TRUE); + } + if (num_columns) + loc_num_columns= num_columns; + else + loc_num_columns= MAX_REF_PARTS; + if (!(col_val_array= + (part_column_list_val*)sql_calloc(loc_num_columns * + sizeof(part_column_list_val)))) + { + mem_alloc_error(loc_num_columns * sizeof(part_elem_value)); + DBUG_RETURN(TRUE); + } + list_val->col_val_array= col_val_array; + list_val->added_items= 0; + curr_list_val= list_val; + curr_list_object= 0; + DBUG_RETURN(FALSE); +} + +/* + In the case of ALTER TABLE ADD/REORGANIZE PARTITION for LIST + partitions we can specify list values as: + VALUES IN (v1, v2,,,, v17) if we're using the first partitioning + variant with a function or a column list partitioned table with + one partition field. In this case the parser knows not the + number of columns start with and allocates MAX_REF_PARTS in the + array. If we try to allocate something beyond MAX_REF_PARTS we + will call this function to reorganize into a structure with + num_columns = 1. Also when the parser knows that we used LIST + partitioning and we used a VALUES IN like above where number of + values was smaller than MAX_REF_PARTS or equal, then we will + reorganize after discovering this in the parser. + + SYNOPSIS + reorganize_into_single_field_col_val() + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +int partition_info::reorganize_into_single_field_col_val() +{ + part_column_list_val *col_val; + Item *part_expr; + uint loc_num_columns= num_columns; + uint i; + DBUG_ENTER("partition_info::reorganize_into_single_field_col_val"); + + num_columns= 1; + curr_list_val->added_items= 1U; + for (i= 1; i < loc_num_columns; i++) + { + col_val= &curr_list_val->col_val_array[i]; + part_expr= col_val->item_expression; + if ((part_type != LIST_PARTITION && + init_column_part()) || + add_column_list_value(part_expr)) + { + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +} + +/* + This function handles the case of function-based partitioning. + It fixes some data structures created in the parser and puts + them in the format required by the rest of the partitioning + code. + + SYNOPSIS + fix_func_partition() + thd Thread object + col_val Array of one value + part_elem The partition instance + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +int partition_info::fix_func_partition(THD *thd, + part_elem_value *val, + partition_element *part_elem) +{ + uint i; + part_column_list_val *col_val= val->col_val_array; + DBUG_ENTER("partition_info::fix_func_partition"); + + if (col_val->fixed) + { + DBUG_RETURN(FALSE); + } + if (val->added_items != 1) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + if (col_val->max_value) + { + /* The parser ensures we're not LIST partitioned here */ + DBUG_ASSERT(part_type == RANGE_PARTITION); + if (defined_max_value) + { + my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + if (i == (num_parts - 1)) + { + defined_max_value= TRUE; + part_elem->max_value= TRUE; + part_elem->range_value= LONGLONG_MAX; + } + else + { + my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + } + else + { + part_elem_value *value_ptr; + Name_resolution_context *context= &thd->lex->current_select->context; + TABLE_LIST *save_list= context->table_list; + const char *save_where= thd->where; + Item *item_expr= col_val->item_expression; + + context->table_list= 0; + thd->where= "partition function"; + + value_ptr= (part_elem_value*)sql_alloc(sizeof(part_elem_value)); + if (!value_ptr) + { + mem_alloc_error(sizeof(part_elem_value)); + DBUG_RETURN(TRUE); + } + if (item_expr->walk(&Item::check_partition_func_processor, 0, + NULL)) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + DBUG_RETURN(TRUE); + } + if (item_expr->fix_fields(thd, (Item**)0) || + ((context->table_list= save_list), FALSE) || + (!item_expr->const_item())) + { + context->table_list= save_list; + thd->where= save_where; + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + thd->where= save_where; + value_ptr->value= part_expr->val_int(); + value_ptr->unsigned_flag= TRUE; + if (!item_expr->unsigned_flag && + value_ptr->value < 0) + value_ptr->unsigned_flag= FALSE; + if ((value_ptr->null_value= item_expr->null_value)) + { + if (part_elem->has_null_value) + { + my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + part_elem->has_null_value= TRUE; + } + else if (item_expr->result_type() != INT_RESULT) + { + my_error(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + if (!value_ptr->unsigned_flag) + part_elem->signed_flag= TRUE; + if (part_type == RANGE_PARTITION) + { + if (part_elem->has_null_value) + { + my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0)); + DBUG_RETURN(TRUE); + } + part_elem->range_value= value_ptr->value; + } + else if (part_type == LIST_PARTITION) + { + if (!value_ptr->null_value && + part_elem->list_val_list.push_back(value_ptr)) + { + mem_alloc_error(sizeof(part_elem_value)); + DBUG_RETURN(TRUE); + } + } + } + col_val->fixed= 2; + DBUG_RETURN(FALSE); +} + + +/* + Evaluate VALUES functions for column list values + SYNOPSIS + fix_column_value_functions() + thd Thread object + col_val List of column values + part_id Partition id we are fixing + + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Fix column VALUES and store in memory array adapted to the data type +*/ + +bool partition_info::fix_column_value_functions(THD *thd, + part_elem_value *val, + uint part_id) +{ + uint num_columns= part_field_list.elements; + Name_resolution_context *context= &thd->lex->current_select->context; + TABLE_LIST *save_list= context->table_list; + bool result= FALSE; + uint i; + const char *save_where= thd->where; + part_column_list_val *col_val= val->col_val_array; + DBUG_ENTER("partition_info::fix_column_value_functions"); + + if (col_val->fixed > 1) + { + DBUG_RETURN(FALSE); + } + if (val->added_items != num_columns) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + context->table_list= 0; + thd->where= "partition function"; + for (i= 0; i < num_columns; col_val++, i++) + { + Item *column_item= col_val->item_expression; + Field *field= part_field_array[i]; + col_val->part_info= this; + col_val->partition_id= part_id; + if (col_val->max_value) + col_val->column_value= NULL; + else + { + if (!col_val->fixed && + (column_item->fix_fields(thd, (Item**)0) || + (!column_item->const_item()))) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + result= TRUE; + goto end; + } + col_val->null_value= column_item->null_value; + col_val->column_value= NULL; + if (!col_val->null_value) + { + uchar *val_ptr; + uint len= field->pack_length(); + if (column_item->save_in_field(field, TRUE)) + { + my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); + result= TRUE; + goto end; + } + if (!(val_ptr= (uchar*) sql_calloc(len))) + { + mem_alloc_error(len); + result= TRUE; + goto end; + } + col_val->column_value= val_ptr; + memcpy(val_ptr, field->ptr, len); + } + } + col_val->fixed= 2; + } +end: + thd->where= save_where; + context->table_list= save_list; + DBUG_RETURN(result); +} + +/* + The parser generates generic data structures, we need to set them up + as the rest of the code expects to find them. This is in reality part + of the syntax check of the parser code. + + It is necessary to call this function in the case of a CREATE TABLE + statement, in this case we do it early in the check_partition_info + function. + + It is necessary to call this function for ALTER TABLE where we + assign a completely new partition structure, in this case we do it + in prep_alter_part_table after discovering that the partition + structure is entirely redefined. + + It's necessary to call this method also for ALTER TABLE ADD/REORGANIZE + of partitions, in this we call it in prep_alter_part_table after + making some initial checks but before going deep to check the partition + info, we also assign the column_list variable before calling this function + here. + + Finally we also call it immediately after returning from parsing the + partitioning text found in the frm file. + + This function mainly fixes the VALUES parts, these are handled differently + whether or not we use column list partitioning. Since the parser doesn't + know which we are using we need to set-up the old data structures after + the parser is complete when we know if what type of partitioning the + base table is using. + + For column lists we will handle this in the fix_column_value_function. + For column lists it is sufficient to verify that the number of columns + and number of elements are in synch with each other. So only partitioning + using functions need to be set-up to their data structures. + + SYNOPSIS + fix_parser_data() + thd Thread object + + RETURN VALUES + TRUE Failure + FALSE Success +*/ + +int partition_info::fix_parser_data(THD *thd) +{ + List_iterator it(partitions); + partition_element *part_elem; + part_elem_value *val; + uint num_elements; + uint i= 0, j; + int result; + DBUG_ENTER("partition_info::fix_parser_data"); + + if (!(part_type == RANGE_PARTITION || + part_type == LIST_PARTITION)) + { + /* Nothing to do for HASH/KEY partitioning */ + DBUG_RETURN(FALSE); + } + do + { + part_elem= it++; + j= 0; + num_elements= part_elem->list_val_list.elements; + DBUG_ASSERT(part_type == RANGE_PARTITION ? + num_elements == 1U : TRUE); + { + List_iterator list_val_it(part_elem->list_val_list); + part_elem_value *val= list_val_it++; + result= column_list ? + fix_column_value_functions(thd, val, i) : + fix_func_partition(thd, val, part_elem); + if (result) + { + DBUG_RETURN(TRUE); + } + } while (++j < num_elements); + } while (++i < num_parts); +} + +void partition_info::print_debug(const char *str, uint *value) +{ + DBUG_ENTER("print_debug"); + if (value) + DBUG_PRINT("info", ("parser: %s, val = %u", str, *value)); + else + DBUG_PRINT("info", ("parser: %s", str)); + DBUG_VOID_RETURN; +} #endif /* WITH_PARTITION_STORAGE_ENGINE */ diff --git a/sql/partition_info.h b/sql/partition_info.h index 6e197198807..bf0d12e2df6 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -280,11 +280,23 @@ public: handler *file, HA_CREATE_INFO *info, bool check_partition_function); void print_no_partition_found(TABLE *table); + void print_debug(const char *str, uint*); + int fix_func_partition(THD *thd, + part_elem_value *val, + partition_element *part_elem); + bool fix_column_value_functions(THD *thd, + part_elem_value *val, + uint part_id); + int fix_parser_data(THD *thd); + int add_max_value(); + int reorganize_into_single_field_col_val(); part_column_list_val *add_column_value(); bool set_part_expr(char *start_token, Item *item_ptr, char *end_token, bool is_subpart); static int compare_column_values(const void *a, const void *b); bool set_up_charset_field_preps(); + bool init_column_part(); + bool add_column_list_value(Item *item); private: static int list_part_cmp(const void* a, const void* b); bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info, @@ -294,9 +306,6 @@ private: uint start_no); char *create_subpartition_name(uint subpart_no, const char *part_name); bool has_unique_name(partition_element *element); - bool fix_column_value_functions(THD *thd, - part_column_list_val *col_val, - uint part_id); }; uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 3d228f58360..470997aa948 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5822,8 +5822,6 @@ ER_SAME_NAME_PARTITION eng "Duplicate partition name %-.192s" ger "Doppelter Partitionsname: %-.192s" swe "Duplicerat partitionsnamn %-.192s" -ER_SAME_NAME_PARTITION_FIELD - eng "Duplicate partition field name %-.192s" ER_NO_BINLOG_ERROR eng "It is not allowed to shut off binlog on this command" ger "Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten" @@ -6192,6 +6190,12 @@ ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR eng "Too many fields in '%s'" ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR eng "Cannot use MAXVALUE as value in List partitioning" +ER_TOO_MANY_VALUES_ERROR + eng "Cannot have more than one value for this type of %-.64s partitioning" +ER_SAME_NAME_PARTITION_FIELD + eng "Duplicate partition field name %-.192s" +ER_ROW_SINGLE_PARTITION_FIELD_ERROR + eng "Row expressions in VALUES IN only allowed for multi-field column partitioning" # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # mysql_priv.h with the new maximal additional length for explain_filename. diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 52e28311ead..4cb001ef659 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1990,8 +1990,11 @@ static int add_column_list_values(File fptr, partition_info *part_info, int err= 0; uint i; uint num_elements= part_info->part_field_list.elements; - err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); - err+= add_begin_parenthesis(fptr); + bool use_parenthesis= (part_info->part_type == LIST_PARTITION && + part_info->num_columns > 1U); + + if (use_parenthesis) + err+= add_begin_parenthesis(fptr); for (i= 0; i < num_elements; i++) { part_column_list_val *col_val= &list_value->col_val_array[i]; @@ -2032,7 +2035,8 @@ static int add_column_list_values(File fptr, partition_info *part_info, if (i != (num_elements - 1)) err+= add_string(fptr, comma_str); } - err+= add_end_parenthesis(fptr); + if (use_parenthesis) + err+= add_end_parenthesis(fptr); return err; } @@ -3894,10 +3898,12 @@ bool mysql_unpack_partition(THD *thd, mem_alloc_error(sizeof(partition_info)); goto end; } - lex.part_info->part_state= part_state; - lex.part_info->part_state_len= part_state_len; + part_info= lex.part_info; + part_info->part_state= part_state; + part_info->part_state_len= part_state_len; DBUG_PRINT("info", ("Parse: %s", part_buf)); - if (parse_sql(thd, & parser_state, NULL)) + if (parse_sql(thd, & parser_state, NULL) || + part_info->fix_parser_data(thd)) { thd->free_items(); goto end; @@ -3918,7 +3924,6 @@ bool mysql_unpack_partition(THD *thd, */ DBUG_PRINT("info", ("Successful parse")); - part_info= lex.part_info; DBUG_PRINT("info", ("default engine = %s, default_db_type = %s", ha_resolve_storage_engine_name(part_info->default_engine_type), ha_resolve_storage_engine_name(default_db_type))); @@ -4370,6 +4375,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, } DBUG_RETURN(TRUE); } + alt_part_info->column_list= tab_part_info->column_list; + if (alt_part_info->fix_parser_data(thd)) + { + DBUG_RETURN(TRUE); + } } if (alter_info->flags & ALTER_ADD_PARTITION) { @@ -5126,6 +5136,10 @@ the generated partition syntax in a correct manner. { DBUG_PRINT("info", ("partition changed")); *partition_changed= TRUE; + if (thd->work_part_info->fix_parser_data(thd)) + { + DBUG_RETURN(TRUE); + } } /* Set up partition default_engine_type either from the create_info diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0610350b38f..9d9fa7cde2e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -515,10 +515,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 168 shift/reduce conflicts. + Currently there are 169 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 168 +%expect 169 /* Comments for TOKENS. @@ -1165,9 +1165,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type ulonglong_num real_ulonglong_num size_number -%type - part_bit_expr - %type replace_lock_option opt_low_priority insert_lock_option load_data_lock @@ -1300,8 +1297,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail install uninstall partition_entry binlog_base64_event init_key_options key_options key_opts key_opt key_using_alg - part_column_list part_column_expr_list part_column_expr_item - part_column_list_value + part_column_list server_def server_options_list server_option definer_opt no_definer definer END_OF_INPUT @@ -3818,6 +3814,7 @@ part_type_def: { partition_info *part_info= Lex->part_info; part_info->list_of_part_fields= TRUE; + part_info->column_list= FALSE; part_info->part_type= HASH_PARTITION; } | opt_linear HASH_SYM @@ -3869,20 +3866,22 @@ part_field_item: ; part_column_list: - COLUMN_LIST_SYM '(' part_field_list ')' - { - partition_info *part_info= Lex->part_info; - part_info->column_list= TRUE; - part_info->list_of_part_fields= TRUE; - } + COLUMN_LIST_SYM '(' part_field_list ')' + { + partition_info *part_info= Lex->part_info; + part_info->column_list= TRUE; + part_info->list_of_part_fields= TRUE; + } ; part_func: '(' remember_name part_func_expr remember_end ')' { - if (Lex->part_info->set_part_expr($2+1, $3, $4, FALSE)) + partition_info *part_info= Lex->part_info; + if (part_info->set_part_expr($2+1, $3, $4, FALSE)) { MYSQL_YYABORT; } + part_info->column_list= FALSE; } ; @@ -4067,7 +4066,7 @@ opt_part_values: else part_info->part_type= HASH_PARTITION; } - | VALUES LESS_SYM THAN_SYM part_func_max + | VALUES LESS_SYM THAN_SYM { LEX *lex= Lex; partition_info *part_info= lex->part_info; @@ -4083,7 +4082,8 @@ opt_part_values: else part_info->part_type= RANGE_PARTITION; } - | VALUES IN_SYM '(' part_list_func ')' + part_func_max {} + | VALUES IN_SYM { LEX *lex= Lex; partition_info *part_info= lex->part_info; @@ -4099,14 +4099,120 @@ opt_part_values: else part_info->part_type= LIST_PARTITION; } + part_values_in {} ; -part_column_expr_list: - part_column_expr_item {} - | part_column_expr_list ',' part_column_expr_item {} +part_func_max: + MAX_VALUE_SYM + { + partition_info *part_info= Lex->part_info; + + if (part_info->num_columns && + part_info->num_columns != 1U) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } + else + part_info->num_columns= 1U; + if (part_info->init_column_part()) + { + MYSQL_YYABORT; + } + if (part_info->add_max_value()) + { + MYSQL_YYABORT; + } + } + | part_value_item {} ; -part_column_expr_item: +part_values_in: + part_value_item + { + LEX *lex= Lex; + partition_info *part_info= lex->part_info; + + if (part_info->num_columns != 1U) + { + if (!lex->is_partition_management() || + part_info->num_columns == 0 || + part_info->num_columns > MAX_REF_PARTS) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } + /* + Reorganize the current large array into a list of small + arrays with one entry in each array. This can happen + in the first partition of an ALTER TABLE statement where + we ADD or REORGANIZE partitions. + */ + if (part_info->reorganize_into_single_field_col_val()) + { + MYSQL_YYABORT; + } + } + } + | '(' part_value_list ')' + { + partition_info *part_info= Lex->part_info; + if (part_info->num_columns < 2U) + { + my_parse_error(ER(ER_ROW_SINGLE_PARTITION_FIELD_ERROR)); + MYSQL_YYABORT; + } + } + ; + +part_value_list: + part_value_item {} + | part_value_list ',' part_value_item {} + ; + +part_value_item: + '(' + { + partition_info *part_info= Lex->part_info; + /* Initialisation code needed for each list of value expressions */ + if (!(part_info->column_list && + part_info->part_type == LIST_PARTITION && + part_info->num_columns == 1U) && + part_info->init_column_part()) + { + MYSQL_YYABORT; + } + } + part_value_item_list {} + ')' + { + LEX *lex= Lex; + partition_info *part_info= Lex->part_info; + + if (part_info->num_columns == 0) + part_info->num_columns= part_info->curr_list_object; + if (part_info->num_columns != part_info->curr_list_object) + { + /* + All value items lists must be of equal length, in some cases + which is covered by the above if-statement we don't know yet + how many columns is in the partition so the assignment above + ensures that we only report errors when we know we have an + error. + */ + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } + part_info->curr_list_object= 0; + } + ; + +part_value_item_list: + part_value_expr_item {} + | part_value_item_list ',' part_value_expr_item {} + ; + +part_value_expr_item: MAX_VALUE_SYM { partition_info *part_info= Lex->part_info; @@ -4116,223 +4222,29 @@ part_column_expr_item: my_parse_error(ER(ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR)); MYSQL_YYABORT; } - if (!(col_val= part_info->add_column_value())) + if (part_info->add_max_value()) { MYSQL_YYABORT; } - col_val->max_value= TRUE; } | bit_expr { - part_column_list_val *col_val; LEX *lex= Lex; + partition_info *part_info= lex->part_info; + Item *part_expr= $1; + if (!lex->safe_to_cache_query) { my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); MYSQL_YYABORT; } - if (!(col_val= lex->part_info->add_column_value())) + if (part_info->add_column_list_value(part_expr)) { MYSQL_YYABORT; } - col_val->item_expression= $1; - col_val->part_info= NULL; } ; -part_column_list_value: - COLUMN_LIST_SYM - { - LEX *lex= Lex; - partition_info *part_info= lex->part_info; - uint num_columns; - partition_element *p_elem= part_info->curr_part_elem; - part_column_list_val *col_val_array; - part_elem_value *list_val; - - if (!part_info->column_list && - !lex->is_partition_management()) - { - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); - MYSQL_YYABORT; - } - if (!(list_val= - (part_elem_value*)sql_calloc(sizeof(part_elem_value))) || - p_elem->list_val_list.push_back(list_val)) - { - mem_alloc_error(sizeof(part_elem_value)); - MYSQL_YYABORT; - } - if (part_info->num_columns) - num_columns= part_info->num_columns; - else - num_columns= MAX_REF_PARTS; - if (!(col_val_array= - (part_column_list_val*)sql_calloc(num_columns * - sizeof(part_column_list_val)))) - { - mem_alloc_error(num_columns * sizeof(part_elem_value)); - MYSQL_YYABORT; - } - list_val->col_val_array= col_val_array; - part_info->curr_list_val= list_val; - part_info->curr_list_object= 0; - } - '(' part_column_expr_list ')' - { - partition_info *part_info= Lex->part_info; - uint num_columns= part_info->num_columns; - if (num_columns && num_columns != part_info->curr_list_object) - { - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); - MYSQL_YYABORT; - } - part_info->num_columns= part_info->curr_list_object; - } - ; - -part_func_max: - max_value_sym - { - partition_info *part_info= Lex->part_info; - if (part_info->defined_max_value) - { - my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR)); - MYSQL_YYABORT; - } - if (part_info->column_list) - { - my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); - MYSQL_YYABORT; - } - part_info->defined_max_value= TRUE; - part_info->curr_part_elem->max_value= TRUE; - part_info->curr_part_elem->range_value= LONGLONG_MAX; - } - | part_range_func - { - partition_info *part_info= Lex->part_info; - if (part_info->defined_max_value) - { - my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR)); - MYSQL_YYABORT; - } - if (part_info->curr_part_elem->has_null_value) - { - my_parse_error(ER(ER_NULL_IN_VALUES_LESS_THAN)); - MYSQL_YYABORT; - } - if (part_info->column_list) - { - my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); - MYSQL_YYABORT; - } - } - | '(' part_column_list_value ')' - {} - ; - -max_value_sym: - MAX_VALUE_SYM - | '(' MAX_VALUE_SYM ')' - ; - -part_range_func: - '(' part_bit_expr ')' - { - partition_info *part_info= Lex->part_info; - if (!($2->unsigned_flag)) - part_info->curr_part_elem->signed_flag= TRUE; - part_info->curr_part_elem->range_value= $2->value; - } - ; - -part_list_func: - part_list_item {} - | part_list_func ',' part_list_item {} - ; - -part_list_item: - part_bit_expr - { - part_elem_value *value_ptr= $1; - partition_info *part_info= Lex->part_info; - if (!value_ptr->unsigned_flag) - part_info->curr_part_elem->signed_flag= TRUE; - if (!value_ptr->null_value && - part_info->curr_part_elem-> - list_val_list.push_back(value_ptr)) - { - mem_alloc_error(sizeof(part_elem_value)); - MYSQL_YYABORT; - } - if (part_info->column_list) - { - my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); - MYSQL_YYABORT; - } - } - | part_column_list_value - ; - -part_bit_expr: - bit_expr - { - Item *part_expr= $1; - THD *thd= YYTHD; - LEX *lex= thd->lex; - partition_info *part_info= lex->part_info; - Name_resolution_context *context= &lex->current_select->context; - TABLE_LIST *save_list= context->table_list; - const char *save_where= thd->where; - - context->table_list= 0; - thd->where= "partition function"; - - part_elem_value *value_ptr= - (part_elem_value*)sql_alloc(sizeof(part_elem_value)); - if (!value_ptr) - { - mem_alloc_error(sizeof(part_elem_value)); - MYSQL_YYABORT; - } - if (part_expr->walk(&Item::check_partition_func_processor, 0, - NULL)) - { - my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); - MYSQL_YYABORT; - } - if (part_expr->fix_fields(YYTHD, (Item**)0) || - ((context->table_list= save_list), FALSE) || - (!part_expr->const_item()) || - (!lex->safe_to_cache_query)) - { - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); - MYSQL_YYABORT; - } - thd->where= save_where; - value_ptr->value= part_expr->val_int(); - value_ptr->unsigned_flag= TRUE; - if (!part_expr->unsigned_flag && - value_ptr->value < 0) - value_ptr->unsigned_flag= FALSE; - if ((value_ptr->null_value= part_expr->null_value)) - { - if (part_info->curr_part_elem->has_null_value) - { - my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); - MYSQL_YYABORT; - } - part_info->curr_part_elem->has_null_value= TRUE; - } - else if (part_expr->result_type() != INT_RESULT) - { - my_parse_error(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR)); - MYSQL_YYABORT; - } - $$= value_ptr; - } - ; opt_sub_partition: /* empty */ From 975c1ff80801060abb7665f84d899cc0a57c7382 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 16 Oct 2009 17:08:34 +0200 Subject: [PATCH 13/27] Fixed review comments --- sql/ha_partition.cc | 2 +- sql/ha_partition.h | 2 +- sql/opt_range.cc | 29 ++++++++++++++++------------- sql/partition_element.h | 2 +- sql/partition_info.cc | 8 ++++---- sql/partition_info.h | 2 +- sql/sql_partition.cc | 40 +++++++++++++++++++++++++++------------- sql/sql_partition.h | 8 ++++---- 8 files changed, 55 insertions(+), 38 deletions(-) diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 1b7165dd590..0b6650ec11e 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1,4 +1,4 @@ -/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 3a09c1d2ea3..e5bb9ed05f5 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1,4 +1,4 @@ -/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 801045a8f6d..c65bcd0af84 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -655,8 +655,10 @@ public: */ uint real_keynr[MAX_KEY]; - /* Used to store 'current key tuples', in both range analysis and - * partitioning (list) analysis*/ + /* + Used to store 'current key tuples', in both range analysis and + partitioning (list) analysis + */ uchar min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; @@ -3131,7 +3133,7 @@ static int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) { int res, left_res=0, right_res=0; - int partno= (int)key_tree->part; + int key_tree_part= (int)key_tree->part; bool set_full_part_if_bad_ret= FALSE; bool ignore_part_fields= ppar->ignore_part_fields; bool did_set_ignore_part_fields= FALSE; @@ -3146,8 +3148,8 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) } /* Push SEL_ARG's to stack to enable looking backwards as well */ - ppar->cur_part_fields+= ppar->is_part_keypart[partno]; - ppar->cur_subpart_fields+= ppar->is_subpart_keypart[partno]; + ppar->cur_part_fields+= ppar->is_part_keypart[key_tree_part]; + ppar->cur_subpart_fields+= ppar->is_subpart_keypart[key_tree_part]; *(ppar->arg_stack_end++)= key_tree; if (key_tree->type == SEL_ARG::KEY_RANGE) @@ -3249,6 +3251,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) but this is a harder case we will solve later. For the harder case this clause then turns into use of all partitions and thus we simply set res= -1 as if the mapper had returned that. + TODO: What to do here is defined in WL#4065. */ if (ppar->arg_stack[0]->part == 0) { @@ -3283,7 +3286,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) Save our intent to mark full partition as used if we will not be able to obtain further limits on subpartitions */ - if (partno < ppar->last_part_partno) + if (key_tree_part < ppar->last_part_partno) { /* We need to ignore the rest of the partitioning fields in all @@ -3296,7 +3299,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) goto process_next_key_part; } - if (partno == ppar->last_subpart_partno && + if (key_tree_part == ppar->last_subpart_partno && (NULL != ppar->part_info->get_subpart_iter_for_interval)) { PARTITION_ITERATOR subpart_iter; @@ -3338,7 +3341,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) if (key_tree->is_singlepoint()) { - if (partno == ppar->last_part_partno && + if (key_tree_part == ppar->last_part_partno && ppar->cur_part_fields == ppar->part_fields && ppar->part_info->get_part_iter_for_interval == NULL) { @@ -3369,7 +3372,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) goto process_next_key_part; } - if (partno == ppar->last_subpart_partno && + if (key_tree_part == ppar->last_subpart_partno && ppar->cur_subpart_fields == ppar->subpart_fields) { /* @@ -3406,7 +3409,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree) we're processing subpartititoning's key parts, this means we'll not be able to infer any suitable condition, so bail out. */ - if (partno >= ppar->last_part_partno) + if (key_tree_part >= ppar->last_part_partno) { res= -1; goto pop_and_go_right; @@ -3455,8 +3458,8 @@ process_next_key_part: pop_and_go_right: /* Pop this key part info off the "stack" */ ppar->arg_stack_end--; - ppar->cur_part_fields-= ppar->is_part_keypart[partno]; - ppar->cur_subpart_fields-= ppar->is_subpart_keypart[partno]; + ppar->cur_part_fields-= ppar->is_part_keypart[key_tree_part]; + ppar->cur_subpart_fields-= ppar->is_subpart_keypart[key_tree_part]; if (res == -1) return -1; diff --git a/sql/partition_element.h b/sql/partition_element.h index d749681fe9b..bd18457fd5b 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006-2009 MySQL AB +/* Copyright (C) 2006-2008 MySQL AB, Sun Microsystems Inc. 2008-2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ef212fce28d..871ce4b8e45 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyright (C) 2006-2008 MySQL AB, Sun Microsystems Inc. 2008-2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -363,7 +363,7 @@ char* partition_info::has_unique_fields() for (j= 0; j < num_fields; j++) { field_name_inner= it_inner++; - if (i == j) + if (i >= j) continue; if (!(my_strcasecmp(system_charset_info, field_name_outer, @@ -660,7 +660,7 @@ bool partition_info::check_range_constants(THD *thd) if (column_list) { - part_column_list_val* loc_range_col_array; + part_column_list_val *loc_range_col_array; part_column_list_val *current_largest_col_val; uint num_column_values= part_field_list.elements; uint size_entries= sizeof(part_column_list_val) * num_column_values; @@ -669,7 +669,7 @@ bool partition_info::check_range_constants(THD *thd) LINT_INIT(current_largest_col_val); if (unlikely(range_col_array == NULL)) { - mem_alloc_error(num_parts * sizeof(longlong)); + mem_alloc_error(num_parts * size_entries); goto end; } loc_range_col_array= range_col_array; diff --git a/sql/partition_info.h b/sql/partition_info.h index 6e197198807..01d6ea93e2b 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -1,4 +1,4 @@ -/* Copyright 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 52e28311ead..52b73a06600 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1,4 +1,4 @@ -/* Copyright 2005-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2005-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1406,8 +1406,8 @@ static void set_up_partition_func_pointers(partition_info *part_info) DBUG_ASSERT(part_info->get_part_partition_id); if (!part_info->column_list) { - part_info->get_part_partition_id= - part_info->get_part_partition_id_charset; + part_info->get_part_partition_id_charset= + part_info->get_part_partition_id; part_info->get_part_partition_id= get_part_id_charset_func_part; } } @@ -2673,7 +2673,7 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr) part_info A reference to the partition_info struct where all the desired information is given out:part_id The partition id is returned through this pointer - out: func_value Value of partition function (longlong) + out:func_value Value of partition function (longlong) RETURN VALUE part_id Partition id of partition that would contain @@ -2731,7 +2731,7 @@ static void restore_part_field_pointers(Field **ptr, uchar **restore_ptr) get_partition_id_range_col get_partition_id_hash_nosub get_partition_id_key_nosub - get_partition_id_linhash_nosub + get_partition_id_linear_hash_nosub get_partition_id_linear_key_nosub */ @@ -2923,12 +2923,12 @@ uint32 get_partition_id_cols_list_for_endpoint(partition_info *part_info, } else { - DBUG_RETURN(list_index + test(left_endpoint ^ include_endpoint)); + DBUG_RETURN(list_index + test(!tailf)); } } while (max_list_index >= min_list_index); -notfound: if (cmp > 0) list_index++; +notfound: DBUG_RETURN(list_index); } @@ -3027,7 +3027,6 @@ int get_partition_id_range_col(partition_info *part_info, DBUG_PRINT("exit",("partition: %d", *part_id)); DBUG_RETURN(0); - return 0; } @@ -6746,13 +6745,28 @@ setup_subparts: } -/* TODO Commenting those functions */ +/* + This function takes a memory of packed fields in opt-range format + and stores it in record format. To avoid having to worry about how + the length of fields are calculated in opt-range format we send + an array of lengths used for each field in store_length_array. + + SYNOPSIS + store_tuple_to_record() + pfield Field array + store_length_array Array of field lengths + value Memory where fields are stored + value_end End of memory + + RETURN VALUE + nparts Number of fields assigned +*/ uint32 store_tuple_to_record(Field **pfield, uint32 *store_length_array, uchar *value, uchar *value_end) { - // see store_key_image_to_rec + /* This function is inspired by store_key_image_rec. */ uint32 nparts= 0; uchar *loc_value; while (value < value_end) @@ -6779,12 +6793,12 @@ uint32 store_tuple_to_record(Field **pfield, /* RANGE(columns) partitioning: compare value bound and probe tuple. - The value bound always is a full tuple (but may include MIN_VALUE and - MAX_VALUE special values). + The value bound always is a full tuple (but may include the MAX_VALUE + special value). The probe tuple may be a prefix of partitioning tuple. The tail_is_min parameter specifies whether the suffix components should be assumed to - hold MIN_VALUE or MAX_VALUE + hold MAX_VALUE */ static int cmp_rec_and_tuple(part_column_list_val *val, uint32 nvals_in_rec) diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 8fce2ebe6d1..47e5df0443f 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyright (C) 2006-2008 MySQL AB, Sun Microsystems Inc. 2008-2009 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -175,12 +175,12 @@ typedef struct st_partition_iter part_info Partitioning info is_subpart store_length_array Length of fields packed in opt_range_key format - min_val Left edge, field value in opt_range_key format. - max_val Right edge, field value in opt_range_key format. + min_val Left edge, field value in opt_range_key format + max_val Right edge, field value in opt_range_key format min_len Length of minimum value max_len Length of maximum value flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE, - NO_MAX_RANGE. + NO_MAX_RANGE part_iter Iterator structure to be initialized DESCRIPTION From 29b7a0aadcb9b18258f0286cbd7af7e3143c4148 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 16 Oct 2009 17:41:15 +0200 Subject: [PATCH 14/27] Removed GLOBAL INDEX syntax, need to develop GLOBAL indexes before adding syntax for it --- mysql-test/r/partition_not_windows.result | 4 ++-- mysql-test/r/partition_range.result | 5 ----- mysql-test/r/partition_symlink.result | 4 ++-- mysql-test/t/partition_range.test | 6 ------ sql/share/errmsg.txt | 2 -- sql/sql_lex.cc | 1 - sql/sql_lex.h | 3 --- sql/sql_yacc.yy | 22 +++------------------- 8 files changed, 7 insertions(+), 40 deletions(-) diff --git a/mysql-test/r/partition_not_windows.result b/mysql-test/r/partition_not_windows.result index 42dca557b3e..af6e3b5b9e3 100644 --- a/mysql-test/r/partition_not_windows.result +++ b/mysql-test/r/partition_not_windows.result @@ -24,8 +24,8 @@ data directory='/not/existing' index directory='/not/existing' ); Warnings: -Warning 1618 option ignored -Warning 1618 option ignored +Warning 1619 option ignored +Warning 1619 option ignored show create table t2; Table Create Table t2 CREATE TABLE `t2` ( diff --git a/mysql-test/r/partition_range.result b/mysql-test/r/partition_range.result index fc15665d698..a3d02b66c0a 100644 --- a/mysql-test/r/partition_range.result +++ b/mysql-test/r/partition_range.result @@ -84,11 +84,6 @@ create table t1 (a int, b char(20)) partition by range(a) (partition p0 values less than (column_list(1,"b"))); ERROR HY000: Inconsistency in usage of column lists for partitioning -create table t1 (a int, b char(20)); -create global index inx on t1 (a,b) -partition by range (a) -(partition p0 values less than (1)); -drop table t1; create table t1 (a int, b char(20)) partition by range column_list(b) (partition p0 values less than (column_list("b"))); diff --git a/mysql-test/r/partition_symlink.result b/mysql-test/r/partition_symlink.result index 60184d11d9c..7d3e220a211 100644 --- a/mysql-test/r/partition_symlink.result +++ b/mysql-test/r/partition_symlink.result @@ -101,8 +101,8 @@ data directory='/not/existing' index directory='/not/existing' ); Warnings: -Warning 1618 option ignored -Warning 1618 option ignored +Warning 1619 option ignored +Warning 1619 option ignored show create table t2; Table Create Table t2 CREATE TABLE `t2` ( diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test index c14dfd1822d..741bae7b3cc 100644 --- a/mysql-test/t/partition_range.test +++ b/mysql-test/t/partition_range.test @@ -74,12 +74,6 @@ create table t1 (a int, b char(20)) partition by range(a) (partition p0 values less than (column_list(1,"b"))); -create table t1 (a int, b char(20)); -create global index inx on t1 (a,b) -partition by range (a) -(partition p0 values less than (1)); -drop table t1; - create table t1 (a int, b char(20)) partition by range column_list(b) (partition p0 values less than (column_list("b"))); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 3d228f58360..78eb0e09c11 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6182,8 +6182,6 @@ ER_TOO_LONG_FIELD_COMMENT ER_FUNC_INEXISTENT_NAME_COLLISION 42000 eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual" -ER_GLOBAL_PARTITION_INDEX_ERROR - eng "Partitioning of indexes only supported for global indexes" ER_PARTITION_COLUMN_LIST_ERROR eng "Inconsistency in usage of column lists for partitioning" ER_WRONG_TYPE_COLUMN_VALUE_ERROR diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 703a97a6565..9f4e4cbd2ca 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -323,7 +323,6 @@ void lex_start(THD *thd) lex->select_lex.select_number= 1; lex->length=0; lex->part_info= 0; - lex->global_flag= 0; lex->select_lex.in_sum_expr=0; lex->select_lex.ftfunc_list_alloc.empty(); lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 3d638689700..d653540a628 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1565,9 +1565,6 @@ typedef struct st_lex : public Query_tables_list /* Partition info structure filled in by PARTITION BY parse part */ partition_info *part_info; - /* Flag to index a global index created */ - bool global_flag; - /* The definer of the object being created (view, trigger, stored routine). I.e. the value of DEFINER clause. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0610350b38f..bb6ea780619 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1157,7 +1157,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_natural_language_mode opt_query_expansion opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt - opt_global %type ulong_num real_ulong_num merge_insert_types @@ -1695,12 +1694,12 @@ create: $5->table.str); } } - | CREATE opt_global opt_unique_or_fulltext INDEX_SYM ident key_alg ON + | CREATE opt_unique_or_fulltext INDEX_SYM ident key_alg ON table_ident { LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_INDEX; - if (!lex->current_select->add_table_to_list(lex->thd, $8, + if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL, TL_OPTION_UPDATING)) MYSQL_YYABORT; @@ -1708,7 +1707,6 @@ create: lex->alter_info.flags= ALTER_ADD_INDEX; lex->col_list.empty(); lex->change=NullS; - lex->global_flag= $2; } '(' key_list ')' key_options { @@ -1719,22 +1717,13 @@ create: my_parse_error(ER(ER_SYNTAX_ERROR)); MYSQL_YYABORT; } - key= new Key($3, $5.str, &lex->key_create_info, 0, + key= new Key($2, $4.str, &lex->key_create_info, 0, lex->col_list); if (key == NULL) MYSQL_YYABORT; lex->alter_info.key_list.push_back(key); lex->col_list.empty(); } - opt_partitioning - { - LEX *lex= Lex; - if (!lex->global_flag && lex->part_info) - { - my_error(ER_GLOBAL_PARTITION_INDEX_ERROR, MYF(0)); - YYABORT; - } - } | CREATE DATABASE opt_if_not_exists ident { Lex->create_info.default_table_charset= NULL; @@ -4454,11 +4443,6 @@ opt_part_option: { Lex->part_info->curr_part_elem->part_comment= $3.str; } ; -opt_global: - /* empty */ { $$= FALSE;} - | GLOBAL_SYM { $$= TRUE; } - ; - /* End of partition parser part */ From 6e7a37d3e8fc1f32c382dae143eb091be1eb1e8f Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Mon, 19 Oct 2009 09:10:25 +0200 Subject: [PATCH 15/27] Fix for non-partition builds --- sql/partition_info.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 871ce4b8e45..c6356896cf7 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1615,5 +1615,25 @@ id_err: return 1; } +#else /* WITH_PARTITION_STORAGE_ENGINE */ + /* + For builds without partitioning we need to define these functions + since we they are called from the parser. The parser cannot + remove code parts using ifdef, but the code parts cannot be called + so we simply need to add empty functions to make the linker happy. + */ +part_column_list_val *partition_info::add_column_value() +{ + return NULL; +} +bool partition_info::set_part_expr(char *start_token, Item *item_ptr, + char *end_token, bool is_subpart) +{ + (void)start_token; + (void)item_ptr; + (void)end_token; + (void)is_subpart; + return FALSE; +} #endif /* WITH_PARTITION_STORAGE_ENGINE */ From ec7c4fb442842b46029f28355ece7d0104ea63ac Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Mon, 19 Oct 2009 13:40:08 +0200 Subject: [PATCH 16/27] port of fixes for bug-20577 and 46362 for TO_SECONDS --- mysql-test/r/partition_pruning.result | 329 ++++++++++++++++++++++++++ mysql-test/t/partition_pruning.test | 20 ++ sql/item_timefunc.cc | 38 ++- 3 files changed, 378 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 769d499fc0a..fc6cedc1081 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -656,6 +656,335 @@ EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01 id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p0001-01-01,pNULL,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where DROP TABLE t1; +# TO_SECONDS, test of LIST and index +CREATE TABLE t1 (a DATE, KEY(a)) +PARTITION BY LIST (TO_SECONDS(a)) +(PARTITION `p0001-01-01` VALUES IN (TO_SECONDS('0001-01-01')), +PARTITION `p2001-01-01` VALUES IN (TO_SECONDS('2001-01-01')), +PARTITION `pNULL` VALUES IN (NULL), +PARTITION `p0000-01-02` VALUES IN (TO_SECONDS('0000-01-02')), +PARTITION `p1001-01-01` VALUES IN (TO_SECONDS('1001-01-01'))); +INSERT INTO t1 VALUES ('0000-00-00'), ('0000-01-02'), ('0001-01-01'), +('1001-00-00'), ('1001-01-01'), ('1002-00-00'), ('2001-01-01'); +SELECT * FROM t1 WHERE a < '1001-01-01'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +SELECT * FROM t1 WHERE a <= '1001-01-01'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +SELECT * FROM t1 WHERE a >= '1001-01-01'; +a +1001-01-01 +1002-00-00 +2001-01-01 +SELECT * FROM t1 WHERE a > '1001-01-01'; +a +1002-00-00 +2001-01-01 +SELECT * FROM t1 WHERE a = '1001-01-01'; +a +1001-01-01 +SELECT * FROM t1 WHERE a < '1001-00-00'; +a +0000-00-00 +0000-01-02 +0001-01-01 +SELECT * FROM t1 WHERE a <= '1001-00-00'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +SELECT * FROM t1 WHERE a >= '1001-00-00'; +a +1001-00-00 +1001-01-01 +1002-00-00 +2001-01-01 +SELECT * FROM t1 WHERE a > '1001-00-00'; +a +1001-01-01 +1002-00-00 +2001-01-01 +SELECT * FROM t1 WHERE a = '1001-00-00'; +a +1001-00-00 +# Disabling warnings for the invalid date +SELECT * FROM t1 WHERE a < '1999-02-31'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +1002-00-00 +SELECT * FROM t1 WHERE a <= '1999-02-31'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +1002-00-00 +SELECT * FROM t1 WHERE a >= '1999-02-31'; +a +2001-01-01 +SELECT * FROM t1 WHERE a > '1999-02-31'; +a +2001-01-01 +SELECT * FROM t1 WHERE a = '1999-02-31'; +a +SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +1002-00-00 +SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1001-01-01'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +SELECT * FROM t1 WHERE a BETWEEN '0001-01-02' AND '1002-00-00'; +a +1001-00-00 +1001-01-01 +1002-00-00 +SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01'; +a +0001-01-01 +1001-00-00 +1001-01-01 +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02 range a a 4 NULL 3 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 range a a 4 NULL 4 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL,p1001-01-01 range a a 4 NULL 4 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL range a a 4 NULL 3 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1001-01-01 system a NULL NULL NULL 1 +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02 range a a 4 NULL 3 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02 range a a 4 NULL 3 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL,p1001-01-01 range a a 4 NULL 4 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL,p1001-01-01 range a a 4 NULL 4 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pNULL ref a a 4 const 1 Using where; Using index +# Disabling warnings for the invalid date +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 range a a 4 NULL 5 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 range a a 4 NULL 5 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL range a a 4 NULL 2 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL range a a 4 NULL 2 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pNULL ref a a 4 const 1 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 range a a 4 NULL 5 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 range a a 4 NULL 4 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-02' AND '1002-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pNULL,p1001-01-01 range a a 4 NULL 2 Using where; Using index +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p1001-01-01 range a a 4 NULL 3 Using where; Using index +# test without index +ALTER TABLE t1 DROP KEY a; +SELECT * FROM t1 WHERE a < '1001-01-01'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +SELECT * FROM t1 WHERE a <= '1001-01-01'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +SELECT * FROM t1 WHERE a >= '1001-01-01'; +a +1001-01-01 +1002-00-00 +2001-01-01 +SELECT * FROM t1 WHERE a > '1001-01-01'; +a +1002-00-00 +2001-01-01 +SELECT * FROM t1 WHERE a = '1001-01-01'; +a +1001-01-01 +SELECT * FROM t1 WHERE a < '1001-00-00'; +a +0000-00-00 +0000-01-02 +0001-01-01 +SELECT * FROM t1 WHERE a <= '1001-00-00'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +SELECT * FROM t1 WHERE a >= '1001-00-00'; +a +1001-00-00 +1001-01-01 +1002-00-00 +2001-01-01 +SELECT * FROM t1 WHERE a > '1001-00-00'; +a +1001-01-01 +1002-00-00 +2001-01-01 +SELECT * FROM t1 WHERE a = '1001-00-00'; +a +1001-00-00 +# Disabling warnings for the invalid date +SELECT * FROM t1 WHERE a < '1999-02-31'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +1002-00-00 +SELECT * FROM t1 WHERE a <= '1999-02-31'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +1002-00-00 +SELECT * FROM t1 WHERE a >= '1999-02-31'; +a +2001-01-01 +SELECT * FROM t1 WHERE a > '1999-02-31'; +a +2001-01-01 +SELECT * FROM t1 WHERE a = '1999-02-31'; +a +SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +1002-00-00 +SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1001-01-01'; +a +0000-00-00 +0000-01-02 +0001-01-01 +1001-00-00 +1001-01-01 +SELECT * FROM t1 WHERE a BETWEEN '0001-01-02' AND '1002-00-00'; +a +1001-00-00 +1001-01-01 +1002-00-00 +SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01'; +a +0001-01-01 +1001-00-00 +1001-01-01 +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p1001-01-01 system NULL NULL NULL NULL 1 +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1001-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pNULL ALL NULL NULL NULL NULL 7 Using where +# Disabling warnings for the invalid date +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a < '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a <= '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a >= '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a > '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p2001-01-01,pNULL ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a = '1999-02-31'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pNULL ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1002-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0000-00-00' AND '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p0000-01-02,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-02' AND '1002-00-00'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 pNULL,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a BETWEEN '0001-01-01' AND '1001-01-01'; +id select_type table partitions type possible_keys key key_len ref rows Extra +1 SIMPLE t1 p0001-01-01,pNULL,p1001-01-01 ALL NULL NULL NULL NULL 7 Using where +DROP TABLE t1; # Test with DATETIME column NOT NULL CREATE TABLE t1 ( a int(10) unsigned NOT NULL, diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test index 11e65be45fc..4a575903866 100644 --- a/mysql-test/t/partition_pruning.test +++ b/mysql-test/t/partition_pruning.test @@ -51,6 +51,26 @@ INSERT INTO t1 VALUES ('0000-00-00'), ('0000-01-02'), ('0001-01-01'), ALTER TABLE t1 DROP KEY a; --source include/partition_date_range.inc DROP TABLE t1; +--echo # TO_SECONDS, test of LIST and index +CREATE TABLE t1 (a DATE, KEY(a)) +PARTITION BY LIST (TO_SECONDS(a)) +(PARTITION `p0001-01-01` VALUES IN (TO_SECONDS('0001-01-01')), + PARTITION `p2001-01-01` VALUES IN (TO_SECONDS('2001-01-01')), + PARTITION `pNULL` VALUES IN (NULL), + PARTITION `p0000-01-02` VALUES IN (TO_SECONDS('0000-01-02')), + PARTITION `p1001-01-01` VALUES IN (TO_SECONDS('1001-01-01'))); +if ($verify_without_partitions) +{ +ALTER TABLE t1 REMOVE PARTITIONING; +} +INSERT INTO t1 VALUES ('0000-00-00'), ('0000-01-02'), ('0001-01-01'), + ('1001-00-00'), ('1001-01-01'), ('1002-00-00'), ('2001-01-01'); +--source include/partition_date_range.inc +--echo # test without index +ALTER TABLE t1 DROP KEY a; +--source include/partition_date_range.inc +DROP TABLE t1; + # # Bug#46362: Endpoint should be set to false for TO_DAYS(DATE) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 29fab2a38a2..fd05737728e 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -944,8 +944,29 @@ longlong Item_func_to_days::val_int() longlong Item_func_to_seconds::val_int_endpoint(bool left_endp, bool *incl_endp) { - longlong res= val_int(); - return null_value ? LONGLONG_MIN : res; + DBUG_ASSERT(fixed == 1); + MYSQL_TIME ltime; + longlong seconds; + longlong days; + int dummy; /* unused */ + if (get_arg0_date(<ime, TIME_FUZZY_DATE)) + { + /* got NULL, leave the incl_endp intact */ + return LONGLONG_MIN; + } + seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second; + seconds= ltime.neg ? -seconds : seconds; + days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day); + seconds+= days * 24L * 3600L; + /* Set to NULL if invalid date, but keep the value */ + null_value= check_date(<ime, + (ltime.year || ltime.month || ltime.day), + (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE), + &dummy); + /* + Even if the evaluation return NULL, seconds is useful for pruning + */ + return seconds; } longlong Item_func_to_seconds::val_int() @@ -956,10 +977,10 @@ longlong Item_func_to_seconds::val_int() longlong days; if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) return 0; - seconds=ltime.hour*3600L+ltime.minute*60+ltime.second; + seconds= ltime.hour * 3600L + ltime.minute * 60 + ltime.second; seconds=ltime.neg ? -seconds : seconds; - days= (longlong) calc_daynr(ltime.year,ltime.month,ltime.day); - return (seconds + days * (24L * 3600L)); + days= (longlong) calc_daynr(ltime.year, ltime.month, ltime.day); + return seconds + days * 24L * 3600L; } /* @@ -992,10 +1013,9 @@ enum_monotonicity_info Item_func_to_seconds::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; + if (args[0]->field_type() == MYSQL_TYPE_DATE || + args[0]->field_type() == MYSQL_TYPE_DATETIME) + return MONOTONIC_STRICT_INCREASING_NOT_NULL; } return NON_MONOTONIC; } From 37b6043070ebed97158c4ef9e3c8534a8c23c860 Mon Sep 17 00:00:00 2001 From: Mattias Jonsson Date: Tue, 20 Oct 2009 14:59:42 +0200 Subject: [PATCH 17/27] WL#3352: Extending Partitioning Types and new partition function Moved the new errors back to the end of errmsg.txt Updated two tests with new error message --- mysql-test/r/partition_not_windows.result | 4 ++-- mysql-test/r/partition_symlink.result | 4 ++-- .../parts/r/partition_special_innodb.result | 2 +- .../parts/r/partition_special_myisam.result | 2 +- sql/share/errmsg.txt | 20 +++++++++---------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/partition_not_windows.result b/mysql-test/r/partition_not_windows.result index af6e3b5b9e3..42dca557b3e 100644 --- a/mysql-test/r/partition_not_windows.result +++ b/mysql-test/r/partition_not_windows.result @@ -24,8 +24,8 @@ data directory='/not/existing' index directory='/not/existing' ); Warnings: -Warning 1619 option ignored -Warning 1619 option ignored +Warning 1618 option ignored +Warning 1618 option ignored show create table t2; Table Create Table t2 CREATE TABLE `t2` ( diff --git a/mysql-test/r/partition_symlink.result b/mysql-test/r/partition_symlink.result index 7d3e220a211..60184d11d9c 100644 --- a/mysql-test/r/partition_symlink.result +++ b/mysql-test/r/partition_symlink.result @@ -101,8 +101,8 @@ data directory='/not/existing' index directory='/not/existing' ); Warnings: -Warning 1619 option ignored -Warning 1619 option ignored +Warning 1618 option ignored +Warning 1618 option ignored show create table t2; Table Create Table t2 CREATE TABLE `t2` ( diff --git a/mysql-test/suite/parts/r/partition_special_innodb.result b/mysql-test/suite/parts/r/partition_special_innodb.result index 8869f6d450c..26c1ac9356c 100644 --- a/mysql-test/suite/parts/r/partition_special_innodb.result +++ b/mysql-test/suite/parts/r/partition_special_innodb.result @@ -133,7 +133,7 @@ partition pa1 max_rows=20 min_rows=2, partition pa2 max_rows=30 min_rows=3, partition pa3 max_rows=30 min_rows=4, partition pa4 max_rows=40 min_rows=2); -ERROR 42000: Too many key parts specified; max 16 parts allowed +ERROR HY000: Too many fields in 'list of partition fields' create table t1 (a date not null, b varchar(50) not null, c varchar(50) not null, d enum('m', 'w') not null, e int not null, f decimal (18,2) not null, g bigint not null, h tinyint not null, a1 date not null, b1 varchar(50) not null, c1 varchar(50) not null, d1 enum('m', 'w') not null, e1 int not null, f1 decimal (18,2) not null, g1 bigint not null, h1 tinyint not null, a2 date not null, b2 varchar(50) not null, c2 varchar(50) not null, d2 enum('m', 'w') not null, e2 int not null, f2 decimal (18,2) not null, g2 bigint not null, h2 tinyint not null, a3 date not null, b3 varchar(50) not null, c3 varchar(50) not null, d3 enum('m', 'w') not null, e3 int not null, f3 decimal (18,2) not null, g3 bigint not null, h3 tinyint not null, i char(255), primary key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1)) engine='InnoDB' partition by key(a,b,c,d,e,f,g,h) ( partition pa1 max_rows=20 min_rows=2, diff --git a/mysql-test/suite/parts/r/partition_special_myisam.result b/mysql-test/suite/parts/r/partition_special_myisam.result index 7167d6af39e..60c9f9666cd 100644 --- a/mysql-test/suite/parts/r/partition_special_myisam.result +++ b/mysql-test/suite/parts/r/partition_special_myisam.result @@ -133,7 +133,7 @@ partition pa1 max_rows=20 min_rows=2, partition pa2 max_rows=30 min_rows=3, partition pa3 max_rows=30 min_rows=4, partition pa4 max_rows=40 min_rows=2); -ERROR 42000: Too many key parts specified; max 16 parts allowed +ERROR HY000: Too many fields in 'list of partition fields' create table t1 (a date not null, b varchar(50) not null, c varchar(50) not null, d enum('m', 'w') not null, e int not null, f decimal (18,2) not null, g bigint not null, h tinyint not null, a1 date not null, b1 varchar(50) not null, c1 varchar(50) not null, d1 enum('m', 'w') not null, e1 int not null, f1 decimal (18,2) not null, g1 bigint not null, h1 tinyint not null, a2 date not null, b2 varchar(50) not null, c2 varchar(50) not null, d2 enum('m', 'w') not null, e2 int not null, f2 decimal (18,2) not null, g2 bigint not null, h2 tinyint not null, a3 date not null, b3 varchar(50) not null, c3 varchar(50) not null, d3 enum('m', 'w') not null, e3 int not null, f3 decimal (18,2) not null, g3 bigint not null, h3 tinyint not null, i char(255), primary key(a,b,c,d,e,f,g,h,a1,b1,c1,d1,e1,f1,g1,h1)) engine='MyISAM' partition by key(a,b,c,d,e,f,g,h) ( partition pa1 max_rows=20 min_rows=2, diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a379b11c812..87ac1810c8e 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5822,8 +5822,6 @@ ER_SAME_NAME_PARTITION eng "Duplicate partition name %-.192s" ger "Doppelter Partitionsname: %-.192s" swe "Duplicerat partitionsnamn %-.192s" -ER_SAME_NAME_PARTITION_FIELD - eng "Duplicate partition field name %-.192s" ER_NO_BINLOG_ERROR eng "It is not allowed to shut off binlog on this command" ger "Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten" @@ -6182,14 +6180,6 @@ ER_TOO_LONG_FIELD_COMMENT ER_FUNC_INEXISTENT_NAME_COLLISION 42000 eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual" -ER_PARTITION_COLUMN_LIST_ERROR - eng "Inconsistency in usage of column lists for partitioning" -ER_WRONG_TYPE_COLUMN_VALUE_ERROR - eng "Partition column values of incorrect type" -ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR - eng "Too many fields in '%s'" -ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR - eng "Cannot use MAXVALUE as value in List partitioning" # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # mysql_priv.h with the new maximal additional length for explain_filename. @@ -6216,3 +6206,13 @@ ER_TOO_MANY_CONCURRENT_TRXS WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" +ER_SAME_NAME_PARTITION_FIELD + eng "Duplicate partition field name %-.192s" +ER_PARTITION_COLUMN_LIST_ERROR + eng "Inconsistency in usage of column lists for partitioning" +ER_WRONG_TYPE_COLUMN_VALUE_ERROR + eng "Partition column values of incorrect type" +ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR + eng "Too many fields in '%-.192s'" +ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR + eng "Cannot use MAXVALUE as value in List partitioning" From bbd922b09c94bafb18e583a00865750164358736 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 21 Oct 2009 12:40:21 +0200 Subject: [PATCH 18/27] Removed column_list and fixed all issues relating to this change --- mysql-test/r/partition.result | 8 +- mysql-test/r/partition_column.result | 134 ++++++------- mysql-test/r/partition_column_prune.result | 34 ++-- mysql-test/r/partition_error.result | 13 +- mysql-test/r/partition_not_windows.result | 4 +- mysql-test/r/partition_range.result | 3 +- mysql-test/r/partition_symlink.result | 4 +- mysql-test/t/disabled.def | 1 - mysql-test/t/partition.test | 6 +- mysql-test/t/partition_column_prune.test | 34 ++-- mysql-test/t/partition_error.test | 10 +- mysql-test/t/partition_range.test | 2 +- sql/partition_info.cc | 213 ++++++++++++--------- sql/partition_info.h | 6 +- sql/sql_partition.cc | 85 ++++---- sql/sql_yacc.yy | 36 +++- 16 files changed, 330 insertions(+), 263 deletions(-) diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 2d54a66fe11..e62d0515508 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -405,14 +405,12 @@ create table t1 (a bigint) partition by range (a) (partition p0 values less than (0xFFFFFFFFFFFFFFFF), partition p1 values less than (10)); -ERROR 42000: VALUES value must be of same type as partition function near '), -partition p1 values less than (10))' at line 3 +ERROR HY000: VALUES value must be of same type as partition function create table t1 (a bigint) partition by list (a) (partition p0 values in (0xFFFFFFFFFFFFFFFF), partition p1 values in (10)); -ERROR 42000: VALUES value must be of same type as partition function near '), -partition p1 values in (10))' at line 3 +ERROR HY000: VALUES value must be of same type as partition function create table t1 (a bigint unsigned) partition by range (a) (partition p0 values less than (100), @@ -1407,7 +1405,7 @@ DROP TABLE t1; CREATE TABLE t1 (a int) PARTITION BY RANGE(a) (PARTITION p0 VALUES LESS THAN (NULL)); -ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '))' at line 3 +ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN create table t1 (s1 int auto_increment primary key) partition by list (s1) (partition p1 values in (1), diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index fb7f815fd98..f4e7cd9bf94 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -4,7 +4,7 @@ partition by key (a,a); ERROR HY000: Duplicate partition field name a create table t1 (a int, b int) partition by list column_list(a,a) -( partition p values in (column_list(1,1))); +( partition p values in ((1,1))); ERROR HY000: Duplicate partition field name a create table t1 (a int signed) partition by list (a) @@ -26,10 +26,8 @@ a drop table t1; create table t1 (a int signed) partition by list column_list(a) -( partition p0 values in (column_list(1), column_list(3), column_list(5), -column_list(7), column_list(9), column_list(NULL)), -partition p1 values in (column_list(2), column_list(4), column_list(6), -column_list(8), column_list(0))); +( partition p0 values in (1, 3, 5, 7, 9, NULL), +partition p1 values in (2, 4, 6, 8, 0)); insert into t1 values (NULL),(0),(1),(2),(2),(4),(4),(4),(8),(8); select * from t1 where a <= NULL; a @@ -46,10 +44,9 @@ a drop table t1; create table t1 (a int, b int) partition by list column_list(a,b) -( partition p0 values in (column_list(1, NULL), column_list(2, NULL), -column_list(NULL, NULL)), -partition p1 values in (column_list(1,1), column_list(2,2)), -partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +( partition p0 values in ((1, NULL), (2, NULL), (NULL, NULL)), +partition p1 values in ((1,1), (2,2)), +partition p2 values in ((3, NULL), (NULL, 1))); insert into t1 values (3, NULL); insert into t1 values (NULL, 1); insert into t1 values (NULL, NULL); @@ -81,9 +78,9 @@ t1 CREATE TABLE `t1` ( `b` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST COLUMN_LIST(a,b) -(PARTITION p0 VALUES IN ( COLUMN_LIST(1,NULL), COLUMN_LIST(2,NULL), COLUMN_LIST(NULL,NULL)) ENGINE = MyISAM, - PARTITION p1 VALUES IN ( COLUMN_LIST(1,1), COLUMN_LIST(2,2)) ENGINE = MyISAM, - PARTITION p2 VALUES IN ( COLUMN_LIST(3,NULL), COLUMN_LIST(NULL,1)) ENGINE = MyISAM) */ +(PARTITION p0 VALUES IN ((1,NULL),(2,NULL),(NULL,NULL)) ENGINE = MyISAM, + PARTITION p1 VALUES IN ((1,1),(2,2)) ENGINE = MyISAM, + PARTITION p2 VALUES IN ((3,NULL),(NULL,1)) ENGINE = MyISAM) */ drop table t1; create table t1 (a int) partition by list (a) @@ -104,8 +101,13 @@ ERROR HY000: Table has no partition for value 5 drop table t1; create table t1 (a int) partition by list column_list(a) -( partition p0 values in (column_list(2), column_list(1)), -partition p1 values in (column_list(4), column_list(NULL), column_list(3))); +( partition p0 values in (2, 1), +partition p1 values in ((4), (NULL), (3))); +ERROR 42000: Row expressions in VALUES IN only allowed for multi-field column partitioning near '))' at line 4 +create table t1 (a int) +partition by list column_list(a) +( partition p0 values in (2, 1), +partition p1 values in (4, NULL, 3)); insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -119,26 +121,26 @@ t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY LIST COLUMN_LIST(a) -(PARTITION p0 VALUES IN ( COLUMN_LIST(2), COLUMN_LIST(1)) ENGINE = MyISAM, - PARTITION p1 VALUES IN ( COLUMN_LIST(4), COLUMN_LIST(NULL), COLUMN_LIST(3)) ENGINE = MyISAM) */ +(PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM, + PARTITION p1 VALUES IN (4,NULL,3) ENGINE = MyISAM) */ drop table t1; create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) subpartitions 4 -( partition p0 values less than (column_list(1, NULL, MAXVALUE, NULL)), -partition p1 values less than (column_list(1, 'a', MAXVALUE, TO_DAYS('1999-01-01'))), -partition p2 values less than (column_list(1, 'a', MAXVALUE, MAXVALUE)), -partition p3 values less than (column_list(1, MAXVALUE, MAXVALUE, MAXVALUE))); +( partition p0 values less than (1, NULL, MAXVALUE, NULL), +partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), +partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), +partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); drop table t1; create table t1 (a int, b char(10), c varchar(5), d int) partition by range column_list(a,b,c) subpartition by key (c,d) subpartitions 3 -( partition p0 values less than (column_list(1,'abc','abc')), -partition p1 values less than (column_list(2,'abc','abc')), -partition p2 values less than (column_list(3,'abc','abc')), -partition p3 values less than (column_list(4,'abc','abc'))); +( partition p0 values less than (1,'abc','abc'), +partition p1 values less than (2,'abc','abc'), +partition p2 values less than (3,'abc','abc'), +partition p3 values less than (4,'abc','abc')); insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); @@ -151,8 +153,8 @@ a b c d drop table t1; create table t1 (a int, b varchar(2), c int) partition by range column_list (a, b, c) -(partition p0 values less than (column_list(1, 'A', 1)), -partition p1 values less than (column_list(1, 'B', 1))); +(partition p0 values less than (1, 'A', 1), +partition p1 values less than (1, 'B', 1)); insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; id select_type table partitions type possible_keys key key_len ref rows Extra @@ -163,7 +165,7 @@ a b c drop table t1; create table t1 (a char, b char, c char) partition by list column_list(a) -( partition p0 values in (column_list('a'))); +( partition p0 values in ('a')); insert into t1 (a) values ('a'); select * from t1 where a = 'a'; a b c @@ -171,32 +173,32 @@ a NULL NULL drop table t1; create table t1 (d timestamp) partition by range column_list(d) -( partition p0 values less than (column_list('2000-01-01')), -partition p1 values less than (column_list('2040-01-01'))); +( partition p0 values less than ('2000-01-01'), +partition p1 values less than ('2040-01-01')); ERROR HY000: Partition column values of incorrect type create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (column_list(null, 10))); +(partition p0 values less than (null, 10)); drop table t1; create table t1 (d date) partition by range column_list(d) -( partition p0 values less than (column_list('2000-01-01')), -partition p1 values less than (column_list('2009-01-01'))); +( partition p0 values less than ('2000-01-01'), +partition p1 values less than ('2009-01-01')); drop table t1; create table t1 (d date) partition by range column_list(d) -( partition p0 values less than (column_list('1999-01-01')), -partition p1 values less than (column_list('2000-01-01'))); +( partition p0 values less than ('1999-01-01'), +partition p1 values less than ('2000-01-01')); drop table t1; create table t1 (d date) partition by range column_list(d) -( partition p0 values less than (column_list('2000-01-01')), -partition p1 values less than (column_list('3000-01-01'))); +( partition p0 values less than ('2000-01-01'), +partition p1 values less than ('3000-01-01')); drop table t1; create table t1 (a int, b int) partition by range column_list(a,b) -(partition p2 values less than (column_list(99,99)), -partition p1 values less than (column_list(99,999))); +(partition p2 values less than (99,99), +partition p1 values less than (99,999)); insert into t1 values (99,998); select * from t1 where b = 998; a b @@ -210,23 +212,23 @@ int drop table t1; create table t1 (a int, b int) partition by list column_list(a,b) -(partition p0 values in (column_list(maxvalue,maxvalue))); +(partition p0 values in ((maxvalue,maxvalue))); ERROR 42000: Cannot use MAXVALUE as value in List partitioning near 'maxvalue,maxvalue)))' at line 3 create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (column_list(maxvalue,maxvalue))); +(partition p0 values less than (maxvalue,maxvalue)); drop table t1; create table t1 (a int) partition by list column_list(a) -(partition p0 values in (column_list(0))); +(partition p0 values in (0)); select partition_method from information_schema.partitions where table_name='t1'; partition_method LIST COLUMN_LIST drop table t1; create table t1 (a char(6)) partition by range column_list(a) -(partition p0 values less than (column_list('H23456')), -partition p1 values less than (column_list('M23456'))); +(partition p0 values less than ('H23456'), +partition p1 values less than ('M23456')); insert into t1 values ('F23456'); select * from t1; a @@ -234,13 +236,13 @@ F23456 drop table t1; create table t1 (a char(6)) partition by range column_list(a) -(partition p0 values less than (column_list(H23456)), -partition p1 values less than (column_list(M23456))); +(partition p0 values less than (H23456), +partition p1 values less than (M23456)); ERROR 42S22: Unknown column 'H23456' in 'field list' create table t1 (a char(6)) partition by range column_list(a) -(partition p0 values less than (column_list(23456)), -partition p1 values less than (column_list(23456))); +(partition p0 values less than (23456), +partition p1 values less than (23456)); ERROR HY000: VALUES LESS THAN value must be strictly increasing for each partition create table t1 (a int, b int) partition by range column_list(a,b) @@ -248,14 +250,14 @@ partition by range column_list(a,b) ERROR 42000: Inconsistency in usage of column lists for partitioning near '))' at line 3 create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (column_list(1,1,1)); +(partition p0 values less than (1,1,1); ERROR HY000: Inconsistency in usage of column lists for partitioning create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (column_list(1, NULL)), -partition p1 values less than (column_list(2, maxvalue)), -partition p2 values less than (column_list(3, 3)), -partition p3 values less than (column_list(10, NULL))); +(partition p0 values less than (1, NULL), +partition p1 values less than (2, maxvalue), +partition p2 values less than (3, 3), +partition p3 values less than (10, NULL)); insert into t1 values (10,0); ERROR HY000: Table has no partition for value from column_list insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1); @@ -270,9 +272,9 @@ a b 9 1 alter table t1 partition by range column_list(b,a) -(partition p0 values less than (column_list(1,2)), -partition p1 values less than (column_list(3,3)), -partition p2 values less than (column_list(9,5))); +(partition p0 values less than (1,2), +partition p1 values less than (3,3), +partition p2 values less than (9,5)); explain partitions select * from t1 where b < 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 7 Using where @@ -294,21 +296,21 @@ a b 3 1 9 1 alter table t1 reorganize partition p1 into -(partition p11 values less than (column_list(2,2)), -partition p12 values less than (column_list(3,3))); +(partition p11 values less than (2,2), +partition p12 values less than (3,3)); alter table t1 reorganize partition p0 into -(partition p01 values less than (column_list(0,3)), -partition p02 values less than (column_list(1,1))); +(partition p01 values less than (0,3), +partition p02 values less than (1,1)); ERROR HY000: Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range alter table t1 reorganize partition p2 into -(partition p2 values less than(column_list(9,6,1))); +(partition p2 values less than(9,6,1)); ERROR HY000: Inconsistency in usage of column lists for partitioning alter table t1 reorganize partition p2 into (partition p2 values less than (10)); ERROR HY000: Inconsistency in usage of column lists for partitioning alter table t1 reorganize partition p2 into -(partition p21 values less than (column_list(4,7)), -partition p22 values less than (column_list(9,5))); +(partition p21 values less than (4,7), +partition p22 values less than (9,5)); explain partitions select * from t1 where b < 4; id select_type table partitions type possible_keys key key_len ref rows Extra 1 SIMPLE t1 p0,p11,p12,p21 ALL NULL NULL NULL NULL 7 Using where @@ -324,13 +326,13 @@ create table t1 (a int, b int) partition by list column_list(a,b) subpartition by hash (b) subpartitions 2 -(partition p0 values in (column_list(0,0), column_list(1,1)), -partition p1 values in (column_list(1000,1000))); +(partition p0 values in ((0,0), (1,1)), +partition p1 values in ((1000,1000))); insert into t1 values (1000,1000); drop table t1; create table t1 (a char, b char, c char) partition by range column_list(a,b,c) -( partition p0 values less than (column_list('a','b','c'))); +( partition p0 values less than ('a','b','c')); alter table t1 add partition -(partition p1 values less than (column_list('b','c','d'))); +(partition p1 values less than ('b','c','d')); drop table t1; diff --git a/mysql-test/r/partition_column_prune.result b/mysql-test/r/partition_column_prune.result index 8f7a8f85d05..5699582a0dc 100644 --- a/mysql-test/r/partition_column_prune.result +++ b/mysql-test/r/partition_column_prune.result @@ -1,7 +1,7 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; create table t1 (a char, b char, c char) partition by range column_list(a,b,c) -( partition p0 values less than (column_list('a','b','c'))); +( partition p0 values less than ('a','b','c')); insert into t1 values ('a', NULL, 'd'); explain partitions select * from t1 where a = 'a' AND c = 'd'; id select_type table partitions type possible_keys key key_len ref rows Extra @@ -11,13 +11,13 @@ a b c a NULL d drop table t1; create table t1 (a int not null) partition by range column_list(a) ( -partition p0 values less than (column_list(10)), -partition p1 values less than (column_list(20)), -partition p2 values less than (column_list(30)), -partition p3 values less than (column_list(40)), -partition p4 values less than (column_list(50)), -partition p5 values less than (column_list(60)), -partition p6 values less than (column_list(70)) +partition p0 values less than (10), +partition p1 values less than (20), +partition p2 values less than (30), +partition p3 values less than (40), +partition p4 values less than (50), +partition p5 values less than (60), +partition p6 values less than (70) ); insert into t1 values (5),(15),(25),(35),(45),(55),(65); insert into t1 values (5),(15),(25),(35),(45),(55),(65); @@ -41,15 +41,15 @@ id select_type table partitions type possible_keys key key_len ref rows Extra drop table t1, t2; create table t1 (a int not null, b int not null ) partition by range column_list(a,b) ( -partition p01 values less than (column_list(2,10)), -partition p02 values less than (column_list(2,20)), -partition p03 values less than (column_list(2,30)), -partition p11 values less than (column_list(4,10)), -partition p12 values less than (column_list(4,20)), -partition p13 values less than (column_list(4,30)), -partition p21 values less than (column_list(6,10)), -partition p22 values less than (column_list(6,20)), -partition p23 values less than (column_list(6,30)) +partition p01 values less than (2,10), +partition p02 values less than (2,20), +partition p03 values less than (2,30), +partition p11 values less than (4,10), +partition p12 values less than (4,20), +partition p13 values less than (4,30), +partition p21 values less than (6,10), +partition p22 values less than (6,20), +partition p23 values less than (6,30) ); insert into t1 values (2,5), (2,15), (2,25), (4,5), (4,15), (4,25), (6,5), (6,15), (6,25); diff --git a/mysql-test/r/partition_error.result b/mysql-test/r/partition_error.result index 511806d64bd..d24c3de3cc0 100644 --- a/mysql-test/r/partition_error.result +++ b/mysql-test/r/partition_error.result @@ -361,8 +361,7 @@ partition by range (a) partitions 2 (partition x1 values less than (4.0) tablespace ts1, partition x2 values less than (8) tablespace ts2); -ERROR 42000: VALUES value must be of same type as partition function near ') tablespace ts1, -partition x2 values less than (8) tablespace ts2)' at line 8 +ERROR HY000: VALUES value must be of same type as partition function CREATE TABLE t1 ( a int not null, b int not null, @@ -412,8 +411,7 @@ partition by list (a) partitions 2 (partition x1 values less than 4, partition x2 values less than (5)); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '4, -partition x2 values less than (5))' at line 8 +ERROR HY000: Only RANGE PARTITIONING can use VALUES LESS THAN in partition definition CREATE TABLE t1 ( a int not null, b int not null, @@ -423,7 +421,7 @@ partition by range (a) partitions 2 (partition x1 values less than maxvalue, partition x2 values less than (5)); -ERROR 42000: MAXVALUE can only be used in last partition definition near '))' at line 9 +ERROR HY000: MAXVALUE can only be used in last partition definition CREATE TABLE t1 ( a int not null, b int not null, @@ -433,7 +431,7 @@ partition by range (a) partitions 2 (partition x1 values less than maxvalue, partition x2 values less than maxvalue); -ERROR 42000: MAXVALUE can only be used in last partition definition near 'maxvalue)' at line 9 +ERROR HY000: MAXVALUE can only be used in last partition definition CREATE TABLE t1 ( a int not null, b int not null, @@ -602,8 +600,7 @@ partition by list (a) partitions 2 (partition x1 values in (4.0, 12+8), partition x2 values in (3, 21)); -ERROR 42000: VALUES value must be of same type as partition function near ' 12+8), -partition x2 values in (3, 21))' at line 8 +ERROR HY000: VALUES value must be of same type as partition function CREATE TABLE t1 ( a int not null, b int not null, diff --git a/mysql-test/r/partition_not_windows.result b/mysql-test/r/partition_not_windows.result index af6e3b5b9e3..42dca557b3e 100644 --- a/mysql-test/r/partition_not_windows.result +++ b/mysql-test/r/partition_not_windows.result @@ -24,8 +24,8 @@ data directory='/not/existing' index directory='/not/existing' ); Warnings: -Warning 1619 option ignored -Warning 1619 option ignored +Warning 1618 option ignored +Warning 1618 option ignored show create table t2; Table Create Table t2 CREATE TABLE `t2` ( diff --git a/mysql-test/r/partition_range.result b/mysql-test/r/partition_range.result index 0eca01b54c7..44e76f8751e 100644 --- a/mysql-test/r/partition_range.result +++ b/mysql-test/r/partition_range.result @@ -3,8 +3,7 @@ create table t1 (a int) partition by range (a) ( partition p0 values less than (NULL), partition p1 values less than (MAXVALUE)); -ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '), -partition p1 values less than (MAXVALUE))' at line 3 +ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN create table t1 (a datetime not null) partition by range (TO_SECONDS(a)) ( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')), diff --git a/mysql-test/r/partition_symlink.result b/mysql-test/r/partition_symlink.result index 7d3e220a211..60184d11d9c 100644 --- a/mysql-test/r/partition_symlink.result +++ b/mysql-test/r/partition_symlink.result @@ -101,8 +101,8 @@ data directory='/not/existing' index directory='/not/existing' ); Warnings: -Warning 1619 option ignored -Warning 1619 option ignored +Warning 1618 option ignored +Warning 1618 option ignored show create table t2; Table Create Table t2 CREATE TABLE `t2` ( diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 5436b7166f4..84680f2d62f 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -13,4 +13,3 @@ kill : Bug#37780 2008-12-03 HHunger need some changes to be innodb_bug39438 : Bug#42383 2009-01-28 lsoares "This fails in embedded and on windows. Note that this test is not run on windows and on embedded in PB for main trees currently" query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically init_connect : Bug#44920 2009-07-06 pcrews MTR not processing master.opt input properly on Windows. *Must be done this way due to the nature of the bug* - diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index c5ed098b678..1348fc9be5d 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -339,12 +339,12 @@ drop table t1; # # BUG 16002: Handle unsigned integer functions properly # ---error ER_PARSE_ERROR +--error ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR create table t1 (a bigint) partition by range (a) (partition p0 values less than (0xFFFFFFFFFFFFFFFF), partition p1 values less than (10)); ---error ER_PARSE_ERROR +--error ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR create table t1 (a bigint) partition by list (a) (partition p0 values in (0xFFFFFFFFFFFFFFFF), @@ -1377,7 +1377,7 @@ PARTITION BY LIST (a) SHOW CREATE TABLE t1; DROP TABLE t1; ---error ER_PARSE_ERROR +--error ER_NULL_IN_VALUES_LESS_THAN CREATE TABLE t1 (a int) PARTITION BY RANGE(a) (PARTITION p0 VALUES LESS THAN (NULL)); diff --git a/mysql-test/t/partition_column_prune.test b/mysql-test/t/partition_column_prune.test index 52267a66b65..ec8ce725b34 100644 --- a/mysql-test/t/partition_column_prune.test +++ b/mysql-test/t/partition_column_prune.test @@ -9,7 +9,7 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; create table t1 (a char, b char, c char) partition by range column_list(a,b,c) -( partition p0 values less than (column_list('a','b','c'))); +( partition p0 values less than ('a','b','c')); insert into t1 values ('a', NULL, 'd'); explain partitions select * from t1 where a = 'a' AND c = 'd'; select * from t1 where a = 'a' AND c = 'd'; @@ -17,13 +17,13 @@ drop table t1; ## COLUMN_LIST partition pruning tests create table t1 (a int not null) partition by range column_list(a) ( - partition p0 values less than (column_list(10)), - partition p1 values less than (column_list(20)), - partition p2 values less than (column_list(30)), - partition p3 values less than (column_list(40)), - partition p4 values less than (column_list(50)), - partition p5 values less than (column_list(60)), - partition p6 values less than (column_list(70)) + partition p0 values less than (10), + partition p1 values less than (20), + partition p2 values less than (30), + partition p3 values less than (40), + partition p4 values less than (50), + partition p5 values less than (60), + partition p6 values less than (70) ); insert into t1 values (5),(15),(25),(35),(45),(55),(65); insert into t1 values (5),(15),(25),(35),(45),(55),(65); @@ -47,17 +47,17 @@ drop table t1, t2; create table t1 (a int not null, b int not null ) partition by range column_list(a,b) ( - partition p01 values less than (column_list(2,10)), - partition p02 values less than (column_list(2,20)), - partition p03 values less than (column_list(2,30)), + partition p01 values less than (2,10), + partition p02 values less than (2,20), + partition p03 values less than (2,30), - partition p11 values less than (column_list(4,10)), - partition p12 values less than (column_list(4,20)), - partition p13 values less than (column_list(4,30)), + partition p11 values less than (4,10), + partition p12 values less than (4,20), + partition p13 values less than (4,30), - partition p21 values less than (column_list(6,10)), - partition p22 values less than (column_list(6,20)), - partition p23 values less than (column_list(6,30)) + partition p21 values less than (6,10), + partition p22 values less than (6,20), + partition p23 values less than (6,30) ); insert into t1 values (2,5), (2,15), (2,25), diff --git a/mysql-test/t/partition_error.test b/mysql-test/t/partition_error.test index 1e76945ca46..eb7a4942f5b 100644 --- a/mysql-test/t/partition_error.test +++ b/mysql-test/t/partition_error.test @@ -452,7 +452,7 @@ partitions 2 # # Partition by range, inconsistent partition function and constants # ---error 1064 +--error ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR CREATE TABLE t1 ( a int not null, b int not null, @@ -522,7 +522,7 @@ partitions 2 # # Partition by range, missing parenthesis # ---error 1064 +--error ER_PARTITION_WRONG_VALUES_ERROR CREATE TABLE t1 ( a int not null, b int not null, @@ -536,7 +536,7 @@ partitions 2 # # Partition by range, maxvalue in wrong place # ---error 1064 +--error ER_PARTITION_MAXVALUE_ERROR CREATE TABLE t1 ( a int not null, b int not null, @@ -550,7 +550,7 @@ partitions 2 # # Partition by range, maxvalue in several places # ---error 1064 +--error ER_PARTITION_MAXVALUE_ERROR CREATE TABLE t1 ( a int not null, b int not null, @@ -765,7 +765,7 @@ partitions 2 # # Partition by list, wrong constant result type (not INT) # ---error 1064 +--error ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR CREATE TABLE t1 ( a int not null, b int not null, diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test index 3ee475f58af..a6d73df5939 100644 --- a/mysql-test/t/partition_range.test +++ b/mysql-test/t/partition_range.test @@ -9,7 +9,7 @@ drop table if exists t1, t2; --enable_warnings ---error ER_PARSE_ERROR +--error ER_NULL_IN_VALUES_LESS_THAN create table t1 (a int) partition by range (a) ( partition p0 values less than (NULL), diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 857ae765135..bdcac00dae9 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1577,11 +1577,58 @@ part_column_list_val *partition_info::add_column_value() } DBUG_RETURN(NULL); } - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + if (column_list) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + } + else + { + if (part_type == RANGE_PARTITION) + my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "RANGE"); + else + my_error(ER_TOO_MANY_VALUES_ERROR, MYF(0), "LIST"); + } DBUG_RETURN(NULL); } +/* + Initialise part_elem_value object at setting of a new object + (Helper functions to functions called by parser) + + SYNOPSIS + init_col_val + col_val Column value object to be initialised + item Item object representing column value + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +void partition_info::init_col_val(part_column_list_val *col_val, Item *item) +{ + DBUG_ENTER("partition_info::init_col_val"); + + col_val->item_expression= item; + col_val->null_value= item->null_value; + if (item->result_type() == INT_RESULT) + { + /* + This could be both column_list partitioning and function + partitioning, but it doesn't hurt to set the function + partitioning flags about unsignedness. + */ + curr_list_val->value= item->val_int(); + curr_list_val->unsigned_flag= TRUE; + if (!item->unsigned_flag && + curr_list_val->value < 0) + curr_list_val->unsigned_flag= FALSE; + if (!curr_list_val->unsigned_flag) + curr_part_elem->signed_flag= TRUE; + } + col_val->part_info= NULL; + DBUG_VOID_RETURN; +} /* Add a column value in VALUES LESS THAN or VALUES IN (Called from parser) @@ -1589,15 +1636,19 @@ part_column_list_val *partition_info::add_column_value() SYNOPSIS add_column_list_value() lex Parser's lex object + thd Thread object item Item object representing column value RETURN VALUES TRUE Failure FALSE Success */ -bool partition_info::add_column_list_value(Item *item) +bool partition_info::add_column_list_value(THD *thd, Item *item) { part_column_list_val *col_val; + Name_resolution_context *context= &thd->lex->current_select->context; + TABLE_LIST *save_list= context->table_list; + const char *save_where= thd->where; DBUG_ENTER("partition_info::add_column_list_value"); if (part_type == LIST_PARTITION && @@ -1608,12 +1659,35 @@ bool partition_info::add_column_list_value(Item *item) DBUG_RETURN(TRUE); } } + + context->table_list= 0; + if (column_list) + thd->where= "field list"; + else + thd->where= "partition function"; + + if (item->walk(&Item::check_partition_func_processor, 0, + NULL)) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + DBUG_RETURN(TRUE); + } + if (item->fix_fields(thd, (Item**)0) || + ((context->table_list= save_list), FALSE) || + (!item->const_item())) + { + context->table_list= save_list; + thd->where= save_where; + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + thd->where= save_where; + if (!(col_val= add_column_value())) { DBUG_RETURN(TRUE); } - col_val->item_expression= item; - col_val->part_info= NULL; + init_col_val(col_val, item); DBUG_RETURN(FALSE); } @@ -1686,25 +1760,32 @@ bool partition_info::init_column_part() */ int partition_info::reorganize_into_single_field_col_val() { - part_column_list_val *col_val; - Item *part_expr; + part_column_list_val *col_val, *new_col_val; + part_elem_value *val= curr_list_val; uint loc_num_columns= num_columns; uint i; DBUG_ENTER("partition_info::reorganize_into_single_field_col_val"); num_columns= 1; - curr_list_val->added_items= 1U; + val->added_items= 1U; + col_val= &val->col_val_array[0]; + init_col_val(col_val, col_val->item_expression); for (i= 1; i < loc_num_columns; i++) { - col_val= &curr_list_val->col_val_array[i]; - part_expr= col_val->item_expression; - if ((part_type != LIST_PARTITION && - init_column_part()) || - add_column_list_value(part_expr)) + col_val= &val->col_val_array[i]; + DBUG_ASSERT(part_type == LIST_PARTITION); + if (init_column_part()) { DBUG_RETURN(TRUE); } + if (!(new_col_val= add_column_value())) + { + DBUG_RETURN(TRUE); + } + memcpy(new_col_val, col_val, sizeof(*col_val)); + init_col_val(new_col_val, col_val->item_expression); } + curr_list_val= val; DBUG_RETURN(FALSE); } @@ -1719,6 +1800,7 @@ int partition_info::reorganize_into_single_field_col_val() thd Thread object col_val Array of one value part_elem The partition instance + part_id Id of partition instance RETURN VALUES TRUE Failure @@ -1726,9 +1808,9 @@ int partition_info::reorganize_into_single_field_col_val() */ int partition_info::fix_func_partition(THD *thd, part_elem_value *val, - partition_element *part_elem) + partition_element *part_elem, + uint part_id) { - uint i; part_column_list_val *col_val= val->col_val_array; DBUG_ENTER("partition_info::fix_func_partition"); @@ -1750,7 +1832,7 @@ int partition_info::fix_func_partition(THD *thd, my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0)); DBUG_RETURN(TRUE); } - if (i == (num_parts - 1)) + if (part_id == (num_parts - 1)) { defined_max_value= TRUE; part_elem->max_value= TRUE; @@ -1764,43 +1846,8 @@ int partition_info::fix_func_partition(THD *thd, } else { - part_elem_value *value_ptr; - Name_resolution_context *context= &thd->lex->current_select->context; - TABLE_LIST *save_list= context->table_list; - const char *save_where= thd->where; Item *item_expr= col_val->item_expression; - - context->table_list= 0; - thd->where= "partition function"; - - value_ptr= (part_elem_value*)sql_alloc(sizeof(part_elem_value)); - if (!value_ptr) - { - mem_alloc_error(sizeof(part_elem_value)); - DBUG_RETURN(TRUE); - } - if (item_expr->walk(&Item::check_partition_func_processor, 0, - NULL)) - { - my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); - DBUG_RETURN(TRUE); - } - if (item_expr->fix_fields(thd, (Item**)0) || - ((context->table_list= save_list), FALSE) || - (!item_expr->const_item())) - { - context->table_list= save_list; - thd->where= save_where; - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); - DBUG_RETURN(TRUE); - } - thd->where= save_where; - value_ptr->value= part_expr->val_int(); - value_ptr->unsigned_flag= TRUE; - if (!item_expr->unsigned_flag && - value_ptr->value < 0) - value_ptr->unsigned_flag= FALSE; - if ((value_ptr->null_value= item_expr->null_value)) + if ((val->null_value= item_expr->null_value)) { if (part_elem->has_null_value) { @@ -1814,8 +1861,6 @@ int partition_info::fix_func_partition(THD *thd, my_error(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR, MYF(0)); DBUG_RETURN(TRUE); } - if (!value_ptr->unsigned_flag) - part_elem->signed_flag= TRUE; if (part_type == RANGE_PARTITION) { if (part_elem->has_null_value) @@ -1823,16 +1868,7 @@ int partition_info::fix_func_partition(THD *thd, my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0)); DBUG_RETURN(TRUE); } - part_elem->range_value= value_ptr->value; - } - else if (part_type == LIST_PARTITION) - { - if (!value_ptr->null_value && - part_elem->list_val_list.push_back(value_ptr)) - { - mem_alloc_error(sizeof(part_elem_value)); - DBUG_RETURN(TRUE); - } + part_elem->range_value= val->value; } } col_val->fixed= 2; @@ -1860,11 +1896,8 @@ bool partition_info::fix_column_value_functions(THD *thd, uint part_id) { uint num_columns= part_field_list.elements; - Name_resolution_context *context= &thd->lex->current_select->context; - TABLE_LIST *save_list= context->table_list; bool result= FALSE; uint i; - const char *save_where= thd->where; part_column_list_val *col_val= val->col_val_array; DBUG_ENTER("partition_info::fix_column_value_functions"); @@ -1872,13 +1905,6 @@ bool partition_info::fix_column_value_functions(THD *thd, { DBUG_RETURN(FALSE); } - if (val->added_items != num_columns) - { - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); - DBUG_RETURN(TRUE); - } - context->table_list= 0; - thd->where= "partition function"; for (i= 0; i < num_columns; col_val++, i++) { Item *column_item= col_val->item_expression; @@ -1889,15 +1915,6 @@ bool partition_info::fix_column_value_functions(THD *thd, col_val->column_value= NULL; else { - if (!col_val->fixed && - (column_item->fix_fields(thd, (Item**)0) || - (!column_item->const_item()))) - { - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); - result= TRUE; - goto end; - } - col_val->null_value= column_item->null_value; col_val->column_value= NULL; if (!col_val->null_value) { @@ -1922,8 +1939,6 @@ bool partition_info::fix_column_value_functions(THD *thd, col_val->fixed= 2; } end: - thd->where= save_where; - context->table_list= save_list; DBUG_RETURN(result); } @@ -1989,22 +2004,40 @@ int partition_info::fix_parser_data(THD *thd) do { part_elem= it++; + List_iterator list_val_it(part_elem->list_val_list); j= 0; num_elements= part_elem->list_val_list.elements; DBUG_ASSERT(part_type == RANGE_PARTITION ? num_elements == 1U : TRUE); + do { - List_iterator list_val_it(part_elem->list_val_list); part_elem_value *val= list_val_it++; - result= column_list ? - fix_column_value_functions(thd, val, i) : - fix_func_partition(thd, val, part_elem); - if (result) + if (column_list) { - DBUG_RETURN(TRUE); + if (val->added_items != num_columns) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + } + else + { + if (fix_func_partition(thd, val, part_elem, i)) + { + DBUG_RETURN(TRUE); + } + if (val->null_value) + { + /* + Null values aren't required in the value part, they are kept per + partition instance, only LIST partitions have NULL values. + */ + list_val_it.remove(); + } } } while (++j < num_elements); } while (++i < num_parts); + DBUG_RETURN(FALSE); } void partition_info::print_debug(const char *str, uint *value) diff --git a/sql/partition_info.h b/sql/partition_info.h index 16f3bff8016..2ed0289f656 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -283,12 +283,14 @@ public: void print_debug(const char *str, uint*); int fix_func_partition(THD *thd, part_elem_value *val, - partition_element *part_elem); + partition_element *part_elem, + uint part_id); bool fix_column_value_functions(THD *thd, part_elem_value *val, uint part_id); int fix_parser_data(THD *thd); int add_max_value(); + void init_col_val(part_column_list_val *col_val, Item *item); int reorganize_into_single_field_col_val(); part_column_list_val *add_column_value(); bool set_part_expr(char *start_token, Item *item_ptr, @@ -296,7 +298,7 @@ public: static int compare_column_values(const void *a, const void *b); bool set_up_charset_field_preps(); bool init_column_part(); - bool add_column_list_value(Item *item); + bool add_column_list_value(THD *thd, Item *item); private: static int list_part_cmp(const void* a, const void* b); bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info, diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 0bd658f7861..690e690a833 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2007,14 +2007,6 @@ static int add_column_list_values(File fptr, partition_info *part_info, char buffer[MAX_STR_SIZE_PF]; String str(buffer, sizeof(buffer), &my_charset_bin); Item *item_expr= col_val->item_expression; - if (!col_val->fixed && - (item_expr->fix_fields(current_thd, (Item**)0) || - (!item_expr->const_item()))) - { - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); - return 1; - } - col_val->fixed= 1; if (item_expr->null_value) err+= add_string(fptr, "NULL"); else @@ -4340,38 +4332,63 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, if ((alter_info->flags & ALTER_ADD_PARTITION) || (alter_info->flags & ALTER_REORGANIZE_PARTITION)) { - if ((tab_part_info->column_list && - alt_part_info->num_columns != tab_part_info->num_columns) || - (!tab_part_info->column_list && alt_part_info->num_columns)) + if (thd->work_part_info->part_type != tab_part_info->part_type) { - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); - DBUG_RETURN(TRUE); - } - if ((thd->work_part_info->part_type != tab_part_info->part_type) && - (thd->work_part_info->part_type != NOT_A_PARTITION)) - { - if (thd->work_part_info->part_type == RANGE_PARTITION) + if (thd->work_part_info->part_type == NOT_A_PARTITION) { - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); - } - else if (thd->work_part_info->part_type == LIST_PARTITION) - { - DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION); - my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "LIST", "IN"); - } - else if (tab_part_info->part_type == RANGE_PARTITION) - { - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "RANGE", "LESS THAN"); + if (tab_part_info->part_type == RANGE_PARTITION) + { + my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "RANGE"); + DBUG_RETURN(TRUE); + } + else if (tab_part_info->part_type == LIST_PARTITION) + { + my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), "LIST"); + DBUG_RETURN(TRUE); + } + /* + Hash partitions can be altered without parser finds out about + that it is HASH partitioned. So no error here. + */ } else { - DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION); - my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), - "LIST", "IN"); + if (thd->work_part_info->part_type == RANGE_PARTITION) + { + my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN"); + } + else if (thd->work_part_info->part_type == LIST_PARTITION) + { + DBUG_ASSERT(thd->work_part_info->part_type == LIST_PARTITION); + my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), + "LIST", "IN"); + } + else if (tab_part_info->part_type == RANGE_PARTITION) + { + my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), + "RANGE", "LESS THAN"); + } + else + { + DBUG_ASSERT(tab_part_info->part_type == LIST_PARTITION); + my_error(ER_PARTITION_REQUIRES_VALUES_ERROR, MYF(0), + "LIST", "IN"); + } + DBUG_RETURN(TRUE); } + } + if ((tab_part_info->column_list && + alt_part_info->num_columns != tab_part_info->num_columns) || + (!tab_part_info->column_list && + (tab_part_info->part_type == RANGE_PARTITION || + tab_part_info->part_type == LIST_PARTITION) && + alt_part_info->num_columns != 1U) || + (!tab_part_info->column_list && + tab_part_info->part_type == HASH_PARTITION && + alt_part_info->num_columns != 0)) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); DBUG_RETURN(TRUE); } alt_part_info->column_list= tab_part_info->column_list; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 8ebc754eb03..6da77d14b0d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3870,6 +3870,7 @@ part_func: partition_info *part_info= Lex->part_info; if (part_info->set_part_expr($2+1, $3, $4, FALSE)) { MYSQL_YYABORT; } + part_info->num_columns= 1; part_info->column_list= FALSE; } ; @@ -3972,7 +3973,21 @@ opt_num_subparts: part_defs: /* empty */ - {} + { + partition_info *part_info= Lex->part_info; + if (part_info->part_type == RANGE_PARTITION) + { + my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), + "RANGE"); + MYSQL_YYABORT; + } + else if (part_info->part_type == LIST_PARTITION) + { + my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), + "LIST"); + MYSQL_YYABORT; + } + } | '(' part_def_list ')' { partition_info *part_info= Lex->part_info; @@ -4081,7 +4096,7 @@ opt_part_values: if (part_info->part_type != LIST_PARTITION) { my_error(ER_PARTITION_WRONG_VALUES_ERROR, MYF(0), - "LIST", "IN"); + "LIST", "IN"); MYSQL_YYABORT; } } @@ -4099,6 +4114,7 @@ part_func_max: if (part_info->num_columns && part_info->num_columns != 1U) { + part_info->print_debug("Kilroy II", NULL); my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); MYSQL_YYABORT; } @@ -4121,6 +4137,7 @@ part_values_in: { LEX *lex= Lex; partition_info *part_info= lex->part_info; + part_info->print_debug("part_values_in: part_value_item", NULL); if (part_info->num_columns != 1U) { @@ -4128,6 +4145,7 @@ part_values_in: part_info->num_columns == 0 || part_info->num_columns > MAX_REF_PARTS) { + part_info->print_debug("Kilroy III", NULL); my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); MYSQL_YYABORT; } @@ -4135,7 +4153,8 @@ part_values_in: Reorganize the current large array into a list of small arrays with one entry in each array. This can happen in the first partition of an ALTER TABLE statement where - we ADD or REORGANIZE partitions. + we ADD or REORGANIZE partitions. Also can only happen + for LIST partitions. */ if (part_info->reorganize_into_single_field_col_val()) { @@ -4163,9 +4182,9 @@ part_value_item: '(' { partition_info *part_info= Lex->part_info; + part_info->print_debug("( part_value_item", NULL); /* Initialisation code needed for each list of value expressions */ - if (!(part_info->column_list && - part_info->part_type == LIST_PARTITION && + if (!(part_info->part_type == LIST_PARTITION && part_info->num_columns == 1U) && part_info->init_column_part()) { @@ -4177,7 +4196,7 @@ part_value_item: { LEX *lex= Lex; partition_info *part_info= Lex->part_info; - + part_info->print_debug(") part_value_item", NULL); if (part_info->num_columns == 0) part_info->num_columns= part_info->curr_list_object; if (part_info->num_columns != part_info->curr_list_object) @@ -4189,6 +4208,7 @@ part_value_item: ensures that we only report errors when we know we have an error. */ + part_info->print_debug("Kilroy I", NULL); my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); MYSQL_YYABORT; } @@ -4227,7 +4247,7 @@ part_value_expr_item: my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); MYSQL_YYABORT; } - if (part_info->add_column_list_value(part_expr)) + if (part_info->add_column_list_value(YYTHD, part_expr)) { MYSQL_YYABORT; } From 93fca66f85475508b82ff86614c3262d74baae8b Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 21 Oct 2009 17:28:10 +0200 Subject: [PATCH 19/27] Removed unnecessary call to fix_parser_data --- sql/partition_info.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index bdcac00dae9..dca026bd2d7 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1047,7 +1047,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); goto end; } - if (fix_parser_data(thd)) + if (thd->lex->sql_command == SQLCOM_CREATE_TABLE && + fix_parser_data(thd)) goto end; } if (unlikely(!is_sub_partitioned() && From 3903aada9bfc0b03156d3810b802807b4075ecb7 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 21 Oct 2009 18:27:34 +0200 Subject: [PATCH 20/27] Fixed test cases with regards to error codes --- mysql-test/suite/parts/inc/partition_syntax.inc | 4 ++-- mysql-test/suite/parts/r/partition_syntax_innodb.result | 6 ++---- mysql-test/suite/parts/r/partition_syntax_myisam.result | 6 ++---- sql/partition_info.cc | 2 +- sql/sql_partition.cc | 6 +++--- sql/sql_yacc.yy | 2 +- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/mysql-test/suite/parts/inc/partition_syntax.inc b/mysql-test/suite/parts/inc/partition_syntax.inc index e72aad80f0a..e7eea73325a 100644 --- a/mysql-test/suite/parts/inc/partition_syntax.inc +++ b/mysql-test/suite/parts/inc/partition_syntax.inc @@ -312,7 +312,7 @@ PARTITION BY RANGE(f_int1) --echo #------------------------------------------------------------------------ --echo # 3.5.1 NULL in RANGE partitioning clause --echo # 3.5.1.1 VALUE LESS THAN (NULL) is not allowed ---error ER_PARSE_ERROR +--error ER_NULL_IN_VALUES_LESS_THAN eval CREATE TABLE t1 ( $column_list ) @@ -320,7 +320,7 @@ PARTITION BY RANGE(f_int1) ( PARTITION part1 VALUES LESS THAN (NULL), PARTITION part2 VALUES LESS THAN (1000)); --echo # 3.5.1.2 VALUE LESS THAN (NULL) is not allowed ---error ER_PARSE_ERROR +--error ER_NULL_IN_VALUES_LESS_THAN eval CREATE TABLE t1 ( $column_list ) diff --git a/mysql-test/suite/parts/r/partition_syntax_innodb.result b/mysql-test/suite/parts/r/partition_syntax_innodb.result index c27a1386409..848a30a13df 100644 --- a/mysql-test/suite/parts/r/partition_syntax_innodb.result +++ b/mysql-test/suite/parts/r/partition_syntax_innodb.result @@ -610,8 +610,7 @@ f_charbig VARCHAR(1000) PARTITION BY RANGE(f_int1) ( PARTITION part1 VALUES LESS THAN (NULL), PARTITION part2 VALUES LESS THAN (1000)); -ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '), -PARTITION part2 VALUES LESS THAN (1000))' at line 9 +ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN # 3.5.1.2 VALUE LESS THAN (NULL) is not allowed CREATE TABLE t1 ( f_int1 INTEGER, @@ -623,8 +622,7 @@ f_charbig VARCHAR(1000) PARTITION BY RANGE(f_int1) ( PARTITION part1 VALUES LESS THAN (NULL), PARTITION part2 VALUES LESS THAN (1000)); -ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '), -PARTITION part2 VALUES LESS THAN (1000))' at line 9 +ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN # 3.5.2 NULL in LIST partitioning clause # 3.5.2.1 VALUE IN (NULL) CREATE TABLE t1 ( diff --git a/mysql-test/suite/parts/r/partition_syntax_myisam.result b/mysql-test/suite/parts/r/partition_syntax_myisam.result index 0cf98765797..f3b7f5b3025 100644 --- a/mysql-test/suite/parts/r/partition_syntax_myisam.result +++ b/mysql-test/suite/parts/r/partition_syntax_myisam.result @@ -610,8 +610,7 @@ f_charbig VARCHAR(1000) PARTITION BY RANGE(f_int1) ( PARTITION part1 VALUES LESS THAN (NULL), PARTITION part2 VALUES LESS THAN (1000)); -ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '), -PARTITION part2 VALUES LESS THAN (1000))' at line 9 +ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN # 3.5.1.2 VALUE LESS THAN (NULL) is not allowed CREATE TABLE t1 ( f_int1 INTEGER, @@ -623,8 +622,7 @@ f_charbig VARCHAR(1000) PARTITION BY RANGE(f_int1) ( PARTITION part1 VALUES LESS THAN (NULL), PARTITION part2 VALUES LESS THAN (1000)); -ERROR 42000: Not allowed to use NULL value in VALUES LESS THAN near '), -PARTITION part2 VALUES LESS THAN (1000))' at line 9 +ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN # 3.5.2 NULL in LIST partitioning clause # 3.5.2.1 VALUE IN (NULL) CREATE TABLE t1 ( diff --git a/sql/partition_info.cc b/sql/partition_info.cc index dca026bd2d7..52535041776 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1679,7 +1679,7 @@ bool partition_info::add_column_list_value(THD *thd, Item *item) { context->table_list= save_list; thd->where= save_where; - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); DBUG_RETURN(TRUE); } thd->where= save_where; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 8fc32ebde80..ab342c0a6fb 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1638,7 +1638,7 @@ bool fix_partition_func(THD *thd, TABLE *table, goto end; if (unlikely(part_info->subpart_expr->result_type() != INT_RESULT)) { - my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0), subpart_str); goto end; } @@ -1666,7 +1666,7 @@ bool fix_partition_func(THD *thd, TABLE *table, goto end; if (unlikely(part_info->part_expr->result_type() != INT_RESULT)) { - my_error(ER_PARTITION_FUNC_NOT_ALLOWED_ERROR, MYF(0), part_str); + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0), part_str); goto end; } part_info->part_result_type= INT_RESULT; @@ -2014,7 +2014,7 @@ static int add_column_list_values(File fptr, partition_info *part_info, String *res= item_expr->val_str(&str); if (!res) { - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); return 1; } if (item_expr->result_type() == STRING_RESULT) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 51b81f5b2af..c2873bffe9e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4245,7 +4245,7 @@ part_value_expr_item: if (!lex->safe_to_cache_query) { - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); MYSQL_YYABORT; } if (part_info->add_column_list_value(YYTHD, part_expr)) From e30ccf7a6772f52f1357d5e7ddba61660c9f73b8 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 21 Oct 2009 20:04:34 +0200 Subject: [PATCH 21/27] Fixed Information schema for column list partitioned tables --- mysql-test/r/partition_column.result | 55 +++++++++++++++++ mysql-test/r/partition_list.result | 11 ++++ mysql-test/r/partition_range.result | 5 ++ mysql-test/t/partition_column.test | 12 ++++ mysql-test/t/partition_list.test | 2 + mysql-test/t/partition_range.test | 2 + sql/sql_show.cc | 92 ++++++++++++++++++++++++---- 7 files changed, 168 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index fb7f815fd98..c4333f9c101 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -50,6 +50,12 @@ partition by list column_list(a,b) column_list(NULL, NULL)), partition p1 values in (column_list(1,1), column_list(2,2)), partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +LIST COLUMN_LIST a,b (1,NULL),(2,NULL),(NULL,NULL) +LIST COLUMN_LIST a,b (1,1),(2,2) +LIST COLUMN_LIST a,b (3,NULL),(NULL,1) insert into t1 values (3, NULL); insert into t1 values (NULL, 1); insert into t1 values (NULL, NULL); @@ -94,6 +100,11 @@ create table t1 (a int) partition by list (a) ( partition p0 values in (2, 1), partition p1 values in (4, NULL, 3)); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +LIST a 2,1 +LIST a NULL,4,3 insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -106,6 +117,11 @@ create table t1 (a int) partition by list column_list(a) ( partition p0 values in (column_list(2), column_list(1)), partition p1 values in (column_list(4), column_list(NULL), column_list(3))); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +LIST COLUMN_LIST a 2,1 +LIST COLUMN_LIST a 4,NULL,3 insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -130,6 +146,25 @@ subpartitions 4 partition p1 values less than (column_list(1, 'a', MAXVALUE, TO_DAYS('1999-01-01'))), partition p2 values less than (column_list(1, 'a', MAXVALUE, MAXVALUE)), partition p3 values less than (column_list(1, MAXVALUE, MAXVALUE, MAXVALUE))); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +RANGE COLUMN_LIST a,b,c,d 1,NULL,MAXVALUE,NULL +RANGE COLUMN_LIST a,b,c,d 1,NULL,MAXVALUE,NULL +RANGE COLUMN_LIST a,b,c,d 1,NULL,MAXVALUE,NULL +RANGE COLUMN_LIST a,b,c,d 1,NULL,MAXVALUE,NULL +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE drop table t1; create table t1 (a int, b char(10), c varchar(5), d int) partition by range column_list(a,b,c) @@ -139,6 +174,21 @@ subpartitions 3 partition p1 values less than (column_list(2,'abc','abc')), partition p2 values less than (column_list(3,'abc','abc')), partition p3 values less than (column_list(4,'abc','abc'))); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +RANGE COLUMN_LIST a,b,c 1,'abc','abc' +RANGE COLUMN_LIST a,b,c 1,'abc','abc' +RANGE COLUMN_LIST a,b,c 1,'abc','abc' +RANGE COLUMN_LIST a,b,c 2,'abc','abc' +RANGE COLUMN_LIST a,b,c 2,'abc','abc' +RANGE COLUMN_LIST a,b,c 2,'abc','abc' +RANGE COLUMN_LIST a,b,c 3,'abc','abc' +RANGE COLUMN_LIST a,b,c 3,'abc','abc' +RANGE COLUMN_LIST a,b,c 3,'abc','abc' +RANGE COLUMN_LIST a,b,c 4,'abc','abc' +RANGE COLUMN_LIST a,b,c 4,'abc','abc' +RANGE COLUMN_LIST a,b,c 4,'abc','abc' insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); @@ -153,6 +203,11 @@ create table t1 (a int, b varchar(2), c int) partition by range column_list (a, b, c) (partition p0 values less than (column_list(1, 'A', 1)), partition p1 values less than (column_list(1, 'B', 1))); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +RANGE COLUMN_LIST a,b,c 1,'A',1 +RANGE COLUMN_LIST a,b,c 1,'B',1 insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; id select_type table partitions type possible_keys key key_len ref rows Extra diff --git a/mysql-test/r/partition_list.result b/mysql-test/r/partition_list.result index a68a67c6386..e22fc11e5bb 100644 --- a/mysql-test/r/partition_list.result +++ b/mysql-test/r/partition_list.result @@ -54,6 +54,17 @@ subpartitions 2 partition p1 values in (1), partition pnull values in (null, 2), partition p3 values in (3)); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +LIST a 0 +LIST a 0 +LIST a 1 +LIST a 1 +LIST a NULL,2 +LIST a NULL,2 +LIST a 3 +LIST a 3 insert into t1 values (0,0),(0,1),(1,0),(1,1),(null,0),(null,1); insert into t1 values (2,0),(2,1),(3,0),(3,1); explain partitions select * from t1 where a is null; diff --git a/mysql-test/r/partition_range.result b/mysql-test/r/partition_range.result index 237d026fe6e..4e18c9668e9 100644 --- a/mysql-test/r/partition_range.result +++ b/mysql-test/r/partition_range.result @@ -9,6 +9,11 @@ create table t1 (a datetime not null) partition by range (TO_SECONDS(a)) ( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')), partition p1 VALUES LESS THAN (TO_SECONDS('2007-04-01 00:00:00'))); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +RANGE TO_SECONDS(a) 63340531200 +RANGE TO_SECONDS(a) 63342604800 INSERT INTO t1 VALUES ('2007-03-01 12:00:00'), ('2007-03-07 12:00:00'); INSERT INTO t1 VALUES ('2007-03-08 12:00:00'), ('2007-03-15 12:00:00'); explain partitions select * from t1 where a < '2007-03-08 00:00:00'; diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index 1c7e8d59895..0cb99ebfcc2 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -52,6 +52,8 @@ partition by list column_list(a,b) column_list(NULL, NULL)), partition p1 values in (column_list(1,1), column_list(2,2)), partition p2 values in (column_list(3, NULL), column_list(NULL, 1))); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; # # BUG#47754 Crash when selecting using NOT BETWEEN for column list partitioning # @@ -79,6 +81,8 @@ create table t1 (a int) partition by list (a) ( partition p0 values in (2, 1), partition p1 values in (4, NULL, 3)); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -92,6 +96,8 @@ create table t1 (a int) partition by list column_list(a) ( partition p0 values in (column_list(2), column_list(1)), partition p1 values in (column_list(4), column_list(NULL), column_list(3))); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -110,6 +116,8 @@ subpartitions 4 partition p1 values less than (column_list(1, 'a', MAXVALUE, TO_DAYS('1999-01-01'))), partition p2 values less than (column_list(1, 'a', MAXVALUE, MAXVALUE)), partition p3 values less than (column_list(1, MAXVALUE, MAXVALUE, MAXVALUE))); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; drop table t1; create table t1 (a int, b char(10), c varchar(5), d int) @@ -120,6 +128,8 @@ subpartitions 3 partition p1 values less than (column_list(2,'abc','abc')), partition p2 values less than (column_list(3,'abc','abc')), partition p3 values less than (column_list(4,'abc','abc'))); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); @@ -133,6 +143,8 @@ create table t1 (a int, b varchar(2), c int) partition by range column_list (a, b, c) (partition p0 values less than (column_list(1, 'A', 1)), partition p1 values less than (column_list(1, 'B', 1))); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; select * from t1 where a = 1 AND b <= 'A' and c = 1; diff --git a/mysql-test/t/partition_list.test b/mysql-test/t/partition_list.test index 1c76de9d55a..8d2ec88e0f4 100644 --- a/mysql-test/t/partition_list.test +++ b/mysql-test/t/partition_list.test @@ -40,6 +40,8 @@ subpartitions 2 partition p1 values in (1), partition pnull values in (null, 2), partition p3 values in (3)); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; insert into t1 values (0,0),(0,1),(1,0),(1,1),(null,0),(null,1); insert into t1 values (2,0),(2,1),(3,0),(3,1); diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test index 741bae7b3cc..df4982298f9 100644 --- a/mysql-test/t/partition_range.test +++ b/mysql-test/t/partition_range.test @@ -21,6 +21,8 @@ create table t1 (a datetime not null) partition by range (TO_SECONDS(a)) ( partition p0 VALUES LESS THAN (TO_SECONDS('2007-03-08 00:00:00')), partition p1 VALUES LESS THAN (TO_SECONDS('2007-04-01 00:00:00'))); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; INSERT INTO t1 VALUES ('2007-03-01 12:00:00'), ('2007-03-07 12:00:00'); INSERT INTO t1 VALUES ('2007-03-08 12:00:00'), ('2007-03-15 12:00:00'); explain partitions select * from t1 where a < '2007-03-08 00:00:00'; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 3aef62dfb31..a74e9363bcf 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4827,6 +4827,43 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table, return; } +static int +get_partition_column_description(partition_info *part_info, + part_elem_value *list_value, + String &tmp_str) +{ + uint num_elements= part_info->part_field_list.elements; + uint i; + DBUG_ENTER("get_partition_column_description"); + + for (i= 0; i < num_elements; i++) + { + part_column_list_val *col_val= &list_value->col_val_array[i]; + if (col_val->max_value) + tmp_str.append(partition_keywords[PKW_MAXVALUE].str); + else if (col_val->null_value) + tmp_str.append("NULL"); + else + { + char buffer[MAX_STR_SIZE_PF]; + String str(buffer, sizeof(buffer), &my_charset_bin); + String *res= col_val->item_expression->val_str(&str); + if (!res) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + DBUG_RETURN(1); + } + if (col_val->item_expression->result_type() == STRING_RESULT) + tmp_str.append("'"); + tmp_str.append(*res); + if (col_val->item_expression->result_type() == STRING_RESULT) + tmp_str.append("'"); + } + if (i != num_elements - 1) + tmp_str.append(","); + } + DBUG_RETURN(0); +} static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, @@ -4837,6 +4874,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, char buff[61]; String tmp_res(buff, sizeof(buff), cs); String tmp_str; + uint num_elements; TABLE *show_table= tables->table; handler *file; #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -4958,36 +4996,68 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, /* Partition description */ if (part_info->part_type == RANGE_PARTITION) { - if (part_elem->range_value != LONGLONG_MAX) - table->field[11]->store((longlong) part_elem->range_value, FALSE); + if (part_info->column_list) + { + List_iterator list_val_it(part_elem->list_val_list); + part_elem_value *list_value= list_val_it++; + tmp_str.length(0); + if (get_partition_column_description(part_info, + list_value, + tmp_str)) + { + DBUG_RETURN(1); + } + table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs); + } else - table->field[11]->store(partition_keywords[PKW_MAXVALUE].str, + { + if (part_elem->range_value != LONGLONG_MAX) + table->field[11]->store((longlong) part_elem->range_value, FALSE); + else + table->field[11]->store(partition_keywords[PKW_MAXVALUE].str, partition_keywords[PKW_MAXVALUE].length, cs); + } table->field[11]->set_notnull(); } else if (part_info->part_type == LIST_PARTITION) { List_iterator list_val_it(part_elem->list_val_list); part_elem_value *list_value; - uint no_items= part_elem->list_val_list.elements; + uint num_items= part_elem->list_val_list.elements; tmp_str.length(0); tmp_res.length(0); if (part_elem->has_null_value) { tmp_str.append("NULL"); - if (no_items > 0) + if (num_items > 0) tmp_str.append(","); } while ((list_value= list_val_it++)) { - if (!list_value->unsigned_flag) - tmp_res.set(list_value->value, cs); + if (part_info->column_list) + { + if (part_info->part_field_list.elements > 1U) + tmp_str.append("("); + if (get_partition_column_description(part_info, + list_value, + tmp_str)) + { + DBUG_RETURN(1); + } + if (part_info->part_field_list.elements > 1U) + tmp_str.append(")"); + } else - tmp_res.set((ulonglong)list_value->value, cs); - tmp_str.append(tmp_res); - if (--no_items != 0) + { + if (!list_value->unsigned_flag) + tmp_res.set(list_value->value, cs); + else + tmp_res.set((ulonglong)list_value->value, cs); + tmp_str.append(tmp_res); + } + if (--num_items != 0) tmp_str.append(","); - }; + } table->field[11]->store(tmp_str.ptr(), tmp_str.length(), cs); table->field[11]->set_notnull(); } From f3f4e41c3704b6a82942de5fd6c918319e0e4bb2 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 21 Oct 2009 20:53:44 +0200 Subject: [PATCH 22/27] Added checks for no NULL values in VALUES LESS THAN, added tests for no MAXVALUE in VALUES IN --- mysql-test/r/partition_column.result | 28 ++++++++++++++++++---------- mysql-test/t/partition_column.test | 20 +++++++++++++++----- sql/partition_info.cc | 11 ++++++++++- sql/share/errmsg.txt | 4 ++-- sql/sql_yacc.yy | 2 +- 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 8bc48553d95..f1bb0a3488a 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,5 +1,13 @@ drop table if exists t1; create table t1 (a int, b int) +partition by range column_list (a,b) +(partition p0 values less than (NULL, maxvalue)); +ERROR HY000: Not allowed to use NULL value in VALUES LESS THAN +create table t1 (a int, b int) +partition by list column_list(a,b) +( partition p0 values in ((maxvalue, 0))); +Got one of the listed errors +create table t1 (a int, b int) partition by key (a,a); ERROR HY000: Duplicate partition field name a create table t1 (a int, b int) @@ -144,17 +152,17 @@ create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) subpartitions 4 -( partition p0 values less than (1, NULL, MAXVALUE, NULL), +( partition p0 values less than (1, 0, MAXVALUE, 0), partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description -RANGE COLUMN_LIST a,b,c,d 1,NULL,MAXVALUE,NULL -RANGE COLUMN_LIST a,b,c,d 1,NULL,MAXVALUE,NULL -RANGE COLUMN_LIST a,b,c,d 1,NULL,MAXVALUE,NULL -RANGE COLUMN_LIST a,b,c,d 1,NULL,MAXVALUE,NULL +RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 @@ -233,7 +241,7 @@ partition p1 values less than ('2040-01-01')); ERROR HY000: Partition column values of incorrect type create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (null, 10)); +(partition p0 values less than (maxvalue, 10)); drop table t1; create table t1 (d date) partition by range column_list(d) @@ -268,7 +276,7 @@ drop table t1; create table t1 (a int, b int) partition by list column_list(a,b) (partition p0 values in ((maxvalue,maxvalue))); -ERROR 42000: Cannot use MAXVALUE as value in List partitioning near 'maxvalue,maxvalue)))' at line 3 +ERROR 42000: Cannot use MAXVALUE as value in VALUES IN near 'maxvalue,maxvalue)))' at line 3 create table t1 (a int, b int) partition by range column_list(a,b) (partition p0 values less than (maxvalue,maxvalue)); @@ -309,11 +317,11 @@ partition by range column_list(a,b) ERROR HY000: Inconsistency in usage of column lists for partitioning create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (1, NULL), +(partition p0 values less than (1, 0), partition p1 values less than (2, maxvalue), partition p2 values less than (3, 3), -partition p3 values less than (10, NULL)); -insert into t1 values (10,0); +partition p3 values less than (10, maxvalue)); +insert into t1 values (11,0); ERROR HY000: Table has no partition for value from column_list insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1); select * from t1; diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index 980aca5a8c5..baeed6bb0a8 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,16 @@ drop table if exists t1; --enable_warnings +--error ER_NULL_IN_VALUES_LESS_THAN +create table t1 (a int, b int) +partition by range column_list (a,b) +(partition p0 values less than (NULL, maxvalue)); + +--error ER_MAXVALUE_IN_VALUES_IN, ER_PARSE_ERROR +create table t1 (a int, b int) +partition by list column_list(a,b) +( partition p0 values in ((maxvalue, 0))); + # # BUG#47837, Crash when two same fields in column list processing # @@ -115,7 +125,7 @@ create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) subpartitions 4 -( partition p0 values less than (1, NULL, MAXVALUE, NULL), +( partition p0 values less than (1, 0, MAXVALUE, 0), partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); @@ -168,7 +178,7 @@ partition by range column_list(d) create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (null, 10)); +(partition p0 values less than (maxvalue, 10)); drop table t1; create table t1 (d date) @@ -250,13 +260,13 @@ partition by range column_list(a,b) create table t1 (a int, b int) partition by range column_list(a,b) -(partition p0 values less than (1, NULL), +(partition p0 values less than (1, 0), partition p1 values less than (2, maxvalue), partition p2 values less than (3, 3), - partition p3 values less than (10, NULL)); + partition p3 values less than (10, maxvalue)); -- error ER_NO_PARTITION_FOR_GIVEN_VALUE -insert into t1 values (10,0); +insert into t1 values (11,0); insert into t1 values (0,1),(1,1),(2,1),(3,1),(3,4),(4,9),(9,1); select * from t1; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 52535041776..3bce7dac1fa 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1992,7 +1992,7 @@ int partition_info::fix_parser_data(THD *thd) partition_element *part_elem; part_elem_value *val; uint num_elements; - uint i= 0, j; + uint i= 0, j, k; int result; DBUG_ENTER("partition_info::fix_parser_data"); @@ -2020,6 +2020,15 @@ int partition_info::fix_parser_data(THD *thd) my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); DBUG_RETURN(TRUE); } + for (k= 0; k < num_columns; k++) + { + part_column_list_val *col_val= &val->col_val_array[k]; + if (col_val->null_value && part_type == RANGE_PARTITION) + { + my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0)); + DBUG_RETURN(TRUE); + } + } } else { diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 69f18088807..0bbdacee0bc 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6214,8 +6214,8 @@ ER_WRONG_TYPE_COLUMN_VALUE_ERROR eng "Partition column values of incorrect type" ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR eng "Too many fields in '%-.192s'" -ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR - eng "Cannot use MAXVALUE as value in List partitioning" +ER_MAXVALUE_IN_VALUES_IN + eng "Cannot use MAXVALUE as value in VALUES IN" ER_TOO_MANY_VALUES_ERROR eng "Cannot have more than one value for this type of %-.64s partitioning" ER_ROW_SINGLE_PARTITION_FIELD_ERROR diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c2873bffe9e..43753b7fab2 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4229,7 +4229,7 @@ part_value_expr_item: part_column_list_val *col_val; if (part_info->part_type == LIST_PARTITION) { - my_parse_error(ER(ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR)); + my_parse_error(ER(ER_MAXVALUE_IN_VALUES_IN)); MYSQL_YYABORT; } if (part_info->add_max_value()) From 6f27ad15b208091d3904bb4f73ffab2871f99581 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 22 Oct 2009 16:15:06 +0200 Subject: [PATCH 23/27] A lot of fixes to make character set work ok, first step to fixing BUG#48163 --- mysql-test/r/partition_column.result | 130 ++++++++++++++++------ mysql-test/t/partition_column.test | 59 +++++++--- sql/mysql_priv.h | 7 ++ sql/partition_info.cc | 34 ++++++ sql/partition_info.h | 1 + sql/share/errmsg.txt | 4 +- sql/sql_partition.cc | 154 +++++++++++++++++++++++++-- sql/sql_partition.h | 4 +- sql/sql_show.cc | 16 ++- sql/sql_table.cc | 64 ++++++++--- 10 files changed, 397 insertions(+), 76 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index f1bb0a3488a..4270af1f83b 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,32 @@ drop table if exists t1; +create table t1 (a int, b char(10), c varchar(25), d datetime) +partition by range column_list(a,b,c,d) +subpartition by hash (to_seconds(d)) +subpartitions 4 +( partition p0 values less than (1, 0, MAXVALUE, 0), +partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), +partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), +partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); +select partition_method, partition_expression, partition_description +from information_schema.partitions where table_name = "t1"; +partition_method partition_expression partition_description +RANGE COLUMN_LIST a,b,c,d 1,'0',MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,'0',MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,'0',MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,'0',MAXVALUE,0 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +drop table t1; create table t1 (a int, b int) partition by range column_list (a,b) (partition p0 values less than (NULL, maxvalue)); @@ -8,12 +36,19 @@ partition by list column_list(a,b) ( partition p0 values in ((maxvalue, 0))); Got one of the listed errors create table t1 (a int, b int) +partition by list column_list (a,b) +( partition p0 values in ((0,0))); +alter table t1 add partition +(partition p1 values in (maxvalue, maxvalue)); +Got one of the listed errors +drop table t1; +create table t1 (a int, b int) partition by key (a,a); -ERROR HY000: Duplicate partition field name a +ERROR HY000: Duplicate partition field name 'a' create table t1 (a int, b int) partition by list column_list(a,a) ( partition p values in ((1,1))); -ERROR HY000: Duplicate partition field name a +ERROR HY000: Duplicate partition field name 'a' create table t1 (a int signed) partition by list (a) ( partition p0 values in (1, 3, 5, 7, 9, NULL), @@ -61,6 +96,16 @@ partition_method partition_expression partition_description LIST COLUMN_LIST a,b (1,NULL),(2,NULL),(NULL,NULL) LIST COLUMN_LIST a,b (1,1),(2,2) LIST COLUMN_LIST a,b (3,NULL),(NULL,1) +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a,b) +(PARTITION p0 VALUES IN ((1,NULL),(2,NULL),(NULL,NULL)) ENGINE = MyISAM, + PARTITION p1 VALUES IN ((1,1),(2,2)) ENGINE = MyISAM, + PARTITION p2 VALUES IN ((3,NULL),(NULL,1)) ENGINE = MyISAM) */ insert into t1 values (3, NULL); insert into t1 values (NULL, 1); insert into t1 values (NULL, NULL); @@ -110,6 +155,14 @@ from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description LIST a 2,1 LIST a NULL,4,3 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST (a) +(PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM, + PARTITION p1 VALUES IN (NULL,4,3) ENGINE = MyISAM) */ insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -132,6 +185,14 @@ from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description LIST COLUMN_LIST a 2,1 LIST COLUMN_LIST a 4,NULL,3 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a) +(PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM, + PARTITION p1 VALUES IN (4,NULL,3) ENGINE = MyISAM) */ insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -148,34 +209,6 @@ t1 CREATE TABLE `t1` ( (PARTITION p0 VALUES IN (2,1) ENGINE = MyISAM, PARTITION p1 VALUES IN (4,NULL,3) ENGINE = MyISAM) */ drop table t1; -create table t1 (a int, b char(10), c varchar(25), d datetime) -partition by range column_list(a,b,c,d) -subpartition by hash (to_seconds(d)) -subpartitions 4 -( partition p0 values less than (1, 0, MAXVALUE, 0), -partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), -partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), -partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); -select partition_method, partition_expression, partition_description -from information_schema.partitions where table_name = "t1"; -partition_method partition_expression partition_description -RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 -RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 -RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 -RANGE COLUMN_LIST a,b,c,d 1,0,MAXVALUE,0 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,730120 -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,'a',MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -drop table t1; create table t1 (a int, b char(10), c varchar(5), d int) partition by range column_list(a,b,c) subpartition by key (c,d) @@ -199,6 +232,21 @@ RANGE COLUMN_LIST a,b,c 3,'abc','abc' RANGE COLUMN_LIST a,b,c 4,'abc','abc' RANGE COLUMN_LIST a,b,c 4,'abc','abc' RANGE COLUMN_LIST a,b,c 4,'abc','abc' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` char(10) DEFAULT NULL, + `c` varchar(5) DEFAULT NULL, + `d` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE COLUMN_LIST(a,b,c) +SUBPARTITION BY KEY (c,d) +SUBPARTITIONS 3 +(PARTITION p0 VALUES LESS THAN (1,'abc','abc') ENGINE = MyISAM, + PARTITION p1 VALUES LESS THAN (2,'abc','abc') ENGINE = MyISAM, + PARTITION p2 VALUES LESS THAN (3,'abc','abc') ENGINE = MyISAM, + PARTITION p3 VALUES LESS THAN (4,'abc','abc') ENGINE = MyISAM) */ insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); @@ -218,6 +266,16 @@ from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description RANGE COLUMN_LIST a,b,c 1,'A',1 RANGE COLUMN_LIST a,b,c 1,'B',1 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` varchar(2) DEFAULT NULL, + `c` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE COLUMN_LIST(a,b,c) +(PARTITION p0 VALUES LESS THAN (1,'A',1) ENGINE = MyISAM, + PARTITION p1 VALUES LESS THAN (1,'B',1) ENGINE = MyISAM) */ insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; id select_type table partitions type possible_keys key key_len ref rows Extra @@ -234,11 +292,21 @@ select * from t1 where a = 'a'; a b c a NULL NULL drop table t1; -create table t1 (d timestamp) +create table t1 (d time) partition by range column_list(d) ( partition p0 values less than ('2000-01-01'), partition p1 values less than ('2040-01-01')); ERROR HY000: Partition column values of incorrect type +create table t1 (d timestamp) +partition by range column_list(d) +( partition p0 values less than ('2000-01-01'), +partition p1 values less than ('2040-01-01')); +ERROR HY000: Field 'd' is of a not allowed type for this type of partitioning +create table t1 (d bit(1)) +partition by range column_list(d) +( partition p0 values less than (0), +partition p1 values less than (1)); +ERROR HY000: Field 'd' is of a not allowed type for this type of partitioning create table t1 (a int, b int) partition by range column_list(a,b) (partition p0 values less than (maxvalue, 10)); diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index baeed6bb0a8..13f422d32f4 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,29 @@ drop table if exists t1; --enable_warnings +create table t1 (a int, b char(10), c varchar(25), d datetime) +partition by range column_list(a,b,c,d) +subpartition by hash (to_seconds(d)) +subpartitions 4 +( partition p0 values less than (1, 0, MAXVALUE, 0), + partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), + partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), + partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); +select partition_method, partition_expression, partition_description + from information_schema.partitions where table_name = "t1"; +#show create table t1; +drop table t1; + +# +# BUG#48163, Dagger in UCS2 not working as partition value +# +#create table t1 (a varchar(2) character set ucs2) +#partition by list column_list (a) +#(partition p0 values in (0x2020), +# partition p1 values in ('')); +#insert into t1 values (''); +#drop table t1; + --error ER_NULL_IN_VALUES_LESS_THAN create table t1 (a int, b int) partition by range column_list (a,b) @@ -18,6 +41,13 @@ create table t1 (a int, b int) partition by list column_list(a,b) ( partition p0 values in ((maxvalue, 0))); +create table t1 (a int, b int) +partition by list column_list (a,b) +( partition p0 values in ((0,0))); +--error ER_MAXVALUE_IN_VALUES_IN, ER_PARSE_ERROR +alter table t1 add partition +(partition p1 values in (maxvalue, maxvalue)); +drop table t1; # # BUG#47837, Crash when two same fields in column list processing # @@ -61,6 +91,7 @@ partition by list column_list(a,b) partition p2 values in ((3, NULL), (NULL, 1))); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; # # BUG#47754 Crash when selecting using NOT BETWEEN for column list partitioning # @@ -90,6 +121,7 @@ partition by list (a) partition p1 values in (4, NULL, 3)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -111,6 +143,7 @@ partition by list column_list(a) partition p1 values in (4, NULL, 3)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; insert into t1 values (1); insert into t1 values (2); insert into t1 values (3); @@ -121,18 +154,6 @@ insert into t1 values (5); show create table t1; drop table t1; -create table t1 (a int, b char(10), c varchar(25), d datetime) -partition by range column_list(a,b,c,d) -subpartition by hash (to_seconds(d)) -subpartitions 4 -( partition p0 values less than (1, 0, MAXVALUE, 0), - partition p1 values less than (1, 'a', MAXVALUE, TO_DAYS('1999-01-01')), - partition p2 values less than (1, 'a', MAXVALUE, MAXVALUE), - partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); -select partition_method, partition_expression, partition_description - from information_schema.partitions where table_name = "t1"; -drop table t1; - create table t1 (a int, b char(10), c varchar(5), d int) partition by range column_list(a,b,c) subpartition by key (c,d) @@ -143,6 +164,7 @@ subpartitions 3 partition p3 values less than (4,'abc','abc')); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); @@ -158,6 +180,7 @@ partition by range column_list (a, b, c) partition p1 values less than (1, 'B', 1)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; +show create table t1; insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; select * from t1 where a = 1 AND b <= 'A' and c = 1; @@ -171,11 +194,23 @@ select * from t1 where a = 'a'; drop table t1; --error ER_WRONG_TYPE_COLUMN_VALUE_ERROR +create table t1 (d time) +partition by range column_list(d) +( partition p0 values less than ('2000-01-01'), + partition p1 values less than ('2040-01-01')); + +--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD create table t1 (d timestamp) partition by range column_list(d) ( partition p0 values less than ('2000-01-01'), partition p1 values less than ('2040-01-01')); +--error ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD +create table t1 (d bit(1)) +partition by range column_list(d) +( partition p0 values less than (0), + partition p1 values less than (1)); + create table t1 (a int, b int) partition by range column_list(a,b) (partition p0 values less than (maxvalue, 10)); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f21c274a23a..7936bffda38 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1222,6 +1222,8 @@ int prepare_create_field(Create_field *sql_field, uint *blob_columns, int *timestamps, int *timestamps_with_niladic, longlong table_flags); +CHARSET_INFO* get_sql_field_charset(Create_field *sql_field, + HA_CREATE_INFO *create_info); bool mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, Alter_info *alter_info, @@ -1611,6 +1613,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, handlerton *old_db_type, bool *partition_changed, uint *fast_alter_partition); +char *generate_partition_syntax(partition_info *part_info, + uint *buf_length, bool use_sql_alloc, + bool show_partition_options, + HA_CREATE_INFO *create_info, + Alter_info *alter_info); #endif /* bits for last argument to remove_table_from_cache() */ diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 3bce7dac1fa..131e1dcf3a6 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1876,6 +1876,34 @@ int partition_info::fix_func_partition(THD *thd, DBUG_RETURN(FALSE); } +/* + Get column item with a proper character set according to the field + + SYNOPSIS + get_column_item() + item Item object to start with + field Field for which the item will be compared to + + RETURN VALUES + NULL Error + item Returned item +*/ + +Item* partition_info::get_column_item(Item *item, Field *field) +{ + if (field->result_type() == STRING_RESULT && + item->collation.collation != field->charset()) + { + if (!(item= convert_charset_partition_constant(item, + field->charset()))) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + return NULL; + } + } + return item; +} + /* Evaluate VALUES functions for column list values @@ -1921,6 +1949,12 @@ bool partition_info::fix_column_value_functions(THD *thd, { uchar *val_ptr; uint len= field->pack_length(); + if (!(column_item= get_column_item(column_item, + field))) + { + result= TRUE; + goto end; + } if (column_item->save_in_field(field, TRUE)) { my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); diff --git a/sql/partition_info.h b/sql/partition_info.h index ab9ee7c6931..4b37b34cecf 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -281,6 +281,7 @@ public: bool check_partition_function); void print_no_partition_found(TABLE *table); void print_debug(const char *str, uint*); + Item* get_column_item(Item *item, Field *field); int fix_func_partition(THD *thd, part_elem_value *val, partition_element *part_elem, diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 0bbdacee0bc..d65945013b9 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6207,7 +6207,7 @@ ER_TOO_MANY_CONCURRENT_TRXS WARN_NON_ASCII_SEPARATOR_NOT_IMPLEMENTED eng "Non-ASCII separator arguments are not fully supported" ER_SAME_NAME_PARTITION_FIELD - eng "Duplicate partition field name %-.192s" + eng "Duplicate partition field name '%-.192s'" ER_PARTITION_COLUMN_LIST_ERROR eng "Inconsistency in usage of column lists for partitioning" ER_WRONG_TYPE_COLUMN_VALUE_ERROR @@ -6220,3 +6220,5 @@ ER_TOO_MANY_VALUES_ERROR eng "Cannot have more than one value for this type of %-.64s partitioning" ER_ROW_SINGLE_PARTITION_FIELD_ERROR eng "Row expressions in VALUES IN only allowed for multi-field column partitioning" +ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD + eng "Field '%-.192s' is of a not allowed type for this type of partitioning" diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ab342c0a6fb..0a6a2b98941 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -150,6 +150,38 @@ static int cmp_rec_and_tuple_prune(part_column_list_val *val, bool tail_is_min); #ifdef WITH_PARTITION_STORAGE_ENGINE +/* + Convert constants in VALUES definition to the character set the + corresponding field uses. + + SYNOPSIS + convert_charset_partition_constant() + item Item to convert + cs Character set to convert to + + RETURN VALUE + NULL Error + item New converted item +*/ + +Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs) +{ + THD *thd= current_thd; + Name_resolution_context *context= &thd->lex->current_select->context; + TABLE_LIST *save_list= context->table_list; + const char *save_where= thd->where; + + item= item->safe_charset_converter(cs); + context->table_list= NULL; + thd->where= "convert character set partition constant"; + if (!item || item->fix_fields(thd, (Item**)NULL)) + item= NULL; + thd->where= save_where; + context->table_list= save_list; + return item; +} + + /* A support function to check if a name is in a list of strings @@ -512,7 +544,9 @@ static bool set_up_field_array(TABLE *table, do { field_name= it++; - if (!strcmp(field_name, field->field_name)) + if (!my_strcasecmp(system_charset_info, + field_name, + field->field_name)) break; } while (++inx < num_fields); if (inx == num_fields) @@ -1984,11 +2018,67 @@ static int add_partition_options(File fptr, partition_element *p_elem) return err + add_engine(fptr,p_elem->engine_type); } +static int check_part_field(Create_field *sql_field, + bool *need_cs_check) +{ + *need_cs_check= FALSE; + if (sql_field->sql_type == MYSQL_TYPE_TIMESTAMP) + goto error; + if (sql_field->sql_type < MYSQL_TYPE_VARCHAR || + sql_field->sql_type == MYSQL_TYPE_NEWDECIMAL) + return FALSE; + if (sql_field->sql_type >= MYSQL_TYPE_TINY_BLOB && + sql_field->sql_type <= MYSQL_TYPE_BLOB) + { + my_error(ER_BLOB_FIELD_IN_PART_FUNC_ERROR, MYF(0)); + return TRUE; + } + switch (sql_field->sql_type) + { + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + if (sql_field->length > MAX_STR_SIZE_PF) + goto error; + *need_cs_check= TRUE; + return FALSE; + break; + default: + goto error; + } +error: + my_error(ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD, MYF(0), + sql_field->field_name); + return TRUE; +} + +static Create_field* get_sql_field(char *field_name, + Alter_info *alter_info) +{ + List_iterator it(alter_info->create_list); + Create_field *sql_field; + DBUG_ENTER("get_sql_field"); + + while ((sql_field= it++)) + { + if (!(my_strcasecmp(system_charset_info, + sql_field->field_name, + field_name))) + { + DBUG_RETURN(sql_field); + } + } + DBUG_RETURN(NULL); +} + static int add_column_list_values(File fptr, partition_info *part_info, - part_elem_value *list_value) + part_elem_value *list_value, + HA_CREATE_INFO *create_info, + Alter_info *alter_info) { int err= 0; uint i; + List_iterator it(part_info->part_field_list); uint num_elements= part_info->part_field_list.elements; bool use_parenthesis= (part_info->part_type == LIST_PARTITION && part_info->num_columns > 1U); @@ -1998,6 +2088,7 @@ static int add_column_list_values(File fptr, partition_info *part_info, for (i= 0; i < num_elements; i++) { part_column_list_val *col_val= &list_value->col_val_array[i]; + char *field_name= it++; if (col_val->max_value) err+= add_string(fptr, partition_keywords[PKW_MAXVALUE].str); else if (col_val->null_value) @@ -2011,7 +2102,45 @@ static int add_column_list_values(File fptr, partition_info *part_info, err+= add_string(fptr, "NULL"); else { - String *res= item_expr->val_str(&str); + String *res; + CHARSET_INFO *field_cs; + + /* + This function is called at a very early stage, even before + we have prepared the sql_field objects. Thus we have to + find the proper sql_field object and get the character set + from that object. + */ + if (create_info) + { + Create_field *sql_field; + bool need_cs_check= FALSE; + + if (!(sql_field= get_sql_field(field_name, + alter_info))) + { + my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0)); + return 1; + } + if (check_part_field(sql_field, &need_cs_check)) + return 1; + if (need_cs_check) + field_cs= get_sql_field_charset(sql_field, create_info); + else + field_cs= NULL; + } + else + field_cs= part_info->part_field_array[i]->charset(); + if (field_cs && field_cs != item_expr->collation.collation) + { + if (!(item_expr= convert_charset_partition_constant(item_expr, + field_cs))) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + return 1; + } + } + res= item_expr->val_str(&str); if (!res) { my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); @@ -2033,7 +2162,9 @@ static int add_column_list_values(File fptr, partition_info *part_info, } static int add_partition_values(File fptr, partition_info *part_info, - partition_element *p_elem) + partition_element *p_elem, + HA_CREATE_INFO *create_info, + Alter_info *alter_info) { int err= 0; @@ -2045,7 +2176,8 @@ static int add_partition_values(File fptr, partition_info *part_info, List_iterator list_val_it(p_elem->list_val_list); part_elem_value *list_value= list_val_it++; err+= add_begin_parenthesis(fptr); - err+= add_column_list_values(fptr, part_info, list_value); + err+= add_column_list_values(fptr, part_info, list_value, + create_info, alter_info); err+= add_end_parenthesis(fptr); } else @@ -2087,7 +2219,8 @@ static int add_partition_values(File fptr, partition_info *part_info, part_elem_value *list_value= list_val_it++; if (part_info->column_list) - err+= add_column_list_values(fptr, part_info, list_value); + err+= add_column_list_values(fptr, part_info, list_value, + create_info, alter_info); else { if (!list_value->unsigned_flag) @@ -2116,6 +2249,8 @@ end: use_sql_alloc Allocate buffer from sql_alloc if true otherwise use my_malloc show_partition_options Should we display partition options + create_info Info generated by parser + alter_info Info generated by parser RETURN VALUES NULL error @@ -2144,7 +2279,9 @@ end: char *generate_partition_syntax(partition_info *part_info, uint *buf_length, bool use_sql_alloc, - bool show_partition_options) + bool show_partition_options, + HA_CREATE_INFO *create_info, + Alter_info *alter_info) { uint i,j, tot_num_parts, num_subparts; partition_element *part_elem; @@ -2263,7 +2400,8 @@ char *generate_partition_syntax(partition_info *part_info, first= FALSE; err+= add_partition(fptr); err+= add_name_string(fptr, part_elem->partition_name); - err+= add_partition_values(fptr, part_info, part_elem); + err+= add_partition_values(fptr, part_info, part_elem, + create_info, alter_info); if (!part_info->is_sub_partitioned() || part_info->use_default_subpartitions) { diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 47e5df0443f..0dac13a3fcc 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -67,9 +67,6 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type, TABLE *table, handler *file, HA_CREATE_INFO *info); void set_linear_hash_mask(partition_info *part_info, uint num_parts); bool fix_partition_func(THD *thd, TABLE *table, bool create_table_ind); -char *generate_partition_syntax(partition_info *part_info, - uint *buf_length, bool use_sql_alloc, - bool show_partition_options); bool partition_key_modified(TABLE *table, const MY_BITMAP *fields); void get_partition_set(const TABLE *table, uchar *buf, const uint index, const key_range *key_spec, @@ -96,6 +93,7 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, bool check_part_func_fields(Field **ptr, bool ok_with_charsets); bool field_is_partition_charset(Field *field); +Item* convert_charset_partition_constant(Item *item, CHARSET_INFO *cs); /* A "Get next" function for partition iterator. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a74e9363bcf..57ab04b5576 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1465,7 +1465,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, ((part_syntax= generate_partition_syntax(table->part_info, &part_syntax_len, FALSE, - show_table_options)))) + show_table_options, + NULL, NULL)))) { packet->append(STRING_WITH_LEN("\n/*!50100")); packet->append(part_syntax, part_syntax_len); @@ -4847,16 +4848,23 @@ get_partition_column_description(partition_info *part_info, { char buffer[MAX_STR_SIZE_PF]; String str(buffer, sizeof(buffer), &my_charset_bin); - String *res= col_val->item_expression->val_str(&str); + Item *item= col_val->item_expression; + + if (!(item= part_info->get_column_item(item, + part_info->part_field_array[i]))) + { + DBUG_RETURN(1); + } + String *res= item->val_str(&str); if (!res) { my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); DBUG_RETURN(1); } - if (col_val->item_expression->result_type() == STRING_RESULT) + if (item->result_type() == STRING_RESULT) tmp_str.append("'"); tmp_str.append(*res); - if (col_val->item_expression->result_type() == STRING_RESULT) + if (item->result_type() == STRING_RESULT) tmp_str.append("'"); } if (i != num_elements - 1) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 036db44d7dc..313503b6f3a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1583,7 +1583,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) { if (!(part_syntax_buf= generate_partition_syntax(part_info, &syntax_len, - TRUE, TRUE))) + TRUE, TRUE, + lpt->create_info, + lpt->alter_info))) { DBUG_RETURN(TRUE); } @@ -1675,7 +1677,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) char *tmp_part_syntax_str; if (!(part_syntax_buf= generate_partition_syntax(part_info, &syntax_len, - TRUE, TRUE))) + TRUE, TRUE, + lpt->create_info, + lpt->alter_info))) { error= 1; goto err; @@ -2494,6 +2498,39 @@ int prepare_create_field(Create_field *sql_field, DBUG_RETURN(0); } + +/* + Get character set from field object generated by parser using + default values when not set. + + SYNOPSIS + get_sql_field_charset() + sql_field The sql_field object + create_info Info generated by parser + + RETURN VALUES + cs Character set +*/ + +CHARSET_INFO* get_sql_field_charset(Create_field *sql_field, + HA_CREATE_INFO *create_info) +{ + CHARSET_INFO *cs= sql_field->charset; + + if (!cs) + cs= create_info->default_table_charset; + /* + table_charset is set only in ALTER TABLE t1 CONVERT TO CHARACTER SET csname + if we want change character set for all varchar/char columns. + But the table charset must not affect the BLOB fields, so don't + allow to change my_charset_bin to somethig else. + */ + if (create_info->table_charset && cs != &my_charset_bin) + cs= create_info->table_charset; + return cs; +} + + /* Preparation for table creation @@ -2557,18 +2594,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, executing a prepared statement for the second time. */ sql_field->length= sql_field->char_length; - if (!sql_field->charset) - sql_field->charset= create_info->default_table_charset; - /* - table_charset is set in ALTER TABLE if we want change character set - for all varchar/char columns. - But the table charset must not affect the BLOB fields, so don't - allow to change my_charset_bin to somethig else. - */ - if (create_info->table_charset && sql_field->charset != &my_charset_bin) - sql_field->charset= create_info->table_charset; - - save_cs= sql_field->charset; + save_cs= sql_field->charset= get_sql_field_charset(sql_field, + create_info); if ((sql_field->flags & BINCMP_FLAG) && !(sql_field->charset= get_charset_by_csname(sql_field->charset->csname, MY_CS_BINSORT,MYF(0)))) @@ -3617,6 +3644,9 @@ bool mysql_create_table_no_lock(THD *thd, } if (check_engine(thd, table_name, create_info)) DBUG_RETURN(TRUE); + + set_table_default_charset(thd, create_info, (char*) db); + db_options= create_info->table_options; if (create_info->row_type == ROW_TYPE_DYNAMIC) db_options|=HA_OPTION_PACK_RECORD; @@ -3720,7 +3750,9 @@ bool mysql_create_table_no_lock(THD *thd, */ if (!(part_syntax_buf= generate_partition_syntax(part_info, &syntax_len, - TRUE, TRUE))) + TRUE, TRUE, + create_info, + alter_info))) goto err; part_info->part_info_string= part_syntax_buf; part_info->part_info_len= syntax_len; @@ -3787,8 +3819,6 @@ bool mysql_create_table_no_lock(THD *thd, } #endif - set_table_default_charset(thd, create_info, (char*) db); - if (mysql_prepare_create_table(thd, create_info, alter_info, internal_tmp_table, &db_options, file, From cecef1c56ecd595218cf08832e2e2fa68aa7c252 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Thu, 22 Oct 2009 18:17:59 +0200 Subject: [PATCH 24/27] BUG#46183, added character set identifier on character constants in VALUES part for column list partitioned tables to ensure constants are handled properly according to character sets --- mysql-test/r/partition_column.result | 42 ++++++++++++++++++++++++---- mysql-test/t/partition_column.test | 24 ++++++++-------- sql/sql_partition.cc | 7 +++++ 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 4270af1f83b..79ab838f6cb 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,19 @@ drop table if exists t1; +create table t1 (a varchar(2) character set ucs2) +partition by list column_list (a) +(partition p0 values in (0x2020), +partition p1 values in ('')); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(2) CHARACTER SET ucs2 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY LIST COLUMN_LIST(a) +(PARTITION p0 VALUES IN (_ucs2' ') ENGINE = MyISAM, + PARTITION p1 VALUES IN (_ucs2'') ENGINE = MyISAM) */ +insert into t1 values (''); +insert into t1 values (_ucs2 0x2020); +drop table t1; create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) @@ -26,6 +41,21 @@ RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE RANGE COLUMN_LIST a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` char(10) DEFAULT NULL, + `c` varchar(25) DEFAULT NULL, + `d` datetime DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE COLUMN_LIST(a,b,c,d) +SUBPARTITION BY HASH (to_seconds(d)) +SUBPARTITIONS 4 +(PARTITION p0 VALUES LESS THAN (1,_latin1'0',MAXVALUE,0) ENGINE = MyISAM, + PARTITION p1 VALUES LESS THAN (1,_latin1'a',MAXVALUE,730120) ENGINE = MyISAM, + PARTITION p2 VALUES LESS THAN (1,_latin1'a',MAXVALUE,MAXVALUE) ENGINE = MyISAM, + PARTITION p3 VALUES LESS THAN (1,MAXVALUE,MAXVALUE,MAXVALUE) ENGINE = MyISAM) */ drop table t1; create table t1 (a int, b int) partition by range column_list (a,b) @@ -243,10 +273,10 @@ t1 CREATE TABLE `t1` ( /*!50100 PARTITION BY RANGE COLUMN_LIST(a,b,c) SUBPARTITION BY KEY (c,d) SUBPARTITIONS 3 -(PARTITION p0 VALUES LESS THAN (1,'abc','abc') ENGINE = MyISAM, - PARTITION p1 VALUES LESS THAN (2,'abc','abc') ENGINE = MyISAM, - PARTITION p2 VALUES LESS THAN (3,'abc','abc') ENGINE = MyISAM, - PARTITION p3 VALUES LESS THAN (4,'abc','abc') ENGINE = MyISAM) */ +(PARTITION p0 VALUES LESS THAN (1,_latin1'abc',_latin1'abc') ENGINE = MyISAM, + PARTITION p1 VALUES LESS THAN (2,_latin1'abc',_latin1'abc') ENGINE = MyISAM, + PARTITION p2 VALUES LESS THAN (3,_latin1'abc',_latin1'abc') ENGINE = MyISAM, + PARTITION p3 VALUES LESS THAN (4,_latin1'abc',_latin1'abc') ENGINE = MyISAM) */ insert into t1 values (1,'a','b',1),(2,'a','b',2),(3,'a','b',3); insert into t1 values (1,'b','c',1),(2,'b','c',2),(3,'b','c',3); insert into t1 values (1,'c','d',1),(2,'c','d',2),(3,'c','d',3); @@ -274,8 +304,8 @@ t1 CREATE TABLE `t1` ( `c` int(11) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE COLUMN_LIST(a,b,c) -(PARTITION p0 VALUES LESS THAN (1,'A',1) ENGINE = MyISAM, - PARTITION p1 VALUES LESS THAN (1,'B',1) ENGINE = MyISAM) */ +(PARTITION p0 VALUES LESS THAN (1,_latin1'A',1) ENGINE = MyISAM, + PARTITION p1 VALUES LESS THAN (1,_latin1'B',1) ENGINE = MyISAM) */ insert into t1 values (1, 'A', 1); explain partitions select * from t1 where a = 1 AND b <= 'A' and c = 1; id select_type table partitions type possible_keys key key_len ref rows Extra diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index 13f422d32f4..6c39557f296 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,18 @@ drop table if exists t1; --enable_warnings +# +# BUG#48163, Dagger in UCS2 not working as partition value +# +create table t1 (a varchar(2) character set ucs2) +partition by list column_list (a) +(partition p0 values in (0x2020), + partition p1 values in ('')); +show create table t1; +insert into t1 values (''); +insert into t1 values (_ucs2 0x2020); +drop table t1; + create table t1 (a int, b char(10), c varchar(25), d datetime) partition by range column_list(a,b,c,d) subpartition by hash (to_seconds(d)) @@ -18,19 +30,9 @@ subpartitions 4 partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; -#show create table t1; +show create table t1; drop table t1; -# -# BUG#48163, Dagger in UCS2 not working as partition value -# -#create table t1 (a varchar(2) character set ucs2) -#partition by list column_list (a) -#(partition p0 values in (0x2020), -# partition p1 values in ('')); -#insert into t1 values (''); -#drop table t1; - --error ER_NULL_IN_VALUES_LESS_THAN create table t1 (a int, b int) partition by range column_list (a,b) diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 0a6a2b98941..8ec3d196c3b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2147,7 +2147,14 @@ static int add_column_list_values(File fptr, partition_info *part_info, return 1; } if (item_expr->result_type() == STRING_RESULT) + { + if (field_cs) + { + err+= add_string(fptr,"_"); + err+= add_string(fptr, field_cs->csname); + } err+= add_string(fptr,"'"); + } err+= add_string_object(fptr, res); if (item_expr->result_type() == STRING_RESULT) err+= add_string(fptr,"'"); From fbac63638067b13331ac14cf4acee80221844dd9 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Fri, 23 Oct 2009 09:36:45 +0200 Subject: [PATCH 25/27] Upped size limit on varchar/char from 512 to 2048 --- sql/partition_info.h | 2 +- sql/sql_partition.cc | 2 +- sql/sql_show.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sql/partition_info.h b/sql/partition_info.h index 4b37b34cecf..015e0c1d6d0 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -19,7 +19,7 @@ #include "partition_element.h" -#define MAX_STR_SIZE_PF 512 +#define MAX_STR_SIZE_PF 2048 class partition_info; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 8ec3d196c3b..83d50ee222e 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2095,7 +2095,7 @@ static int add_column_list_values(File fptr, partition_info *part_info, err+= add_string(fptr, "NULL"); else { - char buffer[MAX_STR_SIZE_PF]; + char buffer[3 * MAX_STR_SIZE_PF + 10]; String str(buffer, sizeof(buffer), &my_charset_bin); Item *item_expr= col_val->item_expression; if (item_expr->null_value) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 57ab04b5576..46a91f7a905 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4846,7 +4846,7 @@ get_partition_column_description(partition_info *part_info, tmp_str.append("NULL"); else { - char buffer[MAX_STR_SIZE_PF]; + char buffer[3 * MAX_STR_SIZE_PF + 10]; String str(buffer, sizeof(buffer), &my_charset_bin); Item *item= col_val->item_expression; From cc43a2089cf6f45afb2cb5c15e2a077b075b80f8 Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 28 Oct 2009 00:06:11 +0100 Subject: [PATCH 26/27] Fixed sql_mode issue in BUG#48164, will ignore sql_mode when generating constants, also warnings will not be tolerated --- mysql-test/r/partition_column.result | 10 ++++++++++ mysql-test/t/partition_column.test | 15 +++++++++++++++ sql/partition_info.cc | 12 +++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 79ab838f6cb..0ba56110116 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,14 @@ drop table if exists t1; +set @@sql_mode=allow_invalid_dates; +create table t1 (a char, b char, c date) +partition by range column_list (a,b,c) +( partition p0 values less than (0,0,to_days('3000-11-31'))); +ERROR HY000: Partition column values of incorrect type +create table t1 (a char, b char, c date) +partition by range column_list (a,b,c) +( partition p0 values less than (0,0,'3000-11-31')); +ERROR HY000: Partition column values of incorrect type +set @@sql_mode=''; create table t1 (a varchar(2) character set ucs2) partition by list column_list (a) (partition p0 values in (0x2020), diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index 6c39557f296..16f12bfad04 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,21 @@ drop table if exists t1; --enable_warnings +# +# BUG#48165, sql_mode gives error +# +set @@sql_mode=allow_invalid_dates; +--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR +create table t1 (a char, b char, c date) +partition by range column_list (a,b,c) +( partition p0 values less than (0,0,to_days('3000-11-31'))); + +--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR +create table t1 (a char, b char, c date) +partition by range column_list (a,b,c) +( partition p0 values less than (0,0,'3000-11-31')); +set @@sql_mode=''; + # # BUG#48163, Dagger in UCS2 not working as partition value # diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 131e1dcf3a6..9d9aa5d4e95 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1949,18 +1949,28 @@ bool partition_info::fix_column_value_functions(THD *thd, { uchar *val_ptr; uint len= field->pack_length(); + ulong save_sql_mode; + bool save_got_warning; + if (!(column_item= get_column_item(column_item, field))) { result= TRUE; goto end; } - if (column_item->save_in_field(field, TRUE)) + save_sql_mode= thd->variables.sql_mode; + thd->variables.sql_mode= 0; + save_got_warning= thd->got_warning; + thd->got_warning= 0; + if (column_item->save_in_field(field, TRUE) || + thd->got_warning) { my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); result= TRUE; goto end; } + thd->got_warning= save_got_warning; + thd->variables.sql_mode= save_sql_mode; if (!(val_ptr= (uchar*) sql_calloc(len))) { mem_alloc_error(len); From 10fed1aca0096acb135c2065233e84d61b00b9cf Mon Sep 17 00:00:00 2001 From: Mikael Ronstrom Date: Wed, 28 Oct 2009 01:11:17 +0100 Subject: [PATCH 27/27] BUG#48165, needed to introduce length restrictions on partitioning fields to ensure that no stack overruns occur --- mysql-test/r/partition_column.result | 15 +++++++++++++ mysql-test/r/partition_datatype.result | 8 ++++--- mysql-test/t/partition_column.test | 17 +++++++++++++++ mysql-test/t/partition_datatype.test | 9 +++++--- sql/opt_range.cc | 8 ++----- sql/partition_info.cc | 30 ++++++++++++++++++++++++++ sql/partition_info.h | 3 +-- sql/share/errmsg.txt | 2 ++ sql/sql_partition.cc | 21 +++++++++++++++--- sql/sql_partition.h | 1 + sql/sql_show.cc | 2 +- 11 files changed, 98 insertions(+), 18 deletions(-) diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 0ba56110116..0dc81240782 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,19 @@ drop table if exists t1; +create table t1 (a varchar(1500), b varchar(1570)) +partition by list column_list(a,b) +( partition p0 values in (('a','b'))); +ERROR HY000: The total length of the partitioning fields is too large +create table t1 (a varchar(1023) character set utf8 collate utf8_spanish2_ci) +partition by range column_list(a) +( partition p0 values less than ('CZ'), +partition p1 values less than ('CH'), +partition p2 values less than ('D')); +insert into t1 values ('czz'),('chi'),('ci'),('cg'); +select * from t1 where a between 'cg' AND 'ci'; +a +ci +cg +drop table t1; set @@sql_mode=allow_invalid_dates; create table t1 (a char, b char, c date) partition by range column_list (a,b,c) diff --git a/mysql-test/r/partition_datatype.result b/mysql-test/r/partition_datatype.result index 607afb71da5..47ea799f497 100644 --- a/mysql-test/r/partition_datatype.result +++ b/mysql-test/r/partition_datatype.result @@ -273,7 +273,7 @@ select * from t1 where a = 'y'; a y drop table t1; -create table t1 (a varchar(65531)) partition by key (a); +create table t1 (a varchar(3068)) partition by key (a); insert into t1 values ('bbbb'); insert into t1 values ('aaaa'); select * from t1 where a = 'aaaa'; @@ -286,7 +286,7 @@ select * from t1 where a = 'bbbb'; a bbbb drop table t1; -create table t1 (a varchar(65532)) partition by key (a); +create table t1 (a varchar(3069)) partition by key (a); insert into t1 values ('bbbb'); insert into t1 values ('aaaa'); select * from t1 where a = 'aaaa'; @@ -299,7 +299,7 @@ select * from t1 where a = 'bbbb'; a bbbb drop table t1; -create table t1 (a varchar(65533) not null) partition by key (a); +create table t1 (a varchar(3070) not null) partition by key (a); insert into t1 values ('bbbb'); insert into t1 values ('aaaa'); select * from t1 where a = 'aaaa'; @@ -312,6 +312,8 @@ select * from t1 where a = 'bbbb'; a bbbb drop table t1; +create table t1 (a varchar(3070)) partition by key (a); +ERROR HY000: The total length of the partitioning fields is too large create table t1 (a varchar(65533)) partition by key (a); ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBs create table t1 (a varchar(65534) not null) partition by key (a); diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index 16f12bfad04..1c5b859a211 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,23 @@ drop table if exists t1; --enable_warnings +# +# BUG#48164, too long partition fields causes crash +# +--error ER_PARTITION_FIELDS_TOO_LONG +create table t1 (a varchar(1500), b varchar(1570)) +partition by list column_list(a,b) +( partition p0 values in (('a','b'))); + +create table t1 (a varchar(1023) character set utf8 collate utf8_spanish2_ci) +partition by range column_list(a) +( partition p0 values less than ('CZ'), + partition p1 values less than ('CH'), + partition p2 values less than ('D')); +insert into t1 values ('czz'),('chi'),('ci'),('cg'); +select * from t1 where a between 'cg' AND 'ci'; +drop table t1; + # # BUG#48165, sql_mode gives error # diff --git a/mysql-test/t/partition_datatype.test b/mysql-test/t/partition_datatype.test index 7440a9bf3a3..0a9fae15354 100644 --- a/mysql-test/t/partition_datatype.test +++ b/mysql-test/t/partition_datatype.test @@ -4,6 +4,7 @@ # as partition by key # Created to verify the fix for Bug#31705 # Partitions: crash if varchar length > 65530 +# BUG#48164 limited size to 3072 bytes # -- source include/have_partition.inc @@ -192,27 +193,29 @@ create table t1 (a set('y','n')) partition by key (a); insert into t1 values ('y'); select * from t1 where a = 'y'; drop table t1; -create table t1 (a varchar(65531)) partition by key (a); +create table t1 (a varchar(3068)) partition by key (a); insert into t1 values ('bbbb'); insert into t1 values ('aaaa'); select * from t1 where a = 'aaaa'; select * from t1 where a like 'aaa%'; select * from t1 where a = 'bbbb'; drop table t1; -create table t1 (a varchar(65532)) partition by key (a); +create table t1 (a varchar(3069)) partition by key (a); insert into t1 values ('bbbb'); insert into t1 values ('aaaa'); select * from t1 where a = 'aaaa'; select * from t1 where a like 'aaa%'; select * from t1 where a = 'bbbb'; drop table t1; -create table t1 (a varchar(65533) not null) partition by key (a); +create table t1 (a varchar(3070) not null) partition by key (a); insert into t1 values ('bbbb'); insert into t1 values ('aaaa'); select * from t1 where a = 'aaaa'; select * from t1 where a like 'aaa%'; select * from t1 where a = 'bbbb'; drop table t1; +-- error ER_PARTITION_FIELDS_TOO_LONG +create table t1 (a varchar(3070)) partition by key (a); -- error ER_TOO_BIG_ROWSIZE create table t1 (a varchar(65533)) partition by key (a); -- error ER_TOO_BIG_ROWSIZE diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 356cfe5e398..19aa06dcae9 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -3600,12 +3600,8 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar) { key_part->key= 0; key_part->part= part; - key_part->store_length= key_part->length= (uint16) (*field)->key_length(); - if ((*field)->real_maybe_null()) - key_part->store_length+= HA_KEY_NULL_LENGTH; - if ((*field)->type() == MYSQL_TYPE_BLOB || - (*field)->real_type() == MYSQL_TYPE_VARCHAR) - key_part->store_length+= HA_KEY_BLOB_LENGTH; + key_part->length= (uint16)get_partition_field_store_length(*field); + key_part->store_length= key_part->length; DBUG_PRINT("info", ("part %u length %u store_length %u", part, key_part->length, key_part->store_length)); diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 9d9aa5d4e95..52a4c4c0c7f 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1343,6 +1343,36 @@ bool partition_info::set_part_expr(char *start_token, Item *item_ptr, } +/* + Check that partition fields and subpartition fields are not too long + + SYNOPSIS + check_partition_field_length() + + RETURN VALUES + TRUE Total length was too big + FALSE Length is ok +*/ + +bool partition_info::check_partition_field_length() +{ + uint store_length= 0; + uint i; + DBUG_ENTER("partition_info::check_partition_field_length"); + + for (i= 0; i < num_part_fields; i++) + store_length+= get_partition_field_store_length(part_field_array[i]); + if (store_length > MAX_KEY_LENGTH) + DBUG_RETURN(TRUE); + store_length= 0; + for (i= 0; i < num_subpart_fields; i++) + store_length+= get_partition_field_store_length(subpart_field_array[i]); + if (store_length > MAX_KEY_LENGTH) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); +} + + /* Set up buffers and arrays for fields requiring preparation SYNOPSIS diff --git a/sql/partition_info.h b/sql/partition_info.h index 015e0c1d6d0..4d3cc2222a6 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -19,8 +19,6 @@ #include "partition_element.h" -#define MAX_STR_SIZE_PF 2048 - class partition_info; /* Some function typedefs */ @@ -298,6 +296,7 @@ public: char *end_token, bool is_subpart); static int compare_column_values(const void *a, const void *b); bool set_up_charset_field_preps(); + bool check_partition_field_length(); bool init_column_part(); bool add_column_list_value(THD *thd, Item *item); private: diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index d65945013b9..ec08885fda4 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6222,3 +6222,5 @@ ER_ROW_SINGLE_PARTITION_FIELD_ERROR eng "Row expressions in VALUES IN only allowed for multi-field column partitioning" ER_FIELD_TYPE_NOT_ALLOWED_AS_PARTITION_FIELD eng "Field '%-.192s' is of a not allowed type for this type of partitioning" +ER_PARTITION_FIELDS_TOO_LONG + eng "The total length of the partitioning fields is too large" diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 83d50ee222e..e21f7da6888 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1779,6 +1779,11 @@ bool fix_partition_func(THD *thd, TABLE *table, my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); goto end; } + if (unlikely(part_info->check_partition_field_length())) + { + my_error(ER_PARTITION_FIELDS_TOO_LONG, MYF(0)); + goto end; + } check_range_capable_PF(table); set_up_partition_key_maps(table, part_info); set_up_partition_func_pointers(part_info); @@ -2038,8 +2043,6 @@ static int check_part_field(Create_field *sql_field, case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_STRING: case MYSQL_TYPE_VAR_STRING: - if (sql_field->length > MAX_STR_SIZE_PF) - goto error; *need_cs_check= TRUE; return FALSE; break; @@ -2095,7 +2098,7 @@ static int add_column_list_values(File fptr, partition_info *part_info, err+= add_string(fptr, "NULL"); else { - char buffer[3 * MAX_STR_SIZE_PF + 10]; + char buffer[MAX_KEY_LENGTH]; String str(buffer, sizeof(buffer), &my_charset_bin); Item *item_expr= col_val->item_expression; if (item_expr->null_value) @@ -7730,5 +7733,17 @@ void create_subpartition_name(char *out, const char *in1, strxmov(out, in1, "#P#", transl_part_name, "#SP#", transl_subpart_name, "#REN#", NullS); } + +uint get_partition_field_store_length(Field *field) +{ + uint store_length; + + store_length= field->key_length(); + if (field->real_maybe_null()) + store_length+= HA_KEY_NULL_LENGTH; + if (field->real_type() == MYSQL_TYPE_VARCHAR) + store_length+= HA_KEY_BLOB_LENGTH; + return store_length; +} #endif diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 0dac13a3fcc..724a63e1d76 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -71,6 +71,7 @@ bool partition_key_modified(TABLE *table, const MY_BITMAP *fields); void get_partition_set(const TABLE *table, uchar *buf, const uint index, const key_range *key_spec, part_id_range *part_spec); +uint get_partition_field_store_length(Field *field); void get_full_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info, const key_range *key_spec, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 46a91f7a905..77c7a3c27f3 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4846,7 +4846,7 @@ get_partition_column_description(partition_info *part_info, tmp_str.append("NULL"); else { - char buffer[3 * MAX_STR_SIZE_PF + 10]; + char buffer[MAX_KEY_LENGTH]; String str(buffer, sizeof(buffer), &my_charset_bin); Item *item= col_val->item_expression;