mariadb/mysql-test/suite/rpl/t/rpl_create_select_row.test
Andrei Elkin 1b4efbeb8c MDEV-35207 ignored error at binlogging by CREATE-TABLE-SELECT leads to assert
MDEV-35499 Errored-out CREATE-or-REPLACE-SELECT does not log DROP table into binlog
MDEV-35502 Failed at ROW-format binlogging CREATE-TABLE-SELECT should
           not generate Incident event

When a CREATE TABLE .. SELECT errors while inserting data, a user
would expect that all changes are rolled back
and the table would not exist after executing the query.

However CREATE-TABLE-SELECT can face an error near the end of its execution
select_create::send_eof() so that the error was never checked which
led to various assert inside binlogging path that should not be
attended at all.
Specifically when binlog_commit() of ha_commit_one_phase() that
CREATE-TABLE-SELECT employs errored out because of a limited cache size
(binlog_commit may try writing to a transactional cache) the cache
was not flushed to binlog. The missed error check allowed further
execution down to trans_commit_implicit() in whose stack

  DBUG_ASSERT(!(entry->using_trx_cache && !mngr->trx_cache.empty() &&
                mngr->get_binlog_cache_log(TRUE)->error));

fired. In a non-debug build that table remains created/populated
inconsistently with binlog.

The fixes need and install the error checking in select_create::send_eof().
That prevents from any further execution when ha_commit_one_phase() fails
for any reason (typically due to binlog_commit()).

This commit also covers CREATE-or-REPLACE-SELECT that additionally had
a specific issue in that DROP TABLE was not logged the binary log, MDEV-35499.
See changes select_create::abort_result_set().

The current commit also corrects an unnecessary Incident event
logging when CREATE-TABLE-SELECT encounters a binloging issue, MDEV-35502.
The Incident was actually only harmful in this case as the table was
never going to be created, therefore replicated, in such a case.
In "normal" cases when the SELECT phase errors due to binlogging, an
internal incident flag gets reset inside select_create::abort_result_set().

A hunk in select_insert::prepare_eof() addresses a specific kind of
this issue that deals with incorrect computation of the binlog cache type.
Because of that in the OLD version execution was allowed to proceed along
ha_commit_trans()..binlog_commit() while a Pending event was not
flushed to the transactional cache. That might lead to the unnecessary
binlogged Incident despite the select_create::abort_result_set()
measures. However now with the corrected cache type any binlogging error
to flush the Pending event is covered according to the normal case.
non-transaction table, updates to the non-transactional table

NOTE the commit contains few tests overlapping with unfixed yet MDEV-36027.

Thanks to Brandon Nesterenko and Kristian Nielsen for thorough review,
and Kristian additionally for ideas to simplify the patch and some
code contribution.
2025-04-03 19:00:02 +03:00

161 lines
5.5 KiB
Text

--source include/have_binlog_format_row.inc
--source include/have_innodb.inc
--source include/master-slave.inc
--connection master
set @max_binlog_cache_size = @@global.max_binlog_cache_size;
set @binlog_cache_size = @@global.binlog_cache_size;
set @@global.max_binlog_cache_size = 4096;
set @@global. binlog_cache_size = 4096;
--echo #
--echo # MDEV-35207 ignored error at binlogging by CREATE-TABLE-SELECT leads to assert
--echo #
# fix the current (write) binlog position
--let $binlog_file_0= query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start_0 = query_get_value(SHOW MASTER STATUS, Position, 1)
# use a separate connection also to validate its close will be clean
connect (conn_err,localhost,root,,);
call mtr.add_suppression("Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage");
--error ER_TRANS_CACHE_FULL
create table t engine=myisam select repeat ('a',4096*3) AS a;
--error ER_TRANS_CACHE_FULL
create table t engine=innodb select repeat ('a',4096*3) AS a;
--error ER_DUP_ENTRY
create table t (a int unique, b char) select 1 AS a, 'b' as b union select 1 as a, 'c' as b;
--error ER_NO_SUCH_TABLE
select * from t;
--disconnect conn_err
--connection master
--let $binlog_file_1= query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start_1= query_get_value(SHOW MASTER STATUS, Position, 1)
--let $cmp = `select strcmp('$binlog_file_1', '$binlog_file_0') <> 0 OR $binlog_start_1 <> $binlog_start_0`
if (!$cmp)
{
--echo *** Error: unexpected advance of binlog position
--die
}
--echo
--echo #
--echo # MDEV-35499 errored CREATE-OR-REPLACE-SELECT does not DROP table in binlog
--echo #
--let $i = 2
while ($i)
{
--let $engine=`select if($i % 2, "myisam", "innodb")`
--echo #
--echo # Engine = $engine
--echo #
set statement binlog_format=statement for create table t (a int) select 1 as a;
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1)
--error ER_DUP_ENTRY
--eval set statement binlog_format=row for create or replace table t (a int primary key, b char) engine=$engine select 1 AS a, 'b' as b union select 1 as a, 'c' as b
--error ER_NO_SUCH_TABLE
select * from t;
--echo #
--echo # Prove an expected lonely `DROP table t'
--source include/show_binlog_events.inc
# error before stmt commit
set statement binlog_format=statement for create table t (a int) select 1 as a;
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1)
--error ER_TRANS_CACHE_FULL
--eval set statement binlog_format=row for create or replace table t (a text) engine=$engine select repeat ('a',1024) AS a union select repeat ('a',3*4096) AS a union select repeat ('a',3*4096) AS a
--error ER_NO_SUCH_TABLE
select * from t;
--echo #
--echo # Prove an expected lonely `DROP table t'
--source include/show_binlog_events.inc
# error at stmt commit
set statement binlog_format=statement for create table t (a int) select 1 as a;
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1)
--error ER_TRANS_CACHE_FULL
--eval set statement binlog_format=row for create or replace table t (a text) engine=$engine select repeat ('a',4096*3) AS a;
--error ER_NO_SUCH_TABLE
select * from t;
--echo #
--echo # Prove an expected lonely `DROP table t'
--source include/show_binlog_events.inc
--dec $i
}
# Tests of mixed engines to demonstrate non-transaction table updates
# are binlogged or otherwise MDEV-36027.
create table ti_pk (a int primary key) engine=innodb;
create table ta (a int) engine=aria;
delimiter |;
create function f_ia(arg int)
returns integer
begin
insert into ti_pk set a=1;
insert into ta set a=1;
insert into ti_pk set a=arg;
return 1;
end |
delimiter ;|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1)
--error ER_DUP_ENTRY
set statement binlog_format = ROW for create table t_y (a int) engine=aria select f_ia(1 /* err */) as a;
--error ER_NO_SUCH_TABLE
select * from t_y;
--echo # correct execution: `ta` is modified and its new record is binlogged
--source include/show_binlog_events.inc
select * from ta;
select * from ti_pk;
--sync_slave_with_master
--let $diff_tables=master:ta,slave:ta
--source include/diff_tables.inc
--connection master
delete from ta;
--sync_slave_with_master
--connection master
# MDEV-36027 Errored-out CREATE-SELECT does not binlog results of any function modifying non-transactional table
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1)
--error ER_DUP_ENTRY
set statement binlog_format = STATEMENT for create table t_y (a int) engine=aria select f_ia(1 /* err */) as a;
--error ER_NO_SUCH_TABLE
select * from t_y;
--echo # ***TODO: fix MDEV-36027***. As of now `ta` is modified but that's not binlogged
--source include/show_binlog_events.inc
select *,'on_master' from ta;
select * from ti_pk;
--sync_slave_with_master
select *,'on_slave' from ta;
# Cleanup
--connection master
drop function f_ia;
drop table ti_pk, ta;
SET @@global.max_binlog_cache_size = @max_binlog_cache_size;
SET @@global. binlog_cache_size = @binlog_cache_size;
# test that binlog replicates correctly to slave
# --connection slave
--sync_slave_with_master
--echo End of the tests
--source include/rpl_end.inc