Loading mysql-test/r/rpl_row_create_table.result +190 −1 Original line number Diff line number Diff line Loading @@ -127,7 +127,7 @@ NULL 5 10 NULL 6 12 CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; ERROR 23000: Duplicate entry '2' for key 'b' SHOW BINLOG EVENTS FROM 1256; SHOW BINLOG EVENTS FROM 1118; Log_name Pos Event_type Server_id End_log_pos Info CREATE TABLE t7 (a INT, b INT UNIQUE); INSERT INTO t7 SELECT a,b FROM tt3; Loading Loading @@ -212,3 +212,192 @@ Create Table CREATE TABLE `t9` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL ) ENGINE=MEMORY DEFAULT CHARSET=latin1 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9; STOP SLAVE; SET GLOBAL storage_engine=@storage_engine; START SLAVE; ================ BUG#22864 ================ STOP SLAVE; RESET SLAVE; RESET MASTER; START SLAVE; SET AUTOCOMMIT=0; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 ENGINE=INNODB SELECT * FROM t1; ROLLBACK; CREATE TABLE t3 ENGINE=INNODB SELECT * FROM t1; INSERT INTO t3 VALUES (4),(5),(6); ROLLBACK; CREATE TABLE t4 ENGINE=INNODB SELECT * FROM t1; INSERT INTO t1 VALUES (4),(5),(6); ROLLBACK; Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back SHOW TABLES; Tables_in_test t1 t2 t3 t4 SELECT TABLE_NAME,ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 't_' ORDER BY TABLE_NAME; TABLE_NAME ENGINE t1 MyISAM t2 InnoDB t3 InnoDB t4 InnoDB SELECT * FROM t1 ORDER BY a; a 1 2 3 4 5 6 SELECT * FROM t2 ORDER BY a; a 1 2 3 SELECT * FROM t3 ORDER BY a; a 1 2 3 SELECT * FROM t4 ORDER BY a; a 1 2 3 SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 102 Server ver: #, Binlog ver: # master-bin.000001 102 Query 1 188 use `test`; CREATE TABLE t1 (a INT) master-bin.000001 188 Table_map 1 227 table_id: # (test.t1) master-bin.000001 227 Write_rows 1 271 table_id: # flags: STMT_END_F master-bin.000001 271 Query 1 339 use `test`; BEGIN master-bin.000001 339 Query 1 125 use `test`; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 464 Table_map 1 164 table_id: # (test.t2) master-bin.000001 503 Write_rows 1 208 table_id: # flags: STMT_END_F master-bin.000001 547 Xid 1 574 COMMIT /* XID */ master-bin.000001 574 Query 1 642 use `test`; BEGIN master-bin.000001 642 Query 1 125 use `test`; CREATE TABLE `t3` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 767 Table_map 1 164 table_id: # (test.t3) master-bin.000001 806 Write_rows 1 208 table_id: # flags: STMT_END_F master-bin.000001 850 Xid 1 877 COMMIT /* XID */ master-bin.000001 877 Query 1 945 use `test`; BEGIN master-bin.000001 945 Query 1 125 use `test`; CREATE TABLE `t4` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 1070 Table_map 1 164 table_id: # (test.t4) master-bin.000001 1109 Write_rows 1 208 table_id: # flags: STMT_END_F master-bin.000001 1153 Xid 1 1180 COMMIT /* XID */ master-bin.000001 1180 Table_map 1 1219 table_id: # (test.t1) master-bin.000001 1219 Write_rows 1 1263 table_id: # flags: STMT_END_F SHOW TABLES; Tables_in_test t1 t2 t3 t4 SELECT TABLE_NAME,ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 't_' ORDER BY TABLE_NAME; TABLE_NAME ENGINE t1 MyISAM t2 InnoDB t3 InnoDB t4 InnoDB SELECT * FROM t1 ORDER BY a; a 1 2 3 4 5 6 SELECT * FROM t2 ORDER BY a; a 1 2 3 SELECT * FROM t3 ORDER BY a; a 1 2 3 SELECT * FROM t4 ORDER BY a; a 1 2 3 DROP TABLE IF EXISTS t1,t2,t3,t4; SET AUTOCOMMIT=1; STOP SLAVE; RESET SLAVE; RESET MASTER; START SLAVE; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 (a INT) ENGINE=INNODB; BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt1 SELECT a+1 AS a FROM t1 WHERE a MOD 2 = 1; INSERT INTO t2 SELECT a+2 FROM tt1; COMMIT; SELECT * FROM t2 ORDER BY a; a 1 4 4 6 9 SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 102 Server ver: #, Binlog ver: # master-bin.000001 102 Query 1 188 use `test`; CREATE TABLE t1 (a INT) master-bin.000001 188 Table_map 1 227 table_id: # (test.t1) master-bin.000001 227 Write_rows 1 271 table_id: # flags: STMT_END_F master-bin.000001 271 Query 1 371 use `test`; CREATE TABLE t2 (a INT) ENGINE=INNODB master-bin.000001 371 Query 1 439 use `test`; BEGIN master-bin.000001 439 Table_map 1 39 table_id: # (test.t2) master-bin.000001 478 Write_rows 1 83 table_id: # flags: STMT_END_F master-bin.000001 522 Table_map 1 122 table_id: # (test.t2) master-bin.000001 561 Write_rows 1 161 table_id: # flags: STMT_END_F master-bin.000001 600 Xid 1 627 COMMIT /* XID */ SELECT * FROM t2 ORDER BY a; a 1 4 4 6 9 TRUNCATE TABLE t2; BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt2 SELECT a+1 AS a FROM t1 WHERE a MOD 2 = 1; INSERT INTO t2 SELECT a+2 FROM tt2; ROLLBACK; SELECT * FROM t2 ORDER BY a; a SHOW BINLOG EVENTS FROM 627; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 627 Query 1 80 use `test`; TRUNCATE TABLE t2 master-bin.000001 707 Xid 1 734 COMMIT /* XID */ SELECT * FROM t2 ORDER BY a; a DROP TABLE t1,t2; mysql-test/t/rpl_row_create_table-slave.opt 0 → 100644 +1 −0 Original line number Diff line number Diff line --innodb mysql-test/t/rpl_row_create_table.test +117 −8 Original line number Diff line number Diff line Loading @@ -2,6 +2,10 @@ --source include/have_binlog_format_row.inc --source include/master-slave.inc --source include/have_innodb.inc connection slave; --source include/have_innodb.inc connection master; # Bug#18326: Do not lock table for writing during prepare of statement # The use of the ps protocol causes extra table maps in the binlog, so Loading Loading @@ -31,7 +35,7 @@ CREATE TABLE t2 (a INT, b INT) ENGINE=Merge; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; --replace_column 1 # 4 # 5 # --replace_regex /table_id: [0-9]+/table_id: #/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ --query_vertical SHOW BINLOG EVENTS FROM 212 --echo **** On Master **** --query_vertical SHOW CREATE TABLE t1 Loading Loading @@ -66,8 +70,8 @@ connection master; --error 1062 CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; # Shouldn't be written to the binary log --replace_regex /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1256; --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1118; # Test that INSERT-SELECT works the same way as for SBR. CREATE TABLE t7 (a INT, b INT UNIQUE); Loading @@ -75,7 +79,7 @@ CREATE TABLE t7 (a INT, b INT UNIQUE); INSERT INTO t7 SELECT a,b FROM tt3; SELECT * FROM t7 ORDER BY a,b; # Should be written to the binary log --replace_regex /table_id: [0-9]+/table_id: #/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1118; sync_slave_with_master; SELECT * FROM t7 ORDER BY a,b; Loading @@ -86,7 +90,7 @@ INSERT INTO tt4 VALUES (4,8), (5,10), (6,12); BEGIN; INSERT INTO t7 SELECT a,b FROM tt4; ROLLBACK; --replace_regex /table_id: [0-9]+/table_id: #/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1314; SELECT * FROM t7 ORDER BY a,b; sync_slave_with_master; Loading @@ -101,7 +105,7 @@ CREATE TEMPORARY TABLE tt7 SELECT 1; --echo **** On Master **** --query_vertical SHOW CREATE TABLE t8 --query_vertical SHOW CREATE TABLE t9 --replace_regex /table_id: [0-9]+/table_id: #/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1410; sync_slave_with_master; --echo **** On Slave **** Loading @@ -109,12 +113,117 @@ sync_slave_with_master; --query_vertical SHOW CREATE TABLE t9 connection master; --disable_query_log DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9; sync_slave_with_master; # Here we reset the value of the default storage engine STOP SLAVE; SET GLOBAL storage_engine=@storage_engine; START SLAVE; --enable_query_log --enable_ps_protocol # BUG#22864 (Rollback following CREATE ... SELECT discards 'CREATE # table' from log): --echo ================ BUG#22864 ================ connection slave; STOP SLAVE; RESET SLAVE; connection master; RESET MASTER; connection slave; START SLAVE; connection master; SET AUTOCOMMIT=0; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 ENGINE=INNODB SELECT * FROM t1; ROLLBACK; CREATE TABLE t3 ENGINE=INNODB SELECT * FROM t1; INSERT INTO t3 VALUES (4),(5),(6); ROLLBACK; CREATE TABLE t4 ENGINE=INNODB SELECT * FROM t1; INSERT INTO t1 VALUES (4),(5),(6); ROLLBACK; SHOW TABLES; SELECT TABLE_NAME,ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 't_' ORDER BY TABLE_NAME; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; SELECT * FROM t3 ORDER BY a; SELECT * FROM t4 ORDER BY a; --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS; sync_slave_with_master; SHOW TABLES; SELECT TABLE_NAME,ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 't_' ORDER BY TABLE_NAME; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; SELECT * FROM t3 ORDER BY a; SELECT * FROM t4 ORDER BY a; connection master; DROP TABLE IF EXISTS t1,t2,t3,t4; SET AUTOCOMMIT=1; sync_slave_with_master; # Some tests with temporary tables connection slave; STOP SLAVE; RESET SLAVE; connection master; RESET MASTER; connection slave; START SLAVE; connection master; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 (a INT) ENGINE=INNODB; BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt1 SELECT a+1 AS a FROM t1 WHERE a MOD 2 = 1; INSERT INTO t2 SELECT a+2 FROM tt1; COMMIT; SELECT * FROM t2 ORDER BY a; --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS; sync_slave_with_master; SELECT * FROM t2 ORDER BY a; connection master; TRUNCATE TABLE t2; BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt2 SELECT a+1 AS a FROM t1 WHERE a MOD 2 = 1; INSERT INTO t2 SELECT a+2 FROM tt2; ROLLBACK; SELECT * FROM t2 ORDER BY a; --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 627; sync_slave_with_master; SELECT * FROM t2 ORDER BY a; connection master; DROP TABLE t1,t2; sync_slave_with_master; sql/log.cc +127 −29 Original line number Diff line number Diff line Loading @@ -81,6 +81,41 @@ char *make_default_log_name(char *buff,const char* log_ext) MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT)); } /* Helper class to hold a mutex for the duration of the block. Eliminates the need for explicit unlocking of mutexes on, e.g., error returns. On passing a null pointer, the sentry will not do anything. */ class Mutex_sentry { public: Mutex_sentry(pthread_mutex_t *mutex) : m_mutex(mutex) { if (m_mutex) pthread_mutex_lock(mutex); } ~Mutex_sentry() { if (m_mutex) pthread_mutex_unlock(m_mutex); #ifndef DBUG_OFF m_mutex= 0; #endif } private: pthread_mutex_t *m_mutex; // It's not allowed to copy this object in any way Mutex_sentry(Mutex_sentry const&); void operator=(Mutex_sentry const&); }; /* Helper class to store binary log transaction data. */ Loading Loading @@ -113,9 +148,13 @@ class binlog_trx_data { */ void truncate(my_off_t pos) { DBUG_PRINT("info", ("truncating to position %lu", pos)); DBUG_PRINT("info", ("before_stmt_pos=%lu", pos)); delete pending(); set_pending(0); reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0); if (pos < before_stmt_pos) before_stmt_pos= MY_OFF_T_UNDEF; } /* Loading Loading @@ -1483,12 +1522,11 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, If rolling back a statement in a transaction, we truncate the transaction cache to remove the statement. */ if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) trx_data->reset(); else trx_data->truncate(trx_data->before_stmt_pos); // ...statement else // ...statement trx_data->truncate(trx_data->before_stmt_pos); /* We need to step the table map version on a rollback to ensure Loading Loading @@ -3415,6 +3453,18 @@ THD::binlog_start_trans_and_stmt() if (trx_data == NULL || trx_data->before_stmt_pos == MY_OFF_T_UNDEF) { this->binlog_set_stmt_begin(); if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(this, TRUE, binlog_hton); trans_register_ha(this, FALSE, binlog_hton); } DBUG_VOID_RETURN; } void THD::binlog_set_stmt_begin() { binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; /* The call to binlog_trans_log_savepos() might create the trx_data structure, if it didn't exist before, so we save the position Loading @@ -3424,16 +3474,38 @@ THD::binlog_start_trans_and_stmt() my_off_t pos= 0; binlog_trans_log_savepos(this, &pos); trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; trx_data->before_stmt_pos= pos; } if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(this, TRUE, binlog_hton); trans_register_ha(this, FALSE, binlog_hton); int THD::binlog_flush_transaction_cache() { DBUG_ENTER("binlog_flush_transaction_cache"); binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; DBUG_PRINT("enter", ("trx_data=0x%lu", trx_data)); if (trx_data) DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%u", trx_data->before_stmt_pos)); /* Write the transaction cache to the binary log. We don't flush and sync the log file since we don't know if more will be written to it. If the caller want the log file sync:ed, the caller has to do it. The transaction data is only reset upon a successful write of the cache to the binary log. */ if (trx_data && likely(mysql_bin_log.is_open())) { if (int error= mysql_bin_log.write_cache(&trx_data->trans_log, true, true)) DBUG_RETURN(error); trx_data->reset(); } DBUG_VOID_RETURN; DBUG_RETURN(0); } /* Write a table map to the binary log. */ Loading Loading @@ -3843,6 +3915,40 @@ uint MYSQL_BIN_LOG::next_file_id() } /* Write the contents of a cache to the binary log. SYNOPSIS write_cache() cache Cache to write to the binary log lock_log True if the LOCK_log mutex should be aquired, false otherwise sync_log True if the log should be flushed and sync:ed DESCRIPTION Write the contents of the cache to the binary log. The cache will be reset as a READ_CACHE to be able to read the contents from it. */ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log) { Mutex_sentry sentry(lock_log ? &LOCK_log : NULL); if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) return ER_ERROR_ON_WRITE; uint bytes= my_b_bytes_in_cache(cache); do { if (my_b_write(&log_file, cache->read_pos, bytes)) return ER_ERROR_ON_WRITE; cache->read_pos= cache->read_end; } while ((bytes= my_b_fill(cache))); if (sync_log) flush_and_sync(); return 0; // All OK } /* Write a cached log entry to the binary log Loading @@ -3850,6 +3956,8 @@ uint MYSQL_BIN_LOG::next_file_id() write() thd cache The cache to copy to the binlog commit_event The commit event to print after writing the contents of the cache. NOTE - We only come here if there is something in the cache. Loading Loading @@ -3909,19 +4017,9 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) if (qinfo.write(&log_file)) goto err; } /* Read from the file used to cache the queries .*/ if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) goto err; length=my_b_bytes_in_cache(cache); DBUG_EXECUTE_IF("half_binlogged_transaction", length-=100;); do { /* Write data to the binary log file */ if (my_b_write(&log_file, cache->read_pos, length)) if ((write_error= write_cache(cache, false, false))) goto err; cache->read_pos=cache->read_end; // Mark buffer used up DBUG_EXECUTE_IF("half_binlogged_transaction", goto DBUG_skip_commit;); } while ((length=my_b_fill(cache))); if (commit_event && commit_event->write(&log_file)) goto err; Loading sql/log.h +2 −0 Original line number Diff line number Diff line Loading @@ -340,6 +340,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG bool write(Log_event* event_info); // binary log write bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event); int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync); void start_union_events(THD *thd); void stop_union_events(THD *thd); bool is_query_in_union(THD *thd, query_id_t query_id_param); Loading Loading
mysql-test/r/rpl_row_create_table.result +190 −1 Original line number Diff line number Diff line Loading @@ -127,7 +127,7 @@ NULL 5 10 NULL 6 12 CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; ERROR 23000: Duplicate entry '2' for key 'b' SHOW BINLOG EVENTS FROM 1256; SHOW BINLOG EVENTS FROM 1118; Log_name Pos Event_type Server_id End_log_pos Info CREATE TABLE t7 (a INT, b INT UNIQUE); INSERT INTO t7 SELECT a,b FROM tt3; Loading Loading @@ -212,3 +212,192 @@ Create Table CREATE TABLE `t9` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL ) ENGINE=MEMORY DEFAULT CHARSET=latin1 DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9; STOP SLAVE; SET GLOBAL storage_engine=@storage_engine; START SLAVE; ================ BUG#22864 ================ STOP SLAVE; RESET SLAVE; RESET MASTER; START SLAVE; SET AUTOCOMMIT=0; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 ENGINE=INNODB SELECT * FROM t1; ROLLBACK; CREATE TABLE t3 ENGINE=INNODB SELECT * FROM t1; INSERT INTO t3 VALUES (4),(5),(6); ROLLBACK; CREATE TABLE t4 ENGINE=INNODB SELECT * FROM t1; INSERT INTO t1 VALUES (4),(5),(6); ROLLBACK; Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back SHOW TABLES; Tables_in_test t1 t2 t3 t4 SELECT TABLE_NAME,ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 't_' ORDER BY TABLE_NAME; TABLE_NAME ENGINE t1 MyISAM t2 InnoDB t3 InnoDB t4 InnoDB SELECT * FROM t1 ORDER BY a; a 1 2 3 4 5 6 SELECT * FROM t2 ORDER BY a; a 1 2 3 SELECT * FROM t3 ORDER BY a; a 1 2 3 SELECT * FROM t4 ORDER BY a; a 1 2 3 SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 102 Server ver: #, Binlog ver: # master-bin.000001 102 Query 1 188 use `test`; CREATE TABLE t1 (a INT) master-bin.000001 188 Table_map 1 227 table_id: # (test.t1) master-bin.000001 227 Write_rows 1 271 table_id: # flags: STMT_END_F master-bin.000001 271 Query 1 339 use `test`; BEGIN master-bin.000001 339 Query 1 125 use `test`; CREATE TABLE `t2` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 464 Table_map 1 164 table_id: # (test.t2) master-bin.000001 503 Write_rows 1 208 table_id: # flags: STMT_END_F master-bin.000001 547 Xid 1 574 COMMIT /* XID */ master-bin.000001 574 Query 1 642 use `test`; BEGIN master-bin.000001 642 Query 1 125 use `test`; CREATE TABLE `t3` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 767 Table_map 1 164 table_id: # (test.t3) master-bin.000001 806 Write_rows 1 208 table_id: # flags: STMT_END_F master-bin.000001 850 Xid 1 877 COMMIT /* XID */ master-bin.000001 877 Query 1 945 use `test`; BEGIN master-bin.000001 945 Query 1 125 use `test`; CREATE TABLE `t4` ( `a` int(11) DEFAULT NULL ) ENGINE=InnoDB master-bin.000001 1070 Table_map 1 164 table_id: # (test.t4) master-bin.000001 1109 Write_rows 1 208 table_id: # flags: STMT_END_F master-bin.000001 1153 Xid 1 1180 COMMIT /* XID */ master-bin.000001 1180 Table_map 1 1219 table_id: # (test.t1) master-bin.000001 1219 Write_rows 1 1263 table_id: # flags: STMT_END_F SHOW TABLES; Tables_in_test t1 t2 t3 t4 SELECT TABLE_NAME,ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 't_' ORDER BY TABLE_NAME; TABLE_NAME ENGINE t1 MyISAM t2 InnoDB t3 InnoDB t4 InnoDB SELECT * FROM t1 ORDER BY a; a 1 2 3 4 5 6 SELECT * FROM t2 ORDER BY a; a 1 2 3 SELECT * FROM t3 ORDER BY a; a 1 2 3 SELECT * FROM t4 ORDER BY a; a 1 2 3 DROP TABLE IF EXISTS t1,t2,t3,t4; SET AUTOCOMMIT=1; STOP SLAVE; RESET SLAVE; RESET MASTER; START SLAVE; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 (a INT) ENGINE=INNODB; BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt1 SELECT a+1 AS a FROM t1 WHERE a MOD 2 = 1; INSERT INTO t2 SELECT a+2 FROM tt1; COMMIT; SELECT * FROM t2 ORDER BY a; a 1 4 4 6 9 SHOW BINLOG EVENTS; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 102 Server ver: #, Binlog ver: # master-bin.000001 102 Query 1 188 use `test`; CREATE TABLE t1 (a INT) master-bin.000001 188 Table_map 1 227 table_id: # (test.t1) master-bin.000001 227 Write_rows 1 271 table_id: # flags: STMT_END_F master-bin.000001 271 Query 1 371 use `test`; CREATE TABLE t2 (a INT) ENGINE=INNODB master-bin.000001 371 Query 1 439 use `test`; BEGIN master-bin.000001 439 Table_map 1 39 table_id: # (test.t2) master-bin.000001 478 Write_rows 1 83 table_id: # flags: STMT_END_F master-bin.000001 522 Table_map 1 122 table_id: # (test.t2) master-bin.000001 561 Write_rows 1 161 table_id: # flags: STMT_END_F master-bin.000001 600 Xid 1 627 COMMIT /* XID */ SELECT * FROM t2 ORDER BY a; a 1 4 4 6 9 TRUNCATE TABLE t2; BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt2 SELECT a+1 AS a FROM t1 WHERE a MOD 2 = 1; INSERT INTO t2 SELECT a+2 FROM tt2; ROLLBACK; SELECT * FROM t2 ORDER BY a; a SHOW BINLOG EVENTS FROM 627; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 627 Query 1 80 use `test`; TRUNCATE TABLE t2 master-bin.000001 707 Xid 1 734 COMMIT /* XID */ SELECT * FROM t2 ORDER BY a; a DROP TABLE t1,t2;
mysql-test/t/rpl_row_create_table-slave.opt 0 → 100644 +1 −0 Original line number Diff line number Diff line --innodb
mysql-test/t/rpl_row_create_table.test +117 −8 Original line number Diff line number Diff line Loading @@ -2,6 +2,10 @@ --source include/have_binlog_format_row.inc --source include/master-slave.inc --source include/have_innodb.inc connection slave; --source include/have_innodb.inc connection master; # Bug#18326: Do not lock table for writing during prepare of statement # The use of the ps protocol causes extra table maps in the binlog, so Loading Loading @@ -31,7 +35,7 @@ CREATE TABLE t2 (a INT, b INT) ENGINE=Merge; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; --replace_column 1 # 4 # 5 # --replace_regex /table_id: [0-9]+/table_id: #/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ --query_vertical SHOW BINLOG EVENTS FROM 212 --echo **** On Master **** --query_vertical SHOW CREATE TABLE t1 Loading Loading @@ -66,8 +70,8 @@ connection master; --error 1062 CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; # Shouldn't be written to the binary log --replace_regex /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1256; --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1118; # Test that INSERT-SELECT works the same way as for SBR. CREATE TABLE t7 (a INT, b INT UNIQUE); Loading @@ -75,7 +79,7 @@ CREATE TABLE t7 (a INT, b INT UNIQUE); INSERT INTO t7 SELECT a,b FROM tt3; SELECT * FROM t7 ORDER BY a,b; # Should be written to the binary log --replace_regex /table_id: [0-9]+/table_id: #/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1118; sync_slave_with_master; SELECT * FROM t7 ORDER BY a,b; Loading @@ -86,7 +90,7 @@ INSERT INTO tt4 VALUES (4,8), (5,10), (6,12); BEGIN; INSERT INTO t7 SELECT a,b FROM tt4; ROLLBACK; --replace_regex /table_id: [0-9]+/table_id: #/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1314; SELECT * FROM t7 ORDER BY a,b; sync_slave_with_master; Loading @@ -101,7 +105,7 @@ CREATE TEMPORARY TABLE tt7 SELECT 1; --echo **** On Master **** --query_vertical SHOW CREATE TABLE t8 --query_vertical SHOW CREATE TABLE t9 --replace_regex /table_id: [0-9]+/table_id: #/ --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 1410; sync_slave_with_master; --echo **** On Slave **** Loading @@ -109,12 +113,117 @@ sync_slave_with_master; --query_vertical SHOW CREATE TABLE t9 connection master; --disable_query_log DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9; sync_slave_with_master; # Here we reset the value of the default storage engine STOP SLAVE; SET GLOBAL storage_engine=@storage_engine; START SLAVE; --enable_query_log --enable_ps_protocol # BUG#22864 (Rollback following CREATE ... SELECT discards 'CREATE # table' from log): --echo ================ BUG#22864 ================ connection slave; STOP SLAVE; RESET SLAVE; connection master; RESET MASTER; connection slave; START SLAVE; connection master; SET AUTOCOMMIT=0; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 ENGINE=INNODB SELECT * FROM t1; ROLLBACK; CREATE TABLE t3 ENGINE=INNODB SELECT * FROM t1; INSERT INTO t3 VALUES (4),(5),(6); ROLLBACK; CREATE TABLE t4 ENGINE=INNODB SELECT * FROM t1; INSERT INTO t1 VALUES (4),(5),(6); ROLLBACK; SHOW TABLES; SELECT TABLE_NAME,ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 't_' ORDER BY TABLE_NAME; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; SELECT * FROM t3 ORDER BY a; SELECT * FROM t4 ORDER BY a; --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS; sync_slave_with_master; SHOW TABLES; SELECT TABLE_NAME,ENGINE FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 't_' ORDER BY TABLE_NAME; SELECT * FROM t1 ORDER BY a; SELECT * FROM t2 ORDER BY a; SELECT * FROM t3 ORDER BY a; SELECT * FROM t4 ORDER BY a; connection master; DROP TABLE IF EXISTS t1,t2,t3,t4; SET AUTOCOMMIT=1; sync_slave_with_master; # Some tests with temporary tables connection slave; STOP SLAVE; RESET SLAVE; connection master; RESET MASTER; connection slave; START SLAVE; connection master; CREATE TABLE t1 (a INT); INSERT INTO t1 VALUES (1),(2),(3); CREATE TABLE t2 (a INT) ENGINE=INNODB; BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt1 SELECT a+1 AS a FROM t1 WHERE a MOD 2 = 1; INSERT INTO t2 SELECT a+2 FROM tt1; COMMIT; SELECT * FROM t2 ORDER BY a; --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS; sync_slave_with_master; SELECT * FROM t2 ORDER BY a; connection master; TRUNCATE TABLE t2; BEGIN; INSERT INTO t2 SELECT a*a FROM t1; CREATE TEMPORARY TABLE tt2 SELECT a+1 AS a FROM t1 WHERE a MOD 2 = 1; INSERT INTO t2 SELECT a+2 FROM tt2; ROLLBACK; SELECT * FROM t2 ORDER BY a; --replace_regex /\/\* xid=.* \*\//\/* XID *\// /Server ver: .*, Binlog ver: .*/Server ver: #, Binlog ver: #/ /table_id: [0-9]+/table_id: #/ SHOW BINLOG EVENTS FROM 627; sync_slave_with_master; SELECT * FROM t2 ORDER BY a; connection master; DROP TABLE t1,t2; sync_slave_with_master;
sql/log.cc +127 −29 Original line number Diff line number Diff line Loading @@ -81,6 +81,41 @@ char *make_default_log_name(char *buff,const char* log_ext) MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT)); } /* Helper class to hold a mutex for the duration of the block. Eliminates the need for explicit unlocking of mutexes on, e.g., error returns. On passing a null pointer, the sentry will not do anything. */ class Mutex_sentry { public: Mutex_sentry(pthread_mutex_t *mutex) : m_mutex(mutex) { if (m_mutex) pthread_mutex_lock(mutex); } ~Mutex_sentry() { if (m_mutex) pthread_mutex_unlock(m_mutex); #ifndef DBUG_OFF m_mutex= 0; #endif } private: pthread_mutex_t *m_mutex; // It's not allowed to copy this object in any way Mutex_sentry(Mutex_sentry const&); void operator=(Mutex_sentry const&); }; /* Helper class to store binary log transaction data. */ Loading Loading @@ -113,9 +148,13 @@ class binlog_trx_data { */ void truncate(my_off_t pos) { DBUG_PRINT("info", ("truncating to position %lu", pos)); DBUG_PRINT("info", ("before_stmt_pos=%lu", pos)); delete pending(); set_pending(0); reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0); if (pos < before_stmt_pos) before_stmt_pos= MY_OFF_T_UNDEF; } /* Loading Loading @@ -1483,12 +1522,11 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, If rolling back a statement in a transaction, we truncate the transaction cache to remove the statement. */ if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) trx_data->reset(); else trx_data->truncate(trx_data->before_stmt_pos); // ...statement else // ...statement trx_data->truncate(trx_data->before_stmt_pos); /* We need to step the table map version on a rollback to ensure Loading Loading @@ -3415,6 +3453,18 @@ THD::binlog_start_trans_and_stmt() if (trx_data == NULL || trx_data->before_stmt_pos == MY_OFF_T_UNDEF) { this->binlog_set_stmt_begin(); if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(this, TRUE, binlog_hton); trans_register_ha(this, FALSE, binlog_hton); } DBUG_VOID_RETURN; } void THD::binlog_set_stmt_begin() { binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; /* The call to binlog_trans_log_savepos() might create the trx_data structure, if it didn't exist before, so we save the position Loading @@ -3424,16 +3474,38 @@ THD::binlog_start_trans_and_stmt() my_off_t pos= 0; binlog_trans_log_savepos(this, &pos); trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; trx_data->before_stmt_pos= pos; } if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(this, TRUE, binlog_hton); trans_register_ha(this, FALSE, binlog_hton); int THD::binlog_flush_transaction_cache() { DBUG_ENTER("binlog_flush_transaction_cache"); binlog_trx_data *trx_data= (binlog_trx_data*) ha_data[binlog_hton->slot]; DBUG_PRINT("enter", ("trx_data=0x%lu", trx_data)); if (trx_data) DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%u", trx_data->before_stmt_pos)); /* Write the transaction cache to the binary log. We don't flush and sync the log file since we don't know if more will be written to it. If the caller want the log file sync:ed, the caller has to do it. The transaction data is only reset upon a successful write of the cache to the binary log. */ if (trx_data && likely(mysql_bin_log.is_open())) { if (int error= mysql_bin_log.write_cache(&trx_data->trans_log, true, true)) DBUG_RETURN(error); trx_data->reset(); } DBUG_VOID_RETURN; DBUG_RETURN(0); } /* Write a table map to the binary log. */ Loading Loading @@ -3843,6 +3915,40 @@ uint MYSQL_BIN_LOG::next_file_id() } /* Write the contents of a cache to the binary log. SYNOPSIS write_cache() cache Cache to write to the binary log lock_log True if the LOCK_log mutex should be aquired, false otherwise sync_log True if the log should be flushed and sync:ed DESCRIPTION Write the contents of the cache to the binary log. The cache will be reset as a READ_CACHE to be able to read the contents from it. */ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log) { Mutex_sentry sentry(lock_log ? &LOCK_log : NULL); if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) return ER_ERROR_ON_WRITE; uint bytes= my_b_bytes_in_cache(cache); do { if (my_b_write(&log_file, cache->read_pos, bytes)) return ER_ERROR_ON_WRITE; cache->read_pos= cache->read_end; } while ((bytes= my_b_fill(cache))); if (sync_log) flush_and_sync(); return 0; // All OK } /* Write a cached log entry to the binary log Loading @@ -3850,6 +3956,8 @@ uint MYSQL_BIN_LOG::next_file_id() write() thd cache The cache to copy to the binlog commit_event The commit event to print after writing the contents of the cache. NOTE - We only come here if there is something in the cache. Loading Loading @@ -3909,19 +4017,9 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) if (qinfo.write(&log_file)) goto err; } /* Read from the file used to cache the queries .*/ if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) goto err; length=my_b_bytes_in_cache(cache); DBUG_EXECUTE_IF("half_binlogged_transaction", length-=100;); do { /* Write data to the binary log file */ if (my_b_write(&log_file, cache->read_pos, length)) if ((write_error= write_cache(cache, false, false))) goto err; cache->read_pos=cache->read_end; // Mark buffer used up DBUG_EXECUTE_IF("half_binlogged_transaction", goto DBUG_skip_commit;); } while ((length=my_b_fill(cache))); if (commit_event && commit_event->write(&log_file)) goto err; Loading
sql/log.h +2 −0 Original line number Diff line number Diff line Loading @@ -340,6 +340,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG bool write(Log_event* event_info); // binary log write bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event); int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync); void start_union_events(THD *thd); void stop_union_events(THD *thd); bool is_query_in_union(THD *thd, query_id_t query_id_param); Loading