List:Commits« Previous MessageNext Message »
From:Mattias Jonsson Date:May 11 2011 2:33pm
Subject:bzr commit into mysql-5.5 branch (mattias.jonsson:3501) Bug#11761296
View as plain text  
#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#11761296Mattias Jonsson11 May