########################################################################################
#    This test verifies if the binlog is not corrupted when the cache buffer is not
#    big enough to accommodate the changes and is divided in five steps:
#
#    1 - Single Statements:
#    1.1 - Single statement on transactional table.
#    1.2 - Single statement on non-transactional table. 
#    1.3 - Single statement on both transactional and non-transactional tables.
#    In both 1.2 and 1.3, an incident event is logged to notify the user that the
#    master and slave are diverging.
#
#    2 - Transactions ended by an implicit commit.
#
#    3 - Transactions ended by a COMMIT.
#
#    4 - Transactions ended by a ROLLBACK.
#
#    5 - Transactions with a failing statement that updates a non-transactional
#    table. In this case, a failure means that the statement does not get into
#    the cache and an incident event is logged to notify the user that the master
#    and slave are diverging.
#    
########################################################################################

########################################################################################
#                                Configuring the environment
########################################################################################
--source include/have_innodb.inc
--source include/master-slave.inc
--source include/not_embedded.inc
--source include/not_windows.inc

let $old_max_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "max_binlog_cache_size", Value, 1);
let $old_binlog_cache_size= query_get_value(SHOW VARIABLES LIKE "binlog_cache_size", Value, 1);

SET GLOBAL max_binlog_cache_size = 4096;
# Becuase of bug#55377, we have to set binlog_cache_size until the bug is
# fixed.
SET GLOBAL binlog_cache_size = 4096;
disconnect master;
connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);

CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
CREATE TABLE t2(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=MyIsam;
CREATE TABLE t3(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;

let $data = `select concat('"', repeat('a',2000), '"')`;

--echo ########################################################################################
--echo #                                   1 - SINGLE STATEMENT
--echo ########################################################################################

connection master;

--echo *** Single statement on transactional table ***
--disable_query_log
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
eval INSERT INTO t1 (a, data) VALUES (1,
     CONCAT($data, $data, $data, $data, $data));
--enable_query_log

--echo *** Single statement on non-transactional table ***
--echo *** After WL#2687 the difference between STATEMENT/MIXED and ROW will not exist. ***
--disable_query_log
--disable_warnings
if (`SELECT @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
{
  eval INSERT INTO t2 (a, data) VALUES (2,
       CONCAT($data, $data, $data, $data, $data, $data));
  # Below code fakes the result of 'ROW' mode.
  --echo Got one of the listed errors
  # Ensure same message as in the case binlog_format=row below
  --echo include/wait_for_slave_sql_error_and_skip.inc [errno=1590]
}
if (`SELECT @@binlog_format = 'ROW'`)
{
  --error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
  eval INSERT INTO t2 (a, data) VALUES (2,
       CONCAT($data, $data, $data, $data, $data, $data));

  # 1590=ER_SLAVE_INCIDENT
  --let $slave_sql_errno= 1590
  --source include/wait_for_slave_sql_error_and_skip.inc
}
--enable_warnings
--enable_query_log

--disable_query_log
eval INSERT INTO t1 (a, data) VALUES (3, $data);
eval INSERT INTO t1 (a, data) VALUES (4, $data);
eval INSERT INTO t1 (a, data) VALUES (5, $data);
eval INSERT INTO t2 (a, data) VALUES (3, $data);
eval INSERT INTO t2 (a, data) VALUES (4, $data);
eval INSERT INTO t2 (a, data) VALUES (5, $data);
--enable_query_log

--echo *** Single statement on both transactional and non-transactional tables. ***
--echo *** After WL#2687 we will be able to change the order of the tables. ***
--disable_query_log
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
eval UPDATE t2, t1 SET t2.data = CONCAT($data, $data, $data, $data),
                       t1.data = CONCAT($data, $data, $data, $data);
--enable_query_log

# 1590=ER_SLAVE_INCIDENT
--let $slave_sql_errno= 1590
--source include/wait_for_slave_sql_error_and_skip.inc

#--echo ########################################################################################
#--echo #                             2 - BEGIN - IMPLICIT COMMIT by DDL
#--echo ########################################################################################

connection master;
TRUNCATE TABLE t1;
TRUNCATE TABLE t2;
TRUNCATE TABLE t3;

BEGIN;
--disable_query_log
--eval INSERT INTO t1 (a, data) VALUES (1, $data);
--eval INSERT INTO t1 (a, data) VALUES (2, $data);
--eval INSERT INTO t1 (a, data) VALUES (3, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (4, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (5, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (6, $data);
--eval INSERT INTO t1 (a, data) VALUES (7, 's');
--eval INSERT INTO t2 (a, data) VALUES (8, 's');
--eval INSERT INTO t1 (a, data) VALUES (9, 's');
--enable_query_log

--disable_query_log
ALTER TABLE t3 ADD COLUMN d int;
--enable_query_log

--disable_query_log
--eval INSERT INTO t2 (a, data) VALUES (10, $data);
--eval INSERT INTO t2 (a, data) VALUES (11, $data);
--eval INSERT INTO t2 (a, data) VALUES (12, $data);
--eval INSERT INTO t2 (a, data) VALUES (13, $data);
--enable_query_log

BEGIN;
--disable_query_log
--eval INSERT INTO t1 (a, data) VALUES (14, $data);
--eval INSERT INTO t1 (a, data) VALUES (15, $data);
--eval INSERT INTO t1 (a, data) VALUES (16, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (17, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (18, $data);
--eval INSERT INTO t1 (a, data) VALUES (19, 's');
--eval INSERT INTO t2 (a, data) VALUES (20, 's');
--eval INSERT INTO t1 (a, data) VALUES (21, 's');
--enable_query_log

if (`SELECT @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
{
  --disable_query_log
  CREATE TABLE t4 SELECT * FROM t1;
  --enable_query_log
  --echo Got one of the listed errors
}
if (`SELECT @@binlog_format = 'ROW'`)
{
  --disable_query_log
  --error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
  CREATE TABLE t4 SELECT * FROM t1;
  --enable_query_log
}

--disable_query_log
--eval INSERT INTO t2 (a, data) VALUES (15, $data);
--enable_query_log

BEGIN;
--disable_query_log
--eval INSERT INTO t1 (a, data) VALUES (22, $data);
--eval INSERT INTO t1 (a, data) VALUES (23, $data);
--eval INSERT INTO t1 (a, data) VALUES (24, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (25, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (26, $data);
--eval INSERT INTO t1 (a, data) VALUES (27, 's');
--eval INSERT INTO t2 (a, data) VALUES (28, 's');
--eval INSERT INTO t1 (a, data) VALUES (29, 's');
--enable_query_log

--disable_query_log
CREATE TABLE t5 (a int);
--enable_query_log

--sync_slave_with_master
--let $diff_tables= master:t1,slave:t1
--source include/diff_tables.inc

--echo ########################################################################################
--echo #                                     3 - BEGIN - COMMIT
--echo ########################################################################################

connection master;
TRUNCATE TABLE t1;
TRUNCATE TABLE t2;
TRUNCATE TABLE t3;

BEGIN;
--disable_query_log
--eval INSERT INTO t1 (a, data) VALUES (1, $data);
--eval INSERT INTO t1 (a, data) VALUES (2, $data);
--eval INSERT INTO t1 (a, data) VALUES (3, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (4, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (5, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (6, $data);
--eval INSERT INTO t1 (a, data) VALUES (7, 's');
--eval INSERT INTO t2 (a, data) VALUES (8, 's');
--eval INSERT INTO t1 (a, data) VALUES (9, 's');
--enable_query_log
COMMIT;

--sync_slave_with_master
--let $diff_tables= master:t1,slave:t1
--source include/diff_tables.inc

--echo ########################################################################################
--echo #                                      4 - BEGIN - ROLLBACK
--echo ########################################################################################

connection master;
TRUNCATE TABLE t1;
TRUNCATE TABLE t2;
TRUNCATE TABLE t3;

BEGIN;
--disable_query_log
--eval INSERT INTO t1 (a, data) VALUES (1, $data);
--eval INSERT INTO t1 (a, data) VALUES (2, $data);
--eval INSERT INTO t1 (a, data) VALUES (3, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (4, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (5, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (6, $data);
--eval INSERT INTO t1 (a, data) VALUES (7, 's');
--eval INSERT INTO t2 (a, data) VALUES (8, 's');
--eval INSERT INTO t1 (a, data) VALUES (9, 's');
--enable_query_log
ROLLBACK;

--sync_slave_with_master
--let $diff_tables= master:t1,slave:t1
--source include/diff_tables.inc

--echo ########################################################################################
--echo #                                         5 - PROCEDURE 
--echo ########################################################################################

connection master;
TRUNCATE TABLE t1;
TRUNCATE TABLE t2;
TRUNCATE TABLE t3;

DELIMITER //;

CREATE PROCEDURE p1(pd VARCHAR(30000))
BEGIN
  INSERT INTO t1 (a, data) VALUES (1, pd);
  INSERT INTO t1 (a, data) VALUES (2, pd);
  INSERT INTO t1 (a, data) VALUES (3, pd);
  INSERT INTO t1 (a, data) VALUES (4, pd);
  INSERT INTO t1 (a, data) VALUES (5, 's');
END//

DELIMITER ;//

TRUNCATE TABLE t1;

--disable_query_log
eval CALL p1($data);
--enable_query_log

TRUNCATE TABLE t1;

BEGIN;
--disable_query_log
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
eval CALL p1($data);
--enable_query_log
COMMIT;

TRUNCATE TABLE t1;

BEGIN;
--disable_query_log
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
eval CALL p1($data);
--enable_query_log
ROLLBACK;

--sync_slave_with_master
--let $diff_tables= master:t1,slave:t1
--source include/diff_tables.inc

--echo ########################################################################################
--echo #                                           6 - XID
--echo ########################################################################################

connection master;
TRUNCATE TABLE t1;
TRUNCATE TABLE t2;
TRUNCATE TABLE t3;

BEGIN;
--disable_query_log
--eval INSERT INTO t1 (a, data) VALUES (1, $data);
--eval INSERT INTO t1 (a, data) VALUES (2, $data);
--eval INSERT INTO t1 (a, data) VALUES (3, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (4, $data);
SAVEPOINT sv;
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (5, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (6, $data);
--eval INSERT INTO t1 (a, data) VALUES (7, 's');
--eval INSERT INTO t2 (a, data) VALUES (8, 's');
--eval INSERT INTO t1 (a, data) VALUES (9, 's');
--enable_query_log
ROLLBACK TO sv;
COMMIT;

--sync_slave_with_master
--let $diff_tables= master:t1,slave:t1
--source include/diff_tables.inc

--echo ########################################################################################
--echo #                                        7 - NON-TRANS TABLE
--echo ########################################################################################

connection master;
TRUNCATE TABLE t1;
TRUNCATE TABLE t2;
TRUNCATE TABLE t3;

BEGIN;
--disable_query_log
--eval INSERT INTO t1 (a, data) VALUES (1, $data);
--eval INSERT INTO t1 (a, data) VALUES (2, $data);
--eval INSERT INTO t2 (a, data) VALUES (3, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (4, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (5, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (6, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (7, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval UPDATE t2 SET data= CONCAT($data, $data);
--eval INSERT INTO t1 (a, data) VALUES (8, 's');
--eval INSERT INTO t1 (a, data) VALUES (9, 's');
--eval INSERT INTO t2 (a, data) VALUES (10, 's');
--eval INSERT INTO t1 (a, data) VALUES (11, 's');
--enable_query_log
COMMIT;

BEGIN;
--disable_query_log
--eval INSERT INTO t1 (a, data) VALUES (15, $data);
--eval INSERT INTO t1 (a, data) VALUES (16, $data);
--eval INSERT INTO t2 (a, data) VALUES (17, $data);
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
--eval INSERT INTO t1 (a, data) VALUES (18, $data);
--enable_query_log
COMMIT;

# 1590=ER_SLAVE_INCIDENT
--let $slave_sql_errno= 1590
--source include/wait_for_slave_sql_error_and_skip.inc

sync_slave_with_master;

--echo ########################################################################
--echo #      8 - Bug#55375(Regression Bug) Transaction bigger than
--echo #          max_binlog_cache_size crashes slave
--echo ########################################################################

SET GLOBAL max_binlog_cache_size = 4096;
SET GLOBAL binlog_cache_size = 4096;

source include/stop_slave.inc;
source include/start_slave.inc;
CALL mtr.add_suppression("Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage.*");
CALL mtr.add_suppression("Writing one row to the row-based binary log failed.*");
CALL mtr.add_suppression("Slave SQL.*The incident LOST_EVENTS occured on the master. Message: error writing to the binary log");

connection master;
TRUNCATE t1;

sync_slave_with_master;
--let binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1)
--let binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)

connection master;
--replace_result $old_max_binlog_cache_size ORIGINAL_VALUE
--eval SET GLOBAL max_binlog_cache_size= $old_max_binlog_cache_size
--replace_result $old_binlog_cache_size ORIGINAL_VALUE
--eval SET GLOBAL binlog_cache_size= $old_binlog_cache_size
disconnect master;
connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);

--let $n=128
BEGIN;
--disable_query_log
--echo Repeat statement 'INSERT INTO t1 VALUES(\$n, repeat("a", 32))' $n times
while ($n)
{
  --eval INSERT INTO t1 VALUES ($n, repeat("a", 32))
  --dec $n
}
--enable_query_log
COMMIT;

--connection slave
--let $slave_sql_errno= 1197
source include/wait_for_slave_sql_error.inc;

SELECT count(*) FROM t1;
source include/show_binlog_events.inc;

--replace_result $old_max_binlog_cache_size ORIGINAL_VALUE
--eval SET GLOBAL max_binlog_cache_size= $old_max_binlog_cache_size
--replace_result $old_binlog_cache_size ORIGINAL_VALUE
--eval SET GLOBAL binlog_cache_size= $old_binlog_cache_size

source include/stop_slave.inc;
source include/start_slave.inc;

connection master;
sync_slave_with_master;
SELECT count(*) FROM t1;

--echo ########################################################################################
--echo #                                        CLEAN
--echo ########################################################################################

connection master;
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
# t4 exists only if binlog_format!=row, so so a warning is generated
# if binog_format=row
--disable_warnings
DROP TABLE IF EXISTS t4;
--enable_warnings
DROP TABLE t5;
DROP PROCEDURE p1;

--source include/rpl_end.inc
