mirror of
https://github.com/MariaDB/server.git
synced 2025-06-09 06:14:44 +02:00

MDEV-36563 Assertion `!mysql_bin_log.is_open()' failed in THD::mark_tmp_table_as_free_for_reuse The purpose of this commit is to ensure that creation and changes of temporary tables are properly and predicable logged to the binary log. It also fixes some bugs where ROW logging was used in MIXED mode, when STATEMENT would be a better (and expected) choice. In this comment STATEMENT stands for logging to binary log in STATEMENT format, MIXED stands for MIXED binlog format and ROW for ROW binlog format. New rules for logging of temporary tables - CREATE of temporary tables are now by default binlogged only if STATEMENT binlog format is used. If it is binlogged, 1 is stored in TABLE_SHARE->table_creation_was_logged. The user can change this behavior by setting create_temporary_table_binlog_formats to MIXED,STATEMENT in which case the create is logged in statement format also in MIXED mode (as before). - Changes to temporary tables are only binlogged if and only if the CREATE was logged. The logging happens under STATEMENT or MIXED. If binlog_format=ROW, temporary table changes are not binlogged. A temporary table that are changed under ROW are marked as 'not up to date in binlog' and no future row changes are logged. Any usage of this temporary table will force row logging of other tables in any future statements using the temporary table to be row logged. - DROP TEMPORARY is binlogged only of the CREATE was binlogged. Changes done: - Row logging is forced for any statement using temporary tables that are not up to date in the binary log. (Before the row logging was forced if the user has a temporary table) - If there is any changes to the temporary table that is not binlogged, the table is marked as not up to date. - TABLE_SHARE->table_creation_was_logged has a new definition for temporary tables: 0 Table creating was not logged to binary log 1 Table creating was logged to binary log and table is up to date. 2 Table creating was logged to binary log but some changes where not logged to binary log. Table is not up to date in binary log is defined as value 0 or 2. - If a multi-table-update or multi-table-delete fails then all updated temporary tables are marked as not up to date. - Enforce row logging if the query is using temporary tables that are not up to date. Before row logging was enforced if the user had any temporary tables. - When dropping temporary tables use IF EXISTS. This ensures that slave will not stop if it had crashed and lost the temporary tables. - Remove comment and version from DROP /*!4000 TEMPORARY.. generated when a connection closes that has open temporary tables. Added 'generated by server' at the end of the DROP. Bugs fixed: - When using temporary tables with commands that forced row based, like INSERT INTO temporary_table VALUES (UUID()), this was never logged which causes the temporary table to be inconsistent on master and slave. - Used binlog format is now clearly defined. It is now only depending on the current binlog_format and the tables used. Before it was depending on the user had ANY temporary tables and the state of 'current_stmt_binlog_format' set by previous queries. This also caused temporary tables to be logged to binary log in some cases. - CREATE TABLE t1 LIKE not_logged_temporary_table caused replication to stop. - Rename of not binlogged temporary tables where binlogged to binary log which caused replication to stop. Changes in behavior: - By default create_temporary_table_binlog_formats=STATEMENT, which means that CREATE TEMPORARY is not logged to binary log under MIXED binary logging. This can be changed by setting create_temporary_table_binlog_formats to MIXED,STATEMENT. - Using temporary tables that was not logged to the binary log will cause any query using them for updating other tables to be logged in ROW format. Before all queries was logged in ROW format if the user had any temporary tables, even if they were not used by the query. - Generated DROP TEMPORARY TABLE is now always using IF EXISTS and has a "generated by server" comment in the binary log. The consequences of the above is that manipulations of a lot of rows through temporary tables will by default be be slower in mixed mode. For example: BEGIN; CREATE TEMPORARY TABLE tmp AS SELECT a, b, c FROM large_table1 JOIN large_table2 ON ...; INSERT INTO other_table SELECT b, c FROM tmp WHERE a <100; DROP TEMPORARY TABLE tmp; COMMIT; By default this will create a huge entry in the binary log, compared to just a few hundred bytes in statement mode. However the change in this commit will make usage of temporary tables more reliable and predicable and is thus worth it. Using statement mode or create_temporary_table_binlog_formats can be used to avoid this issue.
255 lines
6.8 KiB
PHP
255 lines
6.8 KiB
PHP
# Test CREATE OR REPLACE TABLE in replication
|
|
--source include/have_innodb.inc
|
|
|
|
--let $rpl_topology=1->2
|
|
--source include/rpl_init.inc
|
|
|
|
select @@binlog_format, @@create_tmp_table_binlog_formats;
|
|
|
|
# Copy create_tmp_table_binlog_formats from master to slave
|
|
# This is done to get same results as with older versions of MariaDB.
|
|
# The slave will work even if this is not done. However in mixed
|
|
# format on slave temporary tables would not be logged to in the
|
|
# slaves binary log
|
|
let $format=`select @@create_tmp_table_binlog_formats`;
|
|
connection server_2;
|
|
--eval set @@global.create_tmp_table_binlog_formats='$format'
|
|
# Ensure that the slave threads uses the new values.
|
|
--source include/stop_slave.inc
|
|
--source include/start_slave.inc
|
|
connection server_1;
|
|
|
|
--echo #
|
|
--echo # Create help tables
|
|
--echo #
|
|
create table t2 (a int) engine=myisam;
|
|
insert into t2 values (0),(1),(2),(2);
|
|
create temporary table t3 (a_in_temporary int) engine=myisam;
|
|
|
|
--echo #
|
|
--echo # Check how create table and create or replace table are logged
|
|
--echo #
|
|
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
create table t1 (to_be_deleted int);
|
|
|
|
connection server_1;
|
|
CREATE TABLE t1 AS SELECT 1 AS f1;
|
|
CREATE OR REPLACE TABLE t1 AS SELECT 2 AS f1;
|
|
CREATE OR REPLACE table t1 like t2;
|
|
CREATE OR REPLACE table t1 like t3;
|
|
drop table t1;
|
|
|
|
--echo binlog from server 1
|
|
--source include/show_binlog_events.inc
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
--echo binlog from server 2
|
|
--source include/show_binlog_events.inc
|
|
|
|
connection server_1;
|
|
|
|
--echo #
|
|
--echo # Ensure that also failed create_or_replace are logged
|
|
--echo #
|
|
|
|
--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
|
|
|
|
create table t1 (a int);
|
|
--error ER_TABLE_MUST_HAVE_COLUMNS
|
|
create or replace table t1;
|
|
drop table if exists t1;
|
|
# The following is not logged as t1 does not exists;
|
|
--error ER_DUP_ENTRY
|
|
create or replace table t1 (a int primary key) select a from t2;
|
|
|
|
create table t1 (a int);
|
|
# This should as a delete as we will delete t1
|
|
--error ER_DUP_ENTRY
|
|
create or replace table t1 (a int primary key) select a from t2;
|
|
|
|
# Same with temporary table
|
|
create temporary table t9 (a int);
|
|
|
|
--error ER_DUP_ENTRY
|
|
create or replace temporary table t9 (a int primary key) select a from t2;
|
|
|
|
--echo binlog from server 1
|
|
--source include/show_binlog_events.inc
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
show tables;
|
|
connection server_1;
|
|
|
|
--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
|
|
create table t1 (a int);
|
|
--error ER_DUP_FIELDNAME
|
|
create or replace table t1 (a int, a int) select * from t2;
|
|
--source include/show_binlog_events.inc
|
|
|
|
drop table if exists t1,t2;
|
|
drop temporary table if exists t9;
|
|
|
|
--echo #
|
|
--echo # Ensure that CREATE are run as CREATE OR REPLACE on slave
|
|
--echo #
|
|
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
create table t1 (server_2_to_be_delete int);
|
|
connection server_1;
|
|
create table t1 (new_table int);
|
|
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
|
|
show create table t1;
|
|
connection server_1;
|
|
drop table t1;
|
|
|
|
--echo #
|
|
--echo # Check how CREATE is logged on slave in case of conflicts
|
|
--echo #
|
|
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
|
|
create table t1 (server_2_to_be_delete int);
|
|
create table t2 (server_2_to_be_delete int);
|
|
create table t4 (server_2_to_be_delete int);
|
|
set @org_binlog_format=@@binlog_format;
|
|
set @@global.binlog_format="ROW";
|
|
stop slave;
|
|
--source include/wait_for_slave_to_stop.inc
|
|
start slave;
|
|
--source include/wait_for_slave_to_start.inc
|
|
connection server_1;
|
|
create temporary table t9 (a int);
|
|
insert into t9 values(1);
|
|
create table t1 (new_table int);
|
|
create table t2 select * from t9;
|
|
create table t4 like t9;
|
|
create table t5 select * from t9;
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
--echo binlog from server 2
|
|
--source include/show_binlog_events.inc
|
|
set @@global.binlog_format=@org_binlog_format;
|
|
stop slave;
|
|
--source include/wait_for_slave_to_stop.inc
|
|
start slave;
|
|
--source include/wait_for_slave_to_start.inc
|
|
connection server_1;
|
|
drop table t1,t2,t4,t5,t9;
|
|
|
|
--echo #
|
|
--echo # Ensure that DROP TABLE is run as DROP IF NOT EXISTS
|
|
--echo #
|
|
|
|
create table t1 (server_1_ver_1 int);
|
|
create table t4 (server_1_ver_2 int);
|
|
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
|
|
|
|
# Drop the table on the slave
|
|
drop table t1;
|
|
connection server_1;
|
|
drop table t1,t4;
|
|
create table t1 (server_2_ver_2 int);
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
show create table t1;
|
|
--echo binlog from server 2
|
|
--source include/show_binlog_events.inc
|
|
connection server_1;
|
|
drop table t1;
|
|
|
|
--echo #
|
|
--echo # Ensure that CREATE ... SELECT is recorded as one GTID on the slave
|
|
--echo #
|
|
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
|
|
connection server_1;
|
|
|
|
create table t1 (a int);
|
|
insert into t1 values (0),(1),(2);
|
|
create table t2 engine=myisam select * from t1;
|
|
create or replace table t2 engine=innodb select * from t1;
|
|
save_master_pos;
|
|
connection server_2;
|
|
sync_with_master;
|
|
--echo binlog from server 2
|
|
--source include/show_binlog_events.inc
|
|
connection server_1;
|
|
drop table t1;
|
|
|
|
--echo #
|
|
--echo # Check logging of drop temporary table
|
|
--echo #
|
|
|
|
drop temporary table t3;
|
|
|
|
--let $binlog_start=query_get_value(SHOW MASTER STATUS, Position, 1)
|
|
|
|
set @org_binlog_format=@@binlog_format;
|
|
set binlog_format="STATEMENT";
|
|
create temporary table t5 (a int);
|
|
drop temporary table t5;
|
|
set binlog_format="ROW";
|
|
create temporary table t6 (a int);
|
|
drop temporary table t6;
|
|
set binlog_format="STATEMENT";
|
|
create temporary table t7 (a int);
|
|
set binlog_format="ROW";
|
|
drop temporary table t7;
|
|
create temporary table t8 (a int);
|
|
--error ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR
|
|
set binlog_format="STATEMENT";
|
|
drop temporary table t8;
|
|
set @@binlog_format=@org_binlog_format;
|
|
|
|
# MDEV-20091:
|
|
# 1. No DROP should be logged for non-existing tmp table, nor
|
|
# 2. at the connection close when its creation has not been logged.
|
|
set @@session.binlog_format=default;
|
|
drop temporary table if exists t9;
|
|
|
|
--connect(con1,localhost,root,,)
|
|
--let $conid = `SELECT CONNECTION_ID()`
|
|
set session binlog_format=default;
|
|
create temporary table t9 (i int);
|
|
--echo *** Must be no DROP logged for t9 when there was no CREATE, at disconnect too ***
|
|
--disconnect con1
|
|
|
|
--connection server_1
|
|
# The disconnect runs asynchroneously. Wait for it to complete, otherwise the
|
|
# DROP TEMPORARY TABLE may not have been binlogged yet when SHOW BINLOG EVENTS
|
|
# is run.
|
|
--let $wait_condition= SELECT COUNT(*)=0 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID=$conid
|
|
--source include/wait_condition.inc
|
|
|
|
--source include/show_binlog_events.inc
|
|
|
|
# Clean up
|
|
drop table t2;
|
|
|
|
--connection server_2
|
|
set @@global.create_tmp_table_binlog_formats=default;
|
|
--connection server_1
|
|
|
|
--source include/rpl_end.inc
|