--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
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_CHARACTERISTICS
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;

connection con1;
START TRANSACTION;
INSERT INTO t1 VALUES (1000);
COMMIT;

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.
#
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;
--echo Should be 1
COMMIT AND CHAIN;

connection con1;
INSERT INTO t1 VALUES (1002);
COMMIT;

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
#
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;
--echo Should be 1
ROLLBACK AND CHAIN;

connection con1;
INSERT INTO t1 VALUES (1002);
COMMIT;

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;

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;
--echo Should see 1001
COMMIT AND NO CHAIN;
--echo default transaction is now in REPEATABLE READ

connection con1;
INSERT INTO t1 VALUES (1002);
COMMIT;

connection default;
SELECT * FROM t1 WHERE s1 >= 1000;
--echo Should see 1001 and 1002

connection con1;
INSERT INTO t1 VALUES (1003);
COMMIT;

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
#
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;
--echo Should see 1001
ROLLBACK AND NO CHAIN;
--echo default transaction is now in REPEATABLE READ

connection con1;
INSERT INTO t1 VALUES (1002);
COMMIT;

connection default;
SELECT * FROM t1 WHERE s1 >= 1000;
--echo Should see 1001 and 1002

connection con1;
INSERT INTO t1 VALUES (1003);
COMMIT;

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.)
#
connection default;

SET TRANSACTION ISOLATION LEVEL	READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM t1;

connection con1;
INSERT INTO t1 VALUES (1000);
COMMIT;

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'

connection con1;
INSERT INTO t1 VALUES (1001);
COMMIT;

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 #


--echo #
--echo # WL#5968 Implement START TRANSACTION READ (WRITE|ONLY);
--echo #

--echo #
--echo # Test 1: Check supported syntax

START TRANSACTION;
COMMIT;

START TRANSACTION READ ONLY;
COMMIT;

START TRANSACTION READ WRITE;
COMMIT;

--error ER_PARSE_ERROR
START TRANSACTION READ ONLY, READ WRITE;

START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT;
COMMIT;

START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT;
COMMIT;

START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY;
COMMIT;

START TRANSACTION WITH CONSISTENT SNAPSHOT, READ WRITE;
COMMIT;

--error ER_PARSE_ERROR
START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT, READ WRITE;

SET TRANSACTION READ ONLY;
SET TRANSACTION READ WRITE;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ WRITE;
SET TRANSACTION READ ONLY, ISOLATION LEVEL READ COMMITTED;
SET TRANSACTION READ WRITE, ISOLATION LEVEL READ COMMITTED;
--error ER_PARSE_ERROR
SET TRANSACTION READ ONLY, READ WRITE;
COMMIT;

--echo #
--echo # Test 2: Check setting of variable.

SET SESSION TRANSACTION READ WRITE;
SELECT @@tx_read_only;

SET SESSION TRANSACTION READ ONLY;
SELECT @@tx_read_only;

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ WRITE;
SELECT @@tx_read_only;

SET SESSION TRANSACTION READ ONLY, ISOLATION LEVEL REPEATABLE READ;
SELECT @@tx_read_only;

START TRANSACTION;
--echo # Not allowed inside a transaction
--error ER_CANT_CHANGE_TX_CHARACTERISTICS
SET TRANSACTION READ ONLY;
--echo # But these are allowed.
SET SESSION TRANSACTION READ ONLY;
SET GLOBAL TRANSACTION READ ONLY;
COMMIT;

# Reset to defaults
SET SESSION TRANSACTION READ WRITE;
SET GLOBAL TRANSACTION READ WRITE;

--echo #
--echo # Test 3: Test that write operations are properly blocked.

CREATE TABLE t1(a INT);
CREATE TEMPORARY TABLE temp_t2(a INT);

SET SESSION TRANSACTION READ ONLY;

--echo # 1: DDL should be blocked, also on temporary tables.
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
CREATE TABLE t3(a INT);
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
ALTER TABLE t1 COMMENT "Test";
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DROP TABLE t1;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
CREATE TEMPORARY TABLE temp_t3(a INT);
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
ALTER TABLE temp_t2 COMMENT "Test";
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DROP TEMPORARY TABLE temp_t2;

--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
CREATE FUNCTION f1() RETURNS INT RETURN 1;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DROP FUNCTION f1;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
CREATE PROCEDURE p1() BEGIN END;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DROP PROCEDURE p1;

--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
CREATE VIEW v1 AS SELECT 1;
SET SESSION TRANSACTION READ WRITE;
CREATE VIEW v1 AS SELECT 1;
SET SESSION TRANSACTION READ ONLY;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DROP VIEW v1;
SET SESSION TRANSACTION READ WRITE;
DROP VIEW v1;
SET SESSION TRANSACTION READ ONLY;

--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
RENAME TABLE t1 TO t2;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
RENAME TABLE temp_t2 TO temp_t3;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
TRUNCATE TABLE t1;

--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
CREATE DATABASE db1;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DROP DATABASE db1;
SET SESSION TRANSACTION READ WRITE;

--echo # 2: DML should be blocked on non-temporary tables.
START TRANSACTION READ ONLY;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
INSERT INTO t1 VALUES (1), (2);
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
UPDATE t1 SET a= 3;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DELETE FROM t1;

--echo # 3: DML should be allowed on temporary tables.
INSERT INTO temp_t2 VALUES (1), (2);
UPDATE temp_t2 SET a= 3;
DELETE FROM temp_t2;

--echo # 4: Queries should not be blocked.
SELECT * FROM t1;
SELECT * FROM temp_t2;

HANDLER t1 OPEN;
HANDLER t1 READ FIRST;
HANDLER t1 CLOSE;

HANDLER temp_t2 OPEN;
HANDLER temp_t2 READ FIRST;
HANDLER temp_t2 CLOSE;

--echo # 5: Prepared statements
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
PREPARE stmt FROM "DELETE FROM t1";

PREPARE stmt FROM "DELETE FROM temp_t2";
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
COMMIT;

--echo # 6: Stored routines

delimiter |;
CREATE FUNCTION f1() RETURNS INT
BEGIN
  DELETE FROM t1;
  RETURN 1;
END|

CREATE FUNCTION f2() RETURNS INT
BEGIN
  DELETE FROM temp_t2;
  RETURN 1;
END|
delimiter ;|

CREATE PROCEDURE p1() DELETE FROM t1;
CREATE PROCEDURE p2() DELETE FROM temp_t2;

START TRANSACTION READ ONLY;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
SELECT f1();
SELECT f2();
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
CALL p1();
CALL p2();
COMMIT;

DROP FUNCTION f1;
DROP FUNCTION f2;
DROP PROCEDURE p1;
DROP PROCEDURE p2;

--echo # 7: Views
CREATE VIEW v1 AS SELECT a FROM t1;
# Not supported for temporary tables.

START TRANSACTION READ ONLY;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
INSERT INTO v1 VALUES (1), (2);
SELECT * FROM v1;
COMMIT;

DROP VIEW v1;

--echo # 8: LOCK TABLE
SET SESSION TRANSACTION READ ONLY;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
LOCK TABLE t1 WRITE;

LOCK TABLE t1 READ;
UNLOCK TABLES;

# Not supported for temporary tables.

SET SESSION TRANSACTION READ WRITE;
DROP TABLE temp_t2, t1;

--echo #
--echo # Test 4: SET TRANSACTION, CHAINing transactions

CREATE TABLE t1(a INT);

SET SESSION TRANSACTION READ ONLY;
START TRANSACTION;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DELETE FROM t1;
COMMIT;
START TRANSACTION READ WRITE;
DELETE FROM t1;
COMMIT;

SET SESSION TRANSACTION READ WRITE;
SET TRANSACTION READ ONLY;
START TRANSACTION;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DELETE FROM t1;
COMMIT;
START TRANSACTION READ WRITE;
DELETE FROM t1;
COMMIT;

START TRANSACTION READ ONLY;
SELECT * FROM t1;
COMMIT AND CHAIN;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DELETE FROM t1;
COMMIT;

START TRANSACTION READ ONLY;
SELECT * FROM t1;
ROLLBACK AND CHAIN;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DELETE FROM t1;
COMMIT;

DROP TABLE t1;

--echo #
--echo # Test 5: Test that reserved keyword ONLY is still allowed as
--echo #         identifier - both directly and in SPs.

SET @only= 1;

CREATE TABLE t1 (only INT);
INSERT INTO t1 (only) values (1);
SELECT only FROM t1 WHERE only = 1;
DROP TABLE t1;

DELIMITER |;
CREATE PROCEDURE p1()
BEGIN
  DECLARE only INT DEFAULT 1;
END|
DELIMITER ;|

CALL p1();

DROP PROCEDURE p1;

--echo #
--echo # Test 6: Check that XA transactions obey default access mode.

CREATE TABLE t1(a INT);

SET TRANSACTION READ ONLY;
XA START 'test1';
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
INSERT INTO t1 VALUES (1);
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
UPDATE t1 SET a=2;
--error ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
DELETE FROM t1;
XA END 'test1';
XA PREPARE 'test1';
XA COMMIT 'test1';

DROP TABLE t1;

--echo #
--echo # Test 7: SET TRANSACTION inside stored routines

CREATE PROCEDURE p1() SET SESSION TRANSACTION READ ONLY;
CALL p1();
SELECT @@tx_read_only;
SET SESSION TRANSACTION READ WRITE;
DROP PROCEDURE p1;

CREATE PROCEDURE p1() SET SESSION TRANSACTION READ ONLY,
                                              ISOLATION LEVEL SERIALIZABLE;
CALL p1();
SELECT @@tx_read_only;
SET SESSION TRANSACTION READ WRITE, ISOLATION LEVEL REPEATABLE READ;
DROP PROCEDURE p1;

delimiter |;
CREATE FUNCTION f1() RETURNS INT
BEGIN
  SET SESSION TRANSACTION READ ONLY;
  RETURN 1;
END|
delimiter ;|

SELECT f1();
SELECT @@tx_read_only;
SET SESSION TRANSACTION READ WRITE;
DROP FUNCTION f1;

delimiter |;
CREATE FUNCTION f1() RETURNS INT
BEGIN
  SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE, READ ONLY;
  RETURN 1;
END|
delimiter ;|

SELECT f1();
SELECT @@tx_read_only;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ, READ WRITE;
DROP FUNCTION f1;

--echo #
--echo # Test 8: SET TRANSACTION and auto-commit

SELECT @@autocommit;
CREATE TABLE t1(a INT) engine=InnoDB;

SET TRANSACTION READ ONLY;
SELECT * FROM t1;
--echo # This statement should work, since last statement committed.
INSERT INTO t1 VALUES (1);

DROP TABLE t1;
