List:Commits« Previous MessageNext Message »
From:Magne Mahre Date:June 8 2010 5:47pm
Subject:bzr commit into mysql-trunk-runtime branch (magne.mahre:3047)
Bug#20837 Bug#46527 Bug#53343 Bug#53346
View as plain text  
#At file:///data/x/mysql-trunk-runtime-20837/ based on revid:kostja@stripped

 3047 Magne Mahre	2010-06-08 [merge]
      Bug#20837 Apparent change of isolation level during transaction
      Bug#46527 COMMIT AND CHAIN RELEASE does not make sense
      Bug#53343 completion_type=1, COMMIT/ROLLBACK AND CHAIN don't 
                preserve the isolation level
      Bug#53346 completion_type has strange effect in a stored 
                procedure/prepared statement
      
      Added test cases to verify the expected behaviour of :
       SET SESSION TRANSACTION ISOLATION LEVEL, 
       SET TRANSACTION ISOLATION LEVEL,
       @@completion_type,
       COMMIT AND CHAIN,
       ROLLBACK AND CHAIN
       ..and some combinations of the above

    added:
      mysql-test/r/commit.result
      mysql-test/t/commit.test
    modified:
      mysql-test/r/parser.result
      mysql-test/r/partition_innodb_semi_consistent.result
      mysql-test/r/ps.result
      mysql-test/suite/binlog/r/binlog_innodb.result
      mysql-test/suite/binlog/t/binlog_innodb.test
      mysql-test/t/parser.test
      mysql-test/t/partition_innodb_semi_consistent.test
      sql/handler.cc
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_lex.h
      sql/sql_parse.cc
      sql/sql_priv.h
      sql/sql_yacc.yy
      sql/sys_vars.cc
      sql/sys_vars.h
      sql/transaction.cc
=== added file 'mysql-test/r/commit.result'
--- a/mysql-test/r/commit.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/commit.result	2010-06-08 17:47:10 +0000
@@ -0,0 +1,272 @@
+#
+# Bug#20837 Apparent change of isolation level 
+#           during transaction
+#
+# Bug#53343 completion_type=1, COMMIT/ROLLBACK 
+#           AND CHAIN don't preserve the isolation 
+#           level
+connection default;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+CREATE TABLE t1 (s1 INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+COMMIT;
+START TRANSACTION;
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+ERROR 25001: Transaction isolation level can't be changed while a transaction is in progress
+COMMIT;
+SET @@autocommit=0;
+COMMIT;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+START TRANSACTION;
+SELECT @@tx_isolation;
+@@tx_isolation
+REPEATABLE-READ
+Should be REPEATABLE READ
+SELECT * FROM t1;
+s1
+1
+2
+SELECT @@tx_isolation;
+@@tx_isolation
+REPEATABLE-READ
+Should be REPEATABLE READ
+INSERT INTO t1 VALUES (-1);
+SELECT @@tx_isolation;
+@@tx_isolation
+REPEATABLE-READ
+Should be REPEATABLE READ
+COMMIT;
+START TRANSACTION;
+SELECT * FROM t1;
+s1
+1
+2
+-1
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+connection con1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1000);
+COMMIT;
+connection default
+We should not be able to read the '1000'
+SELECT * FROM t1;
+s1
+1
+2
+-1
+COMMIT;
+Now, the '1000' should appear.
+START TRANSACTION;
+SELECT * FROM t1;
+s1
+1
+2
+-1
+1000
+COMMIT;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+connection default
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+connection con1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+connection default
+SELECT COUNT(*) FROM t1 WHERE s1 = 1001;
+COUNT(*)
+1
+Should be 1
+COMMIT AND CHAIN;
+connection con1
+INSERT INTO t1 VALUES (1002);
+COMMIT;
+connection default
+SELECT COUNT(*) FROM t1 WHERE s1 = 1002;
+COUNT(*)
+1
+Should be 1
+COMMIT;
+SELECT * FROM t1;
+s1
+1
+2
+-1
+1000
+1001
+1002
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT;
+connection default
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+connection con1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+connection default
+SELECT COUNT(*) FROM t1 WHERE s1 = 1001;
+COUNT(*)
+1
+Should be 1
+ROLLBACK AND CHAIN;
+connection con1
+INSERT INTO t1 VALUES (1002);
+COMMIT;
+connection default
+SELECT COUNT(*) FROM t1 WHERE s1 = 1002;
+COUNT(*)
+1
+Should be 1
+COMMIT;
+SELECT * FROM t1;
+s1
+1
+2
+-1
+1001
+1002
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT;
+SET @@completion_type=1;
+connection default
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+connection con1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+connection default
+SELECT * FROM t1 WHERE s1 >= 1000;
+s1
+1001
+Should see 1001
+COMMIT AND NO CHAIN;
+default transaction is now in REPEATABLE READ
+connection con1
+INSERT INTO t1 VALUES (1002);
+COMMIT;
+connection default
+SELECT * FROM t1 WHERE s1 >= 1000;
+s1
+1001
+1002
+Should see 1001 and 1002
+connection con1
+INSERT INTO t1 VALUES (1003);
+COMMIT;
+connection default
+SELECT * FROM t1 WHERE s1 >= 1000;
+s1
+1001
+1002
+Should see 1001 and 1002, but NOT 1003
+COMMIT;
+SELECT * FROM t1;
+s1
+1
+2
+-1
+1001
+1002
+1003
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT AND NO CHAIN;
+SET @@completion_type=0;
+COMMIT;
+connection default
+SET @@completion_type=1;
+COMMIT AND NO CHAIN;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+connection con1
+START TRANSACTION;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+connection default
+SELECT * FROM t1 WHERE s1 >= 1000;
+s1
+1001
+Should see 1001
+ROLLBACK AND NO CHAIN;
+default transaction is now in REPEATABLE READ
+connection con1
+INSERT INTO t1 VALUES (1002);
+COMMIT;
+connection default
+SELECT * FROM t1 WHERE s1 >= 1000;
+s1
+1001
+1002
+Should see 1001 and 1002
+connection con1
+INSERT INTO t1 VALUES (1003);
+COMMIT;
+connection default
+SELECT * FROM t1 WHERE s1 >= 1000;
+s1
+1001
+1002
+Should see 1001 and 1002, but NOT 1003
+COMMIT;
+SELECT * FROM t1;
+s1
+1
+2
+-1
+1001
+1002
+1003
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT AND NO CHAIN;
+SET @@completion_type=0;
+COMMIT;
+connection default
+SET TRANSACTION ISOLATION LEVEL	READ COMMITTED;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+START TRANSACTION;
+SELECT * FROM t1;
+s1
+1
+2
+-1
+connection con1
+INSERT INTO t1 VALUES (1000);
+COMMIT;
+connection default
+SELECT * FROM t1;
+s1
+1
+2
+-1
+Should get same result as above (i.e should not read '1000')
+COMMIT;
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT;
+SET @@completion_type=1;
+COMMIT AND NO CHAIN;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (1000);
+SELECT * FROM t1;
+s1
+1000
+Should read '1000'
+connection con1
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+connection default
+SELECT * FROM t1;
+s1
+1000
+Should only read the '1000' as this transaction is now in REP READ
+COMMIT AND NO CHAIN;
+SET @@completion_type=0;
+COMMIT AND NO CHAIN;
+SET @autocommit=1;
+COMMIT;
+DROP TABLE t1;
+#
+# End of test cases for Bug#20837
+#

=== modified file 'mysql-test/r/parser.result'
--- a/mysql-test/r/parser.result	2009-12-22 16:23:13 +0000
+++ b/mysql-test/r/parser.result	2010-05-07 16:28:59 +0000
@@ -618,3 +618,48 @@ DROP TABLE t1, t2, t3;
 #
 # End of 5.1 tests
 #
+# Bug#46527 "COMMIT AND CHAIN RELEASE does not make sense"
+#
+COMMIT AND CHAIN RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE' at line 1
+COMMIT AND NO CHAIN RELEASE;
+COMMIT RELEASE;
+COMMIT CHAIN RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHAIN RELEASE' at line 1
+COMMIT NO CHAIN RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHAIN RELEASE' at line 1
+COMMIT AND NO RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE' at line 1
+COMMIT AND RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE' at line 1
+COMMIT NO RELEASE;
+COMMIT CHAIN NO RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHAIN NO RELEASE' at line 1
+COMMIT NO CHAIN NO RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHAIN NO RELEASE' at line 1
+COMMIT AND RELEASE CHAIN;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE CHAIN' at line 1
+COMMIT AND NO CHAIN NO RELEASE;
+ROLLBACK AND CHAIN RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE' at line 1
+ROLLBACK AND NO CHAIN RELEASE;
+ROLLBACK RELEASE;
+ROLLBACK CHAIN RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHAIN RELEASE' at line 1
+ROLLBACK NO CHAIN RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHAIN RELEASE' at line 1
+ROLLBACK AND NO RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE' at line 1
+ROLLBACK AND RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE' at line 1
+ROLLBACK NO RELEASE;
+ROLLBACK CHAIN NO RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHAIN NO RELEASE' at line 1
+ROLLBACK NO CHAIN NO RELEASE;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CHAIN NO RELEASE' at line 1
+ROLLBACK AND RELEASE CHAIN;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RELEASE CHAIN' at line 1
+ROLLBACK AND NO CHAIN NO RELEASE;
+#
+# End of 5.5 tests
+#

=== modified file 'mysql-test/r/partition_innodb_semi_consistent.result'
--- a/mysql-test/r/partition_innodb_semi_consistent.result	2010-05-25 20:01:38 +0000
+++ b/mysql-test/r/partition_innodb_semi_consistent.result	2010-06-08 17:47:10 +0000
@@ -18,6 +18,7 @@ set autocommit=0;
 update t1 set a=10 where a=5;
 ERROR HY000: Lock wait timeout exceeded; try restarting transaction
 commit;
+commit;
 set session transaction isolation level read committed;
 update t1 set a=10 where a=5;
 select * from t1 where a=2 for update;

=== modified file 'mysql-test/r/ps.result'
--- a/mysql-test/r/ps.result	2010-05-07 16:17:55 +0000
+++ b/mysql-test/r/ps.result	2010-06-08 17:47:10 +0000
@@ -695,11 +695,11 @@ REPEATABLE-READ
 set transaction isolation level read committed;
 execute stmt;
 @@tx_isolation
-READ-COMMITTED
+REPEATABLE-READ
 set transaction isolation level serializable;
 execute stmt;
 @@tx_isolation
-SERIALIZABLE
+REPEATABLE-READ
 set @@tx_isolation=default;
 execute stmt;
 @@tx_isolation

=== modified file 'mysql-test/suite/binlog/r/binlog_innodb.result'
--- a/mysql-test/suite/binlog/r/binlog_innodb.result	2010-04-28 12:47:49 +0000
+++ b/mysql-test/suite/binlog/r/binlog_innodb.result	2010-05-07 16:28:59 +0000
@@ -2,65 +2,65 @@ SET BINLOG_FORMAT=MIXED;
 RESET MASTER;
 CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=INNODB;
 INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6);
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
 UPDATE t1 SET b = 2*a WHERE a > 1;
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+BEGIN;
 UPDATE t1 SET b = a * a WHERE a > 3;
 COMMIT;
 SET BINLOG_FORMAT=STATEMENT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+BEGIN;
 UPDATE t1 SET b = 1*a WHERE a > 1;
 ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+BEGIN;
 UPDATE t1 SET b = 2*a WHERE a > 2;
 ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
 UPDATE t1 SET b = 3*a WHERE a > 3;
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+BEGIN;
 UPDATE t1 SET b = 4*a WHERE a > 4;
 COMMIT;
 SET BINLOG_FORMAT=MIXED;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+BEGIN;
 UPDATE t1 SET b = 1*a WHERE a > 1;
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+BEGIN;
 UPDATE t1 SET b = 2*a WHERE a > 2;
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
 UPDATE t1 SET b = 3*a WHERE a > 3;
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+BEGIN;
 UPDATE t1 SET b = 4*a WHERE a > 4;
 COMMIT;
 SET BINLOG_FORMAT=ROW;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+BEGIN;
 UPDATE t1 SET b = 1*a WHERE a > 1;
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+BEGIN;
 UPDATE t1 SET b = 2*a WHERE a > 2;
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
 UPDATE t1 SET b = 3*a WHERE a > 3;
 COMMIT;
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+BEGIN;
 UPDATE t1 SET b = 4*a WHERE a > 4;
 COMMIT;
 show binlog events from <binlog_start>;

=== modified file 'mysql-test/suite/binlog/t/binlog_innodb.test'
--- a/mysql-test/suite/binlog/t/binlog_innodb.test	2009-10-18 03:57:38 +0000
+++ b/mysql-test/suite/binlog/t/binlog_innodb.test	2010-05-07 16:28:59 +0000
@@ -8,14 +8,14 @@ RESET MASTER;
 CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=INNODB;
 INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6);
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
 # Should be logged as statement
 UPDATE t1 SET b = 2*a WHERE a > 1;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+BEGIN;
 # Should be logged as rows
 UPDATE t1 SET b = a * a WHERE a > 3;
 COMMIT;
@@ -25,69 +25,69 @@ COMMIT;
 
 SET BINLOG_FORMAT=STATEMENT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+BEGIN;
 error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE;
 UPDATE t1 SET b = 1*a WHERE a > 1;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+BEGIN;
 error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE;
 UPDATE t1 SET b = 2*a WHERE a > 2;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
 UPDATE t1 SET b = 3*a WHERE a > 3;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+BEGIN;
 UPDATE t1 SET b = 4*a WHERE a > 4;
 COMMIT;
 
 SET BINLOG_FORMAT=MIXED;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+BEGIN;
 UPDATE t1 SET b = 1*a WHERE a > 1;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+BEGIN;
 UPDATE t1 SET b = 2*a WHERE a > 2;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
 UPDATE t1 SET b = 3*a WHERE a > 3;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+BEGIN;
 UPDATE t1 SET b = 4*a WHERE a > 4;
 COMMIT;
 
 SET BINLOG_FORMAT=ROW;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+BEGIN;
 UPDATE t1 SET b = 1*a WHERE a > 1;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+BEGIN;
 UPDATE t1 SET b = 2*a WHERE a > 2;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+BEGIN;
 UPDATE t1 SET b = 3*a WHERE a > 3;
 COMMIT;
 
-BEGIN;
 SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+BEGIN;
 UPDATE t1 SET b = 4*a WHERE a > 4;
 COMMIT;
 

=== added file 'mysql-test/t/commit.test'
--- a/mysql-test/t/commit.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/commit.test	2010-06-08 17:47:10 +0000
@@ -0,0 +1,350 @@
+--source include/have_innodb.inc
+
+connect (con1,localhost,root,,);
+
+--echo #
+--echo # Bug#20837 Apparent change of isolation level 
+--echo #           during transaction
+--echo #
+--echo # Bug#53343 completion_type=1, COMMIT/ROLLBACK 
+--echo #           AND CHAIN don't preserve the isolation 
+--echo #           level
+#
+# A set of test cases that verifies operation of
+# transaction isolation level and chaining is 
+# provided
+
+# init
+--echo connection default;
+connection default;
+
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+CREATE TABLE t1 (s1 INT) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1),(2);
+COMMIT;
+
+#
+# Verify that SET TRANS ISO LEVEL is not allowed 
+# inside a transaction
+#
+START TRANSACTION;
+--error ER_CANT_CHANGE_TX_ISOLATION
+SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+COMMIT;
+
+#
+# Verify consistent output from 
+# SELECT @@tx_isolation  (Bug#20837)
+#
+# The transaction will be in READ UNCOMMITTED mode,
+# but SELECT @@tx_isolation should report the session
+# value, which is REPEATABLE READ
+#
+SET @@autocommit=0;
+COMMIT;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+START TRANSACTION;
+SELECT @@tx_isolation;
+--echo Should be REPEATABLE READ
+SELECT * FROM t1;
+SELECT @@tx_isolation;
+--echo Should be REPEATABLE READ
+INSERT INTO t1 VALUES (-1);
+SELECT @@tx_isolation;
+--echo Should be REPEATABLE READ
+COMMIT;
+
+#
+# Verify that a change in the session variable
+# does not affect the currently started
+# transaction
+#
+START TRANSACTION;
+SELECT * FROM t1;
+SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+
+--echo connection con1
+connection con1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1000);
+COMMIT;
+
+--echo connection default
+connection default;
+--echo We should not be able to read the '1000'
+SELECT * FROM t1;
+COMMIT;
+
+--echo Now, the '1000' should appear.
+START TRANSACTION;
+SELECT * FROM t1;
+COMMIT;
+
+# restore the session value
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+
+#
+# A set of test cases for verification that
+# isolation level during chaining works. MySQL
+# has three variants of chaining, i.e
+# COMMIT AND CHAIN, ROLLBACK AND CHAIN, and
+# the use of @completion_type
+#
+
+#
+# Verify isolation level with COMMIT AND CHAIN
+#
+# COMMIT AND CHAIN causes a new transaction to
+# begin as soon as the current ends, and the new
+# transaction will have the same tran. iso. level
+# as the first.
+#
+--echo connection default
+connection default;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+
+--echo connection con1
+connection con1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT COUNT(*) FROM t1 WHERE s1 = 1001;
+--echo Should be 1
+COMMIT AND CHAIN;
+
+--echo connection con1
+connection con1;
+INSERT INTO t1 VALUES (1002);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT COUNT(*) FROM t1 WHERE s1 = 1002;
+--echo Should be 1
+COMMIT;
+SELECT * FROM t1;
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT;
+
+#
+# Verify isolation level with ROLLBACK AND CHAIN
+#
+--echo connection default
+connection default;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+
+--echo connection con1
+connection con1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT COUNT(*) FROM t1 WHERE s1 = 1001;
+--echo Should be 1
+ROLLBACK AND CHAIN;
+
+--echo connection con1
+connection con1;
+INSERT INTO t1 VALUES (1002);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT COUNT(*) FROM t1 WHERE s1 = 1002;
+--echo Should be 1
+COMMIT;
+SELECT * FROM t1;
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT;
+
+#
+# Verify isolation level with @completion_type=1.
+# (A @@completion_type value of 1 is equivalentl to 
+# explicitly adding "AND CHAIN" to COMMIT or ROLLBACK)
+#
+
+#
+# Verify that COMMIT AND NO CHAIN  overrides the value
+# of @@completion_type
+#
+SET @@completion_type=1;
+
+--echo connection default
+connection default;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+
+--echo connection con1
+connection con1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT * FROM t1 WHERE s1 >= 1000;
+--echo Should see 1001
+COMMIT AND NO CHAIN;
+--echo default transaction is now in REPEATABLE READ
+
+--echo connection con1
+connection con1;
+INSERT INTO t1 VALUES (1002);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT * FROM t1 WHERE s1 >= 1000;
+--echo Should see 1001 and 1002
+
+--echo connection con1
+connection con1;
+INSERT INTO t1 VALUES (1003);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT * FROM t1 WHERE s1 >= 1000;
+--echo Should see 1001 and 1002, but NOT 1003
+COMMIT;
+
+SELECT * FROM t1;
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT AND NO CHAIN;
+SET @@completion_type=0;
+COMMIT;
+
+#
+# Verify that ROLLBACK AND NO CHAIN  overrides the value
+# of @@completion_type
+#
+--echo connection default
+connection default;
+SET @@completion_type=1;
+COMMIT AND NO CHAIN;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+
+--echo connection con1
+connection con1;
+START TRANSACTION;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT * FROM t1 WHERE s1 >= 1000;
+--echo Should see 1001
+ROLLBACK AND NO CHAIN;
+--echo default transaction is now in REPEATABLE READ
+
+--echo connection con1
+connection con1;
+INSERT INTO t1 VALUES (1002);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT * FROM t1 WHERE s1 >= 1000;
+--echo Should see 1001 and 1002
+
+--echo connection con1
+connection con1;
+INSERT INTO t1 VALUES (1003);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT * FROM t1 WHERE s1 >= 1000;
+--echo Should see 1001 and 1002, but NOT 1003
+
+COMMIT;
+SELECT * FROM t1;
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT AND NO CHAIN;
+SET @@completion_type=0;
+COMMIT;
+
+#
+# Verify that in the sequence:
+#  SET TRANSACTION ISOLATION LEVEL
+#  SET SESSION ISOLATION LEVEL
+#
+# SET SESSION ISOLATION LEVEL has precedence over 
+# SET TRANSACTION.  (Note that this is _not_ 
+# in accordance with ISO 9075.)
+#
+--echo connection default
+connection default;
+
+SET TRANSACTION ISOLATION LEVEL	READ COMMITTED;
+SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+START TRANSACTION;
+SELECT * FROM t1;
+
+--echo connection con1
+connection con1;
+INSERT INTO t1 VALUES (1000);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT * FROM t1;
+--echo Should get same result as above (i.e should not read '1000')
+COMMIT;
+
+DELETE FROM t1 WHERE s1 >= 1000;
+COMMIT;
+
+
+#
+# Verify that a transaction ended with an
+# implicit commit (i.e a DDL statement), the
+# @@completetion_type setting is ignored, and
+# the next transaction's isolation level is
+# the session level.
+#
+SET @@completion_type=1;
+COMMIT AND NO CHAIN;
+SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
+START TRANSACTION;
+TRUNCATE TABLE t1;
+INSERT INTO t1 VALUES (1000);
+SELECT * FROM t1;
+--echo Should read '1000'
+
+--echo connection con1
+connection con1;
+INSERT INTO t1 VALUES (1001);
+COMMIT;
+
+--echo connection default
+connection default;
+SELECT * FROM t1;
+--echo Should only read the '1000' as this transaction is now in REP READ
+COMMIT AND NO CHAIN;
+
+SET @@completion_type=0;
+COMMIT AND NO CHAIN;
+
+
+#
+# Cleanup
+#
+SET @autocommit=1;
+COMMIT;
+
+disconnect con1;
+
+DROP TABLE t1;
+
+--echo #
+--echo # End of test cases for Bug#20837
+--echo #

=== modified file 'mysql-test/t/parser.test'
--- a/mysql-test/t/parser.test	2009-12-22 16:23:13 +0000
+++ b/mysql-test/t/parser.test	2010-05-07 16:28:59 +0000
@@ -732,3 +732,79 @@ DROP TABLE t1, t2, t3;
 --echo #
 --echo # End of 5.1 tests
 --echo #
+
+--echo # Bug#46527 "COMMIT AND CHAIN RELEASE does not make sense"
+--echo #
+--error ER_PARSE_ERROR
+COMMIT AND CHAIN RELEASE;
+
+COMMIT AND NO CHAIN RELEASE;
+disconnect default;
+connect(default, localhost, root,,);
+
+COMMIT RELEASE;
+disconnect default;
+connect(default, localhost, root,,);
+
+--error ER_PARSE_ERROR
+COMMIT CHAIN RELEASE;
+
+--error ER_PARSE_ERROR
+COMMIT NO CHAIN RELEASE;
+
+--error ER_PARSE_ERROR
+COMMIT AND NO RELEASE;
+--error ER_PARSE_ERROR
+COMMIT AND RELEASE;
+
+COMMIT NO RELEASE;
+--error ER_PARSE_ERROR
+COMMIT CHAIN NO RELEASE;
+--error ER_PARSE_ERROR
+COMMIT NO CHAIN NO RELEASE;
+
+--error ER_PARSE_ERROR
+COMMIT AND RELEASE CHAIN;
+
+COMMIT AND NO CHAIN NO RELEASE;
+
+--error ER_PARSE_ERROR
+ROLLBACK AND CHAIN RELEASE;
+
+ROLLBACK AND NO CHAIN RELEASE;
+disconnect default;
+connect(default, localhost, root,,);
+
+ROLLBACK RELEASE;
+disconnect default;
+connect(default, localhost, root,,);
+
+--error ER_PARSE_ERROR
+ROLLBACK CHAIN RELEASE;
+
+--error ER_PARSE_ERROR
+ROLLBACK NO CHAIN RELEASE;
+disconnect default;
+connect(default, localhost, root,,);
+
+--error ER_PARSE_ERROR
+ROLLBACK AND NO RELEASE;
+
+--error ER_PARSE_ERROR
+ROLLBACK AND RELEASE;
+
+ROLLBACK NO RELEASE;
+
+--error ER_PARSE_ERROR
+ROLLBACK CHAIN NO RELEASE;
+
+--error ER_PARSE_ERROR
+ROLLBACK NO CHAIN NO RELEASE;
+--error ER_PARSE_ERROR
+ROLLBACK AND RELEASE CHAIN;
+
+ROLLBACK AND NO CHAIN NO RELEASE;
+
+--echo #
+--echo # End of 5.5 tests
+--echo #

=== modified file 'mysql-test/t/partition_innodb_semi_consistent.test'
--- a/mysql-test/t/partition_innodb_semi_consistent.test	2010-05-25 20:01:38 +0000
+++ b/mysql-test/t/partition_innodb_semi_consistent.test	2010-06-08 17:47:10 +0000
@@ -31,6 +31,7 @@ set session transaction isolation level
 set autocommit=0;
 -- error ER_LOCK_WAIT_TIMEOUT
 update t1 set a=10 where a=5;
+commit;
 connection a;
 #DELETE FROM t1 WHERE a=5;
 commit;

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2010-05-31 15:29:54 +0000
+++ b/sql/handler.cc	2010-06-08 17:47:10 +0000
@@ -1302,7 +1302,6 @@ int ha_commit_one_phase(THD *thd, bool a
       if (thd->transaction.changed_tables)
         query_cache.invalidate(thd->transaction.changed_tables);
 #endif
-      thd->variables.tx_isolation=thd->session_tx_isolation;
     }
   }
   /* Free resources and perform other cleanup even for 'empty' transactions. */
@@ -1379,8 +1378,6 @@ int ha_rollback_trans(THD *thd, bool all
     if (is_real_trans && thd->transaction_rollback_request &&
         thd->transaction.xid_state.xa_state != XA_NOTR)
       thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno();
-    if (all)
-      thd->variables.tx_isolation=thd->session_tx_isolation;
   }
   /* Always cleanup. Even if nht==0. There may be savepoints. */
   if (is_real_trans)

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2010-05-31 15:29:54 +0000
+++ b/sql/sql_class.cc	2010-06-08 17:47:10 +0000
@@ -353,7 +353,7 @@ int thd_sql_command(const THD *thd)
 extern "C"
 int thd_tx_isolation(const THD *thd)
 {
-  return (int) thd->variables.tx_isolation;
+  return (int) thd->tx_isolation;
 }
 
 extern "C"
@@ -957,7 +957,7 @@ void THD::init(void)
   update_lock_default= (variables.low_priority_updates ?
 			TL_WRITE_LOW_PRIORITY :
 			TL_WRITE);
-  session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
+  tx_isolation= (enum_tx_isolation) variables.tx_isolation;
   update_charset();
   reset_current_stmt_binlog_format_row();
   bzero((char *) &status_var, sizeof(status_var));

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-06-08 08:08:46 +0000
+++ b/sql/sql_class.h	2010-06-08 17:47:10 +0000
@@ -1941,8 +1941,31 @@ public:
   uint	     server_status,open_options;
   enum enum_thread_type system_thread;
   uint       select_number;             //number of select (used for EXPLAIN)
-  /* variables.transaction_isolation is reset to this after each commit */
-  enum_tx_isolation session_tx_isolation;
+  /*
+    Current or next transaction isolation level.
+    When a connection is established, the value is taken from
+    @@session.tx_isolation (default transaction isolation for
+    the session), which is in turn taken from @@global.tx_isolation
+    (the global value).
+    If there is no transaction started, this variable
+    holds the value of the next transaction's isolation level.
+    When a transaction starts, the value stored in this variable
+    becomes "actual".
+    At transaction commit or rollback, we assign this variable
+    again from @@session.tx_isolation.
+    The only statement that can otherwise change the value
+    of this variable is SET TRANSACTION ISOLATION LEVEL.
+    Its purpose is to effect the isolation level of the next
+    transaction in this session. When this statement is executed,
+    the value in this variable is changed. However, since
+    this statement is only allowed when there is no active
+    transaction, this assignment (naturally) only affects the
+    upcoming transaction.
+    At the end of the current active transaction the value is
+    be reset again from @@session.tx_isolation, as described
+    above.
+  */
+  enum_tx_isolation tx_isolation;
   enum_check_fields count_cuted_fields;
 
   DYNAMIC_ARRAY user_var_events;        /* For user variables replication */

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2010-06-06 11:19:29 +0000
+++ b/sql/sql_lex.h	2010-06-08 17:47:10 +0000
@@ -1975,7 +1975,7 @@ struct LEX: public Query_tables_list
   bool autocommit;
   bool verbose, no_write_to_binlog;
 
-  bool tx_chain, tx_release;
+  enum enum_yes_no_unknown tx_chain, tx_release;
   /*
     Special JOIN::prepare mode: changing of query is prohibited.
     When creating a view, we need to just check its syntax omitting

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-06-06 11:19:29 +0000
+++ b/sql/sql_parse.cc	2010-06-08 17:47:10 +0000
@@ -4078,33 +4078,65 @@ end_with_restore_list:
     my_ok(thd);
     break;
   case SQLCOM_COMMIT:
+  {
     DBUG_ASSERT(thd->lock == NULL ||
                 thd->locked_tables_mode == LTM_LOCK_TABLES);
+    bool tx_chain= (lex->tx_chain == TVL_YES ||
+                    (thd->variables.completion_type == 1 &&
+                     lex->tx_chain != TVL_NO));
+    bool tx_release= (lex->tx_release == TVL_YES ||
+                      (thd->variables.completion_type == 2 &&
+                       lex->tx_release != TVL_NO));
     if (trans_commit(thd))
       goto error;
     thd->mdl_context.release_transactional_locks();
     /* Begin transaction with the same isolation level. */
-    if (lex->tx_chain && trans_begin(thd))
+    if (tx_chain)
+    {
+      if (trans_begin(thd))
       goto error;
+    }
+    else
+    {
+      /* Reset the isolation level if no chaining transaction. */
+      thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+    }
     /* Disconnect the current client connection. */
-    if (lex->tx_release)
+    if (tx_release)
       thd->killed= THD::KILL_CONNECTION;
     my_ok(thd);
     break;
+  }
   case SQLCOM_ROLLBACK:
+  {
     DBUG_ASSERT(thd->lock == NULL ||
                 thd->locked_tables_mode == LTM_LOCK_TABLES);
+    bool tx_chain= (lex->tx_chain == TVL_YES ||
+                    (thd->variables.completion_type == 1 &&
+                     lex->tx_chain != TVL_NO));
+    bool tx_release= (lex->tx_release == TVL_YES ||
+                      (thd->variables.completion_type == 2 &&
+                       lex->tx_release != TVL_NO));
     if (trans_rollback(thd))
       goto error;
     thd->mdl_context.release_transactional_locks();
     /* Begin transaction with the same isolation level. */
-    if (lex->tx_chain && trans_begin(thd))
-      goto error;
+    if (tx_chain)
+    {
+      if (trans_begin(thd))
+        goto error;
+    }
+    else
+    {
+      /* Reset the isolation level if no chaining transaction. */
+      thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+    }
     /* Disconnect the current client connection. */
-    if (lex->tx_release)
+    if (tx_release)
       thd->killed= THD::KILL_CONNECTION;
     my_ok(thd);
     break;
+  }
   case SQLCOM_RELEASE_SAVEPOINT:
     if (trans_release_savepoint(thd, lex->ident))
       goto error;
@@ -4607,12 +4639,22 @@ create_sp_error:
     if (trans_xa_commit(thd))
       goto error;
     thd->mdl_context.release_transactional_locks();
+    /*
+      We've just done a commit, reset transaction
+      isolation level to the session default.
+    */
+    thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
     my_ok(thd);
     break;
   case SQLCOM_XA_ROLLBACK:
     if (trans_xa_rollback(thd))
       goto error;
     thd->mdl_context.release_transactional_locks();
+    /*
+      We've just done a rollback, reset transaction
+      isolation level to the session default.
+    */
+    thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
     my_ok(thd);
     break;
   case SQLCOM_XA_RECOVER:

=== modified file 'sql/sql_priv.h'
--- a/sql/sql_priv.h	2010-05-28 22:13:31 +0000
+++ b/sql/sql_priv.h	2010-06-08 17:47:10 +0000
@@ -211,6 +211,11 @@ enum enum_var_type
 
 class sys_var;
 
+enum enum_yes_no_unknown
+{
+  TVL_YES, TVL_NO, TVL_UNKNOWN
+};
+
 #ifdef MYSQL_SERVER
 
 #endif /* MYSQL_SERVER */

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2010-06-07 15:27:40 +0000
+++ b/sql/sql_yacc.yy	2010-06-08 17:47:10 +0000
@@ -767,6 +767,7 @@ static bool add_create_index (LEX *lex,
   enum index_hint_type index_hint;
   enum enum_filetype filetype;
   enum Foreign_key::fk_option m_fk_option;
+  enum enum_yes_no_unknown m_yes_no_unk;
   Diag_condition_item_name diag_condition_item_name;
 }
 
@@ -1434,12 +1435,15 @@ bool my_yyoverflow(short **a, YYSTYPE **
         table_option opt_if_not_exists opt_no_write_to_binlog
         opt_temporary all_or_any opt_distinct
         opt_ignore_leaves fulltext_options spatial_type union_option
-        start_transaction_opts opt_chain opt_release
+        start_transaction_opts
         union_opt select_derived_init option_type2
         opt_natural_language_mode opt_query_expansion
         opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
         ev_alter_on_schedule_completion opt_ev_rename_to opt_ev_sql_stmt
 
+%type <m_yes_no_unk>
+        opt_chain opt_release
+
 %type <m_fk_option>
         delete_option
 
@@ -13602,16 +13606,16 @@ opt_work:
 
 opt_chain:
           /* empty */
-          { $$= (YYTHD->variables.completion_type == 1); }
-        | AND_SYM NO_SYM CHAIN_SYM { $$=0; }
-        | AND_SYM CHAIN_SYM        { $$=1; }
+          { $$= TVL_UNKNOWN; }
+        | AND_SYM NO_SYM CHAIN_SYM { $$= TVL_NO; }
+        | AND_SYM CHAIN_SYM        { $$= TVL_YES; }
         ;
 
 opt_release:
           /* empty */
-          { $$= (YYTHD->variables.completion_type == 2); }
-        | RELEASE_SYM        { $$=1; }
-        | NO_SYM RELEASE_SYM { $$=0; }
+          { $$= TVL_UNKNOWN; }
+        | RELEASE_SYM        { $$= TVL_YES; }
+        | NO_SYM RELEASE_SYM { $$= TVL_NO; }
 ;
 
 opt_savepoint:
@@ -13624,7 +13628,9 @@ commit:
           {
             LEX *lex=Lex;
             lex->sql_command= SQLCOM_COMMIT;
-            lex->tx_chain= $3; 
+            /* Don't allow AND CHAIN RELEASE. */
+            MYSQL_YYABORT_UNLESS($3 != TVL_YES || $4 != TVL_YES);
+            lex->tx_chain= $3;
             lex->tx_release= $4;
           }
         ;
@@ -13634,7 +13640,9 @@ rollback:
           {
             LEX *lex=Lex;
             lex->sql_command= SQLCOM_ROLLBACK;
-            lex->tx_chain= $3; 
+            /* Don't allow AND CHAIN RELEASE. */
+            MYSQL_YYABORT_UNLESS($3 != TVL_YES || $4 != TVL_YES);
+            lex->tx_chain= $3;
             lex->tx_release= $4;
           }
         | ROLLBACK_SYM opt_work

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2010-06-01 13:49:31 +0000
+++ b/sql/sys_vars.cc	2010-06-08 17:47:10 +0000
@@ -2029,24 +2029,38 @@ static bool check_tx_isolation(sys_var *
   return FALSE;
 }
 
-/*
-  If one doesn't use the SESSION modifier, the isolation level
-  is only active for the next command.
-*/
-static bool fix_tx_isolation(sys_var *self, THD *thd, enum_var_type type)
+
+bool Sys_var_tx_isolation::session_update(THD *thd, set_var *var)
 {
-  if (type == OPT_SESSION)
-    thd->session_tx_isolation= (enum_tx_isolation)thd->variables.tx_isolation;
-  return false;
+  if (var->type == OPT_SESSION && Sys_var_enum::session_update(thd, var))
+    return TRUE;
+  if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction())
+  {
+    /*
+      Update the isolation level of the next transaction.
+      I.e. if one did:
+      COMMIT;
+      SET SESSION ISOLATION LEVEL ...
+      BEGIN; <-- this transaction has the new isolation
+      Note, that in case of:
+      COMMIT;
+      SET TRANSACTION ISOLATION LEVEL ...
+      SET SESSION ISOLATION LEVEL ...
+      BEGIN; <-- the session isolation level is used, not the
+      result of SET TRANSACTION statement.
+     */
+    thd->tx_isolation= (enum_tx_isolation) var->save_result.ulonglong_value;
+  }
+  return FALSE;
 }
 
+
 // NO_CMD_LINE - different name of the option
-static Sys_var_enum Sys_tx_isolation(
+static Sys_var_tx_isolation Sys_tx_isolation(
        "tx_isolation", "Default transaction isolation level",
        SESSION_VAR(tx_isolation), NO_CMD_LINE,
        tx_isolation_names, DEFAULT(ISO_REPEATABLE_READ),
-       NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_tx_isolation),
-       ON_UPDATE(fix_tx_isolation));
+       NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_tx_isolation));
 
 static Sys_var_ulonglong Sys_tmp_table_size(
        "tmp_table_size",

=== modified file 'sql/sys_vars.h'
--- a/sql/sys_vars.h	2010-03-31 14:05:33 +0000
+++ b/sql/sys_vars.h	2010-05-07 16:28:59 +0000
@@ -1599,6 +1599,22 @@ public:
   { return type != STRING_RESULT; }
 };
 
+
+class Sys_var_tx_isolation: public Sys_var_enum
+{
+public:
+  Sys_var_tx_isolation(const char *name_arg,
+          const char *comment, int flag_args, ptrdiff_t off, size_t size,
+          CMD_LINE getopt,
+          const char *values[], uint def_val, PolyLock *lock,
+          enum binlog_status_enum binlog_status_arg,
+          on_check_function on_check_func)
+    :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
+                  values, def_val, lock, binlog_status_arg, on_check_func)
+  {}
+  virtual bool session_update(THD *thd, set_var *var);
+};
+
 /****************************************************************************
   Used templates
 ****************************************************************************/

=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc	2010-05-05 22:02:08 +0000
+++ b/sql/transaction.cc	2010-05-07 16:28:59 +0000
@@ -96,7 +96,18 @@ bool trans_begin(THD *thd, uint flags)
 
   DBUG_ASSERT(!thd->locked_tables_mode);
 
-  if (trans_commit_implicit(thd))
+  if (thd->in_multi_stmt_transaction_mode() ||
+      (thd->variables.option_bits & OPTION_TABLE_LOCK))
+  {
+    thd->variables.option_bits&= ~OPTION_TABLE_LOCK;
+    thd->server_status&= ~SERVER_STATUS_IN_TRANS;
+    res= test(ha_commit_trans(thd, TRUE));
+  }
+
+  thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
+  thd->transaction.all.modified_non_trans_table= FALSE;
+
+  if (res)
     DBUG_RETURN(TRUE);
 
   /*
@@ -182,6 +193,14 @@ bool trans_commit_implicit(THD *thd)
   thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
   thd->transaction.all.modified_non_trans_table= FALSE;
 
+  /*
+    Upon implicit commit, reset the current transaction
+    isolation level. We do not care about
+    @@session.completion_type since it's documented
+    to not have any effect on implicit commit.
+  */
+  thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+
   DBUG_RETURN(res);
 }
 
@@ -234,7 +253,11 @@ bool trans_commit_stmt(THD *thd)
   DBUG_ENTER("trans_commit_stmt");
   int res= FALSE;
   if (thd->transaction.stmt.ha_list)
+  {
     res= ha_commit_trans(thd, FALSE);
+    if (! thd->in_active_multi_stmt_transaction())
+      thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
+  }
 
   if (res)
     /*
@@ -265,6 +288,8 @@ bool trans_rollback_stmt(THD *thd)
     ha_rollback_trans(thd, FALSE);
     if (thd->transaction_rollback_request && !thd->in_sub_stmt)
       ha_rollback_trans(thd, TRUE);
+    if (! thd->in_active_multi_stmt_transaction())
+      thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation;
   }
 
   RUN_HOOK(transaction, after_rollback, (thd, FALSE));


Attachment: [text/bzr-bundle] bzr/magne.mahre@sun.com-20100608174710-zli2dn08egbapy9x.bundle
Thread
bzr commit into mysql-trunk-runtime branch (magne.mahre:3047)Bug#20837 Bug#46527 Bug#53343 Bug#53346Magne Mahre8 Jun