#At file:///C:/ade/mysql-bzr/b11761296-5.5/ based on revid:serge.kozlov@stripped
3501 Mattias Jonsson 2011-05-11 [merge]
Manual merge from 5.1 of bug#11761296 to 5.5
Including extending it for mdl-locks.
removed:
mysql-test/t/cache_innodb-master.opt
added:
mysql-test/r/cache_myisam.result
mysql-test/r/partition_cache_innodb.result
mysql-test/r/partition_cache_myisam.result
mysql-test/t/cache_myisam.test
mysql-test/t/partition_cache_innodb.test
mysql-test/t/partition_cache_myisam.test
modified:
mysql-test/include/query_cache.inc
mysql-test/r/cache_innodb.result
mysql-test/t/cache_innodb.test
sql/ha_partition.cc
sql/ha_partition.h
sql/sql_base.cc
sql/sql_base.h
sql/table.h
=== modified file 'mysql-test/include/query_cache.inc'
--- a/mysql-test/include/query_cache.inc 2009-12-22 09:35:56 +0000
+++ b/mysql-test/include/query_cache.inc 2011-05-11 14:32:19 +0000
@@ -4,6 +4,9 @@
# $engine_type -- storage engine to be tested
# $test_foreign_keys -- 0, skip foreign key tests
# -- 1, do not skip foreign key tests
+# $partitions_a -- partition clause for tables with column 'a'
+# $partitions_id -- partition clause for tables with column 'id'
+# $partitions_s1 -- partition clause for tables with column 's1'
# have to be set before sourcing this script.
#
# Last update:
@@ -12,6 +15,8 @@
# main code went into include/query_cache.inc
#
+SET @save_query_cache_size= @@global.query_cache_size;
+SET GLOBAL query_cache_size = 1024 * 1024;
eval SET SESSION STORAGE_ENGINE = $engine_type;
# Initialise
@@ -24,7 +29,7 @@ drop table if exists t1,t2,t3;
#
flush status;
set autocommit=0;
-create table t1 (a int not null);
+eval create table t1 (a int not null)$partitions_a;
insert into t1 values (1),(2),(3);
select * from t1;
show status like "Qcache_queries_in_cache";
@@ -32,15 +37,15 @@ drop table t1;
commit;
set autocommit=1;
begin;
-create table t1 (a int not null);
+eval create table t1 (a int not null)$partitions_a;
insert into t1 values (1),(2),(3);
select * from t1;
show status like "Qcache_queries_in_cache";
drop table t1;
commit;
-create table t1 (a int not null);
-create table t2 (a int not null);
-create table t3 (a int not null);
+eval create table t1 (a int not null)$partitions_a;
+eval create table t2 (a int not null)$partitions_a;
+eval create table t3 (a int not null)$partitions_a;
insert into t1 values (1),(2);
insert into t2 values (1),(2);
insert into t3 values (1),(2);
@@ -67,7 +72,7 @@ commit;
show status like "Qcache_queries_in_cache";
drop table t3,t2,t1;
-CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id));
+eval CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id))$partitions_id;
select count(*) from t1;
insert into t1 (id) values (0);
select count(*) from t1;
@@ -78,7 +83,6 @@ if ($test_foreign_keys)
#
# one statement roll back inside transation
#
-let $save_query_cache_size=`select @@global.query_cache_size`;
set GLOBAL query_cache_size=1355776;
CREATE TABLE t1 ( id int(10) NOT NULL auto_increment, a varchar(25) default NULL, PRIMARY KEY (id), UNIQUE KEY a (a));
CREATE TABLE t2 ( id int(10) NOT NULL auto_increment, b varchar(25) default NULL, PRIMARY KEY (id), UNIQUE KEY b (b));
@@ -95,9 +99,7 @@ insert into t3 VALUES ( NULL, 1, 1, 2 );
commit;
select t1.* from t1, t2, t3 where t3.state & 1 = 0 and t3.t1_id = t1.id and t3.t2_id = t2.id and t1.id = 1 order by t1.a asc;
drop table t3,t2,t1;
---disable_query_log
-eval set GLOBAL query_cache_size=$save_query_cache_size;
---enable_query_log
+SET @@global.query_cache_size= @save_query_cache_size;
}
#
@@ -118,7 +120,7 @@ SET GLOBAL query_cache_size = 204800;
flush status;
SET @@autocommit=1;
eval SET SESSION STORAGE_ENGINE = $engine_type;
-CREATE TABLE t2 (s1 int, s2 varchar(1000), key(s1));
+eval CREATE TABLE t2 (s1 int, s2 varchar(1000), key(s1))$partitions_s1;
INSERT INTO t2 VALUES (1,repeat('a',10)),(2,repeat('a',10)),(3,repeat('a',10)),(4,repeat('a',10));
COMMIT;
START TRANSACTION;
@@ -176,8 +178,8 @@ show status like "Qcache_queries_in_cach
show status like "Qcache_hits";
# Final cleanup
-eval set GLOBAL query_cache_size=$save_query_cache_size;
disconnect connection1;
--source include/wait_until_disconnected.inc
connection default;
+SET @@global.query_cache_size= @save_query_cache_size;
drop table t2;
=== modified file 'mysql-test/r/cache_innodb.result'
--- a/mysql-test/r/cache_innodb.result 2010-10-06 09:01:24 +0000
+++ b/mysql-test/r/cache_innodb.result 2011-05-11 14:32:19 +0000
@@ -1,3 +1,5 @@
+SET @save_query_cache_size= @@global.query_cache_size;
+SET GLOBAL query_cache_size = 1024 * 1024;
SET SESSION STORAGE_ENGINE = InnoDB;
drop table if exists t1,t2,t3;
flush status;
@@ -128,6 +130,7 @@ select t1.* from t1, t2, t3 where t3.sta
id a
1 me
drop table t3,t2,t1;
+SET @@global.query_cache_size= @save_query_cache_size;
SET SESSION STORAGE_ENGINE = InnoDB;
SET @@autocommit=1;
connection default
@@ -218,8 +221,9 @@ Qcache_queries_in_cache 1
show status like "Qcache_hits";
Variable_name Value
Qcache_hits 1
-set GLOBAL query_cache_size=1048576;
+SET @@global.query_cache_size= @save_query_cache_size;
drop table t2;
+SET @old_cache_size= @@global.query_cache_size;
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 VALUES(1);
@@ -231,3 +235,4 @@ SELECT a FROM t1;
a
ROLLBACK;
DROP TABLE t1;
+SET @@global.query_cache_size= @old_cache_size;
=== added file 'mysql-test/r/cache_myisam.result'
--- a/mysql-test/r/cache_myisam.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/cache_myisam.result 2011-05-11 14:32:19 +0000
@@ -0,0 +1,205 @@
+SET @save_query_cache_size= @@global.query_cache_size;
+SET GLOBAL query_cache_size = 1024 * 1024;
+SET SESSION STORAGE_ENGINE = MyISAM;
+drop table if exists t1,t2,t3;
+flush status;
+set autocommit=0;
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+drop table t1;
+commit;
+set autocommit=1;
+begin;
+create table t1 (a int not null);
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+drop table t1;
+commit;
+create table t1 (a int not null);
+create table t2 (a int not null);
+create table t3 (a int not null);
+insert into t1 values (1),(2);
+insert into t2 values (1),(2);
+insert into t3 values (1),(2);
+select * from t1;
+a
+1
+2
+select * from t2;
+a
+1
+2
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+begin;
+select * from t1;
+a
+1
+2
+select * from t2;
+a
+1
+2
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+insert into t1 values (3);
+insert into t2 values (3);
+insert into t1 values (4);
+select * from t1;
+a
+1
+2
+3
+4
+select * from t2;
+a
+1
+2
+3
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+commit;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+drop table t3,t2,t1;
+CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id));
+select count(*) from t1;
+count(*)
+0
+insert into t1 (id) values (0);
+select count(*) from t1;
+count(*)
+1
+drop table t1;
+SET SESSION STORAGE_ENGINE = MyISAM;
+SET @@autocommit=1;
+connection default
+SHOW VARIABLES LIKE 'have_query_cache';
+Variable_name Value
+have_query_cache YES
+SET GLOBAL query_cache_size = 204800;
+flush status;
+SET @@autocommit=1;
+SET SESSION STORAGE_ENGINE = MyISAM;
+CREATE TABLE t2 (s1 int, s2 varchar(1000), key(s1));
+INSERT INTO t2 VALUES (1,repeat('a',10)),(2,repeat('a',10)),(3,repeat('a',10)),(4,repeat('a',10));
+COMMIT;
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+0
+UPDATE t2 SET s2 = 'w' WHERE s1 = 3;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+connection connection1
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+INSERT INTO t2 VALUES (5,'w');
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+COMMIT;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+connection default
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+COMMIT;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+connection connection1
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+INSERT INTO t2 VALUES (6,'w');
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+3
+connection default
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+3
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+3
+DELETE from t2 WHERE s1=3;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+COMMIT;
+connection connection1
+COMMIT;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+SET @@global.query_cache_size= @save_query_cache_size;
+drop table t2;
=== added file 'mysql-test/r/partition_cache_innodb.result'
--- a/mysql-test/r/partition_cache_innodb.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/partition_cache_innodb.result 2011-05-11 14:32:19 +0000
@@ -0,0 +1,338 @@
+SET @old_cache_size= @@global.query_cache_size;
+SET @save_query_cache_size= @@global.query_cache_size;
+SET GLOBAL query_cache_size = 1024 * 1024;
+SET SESSION STORAGE_ENGINE = InnoDB;
+drop table if exists t1,t2,t3;
+flush status;
+set autocommit=0;
+create table t1 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+drop table t1;
+commit;
+set autocommit=1;
+begin;
+create table t1 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+drop table t1;
+commit;
+create table t1 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+create table t2 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+create table t3 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+insert into t1 values (1),(2);
+insert into t2 values (1),(2);
+insert into t3 values (1),(2);
+select * from t1;
+a
+1
+2
+select * from t2;
+a
+1
+2
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+begin;
+select * from t1;
+a
+1
+2
+select * from t2;
+a
+1
+2
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+insert into t1 values (3);
+insert into t2 values (3);
+insert into t1 values (4);
+select * from t1;
+a
+1
+2
+3
+4
+select * from t2;
+a
+1
+2
+3
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+commit;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+drop table t3,t2,t1;
+CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) PARTITION BY HASH (id) PARTITIONS 7;
+select count(*) from t1;
+count(*)
+0
+insert into t1 (id) values (0);
+select count(*) from t1;
+count(*)
+1
+drop table t1;
+SET SESSION STORAGE_ENGINE = InnoDB;
+SET @@autocommit=1;
+connection default
+SHOW VARIABLES LIKE 'have_query_cache';
+Variable_name Value
+have_query_cache YES
+SET GLOBAL query_cache_size = 204800;
+flush status;
+SET @@autocommit=1;
+SET SESSION STORAGE_ENGINE = InnoDB;
+CREATE TABLE t2 (s1 int, s2 varchar(1000), key(s1)) PARTITION BY HASH (s1) PARTITIONS 7;
+INSERT INTO t2 VALUES (1,repeat('a',10)),(2,repeat('a',10)),(3,repeat('a',10)),(4,repeat('a',10));
+COMMIT;
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+0
+UPDATE t2 SET s2 = 'w' WHERE s1 = 3;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+connection connection1
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+0
+INSERT INTO t2 VALUES (5,'w');
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+COMMIT;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+connection default
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+COMMIT;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 0
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+connection connection1
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+INSERT INTO t2 VALUES (6,'w');
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+3
+connection default
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+DELETE from t2 WHERE s1=3;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+COMMIT;
+connection connection1
+COMMIT;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+SET @@global.query_cache_size= @save_query_cache_size;
+drop table t2;
+SET GLOBAL query_cache_size = 1024 * 1024;
+create table t1
+(name varchar(128),
+dept int,
+primary key(dept,name))
+ENGINE=InnoDB
+PARTITION BY RANGE (`dept`)
+(
+PARTITION d0 VALUES LESS THAN (1),
+PARTITION d1 VALUES LESS THAN (2),
+PARTITION d2 VALUES LESS THAN (3),
+PARTITION d_other VALUES LESS THAN MAXVALUE);
+set autocommit=0;
+start transaction;
+insert into t1(name,dept) values('a',1);
+insert into t1(name,dept) values('b',1);
+insert into t1(name,dept) values('c',1);
+select count(*) from t1;
+count(*)
+3
+# expecting 3
+rollback;
+select count(*) from t1;
+count(*)
+0
+# expecting 0, and seeing 0
+select count(*) from t1;
+count(*)
+0
+# expecting 0, and seeing 3 before fix!
+drop table t1;
+CREATE TABLE `t1`
+(`id` int(11) NOT NULL ,
+`created_at` datetime NOT NULL,
+`cool` tinyint default 0
+) ENGINE=InnoDB;
+ALTER TABLE t1
+PARTITION BY RANGE (TO_DAYS(created_at))
+(PARTITION month_2010_4 VALUES LESS THAN (734258),
+PARTITION month_2010_5 VALUES LESS THAN (734289),
+PARTITION month_max VALUES LESS THAN MAXVALUE);
+INSERT INTO t1 VALUES (1, now(), 0);
+BEGIN;
+UPDATE `t1` SET `cool` = 1 WHERE `id` = 1;
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+cool
+1
+ROLLBACK;
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+cool
+0
+BEGIN;
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+cool
+0
+ROLLBACK;
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+cool
+0
+DROP TABLE `t1`;
+CREATE TABLE t1 (a INT, b VARCHAR(64))
+ENGINE = InnoDB
+PARTITION BY HASH (a)
+PARTITIONS 5;
+INSERT INTO t1 VALUES (11, 'Eleven'), (1, 'One'), (2, 'Two'), (12, 'aslasdrfa'), (7, 'sdfae'), (4, 'asdfees'), (14, '3asdf3'), (9, 'asdfeea');
+set autocommit=1;
+FLUSH STATUS;
+SELECT * FROM t1;
+a b
+11 Eleven
+1 One
+2 Two
+12 aslasdrfa
+7 sdfae
+4 asdfees
+14 3asdf3
+9 asdfeea
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+SHOW STATUS LIKE "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+SHOW STATUS LIKE "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+SELECT * FROM t1;
+a b
+11 Eleven
+1 One
+2 Two
+12 aslasdrfa
+7 sdfae
+4 asdfees
+14 3asdf3
+9 asdfeea
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+SHOW STATUS LIKE "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+SHOW STATUS LIKE "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+FLUSH TABLES;
+SELECT * FROM t1;
+a b
+11 Eleven
+1 One
+2 Two
+12 aslasdrfa
+7 sdfae
+4 asdfees
+14 3asdf3
+9 asdfeea
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+SHOW STATUS LIKE "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+SHOW STATUS LIKE "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+DROP TABLE t1;
+set GLOBAL query_cache_size=0;
+# TODO: Add tests of partition pruning of
+# 64, 65, 255, 256 and 1024 partitions
+# 0-64, 0-9+65, 0-9+255, 0-5+256 and 0-5+1024
+# non pruned partitions)
+SET @@global.query_cache_size= @old_cache_size;
=== added file 'mysql-test/r/partition_cache_myisam.result'
--- a/mysql-test/r/partition_cache_myisam.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/partition_cache_myisam.result 2011-05-11 14:32:19 +0000
@@ -0,0 +1,338 @@
+SET @old_cache_size= @@global.query_cache_size;
+SET @save_query_cache_size= @@global.query_cache_size;
+SET GLOBAL query_cache_size = 1024 * 1024;
+SET SESSION STORAGE_ENGINE = MyISAM;
+drop table if exists t1,t2,t3;
+flush status;
+set autocommit=0;
+create table t1 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+drop table t1;
+commit;
+set autocommit=1;
+begin;
+create table t1 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+insert into t1 values (1),(2),(3);
+select * from t1;
+a
+1
+2
+3
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+drop table t1;
+commit;
+create table t1 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+create table t2 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+create table t3 (a int not null) PARTITION BY HASH (a) PARTITIONS 7;
+insert into t1 values (1),(2);
+insert into t2 values (1),(2);
+insert into t3 values (1),(2);
+select * from t1;
+a
+1
+2
+select * from t2;
+a
+1
+2
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 3
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+begin;
+select * from t1;
+a
+1
+2
+select * from t2;
+a
+1
+2
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 6
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+insert into t1 values (3);
+insert into t2 values (3);
+insert into t1 values (4);
+select * from t1;
+a
+1
+2
+3
+4
+select * from t2;
+a
+1
+2
+3
+select * from t3;
+a
+1
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+commit;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 4
+drop table t3,t2,t1;
+CREATE TABLE t1 (id int(11) NOT NULL auto_increment, PRIMARY KEY (id)) PARTITION BY HASH (id) PARTITIONS 7;
+select count(*) from t1;
+count(*)
+0
+insert into t1 (id) values (0);
+select count(*) from t1;
+count(*)
+1
+drop table t1;
+SET SESSION STORAGE_ENGINE = MyISAM;
+SET @@autocommit=1;
+connection default
+SHOW VARIABLES LIKE 'have_query_cache';
+Variable_name Value
+have_query_cache YES
+SET GLOBAL query_cache_size = 204800;
+flush status;
+SET @@autocommit=1;
+SET SESSION STORAGE_ENGINE = MyISAM;
+CREATE TABLE t2 (s1 int, s2 varchar(1000), key(s1)) PARTITION BY HASH (s1) PARTITIONS 7;
+INSERT INTO t2 VALUES (1,repeat('a',10)),(2,repeat('a',10)),(3,repeat('a',10)),(4,repeat('a',10));
+COMMIT;
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+0
+UPDATE t2 SET s2 = 'w' WHERE s1 = 3;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+connection connection1
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+1
+INSERT INTO t2 VALUES (5,'w');
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+COMMIT;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+connection default
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+COMMIT;
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+connection connection1
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+INSERT INTO t2 VALUES (6,'w');
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+3
+connection default
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+3
+START TRANSACTION;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+3
+DELETE from t2 WHERE s1=3;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+COMMIT;
+connection connection1
+COMMIT;
+SELECT sql_cache count(*) FROM t2 WHERE s2 = 'w';
+count(*)
+2
+show status like "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 2
+show status like "Qcache_hits";
+Variable_name Value
+Qcache_hits 6
+SET @@global.query_cache_size= @save_query_cache_size;
+drop table t2;
+SET GLOBAL query_cache_size = 1024 * 1024;
+create table t1
+(name varchar(128),
+dept int,
+primary key(dept,name))
+ENGINE=MyISAM
+PARTITION BY RANGE (`dept`)
+(
+PARTITION d0 VALUES LESS THAN (1),
+PARTITION d1 VALUES LESS THAN (2),
+PARTITION d2 VALUES LESS THAN (3),
+PARTITION d_other VALUES LESS THAN MAXVALUE);
+set autocommit=0;
+start transaction;
+insert into t1(name,dept) values('a',1);
+insert into t1(name,dept) values('b',1);
+insert into t1(name,dept) values('c',1);
+select count(*) from t1;
+count(*)
+3
+# expecting 3
+rollback;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+select count(*) from t1;
+count(*)
+3
+# expecting 0, and seeing 0
+select count(*) from t1;
+count(*)
+3
+# expecting 0, and seeing 3 before fix!
+drop table t1;
+CREATE TABLE `t1`
+(`id` int(11) NOT NULL ,
+`created_at` datetime NOT NULL,
+`cool` tinyint default 0
+) ENGINE=MyISAM;
+ALTER TABLE t1
+PARTITION BY RANGE (TO_DAYS(created_at))
+(PARTITION month_2010_4 VALUES LESS THAN (734258),
+PARTITION month_2010_5 VALUES LESS THAN (734289),
+PARTITION month_max VALUES LESS THAN MAXVALUE);
+INSERT INTO t1 VALUES (1, now(), 0);
+BEGIN;
+UPDATE `t1` SET `cool` = 1 WHERE `id` = 1;
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+cool
+1
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+cool
+1
+BEGIN;
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+cool
+1
+ROLLBACK;
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+cool
+1
+DROP TABLE `t1`;
+CREATE TABLE t1 (a INT, b VARCHAR(64))
+ENGINE = MyISAM
+PARTITION BY HASH (a)
+PARTITIONS 5;
+INSERT INTO t1 VALUES (11, 'Eleven'), (1, 'One'), (2, 'Two'), (12, 'aslasdrfa'), (7, 'sdfae'), (4, 'asdfees'), (14, '3asdf3'), (9, 'asdfeea');
+set autocommit=1;
+FLUSH STATUS;
+SELECT * FROM t1;
+a b
+11 Eleven
+1 One
+2 Two
+12 aslasdrfa
+7 sdfae
+4 asdfees
+14 3asdf3
+9 asdfeea
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+SHOW STATUS LIKE "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+SHOW STATUS LIKE "Qcache_hits";
+Variable_name Value
+Qcache_hits 0
+SELECT * FROM t1;
+a b
+11 Eleven
+1 One
+2 Two
+12 aslasdrfa
+7 sdfae
+4 asdfees
+14 3asdf3
+9 asdfeea
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+SHOW STATUS LIKE "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 1
+SHOW STATUS LIKE "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+FLUSH TABLES;
+SELECT * FROM t1;
+a b
+11 Eleven
+1 One
+2 Two
+12 aslasdrfa
+7 sdfae
+4 asdfees
+14 3asdf3
+9 asdfeea
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+Variable_name Value
+Qcache_queries_in_cache 1
+SHOW STATUS LIKE "Qcache_inserts";
+Variable_name Value
+Qcache_inserts 2
+SHOW STATUS LIKE "Qcache_hits";
+Variable_name Value
+Qcache_hits 1
+DROP TABLE t1;
+set GLOBAL query_cache_size=0;
+SET @@global.query_cache_size= @old_cache_size;
=== removed file 'mysql-test/t/cache_innodb-master.opt'
--- a/mysql-test/t/cache_innodb-master.opt 2010-03-03 19:22:02 +0000
+++ b/mysql-test/t/cache_innodb-master.opt 1970-01-01 00:00:00 +0000
@@ -1 +0,0 @@
---query_cache_size=1M
=== modified file 'mysql-test/t/cache_innodb.test'
--- a/mysql-test/t/cache_innodb.test 2010-10-06 09:01:24 +0000
+++ b/mysql-test/t/cache_innodb.test 2011-05-11 14:32:19 +0000
@@ -15,6 +15,7 @@ let $test_foreign_keys= 1;
--source include/query_cache.inc
+SET @old_cache_size= @@global.query_cache_size;
#
# Bug#56452 Assertion failed: thd->transaction.stmt.is_empty() ||
# thd->in_sub_stmt
@@ -29,3 +30,4 @@ SELECT a FROM t1;
ROLLBACK;
DROP TABLE t1;
+SET @@global.query_cache_size= @old_cache_size;
=== added file 'mysql-test/t/cache_myisam.test'
--- a/mysql-test/t/cache_myisam.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/cache_myisam.test 2011-05-08 21:23:01 +0000
@@ -0,0 +1,7 @@
+--source include/have_query_cache.inc
+
+let $engine_type= MyISAM;
+# MyISAM does NOT supports FOREIGN KEYs
+let $test_foreign_keys= 0;
+
+--source include/query_cache.inc
=== added file 'mysql-test/t/partition_cache_innodb.test'
--- a/mysql-test/t/partition_cache_innodb.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/partition_cache_innodb.test 2011-05-11 14:32:19 +0000
@@ -0,0 +1,114 @@
+--source include/have_query_cache.inc
+
+--source include/have_innodb.inc
+--source include/have_partition.inc
+let $engine_type= InnoDB;
+# partitioned InnoDB does NOT supports FOREIGN KEYs
+let $test_foreign_keys= 0;
+
+SET @old_cache_size= @@global.query_cache_size;
+
+# Using SELECT to get a space as first character.
+let $partitions_a= `SELECT ' PARTITION BY HASH (a) PARTITIONS 7'`;
+let $partitions_id= `SELECT ' PARTITION BY HASH (id) PARTITIONS 7'`;
+let $partitions_s1= `SELECT ' PARTITION BY HASH (s1) PARTITIONS 7'`;
+
+--source include/query_cache.inc
+
+let $save_query_cache_size=`select @@global.query_cache_size`;
+SET GLOBAL query_cache_size = 1024 * 1024;
+create table t1
+(name varchar(128),
+ dept int,
+ primary key(dept,name))
+ENGINE=InnoDB
+PARTITION BY RANGE (`dept`)
+(
+ PARTITION d0 VALUES LESS THAN (1),
+ PARTITION d1 VALUES LESS THAN (2),
+ PARTITION d2 VALUES LESS THAN (3),
+ PARTITION d_other VALUES LESS THAN MAXVALUE);
+
+set autocommit=0;
+start transaction;
+
+insert into t1(name,dept) values('a',1);
+insert into t1(name,dept) values('b',1);
+insert into t1(name,dept) values('c',1);
+
+select count(*) from t1;
+--echo # expecting 3
+rollback;
+
+select count(*) from t1;
+--echo # expecting 0, and seeing 0
+
+select count(*) from t1;
+--echo # expecting 0, and seeing 3 before fix!
+
+drop table t1;
+
+
+
+CREATE TABLE `t1`
+(`id` int(11) NOT NULL ,
+ `created_at` datetime NOT NULL,
+ `cool` tinyint default 0
+) ENGINE=InnoDB;
+
+ALTER TABLE t1
+PARTITION BY RANGE (TO_DAYS(created_at))
+(PARTITION month_2010_4 VALUES LESS THAN (734258),
+ PARTITION month_2010_5 VALUES LESS THAN (734289),
+ PARTITION month_max VALUES LESS THAN MAXVALUE);
+
+INSERT INTO t1 VALUES (1, now(), 0);
+
+BEGIN;
+
+UPDATE `t1` SET `cool` = 1 WHERE `id` = 1;
+
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+
+ROLLBACK;
+
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+
+BEGIN;
+
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+
+ROLLBACK;
+
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+
+DROP TABLE `t1`;
+
+CREATE TABLE t1 (a INT, b VARCHAR(64))
+ENGINE = InnoDB
+PARTITION BY HASH (a)
+PARTITIONS 5;
+INSERT INTO t1 VALUES (11, 'Eleven'), (1, 'One'), (2, 'Two'), (12, 'aslasdrfa'), (7, 'sdfae'), (4, 'asdfees'), (14, '3asdf3'), (9, 'asdfeea');
+set autocommit=1;
+FLUSH STATUS;
+SELECT * FROM t1;
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+SHOW STATUS LIKE "Qcache_inserts";
+SHOW STATUS LIKE "Qcache_hits";
+SELECT * FROM t1;
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+SHOW STATUS LIKE "Qcache_inserts";
+SHOW STATUS LIKE "Qcache_hits";
+FLUSH TABLES;
+SELECT * FROM t1;
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+SHOW STATUS LIKE "Qcache_inserts";
+SHOW STATUS LIKE "Qcache_hits";
+DROP TABLE t1;
+eval set GLOBAL query_cache_size=$save_query_cache_size;
+--echo # TODO: Add tests of partition pruning of
+--echo # 64, 65, 255, 256 and 1024 partitions
+--echo # 0-64, 0-9+65, 0-9+255, 0-5+256 and 0-5+1024
+--echo # non pruned partitions)
+
+SET @@global.query_cache_size= @old_cache_size;
=== added file 'mysql-test/t/partition_cache_myisam.test'
--- a/mysql-test/t/partition_cache_myisam.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/partition_cache_myisam.test 2011-05-11 14:32:19 +0000
@@ -0,0 +1,109 @@
+--source include/have_query_cache.inc
+
+--source include/have_partition.inc
+let $engine_type= MyISAM;
+# partitioned MyISAM does NOT supports FOREIGN KEYs
+let $test_foreign_keys= 0;
+
+SET @old_cache_size= @@global.query_cache_size;
+
+# Using SELECT to get a space as first character.
+let $partitions_a= `SELECT ' PARTITION BY HASH (a) PARTITIONS 7'`;
+let $partitions_id= `SELECT ' PARTITION BY HASH (id) PARTITIONS 7'`;
+let $partitions_s1= `SELECT ' PARTITION BY HASH (s1) PARTITIONS 7'`;
+
+--source include/query_cache.inc
+
+let $save_query_cache_size=`select @@global.query_cache_size`;
+SET GLOBAL query_cache_size = 1024 * 1024;
+create table t1
+(name varchar(128),
+ dept int,
+ primary key(dept,name))
+ENGINE=MyISAM
+PARTITION BY RANGE (`dept`)
+(
+ PARTITION d0 VALUES LESS THAN (1),
+ PARTITION d1 VALUES LESS THAN (2),
+ PARTITION d2 VALUES LESS THAN (3),
+ PARTITION d_other VALUES LESS THAN MAXVALUE);
+
+set autocommit=0;
+start transaction;
+
+insert into t1(name,dept) values('a',1);
+insert into t1(name,dept) values('b',1);
+insert into t1(name,dept) values('c',1);
+
+select count(*) from t1;
+--echo # expecting 3
+rollback;
+
+select count(*) from t1;
+--echo # expecting 0, and seeing 0
+
+select count(*) from t1;
+--echo # expecting 0, and seeing 3 before fix!
+
+drop table t1;
+
+
+
+CREATE TABLE `t1`
+(`id` int(11) NOT NULL ,
+ `created_at` datetime NOT NULL,
+ `cool` tinyint default 0
+) ENGINE=MyISAM;
+
+ALTER TABLE t1
+PARTITION BY RANGE (TO_DAYS(created_at))
+(PARTITION month_2010_4 VALUES LESS THAN (734258),
+ PARTITION month_2010_5 VALUES LESS THAN (734289),
+ PARTITION month_max VALUES LESS THAN MAXVALUE);
+
+INSERT INTO t1 VALUES (1, now(), 0);
+
+BEGIN;
+
+UPDATE `t1` SET `cool` = 1 WHERE `id` = 1;
+
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+
+ROLLBACK;
+
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+
+BEGIN;
+
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+
+ROLLBACK;
+
+SELECT cool FROM `t1` WHERE (`t1`.id = 1) LIMIT 1;
+
+DROP TABLE `t1`;
+
+CREATE TABLE t1 (a INT, b VARCHAR(64))
+ENGINE = MyISAM
+PARTITION BY HASH (a)
+PARTITIONS 5;
+INSERT INTO t1 VALUES (11, 'Eleven'), (1, 'One'), (2, 'Two'), (12, 'aslasdrfa'), (7, 'sdfae'), (4, 'asdfees'), (14, '3asdf3'), (9, 'asdfeea');
+set autocommit=1;
+FLUSH STATUS;
+SELECT * FROM t1;
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+SHOW STATUS LIKE "Qcache_inserts";
+SHOW STATUS LIKE "Qcache_hits";
+SELECT * FROM t1;
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+SHOW STATUS LIKE "Qcache_inserts";
+SHOW STATUS LIKE "Qcache_hits";
+FLUSH TABLES;
+SELECT * FROM t1;
+SHOW STATUS LIKE "Qcache_queries_in_cache";
+SHOW STATUS LIKE "Qcache_inserts";
+SHOW STATUS LIKE "Qcache_hits";
+DROP TABLE t1;
+eval set GLOBAL query_cache_size=$save_query_cache_size;
+
+SET @@global.query_cache_size= @old_cache_size;
=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc 2011-04-29 07:56:36 +0000
+++ b/sql/ha_partition.cc 2011-05-11 14:32:19 +0000
@@ -60,6 +60,7 @@
#include "key.h"
#include "sql_plugin.h"
#include "table.h" /* HA_DATA_PARTITION */
+#include "sql_base.h" // get_table_share
#include "debug_sync.h"
@@ -391,7 +392,7 @@ bool ha_partition::initialize_partition(
DBUG_RETURN(0);
}
else if (get_from_handler_file(table_share->normalized_path.str,
- mem_root, false))
+ mem_root, false, NULL))
{
my_error(ER_FAILED_READ_FROM_PAR_FILE, MYF(0));
DBUG_RETURN(1);
@@ -1923,7 +1924,7 @@ uint ha_partition::del_ren_cre_table(con
DBUG_RETURN(TRUE);
}
- if (get_from_handler_file(from, ha_thd()->mem_root, false))
+ if (get_from_handler_file(from, ha_thd()->mem_root, false, NULL))
DBUG_RETURN(TRUE);
DBUG_ASSERT(m_file_buffer);
DBUG_PRINT("enter", ("from: (%s) to: (%s)", from, to ? to : "(nil)"));
@@ -2427,7 +2428,8 @@ error_end:
/**
Read the .par file to get the partitions engines and names
- @param name Name of table file (without extention)
+ @param name Name of table file (without extention)
+ @param[out] name_buffer_length Length of the m_name_buffer
@return Operation status
@retval true Failure
@@ -2437,7 +2439,7 @@ error_end:
freed by the caller. m_name_buffer_ptr and m_tot_parts is also set.
*/
-bool ha_partition::read_par_file(const char *name)
+bool ha_partition::read_par_file(const char *name, uint *name_buffer_length)
{
char buff[FN_REFLEN], *tot_name_len_offset;
File file;
@@ -2486,6 +2488,8 @@ bool ha_partition::read_par_file(const c
goto err2;
(void) mysql_file_close(file, MYF(0));
m_file_buffer= file_buffer; // Will be freed in clear_handler_file()
+ if (name_buffer_length)
+ *name_buffer_length= uint4korr(tot_name_len_offset);
m_name_buffer_ptr= tot_name_len_offset + PAR_WORD_SIZE;
DBUG_RETURN(false);
@@ -2567,16 +2571,22 @@ err:
partitions.
*/
-bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root,
- bool is_clone)
+bool ha_partition::get_from_handler_file(const char *name,
+ MEM_ROOT *mem_root,
+ bool is_clone,
+ uint *name_buffer_length)
{
DBUG_ENTER("ha_partition::get_from_handler_file");
DBUG_PRINT("enter", ("table name: '%s'", name));
if (m_file_buffer)
+ {
+ if (name_buffer_length)
+ *name_buffer_length= uint4korr(m_name_buffer_ptr - PAR_WORD_SIZE);
DBUG_RETURN(false);
+ }
- if (read_par_file(name))
+ if (read_par_file(name, name_buffer_length))
DBUG_RETURN(true);
if (!is_clone && setup_engine_array(mem_root))
@@ -2630,7 +2640,7 @@ int ha_partition::open(const char *name,
{
char *name_buffer_ptr;
int error= HA_ERR_INITIALIZATION;
- uint alloc_len;
+ uint alloc_len, name_buffer_length;
handler **file;
char name_buff[FN_REFLEN];
bool is_not_tmp_table= (table_share->tmp_table == NO_TMP_TABLE);
@@ -2642,7 +2652,8 @@ int ha_partition::open(const char *name,
m_mode= mode;
m_open_test_lock= test_if_locked;
m_part_field_array= m_part_info->full_part_field_array;
- if (get_from_handler_file(name, &table->mem_root, test(m_is_clone_of)))
+ if (get_from_handler_file(name, &table->mem_root, test(m_is_clone_of),
+ &name_buffer_length))
DBUG_RETURN(error);
name_buffer_ptr= m_name_buffer_ptr;
m_start_key.length= 0;
@@ -2675,6 +2686,51 @@ int ha_partition::open(const char *name,
}
}
+ /*
+ Use table_share->ha_part_data to:
+ - share auto_increment_value among all handlers for the same table.
+ - store a copy of all partition names.
+ */
+ if (is_not_tmp_table)
+ mysql_mutex_lock(&table_share->LOCK_ha_data);
+ if (!table_share->ha_part_data)
+ {
+ /* currently only needed for auto_increment */
+ table_share->ha_part_data= (HA_DATA_PARTITION*)
+ alloc_root(&table_share->mem_root,
+ sizeof(HA_DATA_PARTITION));
+ if (!table_share->ha_part_data)
+ {
+ if (is_not_tmp_table)
+ mysql_mutex_unlock(&table_share->LOCK_ha_data);
+ DBUG_RETURN(HA_ERR_INITIALIZATION);
+ }
+ DBUG_PRINT("info", ("table_share->ha_part_data 0x%p",
+ table_share->ha_part_data));
+ bzero(table_share->ha_part_data, sizeof(HA_DATA_PARTITION));
+ table_share->ha_part_data_destroy= ha_data_partition_destroy;
+ mysql_mutex_init(key_PARTITION_LOCK_auto_inc,
+ &table_share->ha_part_data->LOCK_auto_inc,
+ MY_MUTEX_INIT_FAST);
+ table_share->ha_part_data->num_tot_parts= m_tot_parts;
+ /* Allocate space for all partition names + one extra '\0' at the end */
+ table_share->ha_part_data->partition_names=
+ (char*) alloc_root(&table_share->mem_root,
+ name_buffer_length + 1);
+
+ if (!table_share->ha_part_data->partition_names)
+ {
+ if (is_not_tmp_table)
+ mysql_mutex_unlock(&table_share->LOCK_ha_data);
+ DBUG_RETURN(HA_ERR_INITIALIZATION);
+ }
+ memcpy((void *) table_share->ha_part_data->partition_names,
+ (void *) m_name_buffer_ptr, name_buffer_length);
+ (char) table_share->ha_part_data->partition_names[name_buffer_length]= 0;
+ }
+ if (is_not_tmp_table)
+ mysql_mutex_unlock(&table_share->LOCK_ha_data);
+
/* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */
if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE))
DBUG_RETURN(error);
@@ -2777,34 +2833,6 @@ int ha_partition::open(const char *name,
goto err_handler;
/*
- Use table_share->ha_part_data to share auto_increment_value among
- all handlers for the same table.
- */
- if (is_not_tmp_table)
- mysql_mutex_lock(&table_share->LOCK_ha_data);
- if (!table_share->ha_part_data)
- {
- /* currently only needed for auto_increment */
- table_share->ha_part_data= (HA_DATA_PARTITION*)
- alloc_root(&table_share->mem_root,
- sizeof(HA_DATA_PARTITION));
- if (!table_share->ha_part_data)
- {
- if (is_not_tmp_table)
- mysql_mutex_unlock(&table_share->LOCK_ha_data);
- goto err_handler;
- }
- DBUG_PRINT("info", ("table_share->ha_part_data 0x%p",
- table_share->ha_part_data));
- bzero(table_share->ha_part_data, sizeof(HA_DATA_PARTITION));
- table_share->ha_part_data_destroy= ha_data_partition_destroy;
- mysql_mutex_init(key_PARTITION_LOCK_auto_inc,
- &table_share->ha_part_data->LOCK_auto_inc,
- MY_MUTEX_INIT_FAST);
- }
- if (is_not_tmp_table)
- mysql_mutex_unlock(&table_share->LOCK_ha_data);
- /*
Some handlers update statistics as part of the open call. This will in
some cases corrupt the statistics of the partition handler and thus
to ensure we have correct statistics we call info from open after
@@ -3256,7 +3284,7 @@ int ha_partition::write_row(uchar * buf)
my_bitmap_map *old_map;
THD *thd= ha_thd();
timestamp_auto_set_type saved_timestamp_type= table->timestamp_field_type;
- ulong saved_sql_mode= thd->variables.sql_mode;
+ ulonglong saved_sql_mode= thd->variables.sql_mode;
bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null;
#ifdef NOT_NEEDED
uchar *rec0= m_rec0;
@@ -6492,6 +6520,9 @@ bool ha_partition::can_switch_engines()
}
+/****************************************************************************
+ MODULE query cache
+****************************************************************************/
/*
Is table cache supported
@@ -6508,6 +6539,318 @@ uint8 ha_partition::table_cache_type()
}
+/**
+ Callback for verifying that the partitioned table has not changed.
+
+ @param thd THD
+ @param key table key (db\0table)
+ @param len length of key
+ @param engine_data Engine specific data
+
+ @return True if result still is valid.
+*/
+
+static my_bool partition_qc_check_callback(THD *thd,
+ char *key,
+ uint len,
+ ulonglong *engine_data)
+{
+ TABLE_SHARE *share;
+ bool is_still_valid= false;
+ uint tot_parts, part_id= 0;
+ HA_DATA_PARTITION *ha_data;
+ const char *part_name= NULL;
+ MDL_request mdl_request;
+
+ DBUG_ENTER("partition_qc_check_callback");
+ /* Get a shared meta data lock and the look for the table_share */
+ mdl_request.init(MDL_key::TABLE, key, key + strlen(key) + 1, MDL_SHARED,
+ MDL_STATEMENT);
+ if (thd->mdl_context.try_acquire_lock(&mdl_request))
+ DBUG_RETURN(FALSE);
+
+ share= get_cached_table_share(key, len);
+ if (!share)
+ {
+ DBUG_PRINT("info", ("db: %s table: %s no share found (qc_check_callback)",
+ key, key + strlen(key) + 1));
+ DBUG_RETURN(FALSE);
+ }
+
+ /*
+ Since ha_data->partition_names and ha_data->static_qc_callback
+ only are set once and never reset or changed it is safe to check
+ first without holding a mutex.
+ */
+ ha_data= share->ha_part_data;
+ if (ha_data && ha_data->static_qc_callback)
+ {
+ part_name= ha_data->partition_names;
+ tot_parts= ha_data->num_tot_parts;
+ }
+ else
+ {
+ mysql_mutex_lock(&share->LOCK_ha_data);
+ if (ha_data && ha_data->static_qc_callback)
+ {
+ part_name= ha_data->partition_names;
+ tot_parts= ha_data->num_tot_parts;
+ }
+ mysql_mutex_unlock(&share->LOCK_ha_data);
+ }
+
+ /* Remove this if hit, might be possible right after a FLUSH TABLES? */
+ DBUG_ASSERT(part_name && tot_parts);
+
+
+ /* loop through all names and their callbacks */
+ if (part_name)
+ {
+ char part_name_key[FN_REFLEN], *part_name_start;
+ uint part_id= 0, part_count= 0;
+ memcpy(part_name_key, key, len);
+ part_name_start= part_name_key + len - 1;
+ while (*part_name)
+ {
+ if (*engine_data)
+ {
+ /*
+ Check if it is pruning was used (engine_data).
+ See register function below.
+ */
+ if (tot_parts <= 64)
+ {
+ ulonglong pruned_engine_data= *engine_data;
+ if (!(pruned_engine_data & (1ULL << part_id)))
+ goto next_part;
+ }
+ else if (tot_parts <= 255)
+ {
+ uint8 *pruned_engine_data= (uint8*) engine_data;
+ if (part_count >= 8)
+ break;
+ if (!pruned_engine_data[part_count])
+ break;
+ if ((part_id + 1) != pruned_engine_data[part_count])
+ goto next_part;
+ }
+ else
+ {
+ uint16 *pruned_engine_data= (uint16*) engine_data;
+ if (part_count >= 4)
+ break;
+ if (!pruned_engine_data[part_count])
+ break;
+ if ((part_id + 1) != pruned_engine_data[part_count])
+ goto next_part;
+ }
+ }
+ /* create new key + lenght */
+ create_partition_name(part_name_start, "",
+ part_name, NORMAL_PART_NAME, FALSE);
+ if (!ha_data->static_qc_callback(thd, part_name_key,
+ len + strlen(part_name_start),
+ engine_data))
+ {
+ DBUG_PRINT("info", ("part: %s callback does not allow cached result",
+ part_name_start));
+ goto err;
+ }
+ part_count++;
+next_part:
+ part_name+= strlen(part_name) + 1;
+ part_id++;
+ }
+ is_still_valid= 1;
+ }
+err:
+ /* Release the table share and the meta data lock */
+ thd->mdl_context.release_statement_locks();
+ mysql_mutex_lock(&LOCK_open);
+ release_table_share(share);
+ mysql_mutex_unlock(&LOCK_open);
+
+ DBUG_RETURN(test(is_still_valid));
+}
+
+
+/**
+ Register a table to be cached with a query.
+
+ @param thd Thread
+ @param table_key dbname\0tablename\0
+ @param key_length Lenght of table_key
+ @param engine_callback Function callback for checking if table is changed
+ @param engine_data Engine specific data
+
+ @return True if the query can be cached
+ @retval TRUE OK to cache query
+ @retval FALSE can not cache query
+
+ @note Since partitioning does not support foreign keys, there will not be any
+ internal invalidations by InnoDB.
+
+ Implemented by forward the call to every partition, with its unique partition
+ name. If not all partitions return the same callback and engine_data we
+ cannot succeed (both MyISAM and InnoDB have a static callback and don't use
+ the engine_data).
+*/
+
+my_bool ha_partition::register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
+{
+ qc_engine_callback first_callback, part_callback;
+ ulonglong first_data= 0, part_engine_data, pruned_engine_data= 0;
+ bool first_set= false;
+ handler **file;
+ char part_name_key[FN_REFLEN], *part_name_start;
+ const char *part_name= table_share->ha_part_data->partition_names;
+ DBUG_ENTER("ha_partition::register_query_cache_table");
+
+ /*
+ Check if it is possible to use pruning by using
+ the unused engine_data.
+ Use part_id range -> 1..m_tot_parts instead of 0..(m_tot_parts - 1).
+ This way if engine_data == 0 it means that no pruning was used.
+ If <= 64 parts use as bitmap.
+ If (> 64 parts && <= 255 parts && max 8 partitions used) use
+ each byte as (partition id + 1) (uint8).
+ If (> 255 parts && max 4 partitions used) use
+ each pair of byte as (partition id + 1) (uint16).
+ TODO: Change the query cache api to store a 'blob' of arbitrary length
+ instead of a fixed length engine_data. Preferable a pointer + length which
+ the query cache will copy and store. Copying since the query cache manages
+ its own memory and its own limits.
+ */
+ if (m_tot_parts <= 64)
+ {
+ uint part_id= bitmap_get_first_set(&m_part_info->used_partitions);
+ for (;part_id < m_tot_parts; part_id++)
+ {
+ if (bitmap_is_set(&m_part_info->used_partitions, part_id))
+ pruned_engine_data|= 1ULL << part_id;
+ }
+ }
+ else if (m_tot_parts <= 255)
+ {
+ if (bitmap_bits_set(&m_part_info->used_partitions) <= 8)
+ {
+ uint part_id= bitmap_get_first_set(&m_part_info->used_partitions);
+ uint part_count= 0;
+ uint8 *pruned_engine_data_array= (uint8*) &pruned_engine_data;
+ for (;part_id < m_tot_parts; part_id++)
+ {
+ if (bitmap_is_set(&m_part_info->used_partitions, part_id))
+ pruned_engine_data_array[part_count++]= (part_id + 1);
+ DBUG_ASSERT(part_count <= 8);
+ }
+ }
+ }
+ else
+ {
+ if (bitmap_bits_set(&m_part_info->used_partitions) <= 4)
+ {
+ uint part_id= bitmap_get_first_set(&m_part_info->used_partitions);
+ uint part_count= 0;
+ uint16 *pruned_engine_data_array= (uint16*) &pruned_engine_data;
+ for (;part_id < m_tot_parts; part_id++)
+ {
+ if (bitmap_is_set(&m_part_info->used_partitions, part_id))
+ pruned_engine_data_array[part_count++]= (part_id + 1);
+ DBUG_ASSERT(part_count <= 4);
+ }
+ }
+ }
+ file= m_file;
+ memcpy(part_name_key, table_key, key_length);
+ part_name_start= part_name_key + key_length - 1;
+ do
+ {
+ if (!pruned_engine_data || bitmap_is_set(&m_part_info->used_partitions,
+ file - m_file))
+ {
+ create_partition_name(part_name_start, "",
+ part_name, NORMAL_PART_NAME, FALSE);
+ if (!(*file)->register_query_cache_table(thd, part_name_key,
+ key_length +
+ strlen(part_name_start),
+ &part_callback,
+ &part_engine_data))
+ {
+ DBUG_PRINT("info", ("part: %s failed register_query_cache_table",
+ part_name_start));
+ DBUG_RETURN(FALSE);
+ }
+
+ /*
+ All partitions must have same callback function and engine_data.
+ MyISAM sets both callback and data = 0.
+ InnoDB uses a static function for callback and sets data = 0.
+ */
+ if (!first_set)
+ {
+ first_callback= part_callback;
+ first_data= part_engine_data;
+ first_set= true;
+ }
+ if (first_callback != part_callback || first_data != part_engine_data)
+ {
+ DBUG_PRINT("info", ("part: %s different callback function/engine data",
+ part_name_start));
+ DBUG_RETURN(FALSE);
+ }
+ }
+ part_name+= strlen(part_name) + 1;
+
+ } while (*(++file));
+
+ if (first_callback)
+ {
+ HA_DATA_PARTITION *ha_data= table_share->ha_part_data;
+ /*
+ Verify if it is the same as ha_data->qc_callback.
+ Or register if never set.
+ This is only set by the first call from the first instance
+ and never reset or changed, so it is safe to check first without
+ taking the table_share->mutex.
+ */
+ DBUG_ASSERT(ha_data);
+ if (!ha_data->static_qc_callback)
+ {
+ mysql_mutex_lock(&table_share->LOCK_ha_data);
+ if (!ha_data->static_qc_callback)
+ ha_data->static_qc_callback= first_callback;
+ mysql_mutex_unlock(&table_share->LOCK_ha_data);
+ }
+
+ if (ha_data->static_qc_callback != first_callback)
+ {
+ /* If this is hit, the underlying engine have changed the callback! */
+ DBUG_ASSERT(0);
+ DBUG_RETURN(FALSE);
+ }
+
+ *engine_callback= partition_qc_check_callback;
+ }
+
+ /*
+ Neither InnoDB or MyISAM use engine_data.
+ If set, we must remove the pruning optimization!
+ */
+ DBUG_ASSERT(!first_data);
+ if (first_data)
+ {
+ DBUG_RETURN(FALSE);
+ }
+
+ *engine_data= pruned_engine_data;
+
+ DBUG_RETURN(TRUE);
+}
+
/****************************************************************************
MODULE print messages
****************************************************************************/
=== modified file 'sql/ha_partition.h'
--- a/sql/ha_partition.h 2011-04-20 17:53:08 +0000
+++ b/sql/ha_partition.h 2011-05-11 14:32:19 +0000
@@ -271,9 +271,9 @@ private:
*/
bool create_handler_file(const char *name);
bool setup_engine_array(MEM_ROOT *mem_root);
- bool read_par_file(const char *name);
+ bool read_par_file(const char *name, uint *name_buffer_length);
bool get_from_handler_file(const char *name, MEM_ROOT *mem_root,
- bool is_clone);
+ bool is_clone, uint *name_buffer_length);
bool new_handlers_from_part_info(MEM_ROOT *mem_root);
bool create_handlers(MEM_ROOT *mem_root);
void clear_handler_file();
@@ -616,6 +616,11 @@ public:
underlying handlers must have the same implementation for it to work.
*/
virtual uint8 table_cache_type();
+ virtual my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data);
virtual ha_rows records();
/*
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2011-05-06 08:27:04 +0000
+++ b/sql/sql_base.cc 2011-05-11 14:32:19 +0000
@@ -511,11 +511,13 @@ TABLE_SHARE *get_table_share(THD *thd, T
table_list->db,
table_list->table_name,
MDL_SHARED));
+ /* And hold LOCK_open which protects the table_share hash */
+ mysql_mutex_assert_owner(&LOCK_open);
/* Read table definition from cache */
if ((share= (TABLE_SHARE*) my_hash_search_using_hash_value(&table_def_cache,
hash_value, (uchar*) key, key_length)))
- goto found;
+ DBUG_RETURN(check_table_share(share, db_flags));
if (!(share= alloc_table_share(table_list, key, key_length)))
{
@@ -552,8 +554,21 @@ TABLE_SHARE *get_table_share(THD *thd, T
DBUG_PRINT("exit", ("share: 0x%lx ref_count: %u",
(ulong) share, share->ref_count));
DBUG_RETURN(share);
+}
+
+
+/**
+ Check an existing table definition and updates the share lists.
-found:
+ @param share TABLE_SHARE to check and use
+ @param db_flags flags used in open_table_def
+
+ @return NULL on error, otherwise TABLE_SHARE
+*/
+
+TABLE_SHARE *check_table_share(TABLE_SHARE *share, uint db_flags)
+{
+ DBUG_ENTER("check_table_share");
/*
We found an existing table definition. Return it if we didn't get
an error when reading the table definition from file.
@@ -597,6 +612,46 @@ found:
/**
+ Get a cached table share
+
+ @param key table cache key (db\0table_name)
+ @param len length of key
+
+ @return NULL if not found, otherwise TABLE_SHARE*
+*/
+TABLE_SHARE *get_cached_table_share(const char *key, uint len)
+{
+#ifndef DBUG_OFF
+ THD *thd= current_thd;
+#endif
+ TABLE_SHARE *share;
+ my_hash_value_type hash_value;
+ DBUG_ENTER("get_cached_table_share");
+
+ /*
+ To be able perform any operation on table we should own
+ some kind of metadata lock on it.
+ TODO: Verify that this is needed when only using the table_share?
+ */
+ DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE,
+ key,
+ key + strlen(key) + 1,
+ MDL_SHARED));
+
+ hash_value= my_calc_hash(&table_def_cache, (uchar*) key, len);
+
+ /* Read table definition from cache */
+ mysql_mutex_lock(&LOCK_open);
+ share= (TABLE_SHARE*) my_hash_search_using_hash_value(&table_def_cache,
+ hash_value, (uchar*) key, len);
+ if (share)
+ share= check_table_share(share, 0);
+ mysql_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(share);
+}
+
+
+/**
Get a table share. If it didn't exist, try creating it from engine
For arguments and return values, see get_table_share()
=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h 2011-03-07 09:08:10 +0000
+++ b/sql/sql_base.h 2011-05-11 14:32:19 +0000
@@ -81,9 +81,11 @@ uint cached_table_definitions(void);
uint create_table_def_key(THD *thd, char *key,
const TABLE_LIST *table_list,
bool tmp_table);
+TABLE_SHARE *check_table_share(TABLE_SHARE *share, uint db_flags);
TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
uint key_length, uint db_flags, int *error,
my_hash_value_type hash_value);
+TABLE_SHARE *get_cached_table_share(const char *key, uint len);
void release_table_share(TABLE_SHARE *share);
TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
=== modified file 'sql/table.h'
--- a/sql/table.h 2011-03-25 09:06:07 +0000
+++ b/sql/table.h 2011-05-11 14:32:19 +0000
@@ -476,6 +476,13 @@ typedef struct st_ha_data_partition
bool auto_inc_initialized;
mysql_mutex_t LOCK_auto_inc; /**< protecting auto_inc val */
ulonglong next_auto_inc_val; /**< first non reserved value */
+ /*
+ All partition names in file-name format with '\0' in between and two
+ '\0' at the end.
+ */
+ const char *partition_names;
+ qc_engine_callback static_qc_callback;
+ uint num_tot_parts;
} HA_DATA_PARTITION;
#endif
No bundle (reason: revision is a merge (you can force generation of a bundle with env var BZR_FORCE_BUNDLE=1)).
| Thread |
|---|
| • bzr commit into mysql-5.5 branch (mattias.jonsson:3501) Bug#11761296 | Mattias Jonsson | 11 May |