MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:December 4 2009 11:02pm
Subject:bzr commit into mysql-5.6-next-mr branch (kostja:2995) Bug#989 WL#4284
View as plain text  
#At file:///opt/local/work/next-4284/ based on revid:kostja@stripped

 2995 Konstantin Osipov	2009-12-05
      Backport of revno ## 2617.31.1, 2617.31.3, 2617.31.4, 2617.31.5,
      2617.31.12, 2617.31.15, 2617.31.15, 2617.31.16, 2617.43.1
      - initial changeset that introduced the fix for 
      Bug#989 and follow up fixes for all test suite failures
      introduced in the initial changeset. 
      ------------------------------------------------------------
      revno: 2617.31.1
      committer: Davi Arnaut <Davi.Arnaut@stripped>
      branch nick: 4284-6.0
      timestamp: Fri 2009-03-06 19:17:00 -0300
      message:
      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.
      
      - Incompatible change:
      
      If MySQL's metadata locking system encounters a lock conflict,
      the usual schema is to use the try and back-off technique to
      avoid deadlocks -- this schema consists in releasing all locks
      and trying to acquire them all in one go.
      
      But in a transactional context this algorithm can't be utilized
      as its not possible to release locks acquired during the course
      of the transaction without breaking the transaction commitments.
      To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be
      returned if a lock conflict is encountered during a transaction.
      
      Let's consider an example:
      
      A transaction has two statements that modify table t1, then table
      t2, and then commits. The first statement of the transaction will
      acquire a shared metadata lock on table t1, and it will be kept
      utill COMMIT to ensure serializability.
      
      At the moment when the second statement attempts to acquire a
      shared metadata lock on t2, a concurrent ALTER or DROP statement
      might have locked t2 exclusively. The prescription of the current
      locking protocol is that the acquirer of the shared lock backs off
      -- gives up all his current locks and retries. This implies that
      the entire multi-statement transaction has to be rolled back.
      
      - Incompatible change:
      
      FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ
      LOCK won't cause locked tables to be implicitly unlocked anymore.
     @ 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/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 (WL#4284).
     @ mysql-test/r/flush_block_commit_notembedded.result
        Update test case result (WL#4284).
     @ mysql-test/r/innodb.result
        Update test case result (WL#4284).
     @ mysql-test/r/innodb_mysql.result
        Update test case result (WL#4284).
     @ mysql-test/r/lock.result
        Add test case result for an effect of WL#4284/Bug#989
        (all locks should be released when a connection terminates).
     @ mysql-test/r/mix2_myisam.result
        Update test case result (effects of WL#4284/Bug#989).
     @ mysql-test/r/not_embedded_server.result
        Update test case result (effects of WL#4284/Bug#989).
        Add a test case for interaction of WL#4284 and FLUSH PRIVILEGES.
     @ mysql-test/r/partition_innodb_semi_consistent.result
        Update test case result (effects of WL#4284/Bug#989).
     @ mysql-test/r/partition_sync.result
        Temporarily disable the test case for Bug#43867,
        which will be fixed by a subsequent backport.
     @ mysql-test/r/ps.result
        Add a test case for effect of PREPARE on transactional
        locks: we take a savepoint at beginning of PREAPRE
        and release it at the end. Thus PREPARE does not 
        accumulate metadata locks (Bug#989/WL#4284).
     @ mysql-test/r/read_only_innodb.result
        Update test case result (effects of WL#4284/Bug#989).
     @ mysql-test/suite/binlog/r/binlog_row_drop_tbl.result
        Add a test case result (WL#4284/Bug#989).
     @ mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
        Update test case result (effects of WL#4284/Bug#989).
     @ mysql-test/suite/binlog/r/binlog_stm_drop_tbl.result
        Add a test case result (WL#4284/Bug#989).
     @ mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
        Update test case result (effects of WL#4284/Bug#989).
     @ mysql-test/suite/binlog/r/binlog_unsafe.result
        A side effect of Bug#989 -- slightly different table map ids.
     @ mysql-test/suite/binlog/t/binlog_row_drop_tbl.test
        Add a test case for WL#4284/Bug#989.
     @ mysql-test/suite/binlog/t/binlog_stm_drop_tbl.test
        Add a test case for WL#4284/Bug#989.
     @ mysql-test/suite/binlog/t/binlog_stm_row.test
        Update to the new state name. This
        is actually a follow up to another patch for WL#4284, 
        that changes Locked thread state to Table lock.
     @ mysql-test/suite/ndb/r/ndb_index_ordered.result
        Remove result for disabled part of the test case.
     @ mysql-test/suite/ndb/t/disabled.def
        Temporarily disable a test case (Bug#45621).
     @ mysql-test/suite/ndb/t/ndb_index_ordered.test
        Disable a part of a test case (needs update to
        reflect semantics of Bug#989).
     @ mysql-test/suite/rpl/t/disabled.def
        Disable tests made meaningless by transactional metadata
        locking.
     @ mysql-test/suite/sys_vars/r/autocommit_func.result
        Add a commit (Bug#989).
     @ mysql-test/suite/sys_vars/t/autocommit_func.test
        Add a commit (Bug#989).
     @ 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.
        Add a test case for transaction-scope locks and the global
        read lock (Bug#989/WL#4284).
     @ mysql-test/t/innodb.test
        Fix test case to reflect the fact that transactions now hold
        metadata locks for the duration of a transaction
        (effects of Bug#989/WL#4284).
     @ mysql-test/t/lock.test
        Add a test case for Bug#989/WL#4284.
     @ mysql-test/t/not_embedded_server.test
        Add a test case for Bug#989/WL#4284.
     @ mysql-test/t/partition_innodb_semi_consistent.test
        Replace TRUNCATE with DELETE, to not issue
        an implicit commit of a transaction, and not depend
        on metadata locks.
     @ mysql-test/t/partition_sync.test
        Temporarily disable the test case for Bug#43867,
        which needs a fix to be backported from 6.0.
     @ mysql-test/t/ps.test
        Add a test case for semantics of PREPARE and transaction-scope
        locks: metadata locks on tables used in PREPARE are enclosed into a
        temporary savepoint, taken at the beginning of PREPARE,
        and released at the end. Thus PREPARE does not effect
        what locks a transaction owns.
     @ 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 
        (Bug#989/WL#4284).
        
        Wait for the read_only statement to actually flush tables before
        sending other concurrent statements that depend on its state.
     @ mysql-test/t/xa.test
        Fix test case to reflect the fact that transactions now hold
        metadata locks for the duration of a transaction 
        (Bug#989/WL#4284).
     @ sql/ha_ndbcluster_binlog.cc
        Backport bits of changes of ha_ndbcluster_binlog.cc
        from 6.0, to fix the failing binlog test suite with
        WL#4284. WL#4284 implementation does not work
        with 5.1 implementation of ndbcluster binlog index.
     @ sql/log_event.cc
        Release metadata locks after issuing a commit.
     @ sql/mdl.cc
        Style changes (WL#4284).
     @ sql/mysql_priv.h
        Rename parameter to match the name used in the definition (WL#4284).
     @ sql/rpl_injector.cc
        Release metadata locks on commit (WL#4284).
     @ sql/rpl_rli.cc
        Remove assert made meaningless, metadata locks are released
        at the end of the transaction.
     @ sql/set_var.cc
        Close tables and release locks if autocommit mode is set.
     @ sql/slave.cc
        Release metadata locks after a rollback.
     @ sql/sql_acl.cc
        Don't implicitly unlock locked tables. Issue a implicit commit
        at the end and unlock tables.
     @ 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 when closing tables for reopen.
     @ sql/sql_class.cc
        Release metadata locks if the thread is killed.
     @ sql/sql_parse.cc
        Release metadata locks after implicitly committing a active
        transaction, or after explicit commits or rollbacks.
     @ sql/sql_plugin.cc
        Allocate MDL request on the stack as the use of the table
        is contained within the function. It will be removed from
        the context once close_thread_tables is called at the end
        of the function.
     @ sql/sql_prepare.cc
        The problem is that the prepare phase of the CREATE TABLE
        statement takes a exclusive metadata lock lock and this can
        cause a self-deadlock the thread already holds a shared lock
        on the table being that should be created.
        
        The solution is to make the prepare phase take a shared
        metadata lock when preparing a CREATE TABLE statement. The
        execution of the statement will still acquire a exclusive
        lock, but won't cause any problem as it issues a implicit
        commit.
        
        After some discussions with stakeholders it has been decided that
        metadata locks acquired during a PREPARE statement must be released
        once the statement is prepared even if it is prepared within a multi
        statement transaction.
     @ sql/sql_servers.cc
        Don't implicitly unlock locked tables. Issue a implicit commit
        at the end and unlock tables.
     @ sql/sql_table.cc
        Close table and release metadata locks after a admin operation.
     @ sql/table.h
        The problem is that the prepare phase of the CREATE TABLE
        statement takes a exclusive metadata lock lock and this can
        cause a self-deadlock the thread already holds a shared lock
        on the table being that should be created.
        
        The solution is to make the prepare phase take a shared
        metadata lock when preparing a CREATE TABLE statement. The
        execution of the statement will still acquire a exclusive
        lock, but won't cause any problem as it issues a implicit
        commit.
     @ sql/transaction.cc
        Release metadata locks after the implicitly committed due
        to a new transaction being started. Also, release metadata
        locks acquired after a savepoint if the transaction is rolled
        back to the save point.
        
        The problem is that in some cases transaction-long metadata locks
        could be released before the transaction was committed. This could
        happen when a active transaction was ended by a "START TRANSACTION"
        or "BEGIN" statement, in which case the metadata locks would be
        released before the actual commit of the active transaction.
        
        The solution is to defer the release of metadata locks to after the
        transaction has been implicitly committed. No test case is provided
        as the effort to provide one is too disproportional to the size of
        the fix.

    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/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/lock.result
      mysql-test/r/mix2_myisam.result
      mysql-test/r/not_embedded_server.result
      mysql-test/r/partition_innodb_semi_consistent.result
      mysql-test/r/partition_sync.result
      mysql-test/r/ps.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/binlog/r/binlog_unsafe.result
      mysql-test/suite/binlog/t/binlog_stm_row.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/t/disabled.def
      mysql-test/suite/sys_vars/r/autocommit_func.result
      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/lock.test
      mysql-test/t/not_embedded_server.test
      mysql-test/t/partition_innodb_semi_consistent.test
      mysql-test/t/partition_sync.test
      mysql-test/t/ps.test
      mysql-test/t/read_only_innodb.test
      mysql-test/t/xa.test
      sql/ha_ndbcluster_binlog.cc
      sql/log_event.cc
      sql/mdl.cc
      sql/mysql_priv.h
      sql/rpl_injector.cc
      sql/rpl_rli.cc
      sql/set_var.cc
      sql/slave.cc
      sql/sql_acl.cc
      sql/sql_base.cc
      sql/sql_class.cc
      sql/sql_parse.cc
      sql/sql_plugin.cc
      sql/sql_prepare.cc
      sql/sql_servers.cc
      sql/sql_table.cc
      sql/sql_view.cc
      sql/table.h
      sql/transaction.cc
      tests/mysql_client_test.c
=== 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-12-04 23:02:48 +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	2009-09-29 11:16:23 +0000
+++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test	2009-12-04 23:02:48 +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/mix1.inc'
--- a/mysql-test/include/mix1.inc	2009-10-05 13:16:27 +0000
+++ b/mysql-test/include/mix1.inc	2009-12-04 23:02:48 +0000
@@ -1392,6 +1392,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-12-04 23:02:48 +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	2009-03-06 14:56:17 +0000
+++ b/mysql-test/r/flush_block_commit.result	2009-12-04 23:02:48 +0000
@@ -1,3 +1,4 @@
+# Save the initial number of concurrent sessions
 # Establish connection con1 (user=root)
 # Establish connection con2 (user=root)
 # Establish connection con3 (user=root)
@@ -8,13 +9,15 @@ BEGIN;
 INSERT INTO t1 VALUES(1);
 # Switch to connection con2
 FLUSH TABLES WITH READ LOCK;
-SELECT * FROM t1;
-a
 # Switch to connection con1
+# Sending:
 COMMIT;
 # Switch to connection con2
+# Wait until COMMIT gets blocked.
+# Verify that 'con1' was blocked and data did not move.
 SELECT * FROM t1;
 a
+1
 UNLOCK TABLES;
 # Switch to connection con1
 # Switch to connection con1
@@ -32,6 +35,7 @@ COMMIT;
 # Switch to connection con2
 a
 1
+COMMIT;
 # Switch to connection con3
 UNLOCK TABLES;
 # Switch to connection con2
@@ -40,8 +44,6 @@ COMMIT;
 BEGIN;
 INSERT INTO t1 VALUES(10);
 FLUSH TABLES WITH READ LOCK;
-COMMIT;
-UNLOCK TABLES;
 # Switch to connection con2
 FLUSH TABLES WITH READ LOCK;
 UNLOCK TABLES;
@@ -53,5 +55,11 @@ a
 SHOW CREATE DATABASE test;
 Database	Create Database
 test	CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET latin1 */
-DROP TABLE t1;
+COMMIT;
+# Cleanup
 # Switch to connection default and close connections con1, con2, con3
+# We commit open transactions when we disconnect: only then we can
+# drop the table.
+DROP TABLE t1;
+# End of 4.1 tests
+# Wait till all disconnects are completed

=== modified file 'mysql-test/r/flush_block_commit_notembedded.result'
--- a/mysql-test/r/flush_block_commit_notembedded.result	2009-10-01 16:44:53 +0000
+++ b/mysql-test/r/flush_block_commit_notembedded.result	2009-12-04 23:02:48 +0000
@@ -1,17 +1,20 @@
+# Save the initial number of concurrent sessions
 # Establish connection con1 (user=root)
 # Establish connection con2 (user=root)
 # Switch to connection con1
 CREATE TABLE t1 (a INT) ENGINE=innodb;
 RESET MASTER;
 SET AUTOCOMMIT=0;
-INSERT t1 VALUES (1);
+SELECT 1;
+1
+1
 # Switch to connection con2
 FLUSH TABLES WITH READ LOCK;
 SHOW MASTER STATUS;
 File	Position	Binlog_Do_DB	Binlog_Ignore_DB
 master-bin.000001	107		
 # Switch to connection con1
-COMMIT;
+INSERT INTO t1 VALUES (1);
 # Switch to connection con2
 SHOW MASTER STATUS;
 File	Position	Binlog_Do_DB	Binlog_Ignore_DB
@@ -20,4 +23,12 @@ UNLOCK TABLES;
 # Switch to connection con1
 DROP TABLE t1;
 SET AUTOCOMMIT=1;
+create table t1 (a int) engine=innodb;
+flush tables with read lock;
+begin;
+insert into t1 values (1);;
+unlock tables;
+commit;
+drop table t1;
 # Switch to connection default and close connections con1 and con2
+# Wait till all disconnects are completed

=== modified file 'mysql-test/r/innodb.result'
--- a/mysql-test/r/innodb.result	2009-10-15 12:23:43 +0000
+++ b/mysql-test/r/innodb.result	2009-12-04 23:02:48 +0000
@@ -2836,10 +2836,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),
@@ -2887,6 +2887,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-11-06 09:17:01 +0000
+++ b/mysql-test/r/innodb_mysql.result	2009-12-04 23:02:48 +0000
@@ -1618,6 +1618,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/lock.result'
--- a/mysql-test/r/lock.result	2009-12-02 20:47:23 +0000
+++ b/mysql-test/r/lock.result	2009-12-04 23:02:48 +0000
@@ -1,4 +1,4 @@
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
 CREATE TABLE t1 (  `id` int(11) NOT NULL default '0', `id2` int(11) NOT NULL default '0', `id3` int(11) NOT NULL default '0', `dummy1` char(30) default NULL, PRIMARY KEY  (`id`,`id2`), KEY `index_id3` (`id3`)) ENGINE=MyISAM;
 insert into t1 (id,id2) values (1,1),(1,2),(1,3);
 LOCK TABLE t1 WRITE;
@@ -262,5 +262,25 @@ unlock tables;
 drop table t1;
 drop view v1;
 #
+# WL#4284: Transactional DDL locking
+#
+drop table if exists t1;
+create table t1 (a int);
+set autocommit= 0;
+insert into t1 values (1);
+lock table t1 write;
+# Disconnect
+# Ensure that metadata locks will be released if there is an open
+# transaction (autocommit=off) in conjunction with lock tables.
+drop table t1;
+# Same problem but now for BEGIN
+drop table if exists t1;
+create table t1 (a int);
+begin;
+insert into t1 values (1);
+# Disconnect
+# Ensure that metadata locks held by the transaction are released.
+drop table t1;
+#
 # End of 6.0 tests.
 #

=== modified file 'mysql-test/r/mix2_myisam.result'
--- a/mysql-test/r/mix2_myisam.result	2008-05-14 09:13:12 +0000
+++ b/mysql-test/r/mix2_myisam.result	2009-12-04 23:02:48 +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/not_embedded_server.result'
--- a/mysql-test/r/not_embedded_server.result	2009-04-30 10:29:19 +0000
+++ b/mysql-test/r/not_embedded_server.result	2009-12-04 23:02:48 +0000
@@ -1,6 +1,16 @@
-select 1;
-1
-1
+call mtr.add_suppression("Can't open and lock privilege tables: Table 'host' was not locked with LOCK TABLES");
 SHOW VARIABLES like 'slave_skip_errors';
 Variable_name	Value
 slave_skip_errors	OFF
+#
+# WL#4284: Transactional DDL locking
+#
+# FLUSH PRIVILEGES should not implicitly unlock locked tables.
+#
+drop table if exists t1;
+create table t1 (c1 int);
+lock tables t1 read;
+flush privileges;
+ERROR HY000: Table 'host' was not locked with LOCK TABLES
+unlock tables;
+drop table t1;

=== 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-12-04 23:02:48 +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/partition_sync.result'
--- a/mysql-test/r/partition_sync.result	2009-11-04 11:59:46 +0000
+++ b/mysql-test/r/partition_sync.result	2009-12-04 23:02:48 +0000
@@ -1,25 +1,2 @@
-#
-# Bug #43867 ALTER TABLE on a partitioned table 
-#            causes unnecessary deadlocks
-#
-CREATE TABLE t1 (a int) PARTITION BY RANGE (a)
-(PARTITION p0 VALUES LESS THAN (1),
-PARTITION p1 VALUES LESS THAN (2));
-INSERT INTO t1 VALUES (0),(1);
-# Connection 2
-BEGIN;
-SELECT * FROM t1;
-a
-0
-1
-# Connection 1
-ALTER TABLE t1 DROP PARTITION p3;
-ERROR HY000: Error in list of partitions to DROP
-# Connection 2
-# This failed with deadlock and should not do so.
-SELECT * FROM t1;
-a
-0
-1
-# Connection 1
-DROP TABLE t1;
+# Disabled until Bug#46654 False deadlock on concurrent DML/DDL 
+# with partitions, inconsistent behavior is backported

=== modified file 'mysql-test/r/ps.result'
--- a/mysql-test/r/ps.result	2009-10-21 20:02:06 +0000
+++ b/mysql-test/r/ps.result	2009-12-04 23:02:48 +0000
@@ -3086,5 +3086,29 @@ DROP PROCEDURE p1;
 DROP PROCEDURE p2;
 
 # End of WL#4435.
-
-End of 6.0 tests.
+#
+# WL#4284: Transactional DDL locking
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a INT);
+BEGIN;
+SELECT * FROM t1;
+a
+# Test that preparing a CREATE TABLE does not take a exclusive metdata lock.
+PREPARE stmt1 FROM "CREATE TABLE t1 AS SELECT 1";
+EXECUTE stmt1;
+ERROR 42S01: Table 't1' already exists
+DEALLOCATE PREPARE stmt1;
+DROP TABLE t1;
+#
+# WL#4284: Transactional DDL locking
+#
+# Test that metadata locks taken during prepare are released.
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a INT);
+BEGIN;
+PREPARE stmt1 FROM "SELECT * FROM t1";
+DROP TABLE t1;
+#
+# End of 6.0 tests.

=== 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-12-04 23:02:48 +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-12-04 23:02:48 +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	#	#	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	#	#	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-10-06 10:25:36 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result	2009-12-04 23:02:48 +0000
@@ -238,6 +238,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-12-04 23:02:48 +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-12-01 19:07:18 +0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result	2009-12-04 23:02:48 +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;

=== modified file 'mysql-test/suite/binlog/r/binlog_unsafe.result'
--- a/mysql-test/suite/binlog/r/binlog_unsafe.result	2009-12-01 19:07:18 +0000
+++ b/mysql-test/suite/binlog/r/binlog_unsafe.result	2009-12-04 23:02:48 +0000
@@ -320,10 +320,10 @@ INSERT INTO t2 SET a = func_modify_t1();
 SHOW BINLOG EVENTS FROM 12283;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
 master-bin.000001	12283	Query	1	12351	BEGIN
-master-bin.000001	12351	Table_map	1	12393	table_id: 44 (test.t2)
-master-bin.000001	12393	Table_map	1	12435	table_id: 45 (test.t1)
-master-bin.000001	12435	Write_rows	1	12473	table_id: 45
-master-bin.000001	12473	Write_rows	1	12511	table_id: 44 flags: STMT_END_F
+master-bin.000001	12351	Table_map	1	12393	table_id: 41 (test.t2)
+master-bin.000001	12393	Table_map	1	12435	table_id: 42 (test.t1)
+master-bin.000001	12435	Write_rows	1	12473	table_id: 42
+master-bin.000001	12473	Write_rows	1	12511	table_id: 41 flags: STMT_END_F
 master-bin.000001	12511	Query	1	12580	COMMIT
 DROP TABLE t1,t2;
 DROP FUNCTION func_modify_t1;
@@ -347,12 +347,12 @@ INSERT INTO t1 SET a = 2;
 SHOW BINLOG EVENTS FROM 13426;
 Log_name	Pos	Event_type	Server_id	End_log_pos	Info
 master-bin.000001	13426	Query	1	13494	BEGIN
-master-bin.000001	13494	Table_map	1	13535	table_id: 47 (test.t1)
-master-bin.000001	13535	Table_map	1	13577	table_id: 48 (test.t3)
-master-bin.000001	13577	Table_map	1	13619	table_id: 49 (test.t2)
-master-bin.000001	13619	Write_rows	1	13657	table_id: 49
-master-bin.000001	13657	Write_rows	1	13695	table_id: 48
-master-bin.000001	13695	Write_rows	1	13729	table_id: 47 flags: STMT_END_F
+master-bin.000001	13494	Table_map	1	13535	table_id: 44 (test.t1)
+master-bin.000001	13535	Table_map	1	13577	table_id: 45 (test.t3)
+master-bin.000001	13577	Table_map	1	13619	table_id: 46 (test.t2)
+master-bin.000001	13619	Write_rows	1	13657	table_id: 46
+master-bin.000001	13657	Write_rows	1	13695	table_id: 45
+master-bin.000001	13695	Write_rows	1	13729	table_id: 44 flags: STMT_END_F
 master-bin.000001	13729	Query	1	13798	COMMIT
 DROP TABLE t1,t2,t3;
 "End of tests"

=== 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-12-04 23:02:48 +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-12-04 23:02:48 +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/binlog/t/binlog_stm_row.test'
--- a/mysql-test/suite/binlog/t/binlog_stm_row.test	2009-01-30 13:44:49 +0000
+++ b/mysql-test/suite/binlog/t/binlog_stm_row.test	2009-12-04 23:02:48 +0000
@@ -57,7 +57,7 @@ let $wait_condition=
 --echo # con1
 let $wait_condition=
   SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE
-  state = "Locked" and info = "INSERT INTO t2 VALUES (3)";
+  state = "Table lock" and info = "INSERT INTO t2 VALUES (3)";
 --source include/wait_condition.inc
 SELECT RELEASE_LOCK('Bug#34306');
 --connection con2

=== 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-12-04 23:02:48 +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	2008-12-08 14:36:42 +0000
+++ b/mysql-test/suite/ndb/t/disabled.def	2009-12-04 23:02:48 +0000
@@ -13,3 +13,4 @@
 ndb_partition_error2 : Bug#40989 ndb_partition_error2 needs maintenance
 
 # the below testcase have been reworked to avoid the bug, test contains comment, keep bug open
+ndb_alter_table3          : Bug#45621 2009-06-10 alik A few test files are disabled due to WL#4284

=== 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-12-04 23:02:48 +0000
@@ -333,21 +333,29 @@ select count(*)- 4 from t1 use index (v)
 
 drop table t1;
 
+#
+# Disabled due to WL#4284
+#
+# Needs to be reworked. It's not possible anymore to do a non-fast alter table
+# on a table that is being used by a pending transaction (transaction holds a
+# metadata lock on the table).
+#
 # 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/t/disabled.def'
--- a/mysql-test/suite/rpl/t/disabled.def	2009-12-03 11:37:42 +0000
+++ b/mysql-test/suite/rpl/t/disabled.def	2009-12-04 23:02:48 +0000
@@ -12,3 +12,5 @@
 
 rpl_cross_version               : BUG#43913 2009-10-22 luis rpl_cross_version fails with symptom in described in bug report
 rpl_spec_variables		: BUG#47661 2009-10-27 jasonh rpl_spec_variables fails on PB2 hpux
+rpl_failed_optimize        : WL#4284: Can't optimize table used by a pending transaction (there is metadata lock on the table).
+rpl_read_only              : WL#4284: Setting Read only won't succeed until all metadata locks are released.

=== modified file 'mysql-test/suite/sys_vars/r/autocommit_func.result'
--- a/mysql-test/suite/sys_vars/r/autocommit_func.result	2008-12-19 15:12:15 +0000
+++ b/mysql-test/suite/sys_vars/r/autocommit_func.result	2009-12-04 23:02:48 +0000
@@ -104,6 +104,8 @@ id	name
 2	Record_2
 4	Record_4
 5	Record_5
+## Commit changes
+COMMIT;
 ## Dropping table t1 ##
 DROP table t1;
 ## Disconnecting both connections ##

=== 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-12-04 23:02:48 +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	2009-03-06 14:56:17 +0000
+++ b/mysql-test/t/flush_block_commit.test	2009-12-04 23:02:48 +0000
@@ -6,7 +6,7 @@
 # And it requires InnoDB
 --source include/have_innodb.inc
 
-# Save the initial number of concurrent sessions
+--echo # Save the initial number of concurrent sessions
 --source include/count_sessions.inc
 
 --echo # Establish connection con1 (user=root)
@@ -29,19 +29,26 @@ BEGIN;
 INSERT INTO t1 VALUES(1);
 --echo # Switch to connection con2
 connection con2;
-FLUSH TABLES WITH READ LOCK;
-SELECT * FROM t1;
+--send FLUSH TABLES WITH READ LOCK
 --echo # Switch to connection con1
 connection con1;
-send COMMIT; # blocked by con2
-sleep 1;
+--echo # Sending:
+COMMIT;
 --echo # Switch to connection con2
 connection con2;
-SELECT * FROM t1; # verify con1 was blocked and data did not move
+--reap
+--echo # Wait until COMMIT gets blocked.
+#let $wait_condition=
+#  select count(*) = 1 from information_schema.processlist
+#  where state = "Waiting for release of readlock" and info = "COMMIT";
+#--source include/wait_condition.inc
+--echo # Verify that 'con1' was blocked and data did not move.
+SELECT * FROM t1;
 UNLOCK TABLES;
 --echo # Switch to connection con1
 connection con1;
-reap;
+#--echo # Reaping COMMIT
+#--reap
 
 # No deadlock ?
 
@@ -63,6 +70,7 @@ COMMIT; # should not be blocked by con3
 --echo # Switch to connection con2
 connection con2;
 reap;
+COMMIT;
 --echo # Switch to connection con3
 connection con3;
 reap;
@@ -79,8 +87,6 @@ connection con1;
 BEGIN;
 INSERT INTO t1 VALUES(10);
 FLUSH TABLES WITH READ LOCK;
-COMMIT;
-UNLOCK TABLES;
 --echo # Switch to connection con2
 connection con2;
 FLUSH TABLES WITH READ LOCK; # bug caused hang here
@@ -91,19 +97,21 @@ UNLOCK TABLES;
 BEGIN;
 SELECT * FROM t1;
 SHOW CREATE DATABASE test;
-
-DROP TABLE t1;
+COMMIT;
 
 
-# Cleanup
+--echo # Cleanup
 --echo # Switch to connection default and close connections con1, con2, con3
 connection default;
 disconnect con1;
 disconnect con2;
 disconnect con3;
 
-# End of 4.1 tests
+--echo # We commit open transactions when we disconnect: only then we can
+--echo # drop the table.
+DROP TABLE t1;
+--echo # End of 4.1 tests
 
-# Wait till all disconnects are completed
+--echo # Wait till all disconnects are completed
 --source include/wait_until_count_sessions.inc
 

=== modified file 'mysql-test/t/flush_block_commit_notembedded.test'
--- a/mysql-test/t/flush_block_commit_notembedded.test	2009-03-06 14:56:17 +0000
+++ b/mysql-test/t/flush_block_commit_notembedded.test	2009-12-04 23:02:48 +0000
@@ -9,7 +9,7 @@
 --source include/have_log_bin.inc
 --source include/have_innodb.inc
 
-# Save the initial number of concurrent sessions
+--echo # Save the initial number of concurrent sessions
 --source include/count_sessions.inc
 
 
@@ -24,14 +24,14 @@ connection con1;
 CREATE TABLE t1 (a INT) ENGINE=innodb;
 RESET MASTER;
 SET AUTOCOMMIT=0;
-INSERT t1 VALUES (1);
+SELECT 1;
 --echo # Switch to connection con2
 connection con2;
 FLUSH TABLES WITH READ LOCK;
 SHOW MASTER STATUS;
 --echo # Switch to connection con1
 connection con1;
-send COMMIT;
+send INSERT INTO t1 VALUES (1);
 --echo # Switch to connection con2
 connection con2;
 sleep 1;
@@ -43,11 +43,30 @@ reap;
 DROP TABLE t1;
 SET AUTOCOMMIT=1;
 
+# GLR blocks new transactions
+create table t1 (a int) engine=innodb;
+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;
+
 --echo # Switch to connection default and close connections con1 and con2
 connection default;
 disconnect con1;
 disconnect con2;
 
-# Wait till all disconnects are completed
+--echo # Wait till all disconnects are completed
 --source include/wait_until_count_sessions.inc
 

=== modified file 'mysql-test/t/innodb.test'
--- a/mysql-test/t/innodb.test	2009-11-09 11:56:15 +0000
+++ b/mysql-test/t/innodb.test	2009-12-04 23:02:48 +0000
@@ -1849,16 +1849,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),
@@ -1922,6 +1921,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/lock.test'
--- a/mysql-test/t/lock.test	2009-12-02 20:47:23 +0000
+++ b/mysql-test/t/lock.test	2009-12-04 23:02:48 +0000
@@ -3,7 +3,7 @@
 #
 
 --disable_warnings
-drop table if exists t1,t2;
+drop table if exists t1,t2,t3;
 --enable_warnings
 CREATE TABLE t1 (  `id` int(11) NOT NULL default '0', `id2` int(11) NOT NULL default '0', `id3` int(11) NOT NULL default '0', `dummy1` char(30) default NULL, PRIMARY KEY  (`id`,`id2`), KEY `index_id3` (`id3`)) ENGINE=MyISAM;
 insert into t1 (id,id2) values (1,1),(1,2),(1,3);
@@ -311,5 +311,40 @@ drop table t1;
 drop view v1;
 
 --echo #
+--echo # WL#4284: Transactional DDL locking
+--echo #
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a int);
+connect(con1,localhost,root,,);
+set autocommit= 0;
+insert into t1 values (1);
+lock table t1 write;
+--echo # Disconnect
+--echo # Ensure that metadata locks will be released if there is an open
+--echo # transaction (autocommit=off) in conjunction with lock tables.
+disconnect con1;
+connection default;
+drop table t1;
+
+--echo # Same problem but now for BEGIN
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a int);
+connect(con1,localhost,root,,);
+begin;
+insert into t1 values (1);
+--echo # Disconnect
+--echo # Ensure that metadata locks held by the transaction are released.
+disconnect con1;
+connection default;
+drop table t1;
+
+
+--echo #
 --echo # End of 6.0 tests.
 --echo #

=== modified file 'mysql-test/t/not_embedded_server.test'
--- a/mysql-test/t/not_embedded_server.test	2009-04-30 10:29:19 +0000
+++ b/mysql-test/t/not_embedded_server.test	2009-12-04 23:02:48 +0000
@@ -4,12 +4,6 @@
 
 -- source include/not_embedded.inc
 
-#
-# Produce output
-#
-
-select 1;
-
 # The following fails sporadically because 'check-testcase' runs
 # queries before this test and there is no way to guarantee that any
 # previous process finishes.  The purpose of the test is not clearly
@@ -36,6 +30,8 @@ select 1;
 #execute stmt1;
 #deallocate prepare stmt1;
 
+call mtr.add_suppression("Can't open and lock privilege tables: Table 'host' was not locked with LOCK TABLES");
+
 #
 # Bug#43835: SHOW VARIABLES does not include 0 for slave_skip_errors
 #
@@ -43,3 +39,18 @@ select 1;
 SHOW VARIABLES like 'slave_skip_errors';
 
 # End of 5.1 tests
+
+--echo #
+--echo # WL#4284: Transactional DDL locking
+--echo #
+--echo # FLUSH PRIVILEGES should not implicitly unlock locked tables.
+--echo #
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (c1 int);
+lock tables t1 read;
+--error ER_TABLE_NOT_LOCKED
+flush privileges;
+unlock tables;
+drop table t1;

=== 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-12-04 23:02:48 +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/partition_sync.test'
--- a/mysql-test/t/partition_sync.test	2009-11-04 11:59:46 +0000
+++ b/mysql-test/t/partition_sync.test	2009-12-04 23:02:48 +0000
@@ -2,38 +2,41 @@
 # Save the initial number of concurrent sessions.
 --source include/count_sessions.inc
 
---echo #
---echo # Bug #43867 ALTER TABLE on a partitioned table 
---echo #            causes unnecessary deadlocks
---echo #
+--echo # Disabled until Bug#46654 False deadlock on concurrent DML/DDL 
+--echo # with partitions, inconsistent behavior is backported
 
-CREATE TABLE t1 (a int) PARTITION BY RANGE (a)
-(PARTITION p0 VALUES LESS THAN (1),
- PARTITION p1 VALUES LESS THAN (2));
-
-INSERT INTO t1 VALUES (0),(1);
-
-connect(con1,localhost,root);
-
---echo # Connection 2
-connection con1;
-BEGIN;
-SELECT * FROM t1;
-
---echo # Connection 1
-connection default;
---error ER_DROP_PARTITION_NON_EXISTENT
-ALTER TABLE t1 DROP PARTITION p3;
-
---echo # Connection 2
-connection con1;
---echo # This failed with deadlock and should not do so.
-SELECT * FROM t1;
-
---echo # Connection 1
-connection default;
-disconnect con1;
-DROP TABLE t1;
+#--echo #
+#--echo # Bug #43867 ALTER TABLE on a partitioned table 
+#--echo #            causes unnecessary deadlocks
+#--echo #
+#
+#CREATE TABLE t1 (a int) PARTITION BY RANGE (a)
+#(PARTITION p0 VALUES LESS THAN (1),
+# PARTITION p1 VALUES LESS THAN (2));
+#
+#INSERT INTO t1 VALUES (0),(1);
+#
+#connect(con1,localhost,root);
+#
+#--echo # Connection 2
+#connection con1;
+#BEGIN;
+#SELECT * FROM t1;
+#
+#--echo # Connection 1
+#connection default;
+#--error ER_DROP_PARTITION_NON_EXISTENT
+#ALTER TABLE t1 DROP PARTITION p3;
+#
+#--echo # Connection 2
+#connection con1;
+#--echo # This failed with deadlock and should not do so.
+#SELECT * FROM t1;
+#
+#--echo # Connection 1
+#connection default;
+#disconnect con1;
+#DROP TABLE t1;
 
 
 # Check that all connections opened by test cases in this file are really

=== modified file 'mysql-test/t/ps.test'
--- a/mysql-test/t/ps.test	2009-10-21 20:02:06 +0000
+++ b/mysql-test/t/ps.test	2009-12-04 23:02:48 +0000
@@ -3211,7 +3211,44 @@ DROP PROCEDURE p2;
 
 ###########################################################################
 
---echo
---echo End of 6.0 tests.
+
+--echo #
+--echo # WL#4284: Transactional DDL locking
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+CREATE TABLE t1 (a INT);
+BEGIN;
+SELECT * FROM t1;
+--echo # Test that preparing a CREATE TABLE does not take a exclusive metdata lock.
+PREPARE stmt1 FROM "CREATE TABLE t1 AS SELECT 1";
+--error ER_TABLE_EXISTS_ERROR
+EXECUTE stmt1;
+DEALLOCATE PREPARE stmt1;
+DROP TABLE t1;
+
+--echo #
+--echo # WL#4284: Transactional DDL locking
+--echo #
+--echo # Test that metadata locks taken during prepare are released.
+--echo #
+
+connect(con1,localhost,root,,);
+connection default;
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+CREATE TABLE t1 (a INT);
+connection con1;
+BEGIN;
+PREPARE stmt1 FROM "SELECT * FROM t1";
+connection default;
+DROP TABLE t1;
+disconnect con1;
+
+--echo #
+--echo # End of 6.0 tests.
 
 ###########################################################################

=== 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-12-04 23:02:48 +0000
@@ -16,6 +16,8 @@ DROP TABLE IF EXISTS table_11733 ;
 grant CREATE, SELECT, DROP on *.* to test@localhost;
 
 connect (con1,localhost,test,,test);
+connect (con2,localhost,root,,);
+
 
 connection default;
 set global read_only=0;
@@ -28,15 +30,22 @@ BEGIN;
 insert into table_11733 values(11733);
 
 connection default;
-set global read_only=1;
+send set global read_only=1;
+
+connection con2;
+let $wait_condition=
+  select count(*) = 1 from information_schema.processlist
+  where state = "Flushing tables" and info = "set global read_only=1";
+--source include/wait_condition.inc
 
 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;
@@ -81,5 +90,6 @@ DROP TABLE t1;
 DROP USER test@localhost;
 
 disconnect con1;
+disconnect con2;
 
 --echo echo End of 5.1 tests 

=== modified file 'mysql-test/t/xa.test'
--- a/mysql-test/t/xa.test	2009-10-28 15:39:08 +0000
+++ b/mysql-test/t/xa.test	2009-12-04 23:02:48 +0000
@@ -76,9 +76,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/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc	2009-12-03 23:52:05 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2009-12-04 23:02:48 +0000
@@ -2347,7 +2347,7 @@ static int open_ndb_binlog_index(THD *th
   tables->required_type= FRMTYPE_TABLE;
   uint counter;
   thd->clear_error();
-  if (open_tables(thd, &tables, &counter, MYSQL_LOCK_IGNORE_FLUSH))
+  if (simple_open_n_lock_tables(thd, tables))
   {
     if (thd->killed)
       sql_print_error("NDB Binlog: Opening ndb_binlog_index: killed");
@@ -2381,28 +2381,11 @@ int ndb_add_ndb_binlog_index(THD *thd, v
   ulong saved_options= thd->options;
   thd->options&= ~(OPTION_BIN_LOG);
 
-  for ( ; ; ) /* loop for need_reopen */
+  if (!ndb_binlog_index && open_ndb_binlog_index(thd, &ndb_binlog_index))
   {
-    if (!ndb_binlog_index && open_ndb_binlog_index(thd, &ndb_binlog_index))
-    {
-      error= -1;
-      goto add_ndb_binlog_index_err;
-    }
-
-    if (lock_tables(thd, &binlog_tables, 1, 0, &need_reopen))
-    {
-      if (need_reopen)
-      {
-        TABLE_LIST *p_binlog_tables= &binlog_tables;
-        close_tables_for_reopen(thd, &p_binlog_tables, FALSE);
-        ndb_binlog_index= 0;
-        continue;
-      }
-      sql_print_error("NDB Binlog: Unable to lock table ndb_binlog_index");
-      error= -1;
-      goto add_ndb_binlog_index_err;
-    }
-    break;
+    sql_print_error("NDB Binlog: Unable to lock table ndb_binlog_index");
+    error= -1;
+    goto add_ndb_binlog_index_err;
   }
 
   /*
@@ -2428,13 +2411,6 @@ int ndb_add_ndb_binlog_index(THD *thd, v
   }
 
 
-  if (! thd->locked_tables_mode)                /* Is always TRUE */
-  {
-    mysql_unlock_tables(thd, thd->lock);
-    thd->lock= 0;
-  }
-  thd->options= saved_options;
-  return 0;
 add_ndb_binlog_index_err:
   close_thread_tables(thd);
   ndb_binlog_index= 0;
@@ -3905,9 +3881,6 @@ restart:
   {
     static char db[]= "";
     thd->db= db;
-    if (ndb_binlog_running)
-      open_ndb_binlog_index(thd, &ndb_binlog_index);
-    thd->db= db;
   }
   do_ndbcluster_binlog_close_connection= BCCC_running;
   for ( ; !((ndbcluster_binlog_terminating ||

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2009-12-03 23:52:05 +0000
+++ b/sql/log_event.cc	2009-12-04 23:02:48 +0000
@@ -5314,10 +5314,17 @@ void Xid_log_event::print(FILE* file, PR
 #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
 int Xid_log_event::do_apply_event(Relay_log_info const *rli)
 {
+  bool res;
   /* For a slave Xid_log_event is COMMIT */
   general_log_print(thd, COM_QUERY,
                     "COMMIT /* implicit, from Xid_log_event */");
-  return trans_commit(thd);
+  if (!(res= trans_commit(thd)))
+  {
+    close_thread_tables(thd);
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
+  }
+  return res;
 }
 
 Log_event::enum_skip_reason

=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2009-12-03 23:55:26 +0000
+++ b/sql/mdl.cc	2009-12-04 23:02:48 +0000
@@ -491,7 +491,7 @@ void MDL_ticket::destroy(MDL_ticket *tic
   @sa THD::enter_cond()/exit_cond()/killed.
 
   @note We can't use THD::enter_cond()/exit_cond()/killed directly here
-        since this will make metadata subsystem dependant on THD class
+        since this will make metadata subsystem dependent on THD class
         and thus prevent us from writing unit tests for it. And usage of
         wrapper functions to access THD::killed/enter_cond()/exit_cond()
         will probably introduce too much overhead.
@@ -881,6 +881,7 @@ static bool notify_shared_lock(THD *thd,
   if (conflicting_ticket->is_shared())
   {
     THD *conflicting_thd= conflicting_ticket->get_ctx()->get_thd();
+    DBUG_ASSERT(thd != conflicting_thd); /* Self-deadlock */
     woke= mysql_notify_thread_having_shared_lock(thd, conflicting_thd);
   }
   return woke;
@@ -1089,7 +1090,6 @@ MDL_ticket::upgrade_shared_lock_to_exclu
 
   old_msg= MDL_ENTER_COND(thd, mysys_var);
 
-
   /*
     Since we should have already acquired an intention exclusive
     global lock this call is only enforcing asserts.
@@ -1164,7 +1164,7 @@ MDL_ticket::upgrade_shared_lock_to_exclu
   @param conflict   [out] Indicates that conflicting lock exists
 
   @retval TRUE  Failure either conflicting lock exists or some error
-                occured (probably OOM).
+                occurred (probably OOM).
   @retval FALSE Success, lock was acquired.
 
   FIXME: Compared to lock_table_name_if_not_cached()

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-12-03 18:37:38 +0000
+++ b/sql/mysql_priv.h	2009-12-04 23:02:48 +0000
@@ -827,7 +827,7 @@ 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);
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *tables);

=== modified file 'sql/rpl_injector.cc'
--- a/sql/rpl_injector.cc	2009-12-03 18:37:38 +0000
+++ b/sql/rpl_injector.cc	2009-12-04 23:02:48 +0000
@@ -83,10 +83,16 @@ int injector::transaction::commit()
      explicitly.
    */
    trans_commit_stmt(m_thd);
-   trans_commit(m_thd);
+   if (!trans_commit(m_thd))
+   {
+     close_thread_tables(m_thd);
+     if (!m_thd->locked_tables_mode)
+       m_thd->mdl_context.release_all_locks();
+   }
    DBUG_RETURN(0);
 }
 
+
 int injector::transaction::use_table(server_id_type sid, table tbl)
 {
   DBUG_ENTER("injector::transaction::use_table");

=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc	2009-12-03 23:52:05 +0000
+++ b/sql/rpl_rli.cc	2009-12-04 23:02:48 +0000
@@ -1189,6 +1189,8 @@ void Relay_log_info::cleanup_context(THD
   }
   m_table_map.clear_tables();
   slave_close_thread_tables(thd);
+  if (error && !thd->locked_tables_mode)
+    thd->mdl_context.release_all_locks();
   clear_flag(IN_STMT);
   /*
     Cleanup for the flags that have been set at do_apply_event.
@@ -1200,13 +1202,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);
@@ -1225,12 +1220,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/set_var.cc'
--- a/sql/set_var.cc	2009-12-03 18:37:38 +0000
+++ b/sql/set_var.cc	2009-12-04 23:02:48 +0000
@@ -3190,9 +3190,15 @@ static bool set_option_autocommit(THD *t
     need to commit any outstanding transactions.
    */
   if (var->save_result.ulong_value != 0 &&
-      (thd->options & OPTION_NOT_AUTOCOMMIT) &&
-      trans_commit(thd))
-    return 1;
+      (thd->options & OPTION_NOT_AUTOCOMMIT))
+  {
+    if (trans_commit(thd))
+      return TRUE;
+
+    close_thread_tables(thd);
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
+  }
 
   if (var->save_result.ulong_value != 0)
     thd->options&= ~((sys_var_thd_bit*) var->var)->bit_flag;

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2009-12-03 18:37:38 +0000
+++ b/sql/slave.cc	2009-12-04 23:02:48 +0000
@@ -2432,6 +2432,9 @@ static int exec_relay_log_event(THD* thd
           {
             exec_res= 0;
             trans_rollback(thd);
+            close_thread_tables(thd);
+            if (!thd->locked_tables_mode)
+              thd->mdl_context.release_all_locks();
             /* chance for concurrent connection to get more locks */
             safe_sleep(thd, min(rli->trans_retries, MAX_SLAVE_RETRY_PAUSE),
                        (CHECK_KILLED_FUNC)sql_slave_killed, (void*)rli);

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2009-12-03 23:29:40 +0000
+++ b/sql/sql_acl.cc	2009-12-04 23:02:48 +0000
@@ -30,6 +30,7 @@
 #include <stdarg.h>
 #include "sp_head.h"
 #include "sp.h"
+#include "transaction.h"
 
 time_t mysql_db_table_last_check= 0L;
 
@@ -676,9 +677,6 @@ my_bool acl_reload(THD *thd)
   my_bool return_val= 1;
   DBUG_ENTER("acl_reload");
 
-  /* Can't have locked tables here. */
-  thd->locked_tables_list.unlock_locked_tables(thd);
-
   /*
     To avoid deadlocks we should obtain table locks before
     obtaining acl_cache->lock mutex.
@@ -732,7 +730,10 @@ my_bool acl_reload(THD *thd)
   if (old_initialized)
     pthread_mutex_unlock(&acl_cache->lock);
 end:
+  trans_commit_implicit(thd);
   close_thread_tables(thd);
+  if (!thd->locked_tables_mode)
+    thd->mdl_context.release_all_locks();
   DBUG_RETURN(return_val);
 }
 
@@ -3900,7 +3901,10 @@ my_bool grant_reload(THD *thd)
     free_root(&old_mem,MYF(0));
   }
   rw_unlock(&LOCK_grant);
+  trans_commit_implicit(thd);
   close_thread_tables(thd);
+  if (!thd->locked_tables_mode)
+    thd->mdl_context.release_all_locks();
 
   /*
     It is OK failing to load procs_priv table because we may be

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2009-12-03 23:52:05 +0000
+++ b/sql/sql_base.cc	2009-12-04 23:02:48 +0000
@@ -1478,11 +1478,22 @@ 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;
 }
 
@@ -2284,7 +2295,7 @@ open_table_get_mdl_lock(THD *thd, TABLE_
 {
   thd->mdl_context.add_request(mdl_request);
 
-  if (table_list->open_type)
+  if (table_list->lock_strategy)
   {
     /*
       In case of CREATE TABLE .. If NOT EXISTS .. SELECT, the table
@@ -2358,10 +2369,16 @@ open_table_get_mdl_lock(THD *thd, TABLE_
   IMPLEMENTATION
     Uses a cache of open tables to find a table not in use.
 
-    If table list element for the table to be opened has "open_type" set
-    to OPEN_OR_CREATE and table does not exist, this function will take
-    exclusive metadata lock on the table, also it will do this if
-    "open_type" is TAKE_EXCLUSIVE_MDL.
+    If TABLE_LIST::open_strategy is set to OPEN_IF_EXISTS, the table is opened
+    only if it exists. If the open strategy is OPEN_STUB, the underlying table
+    is never opened. In both cases, metadata locks are always taken according
+    to the lock strategy.
+
+    This function will take a exclusive metadata lock on the table if
+    TABLE_LIST::lock_strategy is EXCLUSIVE_DOWNGRADABLE_MDL or EXCLUSIVE_MDL.
+    If the lock strategy is EXCLUSIVE_DOWNGRADABLE_MDL and opening the table
+    is successful, the exclusive metadata lock is downgraded to a shared
+    lock.
 
   RETURN
     TRUE  Open failed. "action" parameter may contain type of action
@@ -2595,7 +2612,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
     DBUG_RETURN(TRUE);
   }
 
-  if (table_list->open_type == TABLE_LIST::OPEN_OR_CREATE)
+  if (table_list->open_strategy == TABLE_LIST::OPEN_IF_EXISTS)
   {
     bool exists;
 
@@ -2609,7 +2626,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
     }
     /* Table exists. Let us try to open it. */
   }
-  else if (table_list->open_type == TABLE_LIST::TAKE_EXCLUSIVE_MDL)
+  else if (table_list->open_strategy == TABLE_LIST::OPEN_STUB)
   {
     pthread_mutex_unlock(&LOCK_open);
     DBUG_RETURN(FALSE);
@@ -2794,7 +2811,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
     table exists now we should downgrade our exclusive metadata
     lock on this table to shared metadata lock.
   */
-  if (table_list->open_type == TABLE_LIST::OPEN_OR_CREATE)
+  if (table_list->lock_strategy == TABLE_LIST::EXCLUSIVE_DOWNGRADABLE_MDL)
     mdl_ticket->downgrade_exclusive_lock();
 
   table->mdl_ticket= mdl_ticket;
@@ -3623,7 +3640,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");
   /*
     temporary mem_root for new .frm parsing.
@@ -3764,6 +3781,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
@@ -3841,7 +3870,7 @@ int open_tables(THD *thd, TABLE_LIST **s
       Special types of open can succeed but still don't set
       TABLE_LIST::table to anything.
     */
-    if (tables->open_type && !tables->table)
+    if (tables->open_strategy && !tables->table)
       continue;
 
     /*
@@ -4122,7 +4151,7 @@ retry:
   if (!error)
   {
     /*
-      We can't have a view or some special "open_type" in this function
+      We can't have a view or some special "open_strategy" in this function
       so there should be a TABLE instance.
     */
     DBUG_ASSERT(table_list->table);
@@ -4662,6 +4691,8 @@ 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);
+  if (!thd->locked_tables_mode)
+    thd->mdl_context.release_all_locks();
 }
 
 

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2009-12-03 23:52:05 +0000
+++ b/sql/sql_class.cc	2009-12-04 23:02:48 +0000
@@ -995,8 +995,18 @@ void THD::cleanup(void)
     trans_rollback(this);
     xid_cache_delete(&transaction.xid_state);
   }
+
   locked_tables_list.unlock_locked_tables(this);
 
+  /*
+    If the thread was in the middle of an ongoing transaction (rolled
+    back a few lines above) or under LOCK TABLES (unlocked the tables
+    and left the mode a few lines above), there will be outstanding
+    metadata locks. Release them.
+  */
+  DBUG_ASSERT(open_tables == NULL);
+  mdl_context.release_all_locks();
+
 #if defined(ENABLED_DEBUG_SYNC)
   /* End the Debug Sync Facility. See debug_sync.cc. */
   debug_sync_end_thread(this);

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2009-12-03 23:52:05 +0000
+++ b/sql/sql_parse.cc	2009-12-04 23:02:48 +0000
@@ -122,11 +122,11 @@ static bool some_non_temp_table_to_be_up
   @param mask   Bitmask used for the SQL command match.
 
 */
-static bool opt_implicit_commit(THD *thd, uint mask)
+static bool stmt_causes_implicit_commit(THD *thd, uint mask)
 {
   LEX *lex= thd->lex;
-  bool res= FALSE, skip= FALSE;
-  DBUG_ENTER("opt_implicit_commit");
+  bool skip= FALSE;
+  DBUG_ENTER("stmt_causes_implicit_commit");
 
   if (!(sql_command_flags[lex->sql_command] & mask))
     DBUG_RETURN(FALSE);
@@ -147,15 +147,7 @@ static bool opt_implicit_commit(THD *thd
     break;
   }
 
-  if (!skip)
-  {
-    /* 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);
-  }
-
-  DBUG_RETURN(res);
+  DBUG_RETURN(!skip);
 }
 
 
@@ -1168,6 +1160,9 @@ bool dispatch_command(enum enum_server_c
     ulong options= (ulong) (uchar) packet[0];
     if (trans_commit_implicit(thd))
       break;
+    close_thread_tables(thd);
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
     if (check_global_access(thd,RELOAD_ACL))
       break;
     general_log_print(thd, command, NullS);
@@ -1196,6 +1191,9 @@ bool dispatch_command(enum enum_server_c
       break;
     if (trans_commit_implicit(thd))
       break;
+    close_thread_tables(thd);
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
     my_ok(thd);
     break;
   }
@@ -1942,8 +1940,18 @@ mysql_execute_command(THD *thd)
     not run in it's own transaction it may simply never appear on
     the slave in case the outside transaction rolls back.
   */
-  if (opt_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN))
-    goto error;
+  if (stmt_causes_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN))
+  {
+    /* 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. */
+    if (trans_commit_implicit(thd))
+      goto error;
+    /* Close tables and release metadata locks. */
+    close_thread_tables(thd);
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
+  }
 
   switch (lex->sql_command) {
 
@@ -2363,7 +2371,9 @@ case SQLCOM_PREPARE:
       if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
       {
         lex->link_first_table_back(create_table, link_to_local);
-        create_table->open_type= TABLE_LIST::OPEN_OR_CREATE;
+        /* Set strategies: reset default or 'prepared' values. */
+        create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
+        create_table->lock_strategy= TABLE_LIST::EXCLUSIVE_DOWNGRADABLE_MDL;
       }
 
       if (!(res= open_and_lock_tables(thd, lex->query_tables)))
@@ -3306,6 +3316,7 @@ end_with_restore_list:
     if (thd->options & OPTION_TABLE_LOCK)
     {
       trans_commit_implicit(thd);
+      thd->mdl_context.release_all_locks();
       thd->options&= ~(OPTION_TABLE_LOCK);
     }
     if (thd->global_read_lock)
@@ -3317,6 +3328,8 @@ end_with_restore_list:
     /* we must end the trasaction first, regardless of anything */
     if (trans_commit_implicit(thd))
       goto error;
+    /* release transactional metadata locks. */
+    thd->mdl_context.release_all_locks();
     if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
                            FALSE, UINT_MAX, FALSE))
       goto error;
@@ -3346,6 +3359,13 @@ end_with_restore_list:
       */
       trans_rollback_stmt(thd);
       trans_commit_implicit(thd);
+      /*
+        Close tables and release metadata locks otherwise a later call to
+        close_thread_tables might not release the locks if autocommit is off.
+      */
+      close_thread_tables(thd);
+      DBUG_ASSERT(!thd->locked_tables_mode);
+      thd->mdl_context.release_all_locks();
       thd->options&= ~(OPTION_TABLE_LOCK);
     }
     else
@@ -3836,6 +3856,8 @@ end_with_restore_list:
                 thd->locked_tables_mode == LTM_LOCK_TABLES);
     if (trans_commit(thd))
       goto error;
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
     /* Begin transaction with the same isolation level. */
     if (lex->tx_chain && trans_begin(thd))
       goto error;
@@ -3849,6 +3871,8 @@ end_with_restore_list:
                 thd->locked_tables_mode == LTM_LOCK_TABLES);
     if (trans_rollback(thd))
       goto error;
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
     /* Begin transaction with the same isolation level. */
     if (lex->tx_chain && trans_begin(thd))
       goto error;
@@ -4196,6 +4220,12 @@ create_sp_error:
 
         if (trans_commit_implicit(thd))
           goto error;
+
+        close_thread_tables(thd);
+
+        if (!thd->locked_tables_mode)
+          thd->mdl_context.release_all_locks();
+
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
 	if (sp_automatic_privileges && !opt_noacl &&
 	    sp_revoke_privileges(thd, db, name, 
@@ -4375,11 +4405,15 @@ create_sp_error:
   case SQLCOM_XA_COMMIT:
     if (trans_xa_commit(thd))
       goto error;
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
     my_ok(thd);
     break;
   case SQLCOM_XA_ROLLBACK:
     if (trans_xa_rollback(thd))
       goto error;
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
     my_ok(thd);
     break;
   case SQLCOM_XA_RECOVER:
@@ -4524,10 +4558,20 @@ finish:
     start_waiting_global_read_lock(thd);
   }
 
-  /* If commit fails, we should be able to reset the OK status. */
-  thd->stmt_da->can_overwrite_status= TRUE;
-  opt_implicit_commit(thd, CF_IMPLICIT_COMMIT_END);
-  thd->stmt_da->can_overwrite_status= FALSE;
+  if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END))
+  {
+    /* If commit fails, we should be able to reset the OK status. */
+    thd->stmt_da->can_overwrite_status= TRUE;
+    /* 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. */
+    trans_commit_implicit(thd);
+    /* Close tables and release metadata locks. */
+    close_thread_tables(thd);
+    if (!thd->locked_tables_mode)
+      thd->mdl_context.release_all_locks();
+    thd->stmt_da->can_overwrite_status= FALSE;
+  }
 
   DBUG_RETURN(res || thd->is_error());
 }
@@ -6508,6 +6552,9 @@ bool reload_acl_and_cache(THD *thd, ulon
     query_cache.flush();			// RESET QUERY CACHE
   }
 #endif /*HAVE_QUERY_CACHE*/
+
+  DBUG_ASSERT(thd->locked_tables_mode || !thd->mdl_context.has_locks());
+
   /*
     Note that if REFRESH_READ_LOCK bit is set then REFRESH_TABLES is set too
     (see sql_yacc.yy)

=== modified file 'sql/sql_plugin.cc'
--- a/sql/sql_plugin.cc	2009-12-03 23:29:40 +0000
+++ b/sql/sql_plugin.cc	2009-12-04 23:02:48 +0000
@@ -1349,6 +1349,7 @@ static void plugin_load(MEM_ROOT *tmp_ro
 #ifdef EMBEDDED_LIBRARY
   bool table_exists;
 #endif /* EMBEDDED_LIBRARY */
+  MDL_request mdl_request;
   DBUG_ENTER("plugin_load");
 
   if (!(new_thd= new THD))
@@ -1366,7 +1367,8 @@ static void plugin_load(MEM_ROOT *tmp_ro
   tables.alias= tables.table_name= (char*)"plugin";
   tables.lock_type= TL_READ;
   tables.db= new_thd->db;
-  alloc_mdl_requests(&tables, tmp_root);
+  tables.mdl_request= &mdl_request;
+  mdl_request.init(0, tables.db, tables.table_name);
 
 #ifdef EMBEDDED_LIBRARY
   /*

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2009-11-30 22:13:06 +0000
+++ b/sql/sql_prepare.cc	2009-12-04 23:02:48 +0000
@@ -1673,7 +1673,13 @@ static bool mysql_test_create_table(Prep
     if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
     {
       lex->link_first_table_back(create_table, link_to_local);
-      create_table->open_type= TABLE_LIST::OPEN_OR_CREATE;
+      /*
+        The open and lock strategies will be set again once the
+        statement is executed. These values are only meaningful
+        for the prepare phase.
+      */
+      create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
+      create_table->lock_strategy= TABLE_LIST::SHARED_MDL;
     }
 
     if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
@@ -3130,6 +3136,7 @@ bool Prepared_statement::prepare(const c
   bool error;
   Statement stmt_backup;
   Query_arena *old_stmt_arena;
+  MDL_ticket *mdl_savepoint= NULL;
   DBUG_ENTER("Prepared_statement::prepare");
   /*
     If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql.
@@ -3188,6 +3195,13 @@ bool Prepared_statement::prepare(const c
   */
   DBUG_ASSERT(thd->change_list.is_empty());
 
+  /*
+    Marker used to release metadata locks acquired while the prepared
+    statement is being checked.
+  */
+  if (thd->in_multi_stmt_transaction())
+    mdl_savepoint= thd->mdl_context.mdl_savepoint();
+
   /* 
    The only case where we should have items in the thd->free_list is
    after stmt->set_params_from_vars(), which may in some cases create
@@ -3211,6 +3225,15 @@ bool Prepared_statement::prepare(const c
 
   lex_end(lex);
   cleanup_stmt();
+  /*
+    If not inside a multi-statement transaction, the metadata locks have
+    already been released and the rollback_to_savepoint is a nop.
+    Otherwise, release acquired locks -- a NULL mdl_savepoint means that
+    all locks are going to be released or that the transaction didn't
+    own any locks.
+  */
+  if (!thd->locked_tables_mode)
+    thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
   thd->restore_backup_statement(this, &stmt_backup);
   thd->stmt_arena= old_stmt_arena;
 

=== modified file 'sql/sql_servers.cc'
--- a/sql/sql_servers.cc	2009-12-03 23:29:40 +0000
+++ b/sql/sql_servers.cc	2009-12-04 23:02:48 +0000
@@ -39,6 +39,7 @@
 #include <stdarg.h>
 #include "sp_head.h"
 #include "sp.h"
+#include "transaction.h"
 
 /*
   We only use 1 mutex to guard the data structures - THR_LOCK_servers.
@@ -224,9 +225,6 @@ bool servers_reload(THD *thd)
   bool return_val= TRUE;
   DBUG_ENTER("servers_reload");
 
-  /* Can't have locked tables here */
-  thd->locked_tables_list.unlock_locked_tables(thd);
-
   DBUG_PRINT("info", ("locking servers_cache"));
   rw_wrlock(&THR_LOCK_servers);
 
@@ -252,7 +250,10 @@ bool servers_reload(THD *thd)
   }
 
 end:
+  trans_commit_implicit(thd);
   close_thread_tables(thd);
+  if (!thd->locked_tables_mode)
+    thd->mdl_context.release_all_locks();
   DBUG_PRINT("info", ("unlocking servers_cache"));
   rw_unlock(&THR_LOCK_servers);
   DBUG_RETURN(return_val);

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2009-12-03 23:52:05 +0000
+++ b/sql/sql_table.cc	2009-12-04 23:02:48 +0000
@@ -1974,7 +1974,8 @@ int mysql_rm_table_part2(THD *thd, TABLE
     }
 
     /* Probably a non-temporary table. */
-    non_temp_tables_count++;
+    if (!drop_temporary)
+      non_temp_tables_count++;
 
     /*
       If row-based replication is used and the table is not a
@@ -4738,6 +4739,8 @@ static bool mysql_admin_table(THD* thd, 
       trans_commit_stmt(thd);
       trans_commit(thd);
       close_thread_tables(thd);
+      if (!thd->locked_tables_mode)
+        thd->mdl_context.release_all_locks();
       lex->reset_query_tables_list(FALSE);
       table->table=0;				// For query cache
       if (protocol->write())
@@ -4786,7 +4789,10 @@ static bool mysql_admin_table(THD* thd, 
       {
         DBUG_PRINT("admin", ("recreating table"));
         trans_rollback_stmt(thd);
+        trans_rollback(thd);
         close_thread_tables(thd);
+        if (!thd->locked_tables_mode)
+          thd->mdl_context.release_all_locks();
         tmp_disable_binlog(thd); // binlogging is done by caller if wanted
         result_code= mysql_recreate_table(thd, table);
         reenable_binlog(thd);
@@ -4899,14 +4905,17 @@ send_result_message:
         reopen the table and do ha_innobase::analyze() on it.
         We have to end the row, so analyze could return more rows.
       */
+      trans_commit_stmt(thd);
+      trans_commit(thd);
+      close_thread_tables(thd);
+      if (!thd->locked_tables_mode)
+        thd->mdl_context.release_all_locks();
       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;
-      trans_commit_stmt(thd);
-      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;
@@ -4923,7 +4932,10 @@ send_result_message:
       if (thd->stmt_da->is_ok())
         thd->stmt_da->reset_diagnostics_area();
       trans_commit_stmt(thd);
+      trans_commit(thd);
       close_thread_tables(thd);
+      if (!thd->locked_tables_mode)
+        thd->mdl_context.release_all_locks();
       if (!result_code) // recreation went ok
       {
         if ((table->table= open_ltable(thd, table, lock_type, 0)) &&
@@ -5017,6 +5029,7 @@ send_result_message:
         query_cache_invalidate3(thd, table->table, 0);
       }
     }
+    /* Error path, a admin command failed. */
     trans_commit_stmt(thd);
     trans_commit_implicit(thd);
     close_thread_tables(thd);

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2009-12-01 14:39:03 +0000
+++ b/sql/sql_view.cc	2009-12-04 23:02:48 +0000
@@ -395,7 +395,8 @@ bool mysql_create_view(THD *thd, TABLE_L
     goto err;
 
   lex->link_first_table_back(view, link_to_local);
-  view->open_type= TABLE_LIST::TAKE_EXCLUSIVE_MDL;
+  view->open_strategy= TABLE_LIST::OPEN_STUB;
+  view->lock_strategy= TABLE_LIST::EXCLUSIVE_MDL;
 
   if (open_and_lock_tables(thd, lex->query_tables))
   {

=== modified file 'sql/table.h'
--- a/sql/table.h	2009-12-03 23:57:01 +0000
+++ b/sql/table.h	2009-12-04 23:02:48 +0000
@@ -1350,24 +1350,36 @@ struct TABLE_LIST
   bool          prelocking_placeholder;
   /**
      Indicates that if TABLE_LIST object corresponds to the table/view
-     which requires special handling/meta-data locking.
+     which requires special handling.
   */
   enum
   {
-    /* Normal open, shared metadata lock should be taken. */
-    NORMAL_OPEN= 0,
-    /*
-      It's target table of CREATE TABLE ... SELECT so we should
-      either open table if it exists (and take shared metadata lock)
-      or take exclusive metadata lock if it doesn't exist.
-    */
-    OPEN_OR_CREATE,
+    /* Normal open. */
+    OPEN_NORMAL= 0,
+    /* Associate a table share only if the the table exists. */
+    OPEN_IF_EXISTS,
+    /* Don't associate a table share. */
+    OPEN_STUB
+  } open_strategy;
+  /**
+    Indicates the locking strategy for the object being opened:
+    whether the associated metadata lock is shared or exclusive.
+  */
+  enum
+  {
+    /* Take a shared metadata lock before the object is opened. */
+    SHARED_MDL= 0,
     /*
-      It's target view of CREATE/ALTER VIEW. We should take exclusive
-      metadata lock for this table list element.
+       Take a exclusive metadata lock before the object is opened.
+       If opening is successful, downgrade to a shared lock.
     */
-    TAKE_EXCLUSIVE_MDL
-  } open_type;
+    EXCLUSIVE_DOWNGRADABLE_MDL,
+    /* Take a exclusive metadata lock before the object is opened. */
+    EXCLUSIVE_MDL
+  } lock_strategy;
+  /* For transactional locking. */
+  int           lock_timeout;           /* NOWAIT or WAIT [X]               */
+  bool          lock_transactional;     /* If transactional lock requested. */
   bool          internal_tmp_table;
   /** TRUE if an alias for this table was specified in the SQL. */
   bool          is_alias;

=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc	2009-12-03 22:46:14 +0000
+++ b/sql/transaction.cc	2009-12-04 23:02:48 +0000
@@ -99,6 +99,12 @@ bool trans_begin(THD *thd, uint flags)
   if (trans_commit_implicit(thd))
     DBUG_RETURN(TRUE);
 
+  /*
+    Release transactional metadata locks only after the
+    transaction has been committed.
+  */
+  thd->mdl_context.release_all_locks();
+
   thd->options|= OPTION_BEGIN;
   thd->server_status|= SERVER_STATUS_IN_TRANS;
 
@@ -331,6 +337,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);
 }
 
@@ -375,6 +388,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));
 }
 

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2009-12-03 15:47:20 +0000
+++ b/tests/mysql_client_test.c	2009-12-04 23:02:48 +0000
@@ -18479,8 +18479,8 @@ static void test_wl4284_1()
 
   mysql_free_result(result);
 
-  /* set AUTOCOMMIT to OFF */
-  rc= mysql_autocommit(mysql, FALSE);
+  /* set AUTOCOMMIT to ON */
+  rc= mysql_autocommit(mysql, TRUE);
   myquery(rc);
 
   rc= mysql_query(mysql, "DROP TABLE trans");
@@ -18637,6 +18637,8 @@ static void test_bug40365(void)
       DIE_UNLESS(tm[i].day == 0);
   }
   mysql_stmt_close(stmt);
+  rc= mysql_commit(mysql);
+  myquery(rc);
 
   DBUG_VOID_RETURN;
 }


Attachment: [text/bzr-bundle] bzr/kostja@sun.com-20091204230248-b5j26g5bcprw0e4d.bundle
Thread
bzr commit into mysql-5.6-next-mr branch (kostja:2995) Bug#989 WL#4284Konstantin Osipov5 Dec