MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:March 5 2009 9:59am
Subject:bzr commit into mysql-6.0 branch (davi:2741) Bug#989 WL#4284
View as plain text  
# At a local mysql-6.0 repository of davi

 2741 Davi Arnaut	2009-03-05
      Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
      WL#4284: Transactional DDL locking
      
      Currently the MySQL server does not keep metadata locks on
      schema objects for the duration of a transaction, thus failing
      to guarantee the integrity of the schema objects being used
      during the transaction and to protect then from concurrent
      DDL operations. This also poses a problem for replication as
      a DDL operation might be replicated even thought there are
      active transactions using the object being modified.
      
      The solution is to defer the release of metadata locks until
      a active transaction is either committed or rolled back. This
      prevents other statements from modifying the table for the
      entire duration of the transaction. This provides commitment
      ordering for guaranteeing serializability across multiple
      transactions.
     @ mysql-test/extra/binlog_tests/drop_table.test
        Add test case for Bug#989
     @ mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/include/locktrans.inc
        Add test case for WL#4284
     @ mysql-test/include/mix1.inc
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/include/mix2.inc
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/r/flush_block_commit.result
        Update test case result.
     @ mysql-test/r/flush_block_commit_notembedded.result
        Update test case result.
     @ mysql-test/r/innodb.result
        Update test case result.
     @ mysql-test/r/innodb_mysql.result
        Update test case result.
     @ mysql-test/r/locktrans_innodb.result
        Add test case result for WL#4284
     @ mysql-test/r/locktrans_myisam.result
        Add test case result for WL#4284
     @ mysql-test/r/mix2_myisam.result
        Update test case result.
     @ mysql-test/r/partition_innodb_semi_consistent.result
        Update test case result.
     @ mysql-test/r/read_only_innodb.result
        Update test case result.
     @ mysql-test/suite/binlog/r/binlog_row_drop_tbl.result
        Add test case result for Bug#989
     @ mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
        Update test case result.
     @ mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result
        Add test case result for Bug#989
     @ mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
        Update test case result.
     @ mysql-test/suite/binlog/t/binlog_row_drop_tbl.test
        Add test case result for Bug#989
     @ mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test
        Add test case result for Bug#989
     @ mysql-test/suite/falcon/r/falcon_bugs2.result
        Update test case result.
     @ mysql-test/suite/falcon/t/disabled.def
        Disable tests made meaningless by transactional metadata locking.
     @ mysql-test/suite/falcon/t/falcon_bugs2.test
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/suite/ndb/r/ndb_index_ordered.result
        Update test case result.
     @ mysql-test/suite/ndb/t/disabled.def
        Disable tests made meaningless by transactional metadata locking.
     @ mysql-test/suite/ndb/t/ndb_index_ordered.test
        Comment out test made meaningless by transactional metadata locking.
     @ mysql-test/suite/rpl/r/rpl_locktrans_falcon.result
        Add test case result for WL#4284
     @ mysql-test/suite/rpl/r/rpl_locktrans_innodb.result
        Add test case result for WL#4284
     @ mysql-test/suite/rpl/r/rpl_locktrans_myisam.result
        Add test case result for WL#4284
     @ mysql-test/suite/rpl/t/disabled.def
        Disable tests made meaningless by transactional metadata locking.
     @ mysql-test/suite/sys_vars/t/autocommit_func.test
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/t/flush_block_commit.test
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/t/flush_block_commit_notembedded.test
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/t/innodb.test
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/t/partition_innodb_semi_consistent.test
        Delete from MyISAM table to avoid taking a exclusive lock.
     @ mysql-test/t/read_only_innodb.test
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ mysql-test/t/xa.test
        Fix test case to Reflect the fact that transactions now hold
        metadata locks for the duration of a transaction.
     @ sql/mysql_priv.h
        Introduce prototype for function which releases metadata locks.
     @ sql/rpl_rli.cc
        Remove assert made meaningless, metadata locks are released
        at the end of the transaction.
     @ sql/sql_base.cc
        Defer the release of metadata locks when closing tables
        if not required to.
        
        Issue a deadlock error if the locking protocol requires
        that a transaction re-acquire its locks.
        
        Release metadata locks after taking transactional locks.
     @ sql/sql_parse.cc
        Add function to implicitly end a active transaction and that
        closes tables and releases the metadata locks afterwards.
        
        Force release of metadata locks when flushing with autocommit
        off.
     @ sql/sql_table.cc
        Remove unnecessary calls to close_thread_tables.
     @ sql/transaction.cc
        Release locks once the transaction is committed or rolled
        back. Same for savepoints.

    added:
      mysql-test/extra/binlog_tests/drop_table.test
      mysql-test/suite/binlog/r/binlog_row_drop_tbl.result
      mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result
      mysql-test/suite/binlog/t/binlog_row_drop_tbl.test
      mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test
    modified:
      mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test
      mysql-test/include/locktrans.inc
      mysql-test/include/mix1.inc
      mysql-test/include/mix2.inc
      mysql-test/r/flush_block_commit.result
      mysql-test/r/flush_block_commit_notembedded.result
      mysql-test/r/innodb.result
      mysql-test/r/innodb_mysql.result
      mysql-test/r/locktrans_innodb.result
      mysql-test/r/locktrans_myisam.result
      mysql-test/r/mix2_myisam.result
      mysql-test/r/partition_innodb_semi_consistent.result
      mysql-test/r/read_only_innodb.result
      mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
      mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
      mysql-test/suite/falcon/r/falcon_bugs2.result
      mysql-test/suite/falcon/t/disabled.def
      mysql-test/suite/falcon/t/falcon_bugs2.test
      mysql-test/suite/ndb/r/ndb_index_ordered.result
      mysql-test/suite/ndb/t/disabled.def
      mysql-test/suite/ndb/t/ndb_index_ordered.test
      mysql-test/suite/rpl/r/rpl_locktrans_falcon.result
      mysql-test/suite/rpl/r/rpl_locktrans_innodb.result
      mysql-test/suite/rpl/r/rpl_locktrans_myisam.result
      mysql-test/suite/rpl/t/disabled.def
      mysql-test/suite/sys_vars/t/autocommit_func.test
      mysql-test/t/flush_block_commit.test
      mysql-test/t/flush_block_commit_notembedded.test
      mysql-test/t/innodb.test
      mysql-test/t/partition_innodb_semi_consistent.test
      mysql-test/t/read_only_innodb.test
      mysql-test/t/xa.test
      sql/mysql_priv.h
      sql/rpl_rli.cc
      sql/sql_base.cc
      sql/sql_parse.cc
      sql/sql_table.cc
      sql/transaction.cc
=== added file 'mysql-test/extra/binlog_tests/drop_table.test'
--- a/mysql-test/extra/binlog_tests/drop_table.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/extra/binlog_tests/drop_table.test	2009-03-05 09:59:19 +0000
@@ -0,0 +1,34 @@
+#
+# Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+
+connection con1;
+RESET MASTER;
+CREATE TABLE t1 (a INT);
+SET AUTOCOMMIT=OFF;
+BEGIN;
+INSERT INTO t1 VALUES(1);
+
+connection con2;
+--send DROP TABLE t1;
+
+connection con1;
+COMMIT;
+
+connection con2;
+--reap
+
+connection default;
+
+--disconnect con1
+--disconnect con2
+
+let $VERSION=`select version()`;
+source include/show_binlog_events.inc;

=== modified file 'mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test'
--- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test	2008-07-22 14:16:22 +0000
+++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test	2009-03-05 09:59:19 +0000
@@ -204,6 +204,10 @@ select (@after:=unix_timestamp())*0; # a
 # the bug, the reap would return immediately after the insert into t2.
 select (@after-@before) >= 2;
 
+connection con3;
+commit;
+
+connection con2;
 drop table t1,t2;
 commit;
 

=== modified file 'mysql-test/include/locktrans.inc'
--- a/mysql-test/include/locktrans.inc	2008-05-23 13:54:03 +0000
+++ b/mysql-test/include/locktrans.inc	2009-03-05 09:59:19 +0000
@@ -1050,6 +1050,19 @@ COMMIT;
 DROP TRIGGER t1_ai;
 }
 
+--echo #
+--echo # WL#4284: Transactional DDL locking
+--echo #
+
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+UNLOCK TABLES;
+
 #
 --echo ## Cleanup.
 connection default;

=== modified file 'mysql-test/include/mix1.inc'
--- a/mysql-test/include/mix1.inc	2009-02-02 15:58:48 +0000
+++ b/mysql-test/include/mix1.inc	2009-03-05 09:59:19 +0000
@@ -1331,6 +1331,7 @@ SELECT * FROM t1;
 connection con2;
 --reap
 SELECT * FROM t1;
+COMMIT;
 
 --echo # Switch to connection con1
 connection con1;

=== modified file 'mysql-test/include/mix2.inc'
--- a/mysql-test/include/mix2.inc	2007-06-06 17:57:07 +0000
+++ b/mysql-test/include/mix2.inc	2009-03-05 09:59:19 +0000
@@ -1994,6 +1994,7 @@ commit;
 connection b;
 set autocommit = 0;
 update t1 set b = 5 where a = 2;
+commit;
 connection a;
 delimiter |;
 create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end |
@@ -2056,6 +2057,7 @@ update t2 set b = b + 5 where a = 1;
 update t3 set b = b + 5 where a = 1;
 update t4 set b = b + 5 where a = 1;
 insert into t5(a) values(20);
+commit;
 connection b;
 set autocommit = 0;
 insert into t1(a) values(7);

=== modified file 'mysql-test/r/flush_block_commit.result'
--- a/mysql-test/r/flush_block_commit.result	2006-12-26 16:22:17 +0000
+++ b/mysql-test/r/flush_block_commit.result	2009-03-05 09:59:19 +0000
@@ -2,12 +2,11 @@ drop table if exists t1;
 create table t1 (a int) engine=innodb;
 begin;
 insert into t1 values(1);
-flush tables with read lock;
-select * from t1;
-a
+flush tables with read lock;;
 commit;
 select * from t1;
 a
+1
 unlock tables;
 begin;
 select * from t1 for update;
@@ -19,13 +18,12 @@ flush tables with read lock;
 commit;
 a
 1
+commit;
 unlock tables;
 commit;
 begin;
 insert into t1 values(10);
 flush tables with read lock;
-commit;
-unlock tables;
 flush tables with read lock;
 unlock tables;
 begin;
@@ -36,4 +34,10 @@ a
 show create database test;
 Database	Create Database
 test	CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */
+commit;
+flush tables with read lock;
+begin;
+insert into t1 values (1);;
+unlock tables;
+commit;
 drop table t1;

=== modified file 'mysql-test/r/flush_block_commit_notembedded.result'
--- a/mysql-test/r/flush_block_commit_notembedded.result	2008-02-03 09:00:49 +0000
+++ b/mysql-test/r/flush_block_commit_notembedded.result	2009-03-05 09:59:19 +0000
@@ -1,12 +1,14 @@
 create table t1 (a int) engine=innodb;
 reset master;
 set autocommit=0;
-insert t1 values (1);
+select 1;
+1
+1
 flush tables with read lock;
 show master status;
 File	Position	Binlog_Do_DB	Binlog_Ignore_DB
 master-bin.000001	107		
-commit;
+insert into t1 values (1);
 show master status;
 File	Position	Binlog_Do_DB	Binlog_Ignore_DB
 master-bin.000001	107		

=== modified file 'mysql-test/r/innodb.result'
--- a/mysql-test/r/innodb.result	2009-02-13 16:30:54 +0000
+++ b/mysql-test/r/innodb.result	2009-03-05 09:59:19 +0000
@@ -2819,10 +2819,10 @@ t2	CREATE TABLE `t2` (
 DROP TABLE t2,t1;
 create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
 insert into t1(a) values (1),(2),(3);
+create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end |
 commit;
 set autocommit = 0;
 update t1 set b = 5 where a = 2;
-create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end |
 set autocommit = 0;
 insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100),
 (11),(21),(31),(41),(51),(61),(71),(81),(91),(101),
@@ -2870,6 +2870,7 @@ insert into t2(a) values(8);
 delete from t2 where a = 3;
 update t4 set b = b + 1 where a = 3;
 commit;
+commit;
 drop trigger t1t;
 drop trigger t2t;
 drop trigger t3t;

=== modified file 'mysql-test/r/innodb_mysql.result'
--- a/mysql-test/r/innodb_mysql.result	2009-02-12 18:27:05 +0000
+++ b/mysql-test/r/innodb_mysql.result	2009-03-05 09:59:19 +0000
@@ -1564,6 +1564,7 @@ a	b
 SELECT * FROM t1;
 a	b
 1	init+con1+con2
+COMMIT;
 # Switch to connection con1
 # 3. test for updated key column:
 TRUNCATE t1;

=== modified file 'mysql-test/r/locktrans_innodb.result'
--- a/mysql-test/r/locktrans_innodb.result	2008-12-24 10:48:24 +0000
+++ b/mysql-test/r/locktrans_innodb.result	2009-03-05 09:59:19 +0000
@@ -920,6 +920,17 @@ TRUNCATE t1;
 TRUNCATE t2;
 COMMIT;
 DROP TRIGGER t1_ai;
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+UNLOCK TABLES;
 ## Cleanup.
 SET AUTOCOMMIT= 1;
 UNLOCK TABLES;

=== modified file 'mysql-test/r/locktrans_myisam.result'
--- a/mysql-test/r/locktrans_myisam.result	2008-12-24 10:48:24 +0000
+++ b/mysql-test/r/locktrans_myisam.result	2009-03-05 09:59:19 +0000
@@ -392,6 +392,19 @@ ERROR 0A000: LOCK is not allowed in stor
 CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW
 LOCK TABLE t2 IN EXCLUSIVE MODE;
 ERROR 0A000: LOCK is not allowed in stored procedures
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+UNLOCK TABLES;
 ## Cleanup.
 SET AUTOCOMMIT= 1;
 UNLOCK TABLES;

=== modified file 'mysql-test/r/mix2_myisam.result'
--- a/mysql-test/r/mix2_myisam.result	2008-10-20 09:16:47 +0000
+++ b/mysql-test/r/mix2_myisam.result	2009-03-05 09:59:19 +0000
@@ -2063,6 +2063,7 @@ insert into t1(a) values (1),(2),(3);
 commit;
 set autocommit = 0;
 update t1 set b = 5 where a = 2;
+commit;
 create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end |
 set autocommit = 0;
 insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100),
@@ -2105,6 +2106,7 @@ update t2 set b = b + 5 where a = 1;
 update t3 set b = b + 5 where a = 1;
 update t4 set b = b + 5 where a = 1;
 insert into t5(a) values(20);
+commit;
 set autocommit = 0;
 insert into t1(a) values(7);
 insert into t2(a) values(8);

=== modified file 'mysql-test/r/partition_innodb_semi_consistent.result'
--- a/mysql-test/r/partition_innodb_semi_consistent.result	2009-01-13 22:12:16 +0000
+++ b/mysql-test/r/partition_innodb_semi_consistent.result	2009-03-05 09:59:19 +0000
@@ -102,7 +102,7 @@ a	b
 # Switch to connection con1
 # 3. test for updated key column:
 TRUNCATE t1;
-TRUNCATE t2;
+DELETE FROM t2;
 INSERT INTO t1 VALUES (1,'init');
 BEGIN;
 UPDATE t1 SET a = 2, b = CONCAT(b, '+con1') WHERE a = 1;

=== modified file 'mysql-test/r/read_only_innodb.result'
--- a/mysql-test/r/read_only_innodb.result	2008-04-08 05:20:58 +0000
+++ b/mysql-test/r/read_only_innodb.result	2009-03-05 09:59:19 +0000
@@ -7,12 +7,10 @@ insert into table_11733 values(11733);
 set global read_only=1;
 select @@global.read_only;
 @@global.read_only
-1
+0
 select * from table_11733 ;
-a
-11733
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
 COMMIT;
-ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
 set global read_only=0;
 drop table table_11733 ;
 drop user test@localhost;

=== added file 'mysql-test/suite/binlog/r/binlog_row_drop_tbl.result'
--- a/mysql-test/suite/binlog/r/binlog_row_drop_tbl.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_drop_tbl.result	2009-03-05 09:59:19 +0000
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS t1;
+RESET MASTER;
+CREATE TABLE t1 (a INT);
+SET AUTOCOMMIT=OFF;
+BEGIN;
+INSERT INTO t1 VALUES(1);
+DROP TABLE t1;;
+COMMIT;
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t1 (a INT)
+master-bin.000001	#	Query	#	#	use `test`; BEGIN
+master-bin.000001	#	Table_map	#	#	table_id: # (test.t1)
+master-bin.000001	#	Write_rows	#	#	table_id: # flags: STMT_END_F
+master-bin.000001	#	Query	#	#	use `test`; COMMIT
+master-bin.000001	#	Query	#	#	use `test`; DROP TABLE t1

=== modified file 'mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result'
--- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result	2009-02-10 14:46:07 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result	2009-03-05 09:59:19 +0000
@@ -232,6 +232,7 @@ select (@after:=unix_timestamp())*0;
 select (@after-@before) >= 2;
 (@after-@before) >= 2
 1
+commit;
 drop table t1,t2;
 commit;
 begin;

=== added file 'mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result'
--- a/mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result	2009-03-05 09:59:19 +0000
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS t1;
+RESET MASTER;
+CREATE TABLE t1 (a INT);
+SET AUTOCOMMIT=OFF;
+BEGIN;
+INSERT INTO t1 VALUES(1);
+DROP TABLE t1;;
+COMMIT;
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	use `test`; CREATE TABLE t1 (a INT)
+master-bin.000001	#	Query	#	#	use `test`; INSERT INTO t1 VALUES(1)
+master-bin.000001	#	Query	#	#	use `test`; DROP TABLE t1

=== modified file 'mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result'
--- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result	2009-02-10 14:46:07 +0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result	2009-03-05 09:59:19 +0000
@@ -207,6 +207,7 @@ select (@after:=unix_timestamp())*0;
 select (@after-@before) >= 2;
 (@after-@before) >= 2
 1
+commit;
 drop table t1,t2;
 commit;
 begin;

=== added file 'mysql-test/suite/binlog/t/binlog_row_drop_tbl.test'
--- a/mysql-test/suite/binlog/t/binlog_row_drop_tbl.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_row_drop_tbl.test	2009-03-05 09:59:19 +0000
@@ -0,0 +1,5 @@
+# This is a wrapper for drop_table.test so that the same test case can be used
+# For both statement and row based bin logs
+
+-- source include/have_binlog_format_row.inc
+-- source extra/binlog_tests/drop_table.test

=== added file 'mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test'
--- a/mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test	2009-03-05 09:59:19 +0000
@@ -0,0 +1,5 @@
+# This is a wrapper for drop_table.test so that the same test case can be used
+# For both statement and row based bin logs
+
+-- source include/have_binlog_format_mixed_or_statement.inc
+-- source extra/binlog_tests/drop_table.test

=== modified file 'mysql-test/suite/falcon/r/falcon_bugs2.result'
--- a/mysql-test/suite/falcon/r/falcon_bugs2.result	2007-09-20 15:44:25 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bugs2.result	2009-03-05 09:59:19 +0000
@@ -290,6 +290,7 @@ SET autocommit=0;
 SELECT * FROM t1;
 a
 DROP TABLE t1;
+COMMIT;
 ***************** falcon_bugs2_022 *****************
 SET autocommit=0;
 SET tx_isolation="READ-COMMITTED";
@@ -306,6 +307,8 @@ a
 SELECT * FROM t1;
 a
 1
+COMMIT;
+COMMIT;
 DROP TABLE t1;
 ***************** falcon_bugs2_023 *****************
 CREATE TABLE t1 (a int);

=== modified file 'mysql-test/suite/falcon/t/disabled.def'
--- a/mysql-test/suite/falcon/t/disabled.def	2009-02-25 13:15:43 +0000
+++ b/mysql-test/suite/falcon/t/disabled.def	2009-03-05 09:59:19 +0000
@@ -11,3 +11,5 @@
 ##############################################################################
 
 falcon_unicode-big    : Bug#43182 2009-02-25 hakank Disabled until licensing details of UnicodeData.txt are cleared
+falcon_bug_22972      : WL#4284: Test case is obsolete, should be reworked or removed.
+falcon_bug_24024      : WL#4284: Test case is obsolete, should be reworked or removed.

=== modified file 'mysql-test/suite/falcon/t/falcon_bugs2.test'
--- a/mysql-test/suite/falcon/t/falcon_bugs2.test	2009-01-07 10:41:07 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bugs2.test	2009-03-05 09:59:19 +0000
@@ -512,7 +512,11 @@ SELECT * FROM t1;
 
 # Final cleanup
 connection default;
-DROP TABLE t1;
+send DROP TABLE t1;
+connection con1;
+COMMIT;
+connection default;
+--reap
 --disconnect con1
 
 #
@@ -539,6 +543,10 @@ SELECT * FROM t1;
 
 connection con1;
 SELECT * FROM t1;
+COMMIT;
+
+connection default;
+COMMIT;
 
 # Final cleanup
 DROP TABLE t1;

=== modified file 'mysql-test/suite/ndb/r/ndb_index_ordered.result'
--- a/mysql-test/suite/ndb/r/ndb_index_ordered.result	2007-06-27 12:28:02 +0000
+++ b/mysql-test/suite/ndb/r/ndb_index_ordered.result	2009-03-05 09:59:19 +0000
@@ -637,21 +637,6 @@ select count(*)- 4 from t1 use index (v)
 count(*)- 4
 0
 drop table t1;
-create table t1(a int primary key, b int not null, index(b));
-insert into t1 values (1,1), (2,2);
-set autocommit=0;
-begin;
-select count(*) from t1;
-count(*)
-2
-ALTER TABLE t1 ADD COLUMN c int;
-select a from t1 where b = 2;
-a
-2
-show tables;
-Tables_in_test
-t1
-drop table t1;
 create table t1 (a int, c varchar(10),
 primary key using hash (a), index(c)) engine=ndb;
 insert into t1 (a, c) values (1,'aaa'),(3,'bbb');

=== modified file 'mysql-test/suite/ndb/t/disabled.def'
--- a/mysql-test/suite/ndb/t/disabled.def	2009-02-13 16:18:07 +0000
+++ b/mysql-test/suite/ndb/t/disabled.def	2009-03-05 09:59:19 +0000
@@ -14,3 +14,5 @@ ndb_partition_error2	  : Bug#40989 msven
 # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open
 #ndb_binlog_ddl_multi     : BUG#18976 2006-04-10 kent    CRBR: multiple binlog, second binlog may miss schema log events
 ndb_cache_trans           : Bug#42565 ndb_cache_trans failure since SERVER_STATUS_IN_TRANS added to hash key
+ndb_alter_table_online    : WL#4284 Test case needs to be reworked
+ndb_alter_table3          : WL#4284 Test case needs to be reworked

=== modified file 'mysql-test/suite/ndb/t/ndb_index_ordered.test'
--- a/mysql-test/suite/ndb/t/ndb_index_ordered.test	2007-07-04 20:38:53 +0000
+++ b/mysql-test/suite/ndb/t/ndb_index_ordered.test	2009-03-05 09:59:19 +0000
@@ -333,21 +333,22 @@ select count(*)- 4 from t1 use index (v)
 
 drop table t1;
 
+# Disabled due to WL#4284
 # bug#7798
-create table t1(a int primary key, b int not null, index(b));
-insert into t1 values (1,1), (2,2);
-connect (con1,localhost,root,,test);
-connect (con2,localhost,root,,test);
-connection con1;
-set autocommit=0;
-begin;
-select count(*) from t1;
-connection con2;
-ALTER TABLE t1 ADD COLUMN c int;
-connection con1;
-select a from t1 where b = 2;
-show tables;
-drop table t1;
+# create table t1(a int primary key, b int not null, c int, index(b));
+# insert into t1 values (1,1,1), (2,2,2);
+# connect (con1,localhost,root,,test);
+# connect (con2,localhost,root,,test);
+# connection con1;
+# set autocommit=0;
+# begin;
+# select count(*) from t1;
+# connection con2;
+# ALTER TABLE t1 ADD COLUMN c int
+# connection con1;
+# select a from t1 where b = 2;
+# show tables;
+# drop table t1;
 
 # mysqld 5.0.13 crash, no bug#
 create table t1 (a int, c varchar(10),

=== modified file 'mysql-test/suite/rpl/r/rpl_locktrans_falcon.result'
--- a/mysql-test/suite/rpl/r/rpl_locktrans_falcon.result	2008-12-15 12:41:31 +0000
+++ b/mysql-test/suite/rpl/r/rpl_locktrans_falcon.result	2009-03-05 09:59:19 +0000
@@ -394,6 +394,17 @@ ERROR 0A000: LOCK is not allowed in stor
 CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW
 LOCK TABLE t2 IN EXCLUSIVE MODE;
 ERROR 0A000: LOCK is not allowed in stored procedures
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+UNLOCK TABLES;
 ## Cleanup.
 SET AUTOCOMMIT= 1;
 UNLOCK TABLES;

=== modified file 'mysql-test/suite/rpl/r/rpl_locktrans_innodb.result'
--- a/mysql-test/suite/rpl/r/rpl_locktrans_innodb.result	2009-01-26 16:03:39 +0000
+++ b/mysql-test/suite/rpl/r/rpl_locktrans_innodb.result	2009-03-05 09:59:19 +0000
@@ -926,6 +926,17 @@ TRUNCATE t1;
 TRUNCATE t2;
 COMMIT;
 DROP TRIGGER t1_ai;
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+UNLOCK TABLES;
 ## Cleanup.
 SET AUTOCOMMIT= 1;
 UNLOCK TABLES;

=== modified file 'mysql-test/suite/rpl/r/rpl_locktrans_myisam.result'
--- a/mysql-test/suite/rpl/r/rpl_locktrans_myisam.result	2008-12-24 10:48:24 +0000
+++ b/mysql-test/suite/rpl/r/rpl_locktrans_myisam.result	2009-03-05 09:59:19 +0000
@@ -439,6 +439,19 @@ ERROR 0A000: LOCK is not allowed in stor
 CREATE TRIGGER t1_ai AFTER INSERT ON t1 FOR EACH ROW
 LOCK TABLE t2 IN EXCLUSIVE MODE;
 ERROR 0A000: LOCK is not allowed in stored procedures
+#
+# WL#4284: Transactional DDL locking
+#
+SET AUTOCOMMIT= 0;
+LOCK TABLES t1 WRITE, t2 WRITE;
+SAVEPOINT sp1;
+INSERT INTO t1 VALUES (1);
+SAVEPOINT sp2;
+INSERT INTO t2 VALUES (2);
+ROLLBACK TO SAVEPOINT sp1;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+UNLOCK TABLES;
 ## Cleanup.
 SET AUTOCOMMIT= 1;
 UNLOCK TABLES;

=== modified file 'mysql-test/suite/rpl/t/disabled.def'
--- a/mysql-test/suite/rpl/t/disabled.def	2009-02-14 11:23:14 +0000
+++ b/mysql-test/suite/rpl/t/disabled.def	2009-03-05 09:59:19 +0000
@@ -17,3 +17,5 @@ rpl_binlog_corruption      : BUG#41793 2
 rpl_extraCol_falcon        : Bug#40930 2008-11-21 johnemb rpl.rpl_extraCol_falcon fails doing STOP SLAVE (on Windows PB2)
 rpl_cross_version	   : Bug#42311 2009-01-23 aelkin
 rpl_log_pos                : Bug#42858 2009-02-14 alik rpl.rpl_log_pos fails, thus was disabled
+rpl_failed_optimize        : WL#4284: Test case is obsolete, should be reworked or removed.
+

=== modified file 'mysql-test/suite/sys_vars/t/autocommit_func.test'
--- a/mysql-test/suite/sys_vars/t/autocommit_func.test	2008-12-19 15:12:15 +0000
+++ b/mysql-test/suite/sys_vars/t/autocommit_func.test	2009-03-05 09:59:19 +0000
@@ -153,6 +153,10 @@ SELECT * from t1;
 CONNECTION test_con2;
 SELECT * from t1;
 
+--echo ## Commit changes
+CONNECTION test_con1;
+COMMIT;
+
 --echo ## Dropping table t1 ##
 DROP table t1;
 

=== modified file 'mysql-test/t/flush_block_commit.test'
--- a/mysql-test/t/flush_block_commit.test	2006-12-26 16:22:17 +0000
+++ b/mysql-test/t/flush_block_commit.test	2009-03-05 09:59:19 +0000
@@ -21,16 +21,13 @@ create table t1 (a int) engine=innodb;
 begin;
 insert into t1 values(1);
 connection con2;
-flush tables with read lock;
-select * from t1;
+--send flush tables with read lock;
 connection con1;
-send commit; # blocked by con2
-sleep 1;
+commit;
 connection con2;
-select * from t1; # verify con1 was blocked and data did not move
+--reap
+select * from t1;
 unlock tables;
-connection con1;
-reap;
 
 # No deadlock ?
 
@@ -47,6 +44,7 @@ connection con1;
 commit; # should not be blocked by con3
 connection con2;
 reap;
+commit;
 connection con3;
 reap;
 unlock tables;
@@ -60,8 +58,6 @@ connection con1;
 begin;
 insert into t1 values(10);
 flush tables with read lock;
-commit;
-unlock tables;
 connection con2;
 flush tables with read lock; # bug caused hang here
 unlock tables;
@@ -71,6 +67,24 @@ unlock tables;
 begin;
 select * from t1;
 show create database test;
+commit;
+
+# GLR blocks new transactions
+connection con1;
+flush tables with read lock;
+connection con2;
+begin;
+--send insert into t1 values (1);
+connection con1;
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = "Waiting for release of readlock" and
+        info = "insert into t1 values (1)";
+--source include/wait_condition.inc
+unlock tables;
+connection con2;
+--reap
+commit;
 
 drop table t1;
 

=== modified file 'mysql-test/t/flush_block_commit_notembedded.test'
--- a/mysql-test/t/flush_block_commit_notembedded.test	2007-06-15 16:56:11 +0000
+++ b/mysql-test/t/flush_block_commit_notembedded.test	2009-03-05 09:59:19 +0000
@@ -17,12 +17,12 @@ connection con1;
 create table t1 (a int) engine=innodb;
 reset master;
 set autocommit=0;
-insert t1 values (1);
+select 1;
 connection con2;
 flush tables with read lock;
 show master status;
 connection con1;
-send commit;
+send insert into t1 values (1);
 connection con2;
 sleep 1;
 show master status;

=== modified file 'mysql-test/t/innodb.test'
--- a/mysql-test/t/innodb.test	2009-01-26 16:32:29 +0000
+++ b/mysql-test/t/innodb.test	2009-03-05 09:59:19 +0000
@@ -1797,16 +1797,15 @@ connect (b,localhost,root,,);
 connection a;
 create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb;
 insert into t1(a) values (1),(2),(3);
+delimiter |;
+create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end |
+delimiter ;|
 commit;
 connection b;
 set autocommit = 0;
 update t1 set b = 5 where a = 2;
 connection a;
-delimiter |;
-create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end |
-delimiter ;|
 set autocommit = 0;
-connection a;
 insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100),
 (11),(21),(31),(41),(51),(61),(71),(81),(91),(101),
 (12),(22),(32),(42),(52),(62),(72),(82),(92),(102),
@@ -1870,6 +1869,9 @@ insert into t2(a) values(8);
 delete from t2 where a = 3;
 update t4 set b = b + 1 where a = 3;
 commit;
+connection a;
+commit;
+connection b;
 drop trigger t1t;
 drop trigger t2t;
 drop trigger t3t;

=== modified file 'mysql-test/t/partition_innodb_semi_consistent.test'
--- a/mysql-test/t/partition_innodb_semi_consistent.test	2009-01-13 22:12:16 +0000
+++ b/mysql-test/t/partition_innodb_semi_consistent.test	2009-03-05 09:59:19 +0000
@@ -157,7 +157,7 @@ connection con1;
 --echo # 3. test for updated key column:
 
 TRUNCATE t1;
-TRUNCATE t2;
+DELETE FROM t2;
 
 INSERT INTO t1 VALUES (1,'init');
 

=== modified file 'mysql-test/t/read_only_innodb.test'
--- a/mysql-test/t/read_only_innodb.test	2008-04-08 05:20:58 +0000
+++ b/mysql-test/t/read_only_innodb.test	2009-03-05 09:59:19 +0000
@@ -28,15 +28,16 @@ BEGIN;
 insert into table_11733 values(11733);
 
 connection default;
-set global read_only=1;
+send set global read_only=1;
 
 connection con1;
 select @@global.read_only;
+-- error ER_LOCK_DEADLOCK
 select * from table_11733 ;
--- error ER_OPTION_PREVENTS_STATEMENT
 COMMIT;
 
 connection default;
+reap;
 set global read_only=0;
 drop table table_11733 ;
 drop user test@localhost;

=== modified file 'mysql-test/t/xa.test'
--- a/mysql-test/t/xa.test	2008-10-23 20:56:03 +0000
+++ b/mysql-test/t/xa.test	2009-03-05 09:59:19 +0000
@@ -72,9 +72,10 @@ xa rollback 'testa','testb';
 xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
 
 select * from t1;
-drop table t1;
 
 disconnect con1;
+connection default;
+drop table t1;
 
 #
 # Bug#28323: Server crashed in xid cache operations

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-02-23 14:53:18 +0000
+++ b/sql/mysql_priv.h	2009-03-05 09:59:19 +0000
@@ -792,7 +792,8 @@ extern my_decimal decimal_zero;
 void free_items(Item *item);
 void cleanup_items(Item *item);
 class THD;
-void close_thread_tables(THD *thd, bool skip_mdl= 0);
+void close_thread_tables(THD *thd, bool is_back_off= 0);
+void release_metadata_locks(THD *thd);
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);

=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc	2009-03-04 13:31:31 +0000
+++ b/sql/rpl_rli.cc	2009-03-05 09:59:19 +0000
@@ -1182,13 +1182,6 @@ void Relay_log_info::cleanup_context(THD
 
 void Relay_log_info::clear_tables_to_lock()
 {
-  /*
-    Deallocating elements of table list below will also free memory where
-    meta-data locks are stored. So we want to be sure that we don't have
-    any references to this memory left.
-  */
-  DBUG_ASSERT(!current_thd->mdl_context.has_locks());
-
   while (tables_to_lock)
   {
     uchar* to_free= reinterpret_cast<uchar*>(tables_to_lock);
@@ -1207,12 +1200,6 @@ void Relay_log_info::clear_tables_to_loc
 
 void Relay_log_info::slave_close_thread_tables(THD *thd)
 {
-  /*
-    Since we use same memory chunks for allocation of metadata lock
-    objects for tables as we use for allocating corresponding elements
-    of 'tables_to_lock' list, we have to release metadata locks by
-    closing tables before calling clear_tables_to_lock().
-  */
   close_thread_tables(thd);
   clear_tables_to_lock();
 }

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2009-03-04 13:33:47 +0000
+++ b/sql/sql_base.cc	2009-03-05 09:59:19 +0000
@@ -1475,11 +1475,43 @@ void close_thread_tables(THD *thd,
   if (thd->open_tables)
     close_open_tables(thd);
 
-  thd->mdl_context.release_all_locks();
   if (!is_back_off)
   {
     thd->mdl_context.remove_all_requests();
   }
+
+  /*
+    Defer the release of metadata locks until the current transaction
+    is either committed or rolled back. This prevents other statements
+    from modifying the table for the entire duration of this transaction.
+    This provides commitment ordering for guaranteeing serializability
+    across multiple transactions.
+  */
+  if (!thd->in_multi_stmt_transaction() ||
+      (thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
+    thd->mdl_context.release_all_locks();
+
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Release metadata locks that were acquired during the current transaction.
+
+  @param thd  Current thread
+*/
+
+void release_metadata_locks(THD *thd)
+{
+  DBUG_ENTER("release_metadata_locks");
+
+  if (thd->locked_tables_mode)
+    DBUG_VOID_RETURN;
+
+  DBUG_ASSERT(thd->open_tables == NULL);
+
+  thd->mdl_context.release_all_locks();
+
   DBUG_VOID_RETURN;
 }
 
@@ -3618,6 +3650,7 @@ int open_tables(THD *thd, TABLE_LIST **s
   /* Also used for indicating that prelocking is need */
   TABLE_LIST **query_tables_last_own;
   bool safe_to_ignore_table;
+  bool has_locks= thd->mdl_context.has_locks();
   DBUG_ENTER("open_tables");
 
   /*
@@ -3759,6 +3792,18 @@ int open_tables(THD *thd, TABLE_LIST **s
       if (action)
       {
         /*
+          We have met a exclusive metadata lock or a old version of table and
+          we are inside a transaction that already hold locks. We can't follow
+          the locking protocol in this scenario as it might lead to deadlocks.
+        */
+        if (thd->in_multi_stmt_transaction() && has_locks)
+        {
+          my_error(ER_LOCK_DEADLOCK, MYF(0));
+          result= -1;
+          goto err;
+        }
+
+        /*
           We have met exclusive metadata lock or old version of table. Now we
           have to close all tables which are not up to date/release metadata
           locks. We also have to throw away set of prelocked tables (and thus
@@ -4625,6 +4670,7 @@ void close_tables_for_reopen(THD *thd, T
   for (TABLE_LIST *tmp= *tables; tmp; tmp= tmp->next_global)
     tmp->table= 0;
   close_thread_tables(thd, is_back_off);
+  release_metadata_locks(thd);
 }
 
 

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2009-03-04 13:33:47 +0000
+++ b/sql/sql_parse.cc	2009-03-05 09:59:19 +0000
@@ -127,6 +127,27 @@ static bool some_non_temp_table_to_be_up
 
 
 /*
+  Implicitly end (commit) a active transaction.
+
+  @note Close tables and releases metadata locks.
+
+  @param thd    Thread handle.
+*/
+
+static bool end_active_trans(THD *thd)
+{
+  bool res;
+  DBUG_ENTER("opt_implicit_commit");
+  if (!(res= trans_commit_implicit(thd)))
+  {
+    close_thread_tables(thd);
+    release_metadata_locks(thd);
+  }
+  DBUG_RETURN(res);
+}
+
+
+/*
   Implicitly commit a active transaction if statement requires so.
 
   @param thd    Thread handle.
@@ -163,7 +184,7 @@ static bool opt_implicit_commit(THD *thd
     /* Commit or rollback the statement transaction. */
     thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
     /* Commit the normal transaction if one is active. */
-    res= trans_commit_implicit(thd);
+    res= end_active_trans(thd);
   }
 
   DBUG_RETURN(res);
@@ -1223,14 +1244,14 @@ bool dispatch_command(enum enum_server_c
     bool not_used;
     status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
     ulong options= (ulong) (uchar) packet[0];
-    if (trans_commit_implicit(thd))
+    if (end_active_trans(thd))
       break;
     if (check_global_access(thd,RELOAD_ACL))
       break;
     general_log_print(thd, command, NullS);
     if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
       break;
-    if (trans_commit_implicit(thd))
+    if (end_active_trans(thd))
       break;
     my_ok(thd);
     break;
@@ -3459,7 +3480,7 @@ ddl_blocker_err:
     thd->locked_tables_list.unlock_locked_tables(thd);
     if (thd->options & OPTION_TABLE_LOCK)
     {
-      trans_commit_implicit(thd);
+      end_active_trans(thd);
       thd->options&= ~(OPTION_TABLE_LOCK);
     }
     if (thd->global_read_lock)
@@ -3513,7 +3534,7 @@ ddl_blocker_err:
       goto error;
     thd->locked_tables_list.unlock_locked_tables(thd);
     /* we must end the trasaction first, regardless of anything */
-    if (trans_commit_implicit(thd))
+    if (end_active_trans(thd))
       goto error;
 
     alloc_mdl_requests(all_tables, thd->locked_tables_list.locked_tables_root());
@@ -3537,7 +3558,7 @@ ddl_blocker_err:
         that it can't lock a table in its list
       */
       trans_rollback_stmt(thd);
-      trans_commit_implicit(thd);
+      end_active_trans(thd);
       thd->options&= ~(OPTION_TABLE_LOCK);
     }
     else
@@ -4411,7 +4432,7 @@ create_sp_error:
                                  lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
           goto error;
 
-        if (trans_commit_implicit(thd))
+        if (end_active_trans(thd))
           goto error;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 	if (sp_automatic_privileges && !opt_noacl &&
@@ -6680,6 +6701,12 @@ bool reload_acl_and_cache(THD *thd, ulon
     query_cache.flush();			// RESET QUERY CACHE
   }
 #endif /*HAVE_QUERY_CACHE*/
+
+  /*
+    Release any metadata locks acquired during the above reloads.
+  */
+  release_metadata_locks(thd);
+
   /*
     Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
     (see sql_yacc.yy)

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2009-03-04 13:33:47 +0000
+++ b/sql/sql_table.cc	2009-03-05 09:59:19 +0000
@@ -4327,7 +4327,6 @@ static bool mysql_admin_table(THD* thd, 
       case  1:           // error, message written to net
         trans_rollback_stmt(thd);
         trans_rollback(thd);
-        close_thread_tables(thd);
         DBUG_PRINT("admin", ("simple error, admin next table"));
         continue;
       case -1:           // error, message could be written to net
@@ -4392,7 +4391,6 @@ static bool mysql_admin_table(THD* thd, 
       protocol->store(buff, length, system_charset_info);
       trans_commit_stmt(thd);
       trans_commit(thd);
-      close_thread_tables(thd);
       lex->reset_query_tables_list(FALSE);
       table->table=0;				// For query cache
       if (protocol->write())
@@ -4442,7 +4440,7 @@ static bool mysql_admin_table(THD* thd, 
       {
         DBUG_PRINT("admin", ("recreating table"));
         trans_rollback_stmt(thd);
-        close_thread_tables(thd);
+        trans_rollback(thd);
         tmp_disable_binlog(thd); // binlogging is done by caller if wanted
         result_code= mysql_recreate_table(thd, table);
         reenable_binlog(thd);
@@ -4556,13 +4554,13 @@ send_result_message:
         We have to end the row, so analyze could return more rows.
       */
       trans_commit_stmt(thd);
+      trans_commit(thd);
       protocol->store(STRING_WITH_LEN("note"), system_charset_info);
       protocol->store(STRING_WITH_LEN(
           "Table does not support optimize, doing recreate + analyze instead"),
                       system_charset_info);
       if (protocol->write())
         goto err;
-      close_thread_tables(thd);
       DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze..."));
       TABLE_LIST *save_next_local= table->next_local,
                  *save_next_global= table->next_global;
@@ -4579,7 +4577,7 @@ send_result_message:
       if (thd->stmt_da->is_ok())
         thd->stmt_da->reset_diagnostics_area();
       trans_commit_stmt(thd);
-      close_thread_tables(thd);
+      trans_commit(thd);
       if (!result_code) // recreation went ok
       {
         if ((table->table= open_ltable(thd, table, lock_type, 0)) &&
@@ -4687,7 +4685,6 @@ send_result_message:
 err:
   trans_rollback_stmt(thd);
   trans_rollback(thd);
-  close_thread_tables(thd);			// Shouldn't be needed
   if (table)
     table->table=0;
   DBUG_RETURN(TRUE);

=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc	2009-01-26 17:19:14 +0000
+++ b/sql/transaction.cc	2009-03-05 09:59:19 +0000
@@ -101,6 +101,8 @@ bool trans_begin(THD *thd, uint flags)
   if (trans_commit_implicit(thd))
     DBUG_RETURN(TRUE);
 
+  release_metadata_locks(thd);
+
   thd->options|= OPTION_BEGIN;
   thd->server_status|= SERVER_STATUS_IN_TRANS;
 
@@ -112,6 +114,36 @@ bool trans_begin(THD *thd, uint flags)
 
 
 /**
+  Close tables and releases metadata locks that were implicitly or
+  explicitly acquired during the current transaction.
+
+  @param thd     Current thread
+*/
+
+static void trans_release_locks(THD *thd)
+{
+  DBUG_ENTER("trans_release_locks");
+
+  /*
+    Relies on close_thread_tables to close tables and to release the locks.
+  */
+  close_thread_tables(thd);
+
+  /*
+    close_thread_tables might have not released the locks if this
+    is a multi-statement transaction due to autocommit being off.
+    In this case, release any locks if not under locked tables mode
+    as the transaction is probably being implicitly committed or
+    rolled back.
+  */
+  if (!thd->locked_tables_mode)
+    thd->mdl_context.release_all_locks();
+
+  DBUG_VOID_RETURN;
+}
+
+
+/**
   Commit the current transaction, making its changes permanent.
 
   @param thd     Current thread
@@ -141,6 +173,7 @@ bool trans_commit(THD *thd)
   thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
   thd->transaction.all.modified_non_trans_table= FALSE;
   thd->lex->start_transaction_opt= 0;
+  trans_release_locks(thd);
 
   DBUG_RETURN(test(res));
 }
@@ -207,6 +240,7 @@ bool trans_rollback(THD *thd)
   thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
   thd->transaction.all.modified_non_trans_table= FALSE;
   thd->lex->start_transaction_opt= 0;
+  trans_release_locks(thd);
 
   DBUG_RETURN(test(res));
 }
@@ -336,6 +370,13 @@ bool trans_savepoint(THD *thd, LEX_STRIN
   newsv->prev= thd->transaction.savepoints;
   thd->transaction.savepoints= newsv;
 
+  /*
+    Remember the last acquired lock before the savepoint was set.
+    This is used as a marker to only release locks acquired after
+    the setting of this savepoint.
+  */
+  newsv->mdl_savepoint = thd->mdl_context.mdl_savepoint();
+
   DBUG_RETURN(FALSE);
 }
 
@@ -380,6 +421,10 @@ bool trans_rollback_to_savepoint(THD *th
 
   thd->transaction.savepoints= sv;
 
+  /* Release metadata locks that were acquired during this savepoint unit. */
+  if (!res && !thd->locked_tables_mode)
+    thd->mdl_context.rollback_to_savepoint(sv->mdl_savepoint);
+
   DBUG_RETURN(test(res));
 }
 
@@ -592,6 +637,7 @@ bool trans_xa_commit(THD *thd)
   thd->server_status&= ~SERVER_STATUS_IN_TRANS;
   xid_cache_delete(&thd->transaction.xid_state);
   thd->transaction.xid_state.xa_state= XA_NOTR;
+  trans_release_locks(thd);
 
   DBUG_RETURN(res);
 }
@@ -640,6 +686,7 @@ bool trans_xa_rollback(THD *thd)
   thd->server_status&= ~SERVER_STATUS_IN_TRANS;
   xid_cache_delete(&thd->transaction.xid_state);
   thd->transaction.xid_state.xa_state= XA_NOTR;
+  trans_release_locks(thd);
 
   DBUG_RETURN(res);
 }


Attachment: [text/bzr-bundle] bzr/davi.arnaut@sun.com-20090305095919-2335lgewdok60p9c.bundle
Thread
bzr commit into mysql-6.0 branch (davi:2741) Bug#989 WL#4284Davi Arnaut5 Mar