#
# The test verifies prepared XA transaction behaviour.
#
# The prepared XA transactions can be disconnected from the client,
# discovered from another connection and commited or rolled back
# later. They also survive the server restart.  The test runs two
# loops each consisting of prepared XA:s generation, their
# manipulation and a server restart followed with survived XA:s
# completion.
#

#
# Prepared XA can't get available to an external connection
# until connection that either leaves actively or is killed
# has completed a necessary part of its cleanup.
# Selecting from P_S.threads provides a method to learn that.
#
--source include/have_perfschema.inc
--source include/gtid_utils.inc

# Total number of connection each performing one insert into table
--let $conn_number=20
# Number of rollbacks and commits from either side of the server restart
--let $rollback_number=5
--let $commit_number=5
# Number of transaction that are terminated before server restarts
--let $term_number=`SELECT $rollback_number + $commit_number`
# Instead of disconnect make some connections killed when their
# transactions got prepared.
--let $killed_number=5
# make some connections disconnected by shutdown rather than actively
--let $server_disconn_number=5
--let $prepared_at_server_restart = `SELECT $conn_number - $term_number`
# number a "warmup" connection after server restart, they all commit
--let $post_restart_conn_number=10

# Counter to be used in GTID consistency check.
# It's incremented per each non-XA transaction commit, including DDL calls and
# also by any DML  quieries like CALL mtr.add_suppression() that are added to
# the top level file of this test.
--let $not_xa_trans_committed = 0
# Local to this file variable to control one-phase commit loop
--let $one_phase_number = 5

--connection default

# Remove possibly preceeding binlogs and clear initialization time
# GTID executed info. In the following all transactions are counted
# to conduct verification at the end of the test.
if (`SELECT @@global.log_bin`)
{
  RESET MASTER;
}

# Disconected and follower threads need synchronization
--inc $not_xa_trans_committed
CREATE VIEW v_processlist  as SELECT * FROM performance_schema.threads where type = 'FOREGROUND';

--inc $not_xa_trans_committed
--eval call mtr.add_suppression("Found $prepared_at_server_restart prepared XA transactions")
# Caused by bug#79416 fixes, see below.
--inc $not_xa_trans_committed
call mtr.add_suppression("Found 1 prepared XA transactions");

--inc $not_xa_trans_committed
CREATE TABLE t (a INT) ENGINE=innodb;

# Counter is incremented at the end of post restart to
# reflect number of loops done in correctness computation.
--let $restart_number = 0
--let $how_to_restart=restart_mysqld.inc
--source extra/binlog_tests/binlog_xa_prepared_do_and_restart.inc

--let $how_to_restart=kill_and_restart_mysqld.inc
--source extra/binlog_tests/binlog_xa_prepared_do_and_restart.inc

--connection default

# Few xs that commit in one phase, not subject to the server restart
# nor reconnect.
# This piece of test is related to mysqlbinlog recovery examine below.
--let $k = 0
while ($k < $one_phase_number)
{
    --eval XA START   'one_phase_trx_$k'
    --eval INSERT INTO t SET a=$k
    --eval XA END     'one_phase_trx_$k'
    --eval XA COMMIT  'one_phase_trx_$k' ONE PHASE

    --inc $k
}

--inc $not_xa_trans_committed
DROP TABLE t;
--inc $not_xa_trans_committed
DROP VIEW v_processlist;

if (`SELECT @@global.log_bin`)
{
  # Recording proper samples of binlogged prepared XA:s
  --source include/show_binlog_events.inc
}

# Multiplier 2 captures the XA two phase binlogging property
--let $gno = `SELECT $not_xa_trans_committed + 2*$restart_number*($conn_number + $post_restart_conn_number) + $one_phase_number`

# Check GTID consistency
# Tests that run wo/ log_bin on and source this file
# can't compute gtid_executed-based assert.
if (`SELECT @@global.gtid_mode = 'ON' and @@global.log_bin = 1`)
{
  --let $lhs = `SELECT GTID_COUNT(@@global.gtid_executed)`
  --let $rhs = $gno
  --let $assert_text = committed gno $gno
  --let $assert_cond = $lhs = $rhs
  --source include/assert.inc
}

if (`SELECT @@global.gtid_mode = 'OFF' or @@global.log_bin = 0`)
{
  # To make this test run regardless GTID mode
  --let $rhs = `SELECT '1-$gno'`
  --let $lhs = $rhs
  --let $assert_text = committed gno $gno
  --let $assert_cond = $lhs = $rhs
  --source include/assert.inc
}

if (`SELECT @@global.log_bin = 1`)
{
  --let $MYSQLD_DATADIR=`SELECT @@datadir`
  --exec $MYSQL_BINLOG -R --to-last-log master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql
  RESET MASTER;

  --exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql

  if (`SELECT @@global.gtid_mode = 'ON' and @@global.log_bin = 1`)
  {
    --let $lhs = `SELECT GTID_COUNT(@@global.gtid_executed)`
    --let $rhs = $gno
    --let $assert_text = committed gno $gno
    --let $assert_cond = $lhs = $rhs
    --source include/assert.inc
  }
  if (`SELECT @@global.gtid_mode = 'OFF' or @@global.log_bin = 0`)
  {
    --let $rhs = `SELECT '1-$gno'`
    --let $lhs = $rhs
    --let $assert_text = committed gno $gno
    --let $assert_cond = $lhs = $rhs
    --source include/assert.inc
}

  --remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.sql
}
--echo All transactions must be completed, to empty-list the following:
XA RECOVER;


# bug#79416 INNODB: FAILING ASSERTION: TOTAL_TRX >= TRX_SYS->N_PREPARED_TRX
# Fixes' prove in that there must be no innodb assert at the server shutdown
--connect (conn_bug79146, 127.0.0.1,root,,test,$MASTER_MYPORT,)
CREATE TABLE t(a INT);
XA START 'xa1';
INSERT INTO t SET a = 1;
XA END 'xa1';
--error ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION
SET @@SESSION.pseudo_slave_mode=1;
XA PREPARE 'xa1';

--connection default
--source include/restart_mysqld.inc

XA ROLLBACK 'xa1';

# bug78695 ASSERTION `STATIC_CAST<SQL_CMD_XA_COMMIT*>(THD->LEX->M_SQL_CMD)-> GET_XA_OPT()
# Fixes' prove in that there must be no assert at the xa commit
XA START 'xa1';
INSERT INTO t SET a = 1;
XA END 'xa1';
XA PREPARE 'xa1';
--error ER_VARIABLE_NOT_SETTABLE_IN_TRANSACTION
SET @@SESSION.pseudo_slave_mode=1;
XA COMMIT 'xa1';

DROP TABLE t;

--source include/gtid_utils_end.inc
