From ea697fd44565e4da42aa0679bffa91af8cf4ada5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Dec 2006 11:32:41 +0100 Subject: [PATCH 01/43] BUG#21132 (Slave fails to reconnect on update_slave_list): The update_slave_list() call is a remainder from attempts to implement failsafe replication. This code is now obsolete and not maintained (see comments in rpl_failsafe.cc). Inspecting the code one can see that this function do not interferre with normal slave operation and thus can be safely removed. This will solve the issue reported in the bug (errors on slave reconnection). A related issue is to remove unneccessary reconnections done by slave. This is handled in the patch for BUG#20435. sql/slave.cc: Removed call to obsolete function update_slave_list() upon slave's I/O thread reconnect. --- sql/slave.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/slave.cc b/sql/slave.cc index d0396444ace..a5d2e01b9ec 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3526,7 +3526,7 @@ connected: on with life. */ thd->proc_info = "Registering slave on master"; - if (register_slave_on_master(mysql) || update_slave_list(mysql, mi)) + if (register_slave_on_master(mysql)) goto err; } From 40f70e75ef5c0babcf07b7d49033c06589f34d72 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Aug 2007 19:51:25 +0200 Subject: [PATCH 02/43] rpl_packet.test: Removed sleep from test per lars request mysql-test/suite/rpl/t/rpl_packet.test: Removed sleep from test per lars request --- mysql-test/suite/rpl/t/rpl_packet.test | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 316278cb75d..c3987f7ee15 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -67,7 +67,6 @@ INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # The slave I/O thread must stop after trying to read the above event connection slave; -sleep 2; --source include/wait_for_slave_io_to_stop.inc SHOW STATUS LIKE 'Slave_running'; From be9619f0472f2ae05efd400f18c09cf756080e72 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Aug 2007 12:31:21 +0400 Subject: [PATCH 03/43] rpl.rpl_innodb_mixed_dml enabled --- mysql-test/suite/rpl/t/disabled.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index d1b636ad9a2..34a8d6988a9 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -12,7 +12,7 @@ rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master #rpl_innodb_mixed_ddl : Bug #29363 rpl.rpl_innodb_mixed_* test failures -rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures +#rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. From 86c92997ea559d1c799d5a91db48a9e3e527641e Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 20 Aug 2007 13:24:37 +0400 Subject: [PATCH 04/43] Bug#29363 mysql-test/suite/rpl/include/rpl_mixed_dml.inc: removed file_id,block_len from SHOW BINLOG EVENTS mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result: updated result file --- mysql-test/suite/rpl/include/rpl_mixed_dml.inc | 4 ++-- mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc index 1accf40160a..96dfdbed541 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc @@ -328,7 +328,7 @@ DROP VIEW v2; --echo --echo ******************** SHOW BINLOG EVENTS ******************** --replace_column 2 # 5 # ---replace_regex /Server ver: .+/Server ver: #/ /table_id: [0-9]+/table_id: #/ /COMMIT.+xid=[0-9]+.+/#/ +--replace_regex /Server ver: .+/Server ver: #/ /table_id: [0-9]+/table_id: #/ /COMMIT.+xid=[0-9]+.+/#/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/ show binlog events from 1; sync_slave_with_master; # as we're using UUID we don't SELECT but use "diff" like in rpl_row_UUID @@ -344,4 +344,4 @@ sync_slave_with_master; # will be created. You will need to go to the mysql-test dir and diff # the files your self to see what is not matching ---exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql; +--exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql diff --git a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result index 462400e12bb..19c5299df25 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@ -867,8 +867,8 @@ master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2 master-bin.000001 # Xid 1 # # -master-bin.000001 # Begin_load_query 1 # ;file_id=1;block_len=30 -master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=1 +master-bin.000001 # Begin_load_query 1 # ;file_id=#;block_len=# +master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=# master-bin.000001 # Xid 1 # # master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 master-bin.000001 # Xid 1 # # From a0849011471dd15c2789436ed57350691e030101 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Aug 2007 15:16:55 +0300 Subject: [PATCH 05/43] Bug #23333 stored function + non-transac table + transac table = breaks stmt-based binlog Binlogging of the statement with a side effect like a modified non-trans table did not happen. The artifact involved all binloggable dml queries. Fixed with changing the binlogging conditions all over the code to exploit thd->transaction.stmt.modified_non_trans_table introduced by the patch for bug@27417. Multi-delete case has own specific addressed by another bug@29136. Multi-update case has been addressed by bug#27716 and patch and will need merging. mysql-test/r/mix_innodb_myisam_binlog.result: results changed mysql-test/r/sp_trans_log.result: results changed mysql-test/t/mix_innodb_myisam_binlog.test: specific to the bug tests added mysql-test/t/sp_trans_log.test: refining of the proof of that there is an event in binlog sql/sql_delete.cc: deploying the binlogging check with thd->transaction.stmt.modified_non_trans_table sql/sql_insert.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is TRUE. Merge with Bug#29571. sql/sql_load.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is true sql/sql_update.cc: binlogging when thd->transaction.stmt.modified_non_trans_table is true --- mysql-test/r/mix_innodb_myisam_binlog.result | 73 ++++++++++- mysql-test/r/sp_trans_log.result | 5 +- mysql-test/t/mix_innodb_myisam_binlog.test | 120 ++++++++++++++++++- mysql-test/t/sp_trans_log.test | 3 +- sql/sql_delete.cc | 6 +- sql/sql_insert.cc | 78 ++++++------ sql/sql_load.cc | 2 +- sql/sql_update.cc | 2 +- 8 files changed, 238 insertions(+), 51 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 5777bd890b2..181f4c67254 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -365,7 +365,7 @@ insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 1 show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 98 +master-bin.000001 196 /* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; count(*) @@ -390,6 +390,75 @@ affected rows: 0 select count(*) from t1 /* must be 7 */; count(*) 7 -drop function bug27417; drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 267 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 290 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 190 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 246 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 1 +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 376 +drop trigger trg_del; +drop table t1,t2,t3; +drop function bug27417; end of tests diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index 96e6f76b23c..14a8ecf6a37 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -12,8 +12,9 @@ end| reset master| insert into t2 values (bug23333(),1)| ERROR 23000: Duplicate entry '1' for key 1 -show binlog events from 98 /* with fixes for #23333 will show there is the query */| -Log_name Pos Event_type Server_id End_log_pos Info +show master status /* the offset must denote there is the query */| +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 284 select count(*),@a from t1 /* must be 1,1 */| count(*) @a 1 1 diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index f9d7235ff84..e5fec37cc23 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -380,8 +380,126 @@ delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; --disable_info select count(*) from t1 /* must be 7 */; -drop function bug27417; +# function bug27417 remains for the following testing of bug#23333 drop table t1,t2; +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + show master status /* the offset must denote there is the query */; + +# +# bug#23333 cleanup +# + + +drop trigger trg_del; +drop table t1,t2,t3; +drop function bug27417; + + --echo end of tests diff --git a/mysql-test/t/sp_trans_log.test b/mysql-test/t/sp_trans_log.test index 3e440b3ccc1..508c730a1cf 100644 --- a/mysql-test/t/sp_trans_log.test +++ b/mysql-test/t/sp_trans_log.test @@ -26,8 +26,7 @@ end| reset master| --error ER_DUP_ENTRY insert into t2 values (bug23333(),1)| ---replace_column 2 # 5 # 6 # -show binlog events from 98 /* with fixes for #23333 will show there is the query */| +show master status /* the offset must denote there is the query */| select count(*),@a from t1 /* must be 1,1 */| drop table t1, t2| diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 56edfa6c5b2..7555219f5d8 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -319,7 +319,7 @@ cleanup: thd->transaction.stmt.modified_non_trans_table= TRUE; /* See similar binlogging code in sql_update.cc, for comments */ - if ((error < 0) || (deleted && !transactional_table)) + if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { @@ -817,7 +817,8 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - if ((local_error == 0) || (deleted && normal_tables)) + DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); + if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { @@ -831,7 +832,6 @@ bool multi_delete::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } - DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); /* Commit or rollback the current SQL statement */ if (transactional_tables) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index bd21d929291..a2fd71ba240 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -866,8 +866,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, transactional_table= table->file->has_transactions(); - if ((changed= (info.copied || info.deleted || info.updated)) || - was_insert_delayed) + if ((changed= (info.copied || info.deleted || info.updated))) { /* Invalidate the table in the query cache if something changed. @@ -876,46 +875,47 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, */ if (changed) query_cache_invalidate3(thd, table_list, 1); - if (error <= 0 || !transactional_table) + } + if (changed && error <= 0 || thd->transaction.stmt.modified_non_trans_table + || was_insert_delayed) + { + if (mysql_bin_log.is_open()) { - if (mysql_bin_log.is_open()) + if (error <= 0) { - if (error <= 0) - { - /* - [Guilhem wrote] Temporary errors may have filled - thd->net.last_error/errno. For example if there has - been a disk full error when writing the row, and it was - MyISAM, then thd->net.last_error/errno will be set to - "disk full"... and the my_pwrite() will wait until free - space appears, and so when it finishes then the - write_row() was entirely successful - */ - /* todo: consider removing */ - thd->clear_error(); - } - /* bug#22725: - - A query which per-row-loop can not be interrupted with - KILLED, like INSERT, and that does not invoke stored - routines can be binlogged with neglecting the KILLED error. - - If there was no error (error == zero) until after the end of - inserting loop the KILLED flag that appeared later can be - disregarded since previously possible invocation of stored - routines did not result in any error due to the KILLED. In - such case the flag is ignored for constructing binlog event. + /* + [Guilhem wrote] Temporary errors may have filled + thd->net.last_error/errno. For example if there has + been a disk full error when writing the row, and it was + MyISAM, then thd->net.last_error/errno will be set to + "disk full"... and the my_pwrite() will wait until free + space appears, and so when it finishes then the + write_row() was entirely successful */ - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_table, FALSE, - (error>0) ? thd->killed : THD::NOT_KILLED); - DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); - if (mysql_bin_log.write(&qinfo) && transactional_table) - error=1; + /* todo: consider removing */ + thd->clear_error(); } - if (thd->transaction.stmt.modified_non_trans_table) - thd->transaction.all.modified_non_trans_table= TRUE; + /* bug#22725: + + A query which per-row-loop can not be interrupted with + KILLED, like INSERT, and that does not invoke stored + routines can be binlogged with neglecting the KILLED error. + + If there was no error (error == zero) until after the end of + inserting loop the KILLED flag that appeared later can be + disregarded since previously possible invocation of stored + routines did not result in any error due to the KILLED. In + such case the flag is ignored for constructing binlog event. + */ + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_table, FALSE, + (error>0) ? thd->killed : THD::NOT_KILLED); + DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); + if (mysql_bin_log.write(&qinfo) && transactional_table) + error=1; } + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE; } DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); @@ -3001,6 +3001,7 @@ void select_insert::abort() */ DBUG_VOID_RETURN; } + changed= (info.copied || info.deleted || info.updated); transactional_table= table->file->has_transactions(); if (!thd->prelocked_mode) table->file->end_bulk_insert(); @@ -3010,8 +3011,7 @@ void select_insert::abort() error while inserting into a MyISAM table) we must write to the binlog (and the error code will make the slave stop). */ - if ((changed= info.copied || info.deleted || info.updated) && - !transactional_table) + if (thd->transaction.stmt.modified_non_trans_table) { if (last_insert_id) thd->insert_id(last_insert_id); // For binary log diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 55cbbf1c540..0dc02ac4a68 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -444,7 +444,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, /* If the file was not empty, wrote_create_file is true */ if (lf_info.wrote_create_file) { - if ((info.copied || info.deleted) && !transactional_table) + if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, handle_duplicates, ignore, transactional_table); else diff --git a/sql/sql_update.cc b/sql/sql_update.cc index c78e246f518..3f38ad8b33c 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -580,7 +580,7 @@ int mysql_update(THD *thd, Sometimes we want to binlog even if we updated no rows, in case user used it to be sure master and slave are in same state. */ - if ((error < 0) || (updated && !transactional_table)) + if ((error < 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) { From bdfe0b5290df00c85b716bbcd3718b842a3fbbdc Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Aug 2007 10:40:38 +0300 Subject: [PATCH 06/43] bug#27417 refining of cleanup of the tests. mysql-test/r/mix_innodb_myisam_binlog.result: results changed. mysql-test/t/mix_innodb_myisam_binlog.test: proper cleanup. --- mysql-test/r/mix_innodb_myisam_binlog.result | 2 +- mysql-test/t/mix_innodb_myisam_binlog.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 181f4c67254..5d5726c9689 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -459,6 +459,6 @@ show master status /* the offset must denote there is the query */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 376 drop trigger trg_del; -drop table t1,t2,t3; +drop table t1,t2,t3,t4; drop function bug27417; end of tests diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index e5fec37cc23..e1740bda03e 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -497,7 +497,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); drop trigger trg_del; -drop table t1,t2,t3; +drop table t1,t2,t3,t4; drop function bug27417; From 116995f9165539a254e058f1be13ae364a0bef4b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 22 Aug 2007 15:43:16 +0300 Subject: [PATCH 07/43] bug#23333 fixing the test due a to different offsets in binlog with ps-protocol (a possible bug to be reported) mysql-test/r/sp_trans_log.result: results changed as prescribed mysql-test/t/sp_trans_log.test: Replacing the reporting pattern ### a possible bug: #show master status /* the offset must denote there is the query */| # displays different offests in ps-protocol with show binlog events --- mysql-test/r/sp_trans_log.result | 7 ++++--- mysql-test/t/sp_trans_log.test | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/sp_trans_log.result b/mysql-test/r/sp_trans_log.result index 14a8ecf6a37..9b644798079 100644 --- a/mysql-test/r/sp_trans_log.result +++ b/mysql-test/r/sp_trans_log.result @@ -12,9 +12,10 @@ end| reset master| insert into t2 values (bug23333(),1)| ERROR 23000: Duplicate entry '1' for key 1 -show master status /* the offset must denote there is the query */| -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 284 +show binlog events from 98 /* with fixes for #23333 will show there are 2 queries */| +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # # +master-bin.000001 # Query 1 # # select count(*),@a from t1 /* must be 1,1 */| count(*) @a 1 1 diff --git a/mysql-test/t/sp_trans_log.test b/mysql-test/t/sp_trans_log.test index 508c730a1cf..93605722f6b 100644 --- a/mysql-test/t/sp_trans_log.test +++ b/mysql-test/t/sp_trans_log.test @@ -26,7 +26,8 @@ end| reset master| --error ER_DUP_ENTRY insert into t2 values (bug23333(),1)| -show master status /* the offset must denote there is the query */| +--replace_column 2 # 5 # 6 # +show binlog events from 98 /* with fixes for #23333 will show there are 2 queries */| select count(*),@a from t1 /* must be 1,1 */| drop table t1, t2| From 79f951adf938f57d2482b2a483d76bcca6d8d842 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Aug 2007 16:17:17 +0200 Subject: [PATCH 08/43] Post merge fixes. sql/log_event.cc: - Rename RELAY_LOG_INFO -> Relay_log_info. - Rows_log_event fields which are used for event application not included when compiling in MYSQL_CLIENT mode. sql/log_event.h: - Rename RELAY_LOG_INFO -> Relay_log_info. - Rows_log_event fields which are used for event application not included when compiling in MYSQL_CLIENT mode. sql/log_event_old.cc: - Rename RELAY_LOG_INFO -> Relay_log_info. sql/log_event_old.h: - Rename RELAY_LOG_INFO -> Relay_log_info. sql/sql_yacc.yy: Reverting to version used in the rpl tree. --- sql/log_event.cc | 41 +++++++++++++++++++++++------------------ sql/log_event.h | 24 ++++++++++++------------ sql/log_event_old.cc | 24 ++++++++++++------------ sql/log_event_old.h | 16 ++++++++-------- sql/sql_yacc.yy | 13 +------------ 5 files changed, 56 insertions(+), 62 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index 2142aa0b54e..b77452d1af4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5653,9 +5653,10 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid, m_table(tbl_arg), m_table_id(tid), m_width(tbl_arg ? tbl_arg->s->fields : 1), - m_rows_buf(0), m_rows_cur(0), m_rows_end(0), - m_curr_row(NULL), m_curr_row_end(NULL), - m_flags(0), m_key(NULL) + m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0) +#ifdef HAVE_REPLICATION + ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL) +#endif { /* We allow a special form of dummy event when the table, and cols @@ -5697,10 +5698,13 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, *description_event) : Log_event(buf, description_event), m_row_count(0), +#ifndef MYSQL_CLIENT m_table(NULL), - m_rows_buf(0), m_rows_cur(0), m_rows_end(0), - m_curr_row(NULL), m_curr_row_end(NULL), - m_key(NULL) +#endif + m_rows_buf(0), m_rows_cur(0), m_rows_end(0) +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + ,m_key(NULL), m_curr_row(NULL), m_curr_row_end(NULL) +#endif { DBUG_ENTER("Rows_log_event::Rows_log_event(const char*,...)"); uint8 const common_header_len= description_event->common_header_len; @@ -5789,7 +5793,9 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, m_rows_buf= (uchar*) my_malloc(data_size, MYF(MY_WME)); if (likely((bool)m_rows_buf)) { +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) m_curr_row= m_rows_buf; +#endif m_rows_end= m_rows_buf + data_size; m_rows_cur= m_rows_end; memcpy(m_rows_buf, ptr_rows_data, data_size); @@ -6055,7 +6061,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) TABLE* table= - m_table= const_cast(rli)->m_table_map.get_table(m_table_id); + m_table= const_cast(rli)->m_table_map.get_table(m_table_id); if (table) { @@ -6100,7 +6106,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) inside a statement and halting abruptly might cause problems when restarting. */ - const_cast(rli)->set_flag(RELAY_LOG_INFO::IN_STMT); + const_cast(rli)->set_flag(Relay_log_info::IN_STMT); if ( m_width == table->s->fields && bitmap_is_set_all(&m_cols)) set_flags(COMPLETE_ROWS_F); @@ -6187,8 +6193,8 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) } // if (table) /* - We need to delay this clear until the table def stored in m_table_def is no - longer needed. It is used in unpack_current_row(). + We need to delay this clear until here bacause unpack_current_row() uses + master-side table definitions stored in rli. */ if (rli->tables_to_lock && get_flags(STMT_END_F)) const_cast(rli)->clear_tables_to_lock(); @@ -7136,7 +7142,7 @@ is_duplicate_key_error(int errcode) */ int -Rows_log_event::write_row(const RELAY_LOG_INFO *const rli, +Rows_log_event::write_row(const Relay_log_info *const rli, const bool overwrite) { DBUG_ENTER("write_row"); @@ -7323,7 +7329,7 @@ Rows_log_event::write_row(const RELAY_LOG_INFO *const rli, #endif int -Write_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +Write_rows_log_event::do_exec_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table != NULL); int error= write_row(rli, TRUE /* overwrite */); @@ -7453,7 +7459,7 @@ record_compare_exit: @c position() and @c rnd_pos() will be used. */ -int Rows_log_event::find_row(const RELAY_LOG_INFO *rli) +int Rows_log_event::find_row(const Relay_log_info *rli) { DBUG_ENTER("find_row"); @@ -7505,7 +7511,7 @@ int Rows_log_event::find_row(const RELAY_LOG_INFO *rli) DBUG_RETURN(error); } - // We can't use pisition() - try other methods. + // We can't use position() - try other methods. /* We need to retrieve all fields @@ -7721,8 +7727,7 @@ Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability m_table->s->primary_key < MAX_KEY) { /* - We don't need to allocate any memory for m_after_image and - m_key since they are not used. + We don't need to allocate any memory for m_key since it is not used. */ return 0; } @@ -7749,7 +7754,7 @@ Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability return error; } -int Delete_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +int Delete_rows_log_event::do_exec_row(const Relay_log_info *const rli) { int error; DBUG_ASSERT(m_table != NULL); @@ -7873,7 +7878,7 @@ Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability } int -Update_rows_log_event::do_exec_row(const RELAY_LOG_INFO *const rli) +Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table != NULL); diff --git a/sql/log_event.h b/sql/log_event.h index 0ec98561ae0..5c6a52fd9db 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -829,7 +829,7 @@ public: @see do_apply_event */ - int apply_event(RELAY_LOG_INFO const *rli) + int apply_event(Relay_log_info const *rli) { return do_apply_event(rli); } @@ -2291,20 +2291,20 @@ protected: uchar *m_rows_cur; /* One-after the end of the data */ uchar *m_rows_end; /* One-after the end of the allocated space */ - const uchar *m_curr_row; /* Start of the row being processed */ - const uchar *m_curr_row_end; /* One-after the end of the current row */ - flag_set m_flags; /* Flags for row-level events */ - uchar *m_key; /* Buffer to keep key value during searches */ /* helper functions */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - int find_row(const RELAY_LOG_INFO *const); - int write_row(const RELAY_LOG_INFO *const, const bool); + const uchar *m_curr_row; /* Start of the row being processed */ + const uchar *m_curr_row_end; /* One-after the end of the current row */ + uchar *m_key; /* Buffer to keep key value during searches */ + + int find_row(const Relay_log_info *const); + int write_row(const Relay_log_info *const, const bool); // Unpack the current row into m_table->record[0] - int unpack_current_row(const RELAY_LOG_INFO *const rli) + int unpack_current_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table); return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, @@ -2368,7 +2368,7 @@ private: 0 if execution succeeded, 1 if execution failed. */ - virtual int do_exec_row(const RELAY_LOG_INFO *const rli) = 0; + virtual int do_exec_row(const Relay_log_info *const rli) = 0; #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ friend class Old_rows_log_event; @@ -2424,7 +2424,7 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif }; @@ -2498,7 +2498,7 @@ protected: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ }; @@ -2563,7 +2563,7 @@ protected: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_before_row_operations(const Slave_reporting_capability *const); virtual int do_after_row_operations(const Slave_reporting_capability *const,int); - virtual int do_exec_row(const RELAY_LOG_INFO *const); + virtual int do_exec_row(const Relay_log_info *const); #endif }; diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 420df67dc54..949179386ea 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -11,7 +11,7 @@ // Old implementation of do_apply_event() int -Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli) +Old_rows_log_event::do_apply_event(Rows_log_event *ev, const Relay_log_info *rli) { DBUG_ENTER("Rows_log_event::do_apply_event(st_relay_log_info*)"); int error= 0; @@ -32,7 +32,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli */ DBUG_ASSERT(ev->get_flags(Rows_log_event::STMT_END_F)); - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); close_thread_tables(thd); thd->clear_error(); DBUG_RETURN(0); @@ -88,7 +88,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli "Error in %s event: when locking tables", ev->get_type_str()); } - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(error); } @@ -125,7 +125,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli "unexpected success or fatal error")); thd->query_error= 1; } - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(error); } } @@ -147,7 +147,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli mysql_unlock_tables(thd, thd->lock); thd->lock= 0; thd->query_error= 1; - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); DBUG_RETURN(Rows_log_event::ERR_BAD_TABLE_DEF); } } @@ -169,14 +169,14 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli */ for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global) { - const_cast(rli)->m_table_map.set_table(ptr->table_id, ptr->table); + const_cast(rli)->m_table_map.set_table(ptr->table_id, ptr->table); } #ifdef HAVE_QUERY_CACHE query_cache.invalidate_locked_for_write(rli->tables_to_lock); #endif } - TABLE* table= const_cast(rli)->m_table_map.get_table(ev->m_table_id); + TABLE* table= const_cast(rli)->m_table_map.get_table(ev->m_table_id); if (table) { @@ -221,7 +221,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli inside a statement and halting abruptly might cause problems when restarting. */ - const_cast(rli)->set_flag(RELAY_LOG_INFO::IN_STMT); + const_cast(rli)->set_flag(Relay_log_info::IN_STMT); error= do_before_row_operations(table); while (error == 0 && row_start < ev->m_rows_end) @@ -262,7 +262,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli row_start= row_end; } DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event", - const_cast(rli)->abort_slave= 1;); + const_cast(rli)->abort_slave= 1;); error= do_after_row_operations(table, error); if (!ev->cache_stmt) { @@ -276,7 +276,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli The table def is needed in unpack_row(). */ if (rli->tables_to_lock && ev->get_flags(Rows_log_event::STMT_END_F)) - const_cast(rli)->clear_tables_to_lock(); + const_cast(rli)->clear_tables_to_lock(); if (error) { /* error has occured during the transaction */ @@ -299,7 +299,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli rollback at the caller along with sbr. */ thd->reset_current_stmt_binlog_row_based(); - const_cast(rli)->cleanup_context(thd, error); + const_cast(rli)->cleanup_context(thd, error); thd->query_error= 1; DBUG_RETURN(error); } @@ -329,7 +329,7 @@ Old_rows_log_event::do_apply_event(Rows_log_event *ev, const RELAY_LOG_INFO *rli problem. When WL#2975 is implemented, just remove the member st_relay_log_info::last_event_start_time and all its occurences. */ - const_cast(rli)->last_event_start_time= my_time(0); + const_cast(rli)->last_event_start_time= my_time(0); } DBUG_RETURN(0); diff --git a/sql/log_event_old.h b/sql/log_event_old.h index ffe87a045cc..81e55097905 100644 --- a/sql/log_event_old.h +++ b/sql/log_event_old.h @@ -31,7 +31,7 @@ class Old_rows_log_event #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) - int do_apply_event(Rows_log_event*,const RELAY_LOG_INFO*); + int do_apply_event(Rows_log_event*,const Relay_log_info*); /* Primitive to prepare for a sequence of row executions. @@ -80,7 +80,7 @@ class Old_rows_log_event RETURN VALUE Error code, if something went wrong, 0 otherwise. */ - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end) = 0; @@ -131,13 +131,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); @@ -179,13 +179,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ @@ -226,13 +226,13 @@ private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) // use old definition of do_apply_event() - virtual int do_apply_event(const RELAY_LOG_INFO *rli) + virtual int do_apply_event(const Relay_log_info *rli) { return Old_rows_log_event::do_apply_event(this,rli); } // primitives for old version of do_apply_event() virtual int do_before_row_operations(TABLE *table); virtual int do_after_row_operations(TABLE *table, int error); - virtual int do_prepare_row(THD*, RELAY_LOG_INFO const*, TABLE*, + virtual int do_prepare_row(THD*, Relay_log_info const*, TABLE*, uchar const *row_start, uchar const **row_end); virtual int do_exec_row(TABLE *table); #endif diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index af6dd590679..ddd63da9adb 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -857,7 +857,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token OUT_SYM /* SQL-2003-R */ %token OWNER_SYM %token PACK_KEYS_SYM -%token PAGE_SYM %token PARAM_MARKER %token PARSER_SYM %token PARTIAL /* SQL-2003-N */ @@ -1010,7 +1009,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TO_SYM /* SQL-2003-R */ %token TRAILING /* SQL-2003-R */ %token TRANSACTION_SYM -%token TRANSACTIONAL_SYM %token TRIGGERS_SYM %token TRIGGER_SYM /* SQL-2003-R */ %token TRIM /* SQL-2003-N */ @@ -4366,12 +4364,6 @@ create_table_option: Lex->create_info.used_fields|= HA_CREATE_USED_KEY_BLOCK_SIZE; Lex->create_info.key_block_size= $3; } - | TRANSACTIONAL_SYM opt_equal ulong_num - { - Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL; - Lex->create_info.transactional= ($3 != 0 ? HA_CHOICE_YES : - HA_CHOICE_NO); - } ; default_charset: @@ -4450,8 +4442,7 @@ row_types: | DYNAMIC_SYM { $$= ROW_TYPE_DYNAMIC; } | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; } | REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; } - | COMPACT_SYM { $$= ROW_TYPE_COMPACT; } - | PAGE_SYM { $$= ROW_TYPE_PAGE; }; + | COMPACT_SYM { $$= ROW_TYPE_COMPACT; }; merge_insert_types: NO_SYM { $$= MERGE_INSERT_DISABLED; } @@ -10082,7 +10073,6 @@ keyword_sp: | ONE_SHOT_SYM {} | ONE_SYM {} | PACK_KEYS_SYM {} - | PAGE_SYM {} | PARTIAL {} | PARTITIONING_SYM {} | PARTITIONS_SYM {} @@ -10152,7 +10142,6 @@ keyword_sp: | TEXT_SYM {} | THAN_SYM {} | TRANSACTION_SYM {} - | TRANSACTIONAL_SYM {} | TRIGGERS_SYM {} | TIMESTAMP {} | TIMESTAMP_ADD {} From 013c96ceaabc5059682959d7904ad82ffa648c5f Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 27 Aug 2007 18:44:13 +0400 Subject: [PATCH 09/43] WL#3694 Replication of Invocation and Invoked Features Testing. Bug#29020 Event results not correctly replicated to slave in RBR: partially. mysql-test/suite/rpl/r/rpl_invoked_features.result: Updated result file. mysql-test/suite/rpl/t/disabled.def: removed test cases: rpl_invoked_features and rpl_innodb_mixed_* (alreade were commented out) mysql-test/suite/rpl/t/rpl_invoked_features.test: Added comments, implemented the waiting via include/wait_condition, minor fixes. --- .../suite/rpl/r/rpl_invoked_features.result | 30 +++--- mysql-test/suite/rpl/t/disabled.def | 3 - .../suite/rpl/t/rpl_invoked_features.test | 92 +++++++++++-------- 3 files changed, 69 insertions(+), 56 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_invoked_features.result b/mysql-test/suite/rpl/r/rpl_invoked_features.result index 3bcef762497..502bb040218 100644 --- a/mysql-test/suite/rpl/r/rpl_invoked_features.result +++ b/mysql-test/suite/rpl/r/rpl_invoked_features.result @@ -17,13 +17,13 @@ DROP EVENT IF EXISTS e11; CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=myisam; INSERT INTO t1 VALUES (1,1,'1'); INSERT INTO t1 VALUES (2,2,UUID()); -CREATE TABLE t2 (a INT, b INT, c VARCHAR(64)) ENGINE=myisam; +CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=myisam; INSERT INTO t2 VALUES (1,1,'1'); INSERT INTO t2 VALUES (2,2,UUID()); CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=innodb; INSERT INTO t11 VALUES (1,1,'1'); INSERT INTO t11 VALUES (2,2,UUID()); -CREATE TABLE t12 (a INT, b INT, c VARCHAR(64)) ENGINE=innodb; +CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=innodb; INSERT INTO t12 VALUES (1,1,'1'); INSERT INTO t12 VALUES (2,2,UUID()); @@ -49,21 +49,15 @@ BEGIN UPDATE t12 SET c = ''; UPDATE t13 SET c = ''; END| -CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN -DECLARE c INT; -SELECT a INTO c FROM t1 WHERE a < 11 ORDER BY a DESC LIMIT 1; -IF c = 7 THEN +ALTER EVENT e1 DISABLE; CALL p1(10, ''); -END IF; END| -CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN -DECLARE c INT; -SELECT a INTO c FROM t11 WHERE a < 11 ORDER BY a DESC LIMIT 1; -IF c = 7 THEN +ALTER EVENT e11 DISABLE; CALL p11(10, ''); -END IF; END| CREATE FUNCTION f1 (x INT) RETURNS VARCHAR(64) BEGIN @@ -78,11 +72,11 @@ RETURN f1(x); END| CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64)) BEGIN -INSERT INTO t1 VALUES (x,x,y); +INSERT IGNORE INTO t1 VALUES (x,x,y); END| CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64)) BEGIN -INSERT INTO t11 VALUES (x,x,y); +INSERT IGNORE INTO t11 VALUES (x,x,y); END| CREATE TABLE t3 SELECT * FROM v1; @@ -110,6 +104,8 @@ INSERT INTO t11 VALUES(7,7,f2(7)); INSERT INTO t11 VALUES (103,103,''); SET GLOBAL EVENT_SCHEDULER = on; +ALTER EVENT e1 ENABLE; +ALTER EVENT e11 ENABLE; SET GLOBAL EVENT_SCHEDULER = off; SHOW TABLES LIKE 't%'; @@ -138,8 +134,8 @@ PROCEDURE p1 PROCEDURE p11 SELECT event_name, status FROM information_schema.events WHERE event_schema='test'; event_name status -e1 ENABLED -e11 ENABLED +e1 DISABLED +e11 DISABLED SELECT COUNT(*) FROM t1; COUNT(*) @@ -438,6 +434,8 @@ UPDATE t3 SET c=''; UPDATE t11 SET c=''; UPDATE t12 SET c=''; UPDATE t13 SET c=''; +ALTER TABLE t3 ORDER BY a; +ALTER TABLE t13 ORDER BY a; diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def index 34a8d6988a9..72b68fa59db 100644 --- a/mysql-test/suite/rpl/t/disabled.def +++ b/mysql-test/suite/rpl/t/disabled.def @@ -11,9 +11,6 @@ ############################################################################## rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after CREATE/DROP TEMPORARY TABLE + ROLLBACK on master -#rpl_innodb_mixed_ddl : Bug #29363 rpl.rpl_innodb_mixed_* test failures -#rpl_innodb_mixed_dml : Bug #29363 rpl.rpl_innodb_mixed_* test failures -rpl_invoked_features : BUG#29020 2007-06-21 Lars Non-deterministic test case rpl_auto_increment_11932 : Bug#29809 2007-07-16 ingo Slave SQL errors in warnings file rpl_stm_extraColmaster_ndb : WL#3915 : Statement-based replication not supported in ndb. Enable test when supported. rpl_row_extraColmaster_ndb : BUG#29549 : Replication of BLOBs fail for NDB diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features.test b/mysql-test/suite/rpl/t/rpl_invoked_features.test index e797e0552ef..0fc5d917566 100644 --- a/mysql-test/suite/rpl/t/rpl_invoked_features.test +++ b/mysql-test/suite/rpl/t/rpl_invoked_features.test @@ -8,10 +8,9 @@ --source include/master-slave.inc --source include/have_innodb.inc - -# -# Define variables used by test case -# +# --disable_warnings/--enable_warnings added before/after query +# if one uses UUID() function because we need to avoid warnings +# for STATEMENT binlog format # Non-transactional engine --let $engine_type= myisam @@ -45,20 +44,24 @@ DROP EVENT IF EXISTS e11; --echo eval CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type; ---disable_warnings INSERT INTO t1 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t1 VALUES (2,2,UUID()); -eval CREATE TABLE t2 (a INT, b INT, c VARCHAR(64)) ENGINE=$engine_type; +--enable_warnings +eval CREATE TABLE t2 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type; INSERT INTO t2 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t2 VALUES (2,2,UUID()); --enable_warnings eval CREATE TABLE t11 (a INT NOT NULL PRIMARY KEY, b INT, c VARCHAR(64)) ENGINE=$engine_type2; ---disable_warnings INSERT INTO t11 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t11 VALUES (2,2,UUID()); -eval CREATE TABLE t12 (a INT, b INT, c VARCHAR(64)) ENGINE=$engine_type2; +--enable_warnings +eval CREATE TABLE t12 (a INT UNIQUE, b INT, c VARCHAR(64)) ENGINE=$engine_type2; INSERT INTO t12 VALUES (1,1,'1'); +--disable_warnings INSERT INTO t12 VALUES (2,2,UUID()); --enable_warnings @@ -96,22 +99,16 @@ BEGIN END| # Create events which will run every 1 sec -CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e1 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN - DECLARE c INT; - SELECT a INTO c FROM t1 WHERE a < 11 ORDER BY a DESC LIMIT 1; - IF c = 7 THEN - CALL p1(10, ''); - END IF; + ALTER EVENT e1 DISABLE; + CALL p1(10, ''); END| -CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND ENABLE DO +CREATE EVENT e11 ON SCHEDULE EVERY 1 SECOND DISABLE DO BEGIN - DECLARE c INT; - SELECT a INTO c FROM t11 WHERE a < 11 ORDER BY a DESC LIMIT 1; - IF c = 7 THEN - CALL p11(10, ''); - END IF; + ALTER EVENT e11 DISABLE; + CALL p11(10, ''); END| # Create functions and procedures used for events @@ -130,12 +127,12 @@ END| CREATE PROCEDURE p1 (IN x INT, IN y VARCHAR(64)) BEGIN - INSERT INTO t1 VALUES (x,x,y); + INSERT IGNORE INTO t1 VALUES (x,x,y); END| CREATE PROCEDURE p11 (IN x INT, IN y VARCHAR(64)) BEGIN - INSERT INTO t11 VALUES (x,x,y); + INSERT IGNORE INTO t11 VALUES (x,x,y); END| DELIMITER ;| @@ -147,17 +144,24 @@ DELIMITER ;| # Do some actions for non-transactional tables --echo ---disable_warnings CREATE TABLE t3 SELECT * FROM v1; INSERT INTO t1 VALUES (3,3,''); UPDATE t1 SET c='2' WHERE a = 1; +--disable_warnings INSERT INTO t1 VALUES(4,4,f1(4)); +--enable_warnings INSERT INTO t1 VALUES (100,100,''); +--disable_warnings CALL p1(5, UUID()); +--enable_warnings INSERT INTO t1 VALUES (101,101,''); +--disable_warnings INSERT INTO t1 VALUES(6,6,f1(6)); +--enable_warnings INSERT INTO t1 VALUES (102,102,''); +--disable_warnings INSERT INTO t1 VALUES(7,7,f2(7)); +--enable_warnings INSERT INTO t1 VALUES (103,103,''); # Do some actions for transactional tables @@ -165,21 +169,34 @@ INSERT INTO t1 VALUES (103,103,''); CREATE TABLE t13 SELECT * FROM v11; INSERT INTO t11 VALUES (3,3,''); UPDATE t11 SET c='2' WHERE a = 1; +--disable_warnings INSERT INTO t11 VALUES(4,4,f1(4)); -INSERT INTO t11 VALUES (100,100,''); -CALL p11(5, UUID()); -INSERT INTO t11 VALUES (101,101,''); -INSERT INTO t11 VALUES(6,6,f1(6)); -INSERT INTO t11 VALUES (102,102,''); -INSERT INTO t11 VALUES(7,7,f2(7)); -INSERT INTO t11 VALUES (103,103,''); --enable_warnings +INSERT INTO t11 VALUES (100,100,''); +--disable_warnings +CALL p11(5, UUID()); +--enable_warnings +INSERT INTO t11 VALUES (101,101,''); +--disable_warnings +INSERT INTO t11 VALUES(6,6,f1(6)); +--enable_warnings +INSERT INTO t11 VALUES (102,102,''); +--disable_warnings +INSERT INTO t11 VALUES(7,7,f2(7)); +--enable_warnings +INSERT INTO t11 VALUES (103,103,''); # Scheduler is on --echo +# Temporally events fire sequentally due Bug#29020. SET GLOBAL EVENT_SCHEDULER = on; -# Wait 2 sec while events will executed ---sleep 2 +# Wait while events will executed +ALTER EVENT e1 ENABLE; +let $wait_condition= SELECT COUNT(*) = 1 FROM t1 WHERE t1.a = 10; +--source include/wait_condition.inc +ALTER EVENT e11 ENABLE; +let $wait_condition= SELECT COUNT(*) = 1 FROM t11 WHERE t11.a = 10; +--source include/wait_condition.inc SET GLOBAL EVENT_SCHEDULER = off; # Check original objects @@ -234,7 +251,7 @@ SELECT COUNT(*) FROM t13; SELECT a,b FROM t13 ORDER BY a; SELECT a,b FROM v11 ORDER BY a; -# Remove UUID() before comparing +# Remove UUID() before comparing and sort tables --connection master --echo @@ -245,6 +262,9 @@ UPDATE t11 SET c=''; UPDATE t12 SET c=''; UPDATE t13 SET c=''; +ALTER TABLE t3 ORDER BY a; +ALTER TABLE t13 ORDER BY a; + --sync_slave_with_master slave # Compare a data from master and slave @@ -260,13 +280,12 @@ UPDATE t13 SET c=''; # Remove dumps --echo ---exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql ---exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql +#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql +#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql # Remove tables,views,procedures,functions --connection master --echo ---disable_warnings DROP VIEW IF EXISTS v1,v11; DROP TABLE IF EXISTS t1,t2,t3,t11,t12,t13; DROP PROCEDURE IF EXISTS p1; @@ -275,7 +294,6 @@ DROP FUNCTION IF EXISTS f1; DROP FUNCTION IF EXISTS f2; DROP EVENT IF EXISTS e1; DROP EVENT IF EXISTS e11; ---enable_warnings --sync_slave_with_master slave From ce291125f07df1d77bdba1ff32d8d16f364525ae Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 29 Aug 2007 19:57:10 +0300 Subject: [PATCH 10/43] Bug #30209 rpl_packet.test: Slave_running mismatch (timing bug?) explicit --sleep is removed in favor of wait_for_slave_io_to_stop.inc. The status reporting uses `SHOW SLAVE STATUS' *not* possibly buggy "SHOW STATUS LIKE 'Slave_running'". mysql-test/r/rpl_packet.result: Recording the necessary Slave_IO_Running status at the end of the bug test. It must be No. mysql-test/t/rpl_packet.test: Removing sleep; wait_for_slave_io_to_stop.inc instead; Original "SHOW STATUS LIKE 'Slave_running'" seems to be buggy (to be reported) as with the macro above there were evidence slave IO was stopped indeed but "SHOW STATUS" did not find that (see failures in pb) --- mysql-test/r/rpl_packet.result | 37 +++++++++++++++++++++++++++++++--- mysql-test/t/rpl_packet.test | 10 +++++---- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/rpl_packet.result b/mysql-test/r/rpl_packet.result index 894bc81b08d..9425724b434 100644 --- a/mysql-test/r/rpl_packet.result +++ b/mysql-test/r/rpl_packet.result @@ -21,6 +21,37 @@ STOP SLAVE; START SLAVE; CREATE TABLe `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); -SHOW STATUS LIKE 'Slave_running'; -Variable_name Value -Slave_running OFF +show slave status; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_MYPORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 2138 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running No +Slave_SQL_Running # +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 2138 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # diff --git a/mysql-test/t/rpl_packet.test b/mysql-test/t/rpl_packet.test index f410b561663..84bc5d908bf 100644 --- a/mysql-test/t/rpl_packet.test +++ b/mysql-test/t/rpl_packet.test @@ -64,9 +64,11 @@ CREATE TABLe `t1` (`f1` LONGTEXT) ENGINE=MyISAM; INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048'); # The slave I/O thread must stop after trying to read the above event -connection slave; -sleep 2; -SHOW STATUS LIKE 'Slave_running'; - +connection slave; +--source include/wait_for_slave_io_to_stop.inc +--replace_result $MASTER_MYPORT MASTER_MYPORT +# import is only the 11th column Slave_IO_Running +--replace_column 1 # 8 # 9 # 12 # 23 # 33 # +query_vertical show slave status; # End of tests From 0e466b540cdcdb94fb438753e6f987c26fd9d0dd Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 4 Sep 2007 15:24:04 +0200 Subject: [PATCH 11/43] Disabling rpl_ndb_2other test. mysql-test/suite/rpl_ndb/t/disabled.def: The rpl_ndb_2other test must be disabled until replication correctly handles endianess issues. --- mysql-test/suite/rpl_ndb/t/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def index 90286ecc421..5b102a915ef 100644 --- a/mysql-test/suite/rpl_ndb/t/disabled.def +++ b/mysql-test/suite/rpl_ndb/t/disabled.def @@ -13,6 +13,7 @@ rpl_ndb_2innodb : BUG#19227 2006-04-20 pekka pk delete apparently not replicated rpl_ndb_2myisam : BUG#19227 Seems to pass currently +rpl_ndb_2other : BUG#29549 2007-09-04 rafal test fails on big-endian architectures rpl_ndb_dd_partitions : BUG#19259 2006-04-21 rpl_ndb_dd_partitions fails on s/AMD rpl_ndb_innodb2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue rpl_ndb_myisam2ndb : Bug#29549 rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb failed on Solaris for pack_length issue From 4b2606f3822c4aee9aa8fb8ee1f711221fb54f10 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Sep 2007 12:04:57 +0400 Subject: [PATCH 12/43] replaced '--exec rm' to '--remove_file' --- mysql-test/suite/rpl/t/rpl_invoked_features.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_invoked_features.test b/mysql-test/suite/rpl/t/rpl_invoked_features.test index 0fc5d917566..2e69c0fabd9 100644 --- a/mysql-test/suite/rpl/t/rpl_invoked_features.test +++ b/mysql-test/suite/rpl/t/rpl_invoked_features.test @@ -280,8 +280,8 @@ ALTER TABLE t13 ORDER BY a; # Remove dumps --echo -#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql -#--exec rm $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_master.sql +--remove_file $MYSQLTEST_VARDIR/tmp/rpl_invoked_features_slave.sql # Remove tables,views,procedures,functions --connection master From 431fd2c1aaa4991ae6fe65f321f3ee84397cc0ef Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Sep 2007 11:22:41 -0400 Subject: [PATCH 13/43] BUG#30790 : Suspicious code in rpl_utility.cc This patch clarifies some of the coding choices with documentationa and removes a limitation in the code for future expansion of the CHAR and BINARY fields to length > 255. sql/field.cc: BUG#30790 : Suspicious code in rpl_utility.cc This patch adds an assertion to ensure we are not attempting to encode negative values. sql/log_event.cc: BUG#30790 : Suspicious code in rpl_utility.cc This patch adds comments to help explain the choice of variable types. sql/rpl_utility.cc: BUG#30790 : Suspicious code in rpl_utility.cc This patch removes code from the calc_field_size that is not needed and was ambiguous. Originally intended to future expansion, the code was not needed. Also added are comments to help explain some portions of the code. A change was made to the korr method to use the unsigned version to avoid extended sign problems. sql/rpl_utility.h: BUG#30790 : Suspicious code in rpl_utility.cc This patch corrects some type discrepencies and removes an extra cast. --- sql/field.cc | 1 + sql/log_event.cc | 10 ++++++++++ sql/rpl_utility.cc | 36 +++++++++++++++++++++++------------- sql/rpl_utility.h | 14 +++++++------- 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/sql/field.cc b/sql/field.cc index 1b01d626512..9e86e405512 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -6732,6 +6732,7 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16; int Field_varstring::do_save_field_metadata(uchar *metadata_ptr) { char *ptr= (char *)metadata_ptr; + DBUG_ASSERT(field_length <= 65535); int2store(ptr, field_length); return 2; } diff --git a/sql/log_event.cc b/sql/log_event.cc index 33442baaf90..0dee50c8179 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6469,6 +6469,16 @@ void Rows_log_event::print_helper(FILE *file, data) in the table map are initialized as zero (0). The array size is the same as the columns for the table on the slave. + Additionally, values saved for field metadata on the master are saved as a + string of bytes (uchar) in the binlog. A field may require 1 or more bytes + to store the information. In cases where values require multiple bytes + (e.g. values > 255), the endian-safe methods are used to properly encode + the values on the master and decode them on the slave. When the field + metadata values are captured on the slave, they are stored in an array of + type uint16. This allows the least number of casts to prevent casting bugs + when the field metadata is used in comparisons of field attributes. When + the field metadata is used for calculating addresses in pointer math, the + type used is uint32. */ /** diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index d1ce5bf3b7b..b3ca26d4c2c 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -31,31 +31,34 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const switch (type(col)) { case MYSQL_TYPE_NEWDECIMAL: length= my_decimal_get_binary_size(m_field_metadata[col] >> 8, - m_field_metadata[col] - ((m_field_metadata[col] >> 8) << 8)); + m_field_metadata[col] & 0xff); break; case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: length= m_field_metadata[col]; break; + /* + The cases for SET and ENUM are include for completeness, however + both are mapped to type MYSQL_TYPE_STRING and their real types + are encoded in the field metadata. + */ case MYSQL_TYPE_SET: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_STRING: { - if (((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_SET << 8)) || - ((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_ENUM << 8))) + uchar type= m_field_metadata[col] >> 8U; + if ((type == MYSQL_TYPE_SET) || (type == MYSQL_TYPE_ENUM)) length= m_field_metadata[col] & 0x00ff; else { - length= m_field_metadata[col] & 0x00ff; - DBUG_ASSERT(length > 0); - if (length > 255) - { - DBUG_ASSERT(uint2korr(master_data) > 0); - length= uint2korr(master_data) + 2; - } - else - length= (uint) *master_data + 1; + /* + We are reading the actual size from the master_data record + because this field has the actual lengh stored in the first + byte. + */ + length= (uint) *master_data + 1; + DBUG_ASSERT(length != 0); } break; } @@ -95,6 +98,13 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const break; case MYSQL_TYPE_BIT: { + /* + Decode the size of the bit field from the master. + from_len is the length in bytes from the master + from_bit_len is the number of extra bits stored in the master record + If from_bit_len is not 0, add 1 to the length to account for accurate + number of bytes needed. + */ uint from_len= (m_field_metadata[col] >> 8U) & 0x00ff; uint from_bit_len= m_field_metadata[col] & 0x00ff; DBUG_ASSERT(from_bit_len <= 7); @@ -136,7 +146,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const length= *master_data; break; case 2: - length= sint2korr(master_data); + length= uint2korr(master_data); break; case 3: length= uint3korr(master_data); diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 4fd38022da0..f2ab34fe947 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -99,7 +99,7 @@ public: /* These types store a single byte. */ - m_field_metadata[i]= (uchar)field_metadata[index]; + m_field_metadata[i]= field_metadata[index]; index++; break; } @@ -107,14 +107,14 @@ public: case MYSQL_TYPE_ENUM: case MYSQL_TYPE_STRING: { - short int x= field_metadata[index++] << 8U; // real_type - x = x + field_metadata[index++]; // pack or field length + uint16 x= field_metadata[index++] << 8U; // real_type + x+= field_metadata[index++]; // pack or field length m_field_metadata[i]= x; break; } case MYSQL_TYPE_BIT: { - short int x= field_metadata[index++]; + uint16 x= field_metadata[index++]; x = x + (field_metadata[index++] << 8U); m_field_metadata[i]= x; break; @@ -125,14 +125,14 @@ public: These types store two bytes. */ char *ptr= (char *)&field_metadata[index]; - m_field_metadata[i]= sint2korr(ptr); + m_field_metadata[i]= uint2korr(ptr); index= index + 2; break; } case MYSQL_TYPE_NEWDECIMAL: { - short int x= field_metadata[index++] << 8U; // precision - x = x + field_metadata[index++]; // decimals + uint16 x= field_metadata[index++] << 8U; // precision + x+= field_metadata[index++]; // decimals m_field_metadata[i]= x; break; } From 68297025a01fc6094d39a0f1fa01cc079240d026 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Sep 2007 12:07:00 +0200 Subject: [PATCH 14/43] Manual merge fixes/tests for bugs_28960,27417,23333. mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test: follow-up of the previous manual resolve. The snippet is moved into the heading file. mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test: removing explicit offsets from report; appending bug#27417,23333,28960 related snippet, addressing left TODO:s. mysql-test/suite/rpl/r/rpl_packet.result: results changed mysql-test/suite/rpl/t/rpl_packet.test: fixing row/stmt compatibility with #-ing out unneeded values --- .../mix_innodb_myisam_binlog.test | 250 ------------------ .../r/binlog_stm_mix_innodb_myisam.result | 108 ++++++-- .../t/binlog_stm_mix_innodb_myisam.test | 138 +++++++++- mysql-test/suite/rpl/r/rpl_packet.result | 9 +- mysql-test/suite/rpl/t/rpl_packet.test | 2 +- 5 files changed, 223 insertions(+), 284 deletions(-) diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test index 8d530261662..7141bd1abb9 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_binlog.test @@ -316,253 +316,3 @@ disconnect con3; connection con4; select get_lock("a",10); # wait for rollback to finish -# we check that the error code of the "ROLLBACK" event is 0 and not -# ER_SERVER_SHUTDOWN (i.e. disconnection just rolls back transaction -# and does not make slave to stop) ---exec $MYSQL_BINLOG --start-position=547 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output ---replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR -eval select -(@a:=load_file("$MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output")) -is not null; ---replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR -eval select -@a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%", -@a not like "%#%error_code=%error_code=%"; -drop table t1, t2; - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# bug #28960 non-trans temp table changes with insert .. select -# not binlogged after rollback -# -# testing appearence of insert into temp_table in binlog. -# There are two branches of execution that require different setup. - -## send_eof() branch - -# prepare - -create temporary table tt (a int unique); -create table ti (a int) engine=innodb; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) ; -insert into tt select * from ti; -rollback; - -# check - -select count(*) from tt /* 2 */; -show master status; ---replace_column 2 # 5 # -show binlog events from 98; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; - - -## send_error() branch -delete from ti; -delete from tt where a=1; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) /* to make the dup error in the following */; ---error ER_DUP_ENTRY -insert into tt select * from ti /* one affected and error */; -rollback; - -# check - -show master status; ---replace_column 2 # 5 # -show binlog events from 98; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from tt /* that is what otherwise slave missed - the bug */; - -drop table ti; - - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# -# Testing asserts: if there is a side effect of modifying non-transactional -# table thd->no_trans_update.stmt must be TRUE; -# the assert is active with debug build -# - ---disable_warnings -drop function if exists bug27417; -drop table if exists t1,t2; ---enable_warnings -# side effect table -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -# target tables -CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); - -delimiter |; -create function bug27417(n int) -RETURNS int(11) -begin - insert into t1 values (null); - return n; -end| -delimiter ;| - -reset master; - -# execute - -insert into t2 values (bug27417(1)); -insert into t2 select bug27417(2); -reset master; - ---error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -show master status; /* only (!) with fixes for #23333 will show there is the query */; -select count(*) from t1 /* must be 3 */; - -reset master; -select count(*) from t2; -delete from t2 where a=bug27417(3); -select count(*) from t2 /* nothing got deleted */; -show master status; /* the query must be in regardless of #23333 */; -select count(*) from t1 /* must be 5 */; - ---enable_info -delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; ---disable_info -select count(*) from t1 /* must be 7 */; - -# function bug27417 remains for the following testing of bug#23333 -drop table t1,t2; - -# -# Bug#23333 using the patch (and the test) for bug#27471 -# throughout the bug tests -# t1 - non-trans side effects gatherer; -# t2 - transactional table; -# -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); - - -# -# INSERT -# - -# prepare - - insert into t2 values (1); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 values (bug27417(1)); - -# check - - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 1 */; - -# -# INSERT SELECT -# - -# prepare - delete from t1; - delete from t2; - insert into t2 values (2); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 select bug27417(1) union select bug27417(2); - -# check - - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 2 */; - -# -# UPDATE (multi-update see bug#27716) -# - -# prepare - delete from t1; - insert into t3 values (1,1),(2,3),(3,4); - reset master; - -# execute - --error ER_DUP_ENTRY - update t3 set b=b+bug27417(1); - -# check - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 2 */; - - -# -# DELETE (for multi-delete see Bug #29136) -# - -# prepare - delete from t1; - delete from t2; - delete from t3; - insert into t2 values (1); - insert into t3 values (1,1); - create trigger trg_del before delete on t2 for each row - insert into t3 values (bug27417(1), 2); - reset master; - -# execute - --error ER_DUP_ENTRY - delete from t2; -# check - show master status /* the offset must denote there is the query */; - select count(*) from t1 /* must be 1 */; - - -# -# LOAD DATA -# - -# prepare - delete from t1; - create table t4 (a int default 0, b int primary key) engine=innodb; - insert into t4 values (0, 17); - reset master; - -# execute - --error ER_DUP_ENTRY - load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); -# check - select * from t4; - select count(*) from t1 /* must be 2 */; - show master status /* the offset must denote there is the query */; - -# -# bug#23333 cleanup -# - - -drop trigger trg_del; -drop table t1,t2,t3,t4; -drop function bug27417; - - ---echo end of tests diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 5ef36861c30..62c111af19a 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -380,7 +380,7 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; -create table tt (a int unique); +create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; show master status; @@ -399,18 +399,18 @@ count(*) show master status; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 515 -show binlog events from 106; +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `test`; BEGIN -master-bin.000001 # Query 1 # use `test`; insert into ti values (1) -master-bin.000001 # Query 1 # use `test`; insert into ti values (2) -master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti -master-bin.000001 # Query 1 # use `test`; ROLLBACK +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; insert into ti values (1) +master-bin.000001 # Query # # use `test`; insert into ti values (2) +master-bin.000001 # Query # # use `test`; insert into tt select * from ti +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; +select * from ti /* that is what slave would miss - bug#28960 */; a 1 2 @@ -426,18 +426,11 @@ insert into ti values (2) /* to make the dup error in the following */; insert into tt select * from ti /* one affected and error */; ERROR 23000: Duplicate entry '2' for key 'a' rollback; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 589 -show binlog events from 106; +master-bin.000001 106 +show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `test`; BEGIN -master-bin.000001 # Query 1 # use `test`; insert into ti values (1) -master-bin.000001 # Query 1 # use `test`; insert into ti values (2) /* to make the dup error in the following */ -master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti /* one affected and error */ -master-bin.000001 # Query 1 # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 @@ -446,7 +439,7 @@ select * from tt /* that is what otherwise slave missed - the bug */; a 1 2 -drop table ti,tt; +drop table ti; drop function if exists bug27417; drop table if exists t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; @@ -463,6 +456,10 @@ insert into t2 select bug27417(2); reset master; insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 222 +/* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; count(*) 3 @@ -474,6 +471,10 @@ delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; count(*) 2 +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 227 +/* the query must be in regardless of #23333 */; select count(*) from t1 /* must be 5 */; count(*) 5 @@ -482,6 +483,75 @@ affected rows: 0 select count(*) from t1 /* must be 7 */; count(*) 7 -drop function bug27417; drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 293 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 332 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 'b' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 305 +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 335 +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 'PRIMARY' +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 362 +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; end of tests diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 1815f3deb34..826206a1425 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -36,7 +36,7 @@ drop table t1, t2; # prepare -create table tt (a int unique); +create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; show master status; @@ -53,11 +53,10 @@ rollback; select count(*) from tt /* 2 */; show master status; ---replace_column 2 # 5 # -show binlog events from 106; +source include/show_binlog_events.inc; select count(*) from ti /* zero */; insert into ti select * from tt; -select * from ti /* that is what slave would miss - a bug */; +select * from ti /* that is what slave would miss - bug#28960 */; ## send_error() branch @@ -78,13 +77,12 @@ rollback; # check show master status; ---replace_column 2 # 5 # -show binlog events from 106; +source include/show_binlog_events.inc; select count(*) from ti /* zero */; insert into ti select * from tt; select * from tt /* that is what otherwise slave missed - the bug */; -drop table ti,tt; +drop table ti; # @@ -123,16 +121,14 @@ reset master; --error ER_DUP_ENTRY insert into t2 values (bug27417(2)); -#TODO: Andrei: enable this test after 23333 is pushed -#show master status; /* only (!) with fixes for #23333 will show there is the query */; +show master status; /* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; reset master; select count(*) from t2; delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; -#TODO: Andrei: enable this test after 23333 is pushed -#show master status; /* the query must be in regardless of #23333 */; +show master status; /* the query must be in regardless of #23333 */; select count(*) from t1 /* must be 5 */; --enable_info @@ -140,7 +136,125 @@ delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; --disable_info select count(*) from t1 /* must be 7 */; -drop function bug27417; +# function bug27417 remains for the following testing of bug#23333 drop table t1,t2; +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + show master status /* the offset must denote there is the query */; + +# +# bug#23333 cleanup +# + + +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; + + --echo end of tests diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index c23b990acd4..dd56eb0471c 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -34,7 +34,7 @@ Master_User root Master_Port MASTER_MYPORT Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 2138 +Read_Master_Log_Pos # Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -49,7 +49,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 2138 +Exec_Master_Log_Pos # Relay_Log_Space # Until_Condition None Until_Log_File @@ -61,3 +61,8 @@ Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index a4b290f89a3..0e17ae3144c 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -70,7 +70,7 @@ connection slave; --source include/wait_for_slave_io_to_stop.inc --replace_result $MASTER_MYPORT MASTER_MYPORT # import is only the 11th column Slave_IO_Running ---replace_column 1 # 8 # 9 # 12 # 23 # 33 # +--replace_column 1 # 7 # 8 # 9 # 12 # 22 # 23 # 33 # query_vertical show slave status; # End of tests From 14f5002d83fc4fe242f311501259955651214122 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 16 Sep 2007 18:16:40 +0200 Subject: [PATCH 15/43] Merge: bug#27417,23333 manual work for fixing tests and a source code. mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed due to 1. tt table made temporary is it's supposed to; 2. show master status is turned into binlog pos masking-out macro 3. merge defect for select_insert::abort() mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test: masking-out binlog postions in the results via source include/show_binlog_events.inc; sql/sql_insert.cc: merging defect in not applied hunk for select_insert::abort() is fixed --- .../r/binlog_stm_mix_innodb_myisam.result | 77 +++++++++++++------ .../t/binlog_stm_mix_innodb_myisam.test | 16 ++-- sql/sql_insert.cc | 19 ++--- 3 files changed, 71 insertions(+), 41 deletions(-) diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 62c111af19a..564fa8d86bd 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -426,11 +426,18 @@ insert into ti values (2) /* to make the dup error in the following */; insert into tt select * from ti /* one affected and error */; ERROR 23000: Duplicate entry '2' for key 'a' rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 106 +master-bin.000001 589 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Query # # use `test`; insert into ti values (1) +master-bin.000001 # Query # # use `test`; insert into ti values (2) /* to make the dup error in the following */ +master-bin.000001 # Query # # use `test`; insert into tt select * from ti /* one affected and error */ +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from ti /* zero */; count(*) 0 @@ -456,10 +463,11 @@ insert into t2 select bug27417(2); reset master; insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' -show master status; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 222 -/* only (!) with fixes for #23333 will show there is the query */; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F select count(*) from t1 /* must be 3 */; count(*) 3 @@ -471,10 +479,11 @@ delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; count(*) 2 -show master status; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 227 -/* the query must be in regardless of #23333 */; +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F select count(*) from t1 /* must be 5 */; count(*) 5 @@ -491,9 +500,12 @@ insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 293 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 @@ -503,9 +515,13 @@ insert into t2 values (2); reset master; insert into t2 select bug27417(1) union select bug27417(2); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 332 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 2 */; count(*) 2 @@ -514,9 +530,13 @@ insert into t3 values (1,1),(2,3),(3,4); reset master; update t3 set b=b+bug27417(1); ERROR 23000: Duplicate entry '4' for key 'b' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 305 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Update_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F select count(*) from t1 /* must be 2 */; count(*) 2 @@ -530,9 +550,13 @@ insert into t3 values (bug27417(1), 2); reset master; delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 335 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t2) +master-bin.000001 # Table_map # # table_id: # (test.t3) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 @@ -548,9 +572,14 @@ a b select count(*) from t1 /* must be 2 */; count(*) 2 -show master status /* the offset must denote there is the query */; -File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 362 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Table_map # # table_id: # (test.t4) +master-bin.000001 # Table_map # # table_id: # (test.t1) +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK drop trigger trg_del; drop table t1,t2,t3,t4; drop function bug27417; diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 826206a1425..14397f85c38 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -120,15 +120,15 @@ insert into t2 select bug27417(2); reset master; --error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -show master status; /* only (!) with fixes for #23333 will show there is the query */; +insert into t2 values (bug27417(2)); +source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query select count(*) from t1 /* must be 3 */; reset master; select count(*) from t2; delete from t2 where a=bug27417(3); select count(*) from t2 /* nothing got deleted */; -show master status; /* the query must be in regardless of #23333 */; +source include/show_binlog_events.inc; # the query must be in regardless of #23333 select count(*) from t1 /* must be 5 */; --enable_info @@ -166,7 +166,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be event of the query select count(*) from t1 /* must be 1 */; # @@ -186,7 +186,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; # @@ -203,7 +203,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); update t3 set b=b+bug27417(1); # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; @@ -225,7 +225,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); --error ER_DUP_ENTRY delete from t2; # check - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 1 */; @@ -245,7 +245,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # check select * from t4; select count(*) from t1 /* must be 2 */; - show master status /* the offset must denote there is the query */; + source include/show_binlog_events.inc; # must be events of the query # # bug#23333 cleanup diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 16ad280c690..2f899a35179 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3163,6 +3163,7 @@ void select_insert::abort() { */ if (table) { + bool changed, transactional_table; /* If we are not in prelocked mode, we end the bulk insert started before. @@ -3184,20 +3185,20 @@ void select_insert::abort() { If table creation failed, the number of rows modified will also be zero, so no check for that is made. */ - if (info.copied || info.deleted || info.updated) + changed= (info.copied || info.deleted || info.updated); + transactional_table= table->file->has_transactions(); + if (thd->transaction.stmt.modified_non_trans_table) { - DBUG_ASSERT(table != NULL); - if (!table->file->has_transactions()) - { if (mysql_bin_log.is_open()) thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, - table->file->has_transactions(), FALSE); - if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table && - !can_rollback_data()) + transactional_table, FALSE); + if (!thd->current_stmt_binlog_row_based && !can_rollback_data()) thd->transaction.all.modified_non_trans_table= TRUE; - query_cache_invalidate3(thd, table, 1); - } + if (changed) + query_cache_invalidate3(thd, table, 1); } + DBUG_ASSERT(transactional_table || !changed || + thd->transaction.stmt.modified_non_trans_table); table->file->ha_release_auto_increment(); } From fe24b460c40ef994d9655b3682dfe17f1f6f4339 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Sep 2007 12:31:10 +0200 Subject: [PATCH 16/43] Merge: bug@27417,23333 and bug#28960 tests with 5.1 mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: results changed mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test: calling included file with testing bug#27417,23333. bug#28960 is not an rbr bug. mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test: moved SF() with side effects bugs to a separate includable file. This test verifies STMT format whereas binlog_row test is reposible for ROW format. mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test: sourced part for bugs with SF() etc having side effects of midifying non-transactional tables. --- .../mix_innodb_myisam_side_effects.test | 234 ++++++++++++++++++ .../r/binlog_row_mix_innodb_myisam.result | 186 ++++++++++++++ .../r/binlog_stm_mix_innodb_myisam.result | 45 ++-- .../t/binlog_row_mix_innodb_myisam.test | 2 + .../t/binlog_stm_mix_innodb_myisam.test | 234 +----------------- 5 files changed, 443 insertions(+), 258 deletions(-) create mode 100644 mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test new file mode 100644 index 00000000000..6c961c4694d --- /dev/null +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test @@ -0,0 +1,234 @@ +# the file to be sourced from binlog.binlog_mix_innodb_myisam + +# +# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack +# bug #28960 non-trans temp table changes with insert .. select +# not binlogged after rollback +# +# testing appearence of insert into temp_table in binlog. +# There are two branches of execution that require different setup. + +# checking binlog content filled with row-based events due to +# a used stored function modifies non-transactional table + +## send_eof() branch + +# prepare + +create temporary table tt (a int unique); +create table ti (a int) engine=innodb; +reset master; +show master status; + +# action + +begin; +insert into ti values (1); +insert into ti values (2) ; +insert into tt select * from ti; +rollback; + +# check + +select count(*) from tt /* 2 */; +show master status; +source include/show_binlog_events.inc; +select count(*) from ti /* zero */; +insert into ti select * from tt; +select * from ti /* that is what slave would miss - bug#28960 */; + + +## send_error() branch +delete from ti; +delete from tt where a=1; +reset master; +show master status; + +# action + +begin; +insert into ti values (1); +insert into ti values (2) /* to make the dup error in the following */; +--error ER_DUP_ENTRY +insert into tt select * from ti /* one affected and error */; +rollback; + +# check + +show master status; +source include/show_binlog_events.inc; # nothing in binlog with row bilog format +select count(*) from ti /* zero */; +insert into ti select * from tt; +select * from tt /* that is what otherwise slave missed - the bug */; + +drop table ti; + + +# +# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack +# +# Testing asserts: if there is a side effect of modifying non-transactional +# table thd->no_trans_update.stmt must be TRUE; +# the assert is active with debug build +# + +--disable_warnings +drop function if exists bug27417; +drop table if exists t1,t2; +--enable_warnings +# side effect table +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +# target tables +CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); + +delimiter |; +create function bug27417(n int) +RETURNS int(11) +begin + insert into t1 values (null); + return n; +end| +delimiter ;| + +reset master; + +# execute + +insert into t2 values (bug27417(1)); +insert into t2 select bug27417(2); +reset master; + +--error ER_DUP_ENTRY +insert into t2 values (bug27417(2)); +source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query +select count(*) from t1 /* must be 3 */; + +reset master; +select count(*) from t2; +delete from t2 where a=bug27417(3); +select count(*) from t2 /* nothing got deleted */; +source include/show_binlog_events.inc; # the query must be in regardless of #23333 +select count(*) from t1 /* must be 5 */; + +--enable_info +delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; +--disable_info +select count(*) from t1 /* must be 7 */; + +# function bug27417 remains for the following testing of bug#23333 +drop table t1,t2; + +# +# Bug#23333 using the patch (and the test) for bug#27471 +# throughout the bug tests +# t1 - non-trans side effects gatherer; +# t2 - transactional table; +# +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); + + +# +# INSERT +# + +# prepare + + insert into t2 values (1); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 values (bug27417(1)); + +# check + + source include/show_binlog_events.inc; # must be event of the query + select count(*) from t1 /* must be 1 */; + +# +# INSERT SELECT +# + +# prepare + delete from t1; + delete from t2; + insert into t2 values (2); + reset master; + +# execute + + --error ER_DUP_ENTRY + insert into t2 select bug27417(1) union select bug27417(2); + +# check + + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 2 */; + +# +# UPDATE (multi-update see bug#27716) +# + +# prepare + delete from t1; + insert into t3 values (1,1),(2,3),(3,4); + reset master; + +# execute + --error ER_DUP_ENTRY + update t3 set b=b+bug27417(1); + +# check + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 2 */; + + +# +# DELETE (for multi-delete see Bug #29136) +# + +# prepare + delete from t1; + delete from t2; + delete from t3; + insert into t2 values (1); + insert into t3 values (1,1); + create trigger trg_del before delete on t2 for each row + insert into t3 values (bug27417(1), 2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete from t2; +# check + source include/show_binlog_events.inc; # must be events of the query + select count(*) from t1 /* must be 1 */; + + +# +# LOAD DATA +# + +# prepare + delete from t1; + create table t4 (a int default 0, b int primary key) engine=innodb; + insert into t4 values (0, 17); + reset master; + +# execute + --error ER_DUP_ENTRY + load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +# check + select * from t4; + select count(*) from t1 /* must be 2 */; + source include/show_binlog_events.inc; # must be events of the query + +# +# bug#23333 cleanup +# +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 6ac942176c7..8022f2b1e10 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -413,3 +413,189 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; +create temporary table tt (a int unique); +create table ti (a int) engine=innodb; +reset master; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +begin; +insert into ti values (1); +insert into ti values (2) ; +insert into tt select * from ti; +rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +select count(*) from tt /* 2 */; +count(*) +2 +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 395 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; BEGIN +master-bin.000001 # Table_map # # table_id: # (test.ti) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Table_map # # table_id: # (test.ti) +master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from ti /* zero */; +count(*) +0 +insert into ti select * from tt; +select * from ti /* that is what slave would miss - bug#28960 */; +a +1 +2 +delete from ti; +delete from tt where a=1; +reset master; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +begin; +insert into ti values (1); +insert into ti values (2) /* to make the dup error in the following */; +insert into tt select * from ti /* one affected and error */; +ERROR 23000: Duplicate entry '2' for key 'a' +rollback; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 106 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +select count(*) from ti /* zero */; +count(*) +0 +insert into ti select * from tt; +select * from tt /* that is what otherwise slave missed - the bug */; +a +1 +2 +drop table ti; +drop function if exists bug27417; +drop table if exists t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); +create function bug27417(n int) +RETURNS int(11) +begin +insert into t1 values (null); +return n; +end| +reset master; +insert into t2 values (bug27417(1)); +insert into t2 select bug27417(2); +reset master; +insert into t2 values (bug27417(2)); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(2)) +select count(*) from t1 /* must be 3 */; +count(*) +3 +reset master; +select count(*) from t2; +count(*) +2 +delete from t2 where a=bug27417(3); +select count(*) from t2 /* nothing got deleted */; +count(*) +2 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; delete from t2 where a=bug27417(3) +select count(*) from t1 /* must be 5 */; +count(*) +5 +delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; +affected rows: 0 +select count(*) from t1 /* must be 7 */; +count(*) +7 +drop table t1,t2; +CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +insert into t2 values (1); +reset master; +insert into t2 values (bug27417(1)); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1)) +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +delete from t2; +insert into t2 values (2); +reset master; +insert into t2 select bug27417(1) union select bug27417(2); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=2 +master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2) +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +insert into t3 values (1,1),(2,3),(3,4); +reset master; +update t3 set b=b+bug27417(1); +ERROR 23000: Duplicate entry '4' for key 'b' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) +select count(*) from t1 /* must be 2 */; +count(*) +2 +delete from t1; +delete from t2; +delete from t3; +insert into t2 values (1); +insert into t3 values (1,1); +create trigger trg_del before delete on t2 for each row +insert into t3 values (bug27417(1), 2); +reset master; +delete from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; delete from t2 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 +delete from t1; +create table t4 (a int default 0, b int primary key) engine=innodb; +insert into t4 values (0, 17); +reset master; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); +ERROR 23000: Duplicate entry '17' for key 'PRIMARY' +select * from t4; +a b +0 17 +select count(*) from t1 /* must be 2 */; +count(*) +2 +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 +master-bin.000001 # Query # # use `test`; ROLLBACK +drop trigger trg_del; +drop table t1,t2,t3,t4; +drop function bug27417; diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 564fa8d86bd..9c580b2312e 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -380,6 +380,7 @@ select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; +set @@session.binlog_format=statement; create temporary table tt (a int unique); create table ti (a int) engine=innodb; reset master; @@ -465,9 +466,8 @@ insert into t2 values (bug27417(2)); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=3 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(2)) select count(*) from t1 /* must be 3 */; count(*) 3 @@ -481,9 +481,8 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; delete from t2 where a=bug27417(3) select count(*) from t1 /* must be 5 */; count(*) 5 @@ -502,9 +501,8 @@ insert into t2 values (bug27417(1)); ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=1 +master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1)) master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) @@ -517,10 +515,8 @@ insert into t2 select bug27417(1) union select bug27417(2); ERROR 23000: Duplicate entry '2' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=2 +master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2) master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 2 */; count(*) @@ -532,11 +528,8 @@ update t3 set b=b+bug27417(1); ERROR 23000: Duplicate entry '4' for key 'b' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t3) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Update_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=4 +master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 @@ -552,10 +545,8 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t2) -master-bin.000001 # Table_map # # table_id: # (test.t3) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) @@ -574,13 +565,13 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Table_map # # table_id: # (test.t4) -master-bin.000001 # Table_map # # table_id: # (test.t1) -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # -master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 +master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK drop trigger trg_del; drop table t1,t2,t3,t4; drop function bug27417; +set @@session.binlog_format=@@global.binlog_format; end of tests diff --git a/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test index 7b7753a487e..3148cc50fd0 100644 --- a/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_row_mix_innodb_myisam.test @@ -31,3 +31,5 @@ eval select @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%", @a not like "%#%error_code=%error_code=%"; drop table t1, t2; + +-- source extra/binlog_tests/mix_innodb_myisam_side_effects.test diff --git a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test index 14397f85c38..e7149e03b87 100644 --- a/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test +++ b/mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test @@ -24,237 +24,9 @@ eval select drop table t1, t2; -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# bug #28960 non-trans temp table changes with insert .. select -# not binlogged after rollback -# -# testing appearence of insert into temp_table in binlog. -# There are two branches of execution that require different setup. - -## send_eof() branch - -# prepare - -create temporary table tt (a int unique); -create table ti (a int) engine=innodb; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) ; -insert into tt select * from ti; -rollback; - -# check - -select count(*) from tt /* 2 */; -show master status; -source include/show_binlog_events.inc; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from ti /* that is what slave would miss - bug#28960 */; - - -## send_error() branch -delete from ti; -delete from tt where a=1; -reset master; -show master status; - -# action - -begin; -insert into ti values (1); -insert into ti values (2) /* to make the dup error in the following */; ---error ER_DUP_ENTRY -insert into tt select * from ti /* one affected and error */; -rollback; - -# check - -show master status; -source include/show_binlog_events.inc; -select count(*) from ti /* zero */; -insert into ti select * from tt; -select * from tt /* that is what otherwise slave missed - the bug */; - -drop table ti; - - -# -# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack -# -# Testing asserts: if there is a side effect of modifying non-transactional -# table thd->no_trans_update.stmt must be TRUE; -# the assert is active with debug build -# - ---disable_warnings -drop function if exists bug27417; -drop table if exists t1,t2; ---enable_warnings -# side effect table -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -# target tables -CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); - -delimiter |; -create function bug27417(n int) -RETURNS int(11) -begin - insert into t1 values (null); - return n; -end| -delimiter ;| - -reset master; - -# execute - -insert into t2 values (bug27417(1)); -insert into t2 select bug27417(2); -reset master; - ---error ER_DUP_ENTRY -insert into t2 values (bug27417(2)); -source include/show_binlog_events.inc; #only (!) with fixes for #23333 will show there is the query -select count(*) from t1 /* must be 3 */; - -reset master; -select count(*) from t2; -delete from t2 where a=bug27417(3); -select count(*) from t2 /* nothing got deleted */; -source include/show_binlog_events.inc; # the query must be in regardless of #23333 -select count(*) from t1 /* must be 5 */; - ---enable_info -delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; ---disable_info -select count(*) from t1 /* must be 7 */; - -# function bug27417 remains for the following testing of bug#23333 -drop table t1,t2; - -# -# Bug#23333 using the patch (and the test) for bug#27471 -# throughout the bug tests -# t1 - non-trans side effects gatherer; -# t2 - transactional table; -# -CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); - - -# -# INSERT -# - -# prepare - - insert into t2 values (1); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 values (bug27417(1)); - -# check - - source include/show_binlog_events.inc; # must be event of the query - select count(*) from t1 /* must be 1 */; - -# -# INSERT SELECT -# - -# prepare - delete from t1; - delete from t2; - insert into t2 values (2); - reset master; - -# execute - - --error ER_DUP_ENTRY - insert into t2 select bug27417(1) union select bug27417(2); - -# check - - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 2 */; - -# -# UPDATE (multi-update see bug#27716) -# - -# prepare - delete from t1; - insert into t3 values (1,1),(2,3),(3,4); - reset master; - -# execute - --error ER_DUP_ENTRY - update t3 set b=b+bug27417(1); - -# check - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 2 */; - - -# -# DELETE (for multi-delete see Bug #29136) -# - -# prepare - delete from t1; - delete from t2; - delete from t3; - insert into t2 values (1); - insert into t3 values (1,1); - create trigger trg_del before delete on t2 for each row - insert into t3 values (bug27417(1), 2); - reset master; - -# execute - --error ER_DUP_ENTRY - delete from t2; -# check - source include/show_binlog_events.inc; # must be events of the query - select count(*) from t1 /* must be 1 */; - - -# -# LOAD DATA -# - -# prepare - delete from t1; - create table t4 (a int default 0, b int primary key) engine=innodb; - insert into t4 values (0, 17); - reset master; - -# execute - --error ER_DUP_ENTRY - load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2); -# check - select * from t4; - select count(*) from t1 /* must be 2 */; - source include/show_binlog_events.inc; # must be events of the query - -# -# bug#23333 cleanup -# - - -drop trigger trg_del; -drop table t1,t2,t3,t4; -drop function bug27417; +set @@session.binlog_format=statement; +-- source extra/binlog_tests/mix_innodb_myisam_side_effects.test +set @@session.binlog_format=@@global.binlog_format; --echo end of tests From 08c5f2678480cdc9a52f65df77f4af93d4007265 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Sep 2007 08:13:52 +0200 Subject: [PATCH 17/43] Fixing bug in test in that a database was not dropped and was visible in following tests. mysql-test/suite/rpl/r/rpl_bug31076.result: Result file change. mysql-test/suite/rpl/t/rpl_bug31076.test: Dropping database so that following tests don't see it. --- mysql-test/suite/rpl/r/rpl_bug31076.result | 1 + mysql-test/suite/rpl/t/rpl_bug31076.test | 3 +++ 2 files changed, 4 insertions(+) diff --git a/mysql-test/suite/rpl/r/rpl_bug31076.result b/mysql-test/suite/rpl/r/rpl_bug31076.result index c991b2f1946..2d6bed37901 100644 --- a/mysql-test/suite/rpl/r/rpl_bug31076.result +++ b/mysql-test/suite/rpl/r/rpl_bug31076.result @@ -61,3 +61,4 @@ visits_id myid src ip cc org ref time host entry visit_exit user_id visit_start SELECT * FROM visits_events; event_id visit_id timestamp src data visits_events_id 20000 21231038 2007-09-18 03:59:02 Downloads/MySQL-4.1/mysql-4.1.12a-win32.zip 33712207 +DROP DATABASE track; diff --git a/mysql-test/suite/rpl/t/rpl_bug31076.test b/mysql-test/suite/rpl/t/rpl_bug31076.test index 6cb8cc0d902..95fb1e5fb96 100644 --- a/mysql-test/suite/rpl/t/rpl_bug31076.test +++ b/mysql-test/suite/rpl/t/rpl_bug31076.test @@ -111,3 +111,6 @@ VALUES ('3m3l4rhs6do0sf5p1i9lr94g928a272v', '', '', INET_ATON('71.118.124.98'), SELECT * FROM visits; SELECT * FROM visits_events; + +DROP DATABASE track; +sync_slave_with_master; From 184cddab1328c755e9076028db6ab1deaeed675b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Sep 2007 21:59:17 +0200 Subject: [PATCH 18/43] Bug #26000 SHOW SLAVE STATUS can crash mysqld during shutdown process active_mi has been reset (shutdown) at the time of quering with SHOW SLAVE STATUS so that at handling of SHOW an attempt to read its members segfaults. Fixed with checking the value of active_mi before to call show_master_info() Merely send_ok() is invoked when active_mi does not exist. A test can not be easiely written. Notice, there are more analogical cases in the code which require a similar treatment (to be reported as a bug separately). sql/sql_parse.cc: Ignore reporting and send only OK if master info struct has been destoyed. As this must be at shutdown merely a warning is sent to the client. --- sql/sql_parse.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 58f5ffc5235..075ce2c9e8c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2844,7 +2844,16 @@ mysql_execute_command(THD *thd) if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; pthread_mutex_lock(&LOCK_active_mi); - res = show_master_info(thd,active_mi); + if (active_mi != NULL) + { + res = show_master_info(thd, active_mi); + } + else + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "the master info structure does not exist"); + send_ok(thd); + } pthread_mutex_unlock(&LOCK_active_mi); break; } From 1ff1ff869ca7730b272c33765f1c7e1cff90c8a1 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Oct 2007 15:35:42 +0500 Subject: [PATCH 19/43] Bug#30315 Character sets: insertion of euckr code value 0xa141 fails Problem: some valid euc-kr characters were rejected because condition checking multi-byte tail didn't allow multi-byte characters having the second byte in the ranges [0x41..0x5A] and [0x61..0x7A]. Fix: allow these byte ranges for mb tails mysql-test/r/ctype_euckr.result: Adding tests mysql-test/t/ctype_euckr.test: Adding tests strings/ctype-euc_kr.c: Fixing wrong tail character pattern --- mysql-test/r/ctype_euckr.result | 41 +++++++++++++++++++++++++++++++++ mysql-test/t/ctype_euckr.test | 23 ++++++++++++++++++ strings/ctype-euc_kr.c | 27 ++++++++++++++++++---- 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/ctype_euckr.result b/mysql-test/r/ctype_euckr.result index 6017bc07763..57e3e2ed8f8 100644 --- a/mysql-test/r/ctype_euckr.result +++ b/mysql-test/r/ctype_euckr.result @@ -165,3 +165,44 @@ hex(a) A2E6 FEF7 DROP TABLE t1; +create table t1 (s1 varchar(5) character set euckr); +insert into t1 values (0xA141); +insert into t1 values (0xA15A); +insert into t1 values (0xA161); +insert into t1 values (0xA17A); +insert into t1 values (0xA181); +insert into t1 values (0xA1FE); +insert into t1 values (0xA140); +Warnings: +Warning 1366 Incorrect string value: '\xA1@' for column 's1' at row 1 +insert into t1 values (0xA15B); +Warnings: +Warning 1366 Incorrect string value: '\xA1[' for column 's1' at row 1 +insert into t1 values (0xA160); +Warnings: +Warning 1366 Incorrect string value: '\xA1`' for column 's1' at row 1 +insert into t1 values (0xA17B); +Warnings: +Warning 1366 Incorrect string value: '\xA1{' for column 's1' at row 1 +insert into t1 values (0xA180); +Warnings: +Warning 1366 Incorrect string value: '\xA1\x80' for column 's1' at row 1 +insert into t1 values (0xA1FF); +Warnings: +Warning 1366 Incorrect string value: '\xA1\xFF' for column 's1' at row 1 +select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1; +hex(s1) hex(convert(s1 using utf8)) + + + + + + +A141 ECA2A5 +A15A ECA381 +A161 ECA382 +A17A ECA3A5 +A181 ECA3A6 +A1FE EFBFA2 +drop table t1; +End of 5.0 tests diff --git a/mysql-test/t/ctype_euckr.test b/mysql-test/t/ctype_euckr.test index 56939817b2f..05e4b04eded 100644 --- a/mysql-test/t/ctype_euckr.test +++ b/mysql-test/t/ctype_euckr.test @@ -31,3 +31,26 @@ SELECT hex(a) FROM t1 ORDER BY a; DROP TABLE t1; # End of 4.1 tests + +# +#Bug #30315 Character sets: insertion of euckr code value 0xa141 fails +# +create table t1 (s1 varchar(5) character set euckr); +# Insert some valid characters +insert into t1 values (0xA141); +insert into t1 values (0xA15A); +insert into t1 values (0xA161); +insert into t1 values (0xA17A); +insert into t1 values (0xA181); +insert into t1 values (0xA1FE); +# Insert some invalid characters +insert into t1 values (0xA140); +insert into t1 values (0xA15B); +insert into t1 values (0xA160); +insert into t1 values (0xA17B); +insert into t1 values (0xA180); +insert into t1 values (0xA1FF); +select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1; +drop table t1; + +--echo End of 5.0 tests diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index abaa8f1a516..1aaf65c98b3 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -179,20 +179,39 @@ static uchar NEAR sort_order_euc_kr[]= /* Support for Korean(EUC_KR) characters, by powerm90@tinc.co.kr and mrpark@tinc.co.kr */ -#define iseuc_kr(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe)) +/* + Unicode mapping is done according to: + ftp://ftp.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/KSC/KSC5601.TXT + + Valid multi-byte characters: + + [A1..FE][41..5A,61..7A,81..FE] + + Note, 0x5C is not a valid MB tail, + so escape_with_backslash_is_dangerous is not set. +*/ +#define iseuc_kr_head(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe)) + +#define iseuc_kr_tail1(c) ((uchar) (c) >= 0x41 && (uchar) (c) <= 0x5A) +#define iseuc_kr_tail2(c) ((uchar) (c) >= 0x61 && (uchar) (c) <= 0x7A) +#define iseuc_kr_tail3(c) ((uchar) (c) >= 0x81 && (uchar) (c) <= 0xFE) + +#define iseuc_kr_tail(c) (iseuc_kr_tail1(c) || \ + iseuc_kr_tail2(c) || \ + iseuc_kr_tail3(c)) static int ismbchar_euc_kr(CHARSET_INFO *cs __attribute__((unused)), const char* p, const char *e) { return ((*(uchar*)(p)<0x80)? 0:\ - iseuc_kr(*(p)) && (e)-(p)>1 && iseuc_kr(*((p)+1))? 2:\ + iseuc_kr_head(*(p)) && (e)-(p)>1 && iseuc_kr_tail(*((p)+1))? 2:\ 0); } static int mbcharlen_euc_kr(CHARSET_INFO *cs __attribute__((unused)),uint c) { - return (iseuc_kr(c) ? 2 : 1); + return (iseuc_kr_head(c) ? 2 : 1); } @@ -8653,7 +8672,7 @@ my_well_formed_len_euckr(CHARSET_INFO *cs __attribute__((unused)), /* Single byte ascii character */ b++; } - else if (b < emb && iseuc_kr(*b) && iseuc_kr(b[1])) + else if (b < emb && iseuc_kr_head(*b) && iseuc_kr_tail(b[1])) { /* Double byte character */ b+= 2; From a9571690cb8a4369cd6f9490501650402e61fd9b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Oct 2007 13:28:58 +0500 Subject: [PATCH 20/43] Fixing comments to use "#" instead of "--" --- mysql-test/t/ctype_uca.test | 2 +- mysql-test/t/subselect.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 17632e7c8fc..695a21adbf5 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -530,7 +530,7 @@ create table t1 ( a varchar(255), key a(a) ) character set utf8 collate utf8_czech_ci; --- In Czech 'ch' is a single letter between 'h' and 'i' +# In Czech 'ch' is a single letter between 'h' and 'i' insert into t1 values ('b'),('c'),('d'),('e'),('f'),('g'),('h'),('ch'),('i'),('j'); select * from t1 where a like 'c%'; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index d076ca6bd33..86d2aec870c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -2970,7 +2970,7 @@ DROP TABLE t1,t2; CREATE TABLE t1 (a INT, b INT); INSERT INTO t1 VALUES (1, 2), (1,3), (1,4), (2,1), (2,2); --- returns no rows, when it should +# returns no rows, when it should SELECT a1.a, COUNT(*) FROM t1 a1 WHERE a1.a = 1 AND EXISTS( SELECT a2.a FROM t1 a2 WHERE a2.a = a1.a) GROUP BY a1.a; From c359f7ff33d17e1af0bfd1268a68af8332d2538c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 2 Oct 2007 15:20:45 +0500 Subject: [PATCH 21/43] Bug#29675 collation_connection is defined twice for the same value Removing redundant initialization. sql/mysqld.cc: Removing redundant variable initialization. --- sql/mysqld.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 08c2b60fa79..9b339a59946 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2849,7 +2849,6 @@ static int init_common_variables(const char *conf_file_name, int argc, global_system_variables.collation_connection= default_charset_info; global_system_variables.character_set_results= default_charset_info; global_system_variables.character_set_client= default_charset_info; - global_system_variables.collation_connection= default_charset_info; if (!(character_set_filesystem= get_charset_by_csname(character_set_filesystem_name, From 42cea00e036c1191b7c9251ac1e123df8273d86c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 3 Oct 2007 11:57:14 +0200 Subject: [PATCH 22/43] BUG#30752 rpl_dual_pos_advance valgrind (jump depends on uninitialized LOG_INFO) Problem: one thread could read uninitialized memory from (the stack of) another thread. Fix: swapped order of initializing the memory and making it available to the other thread. Fix: put lock around the statement that makes the memory available to the other thread. Fix: all fields of the struct are now initialized in the constructor, to avoid future problems. sql/sql_class.h: Initialize all members in constructor for more safe future code. sql/sql_repl.cc: Swap order so that linfo is first initialized, then assigned, instead of the other way around. Put a lock around the assignment. We use LOCK_thread_count since log_in_use uses it: log_in_use may be running concurrently, called from MYSQL_LOG::purge_logs. --- sql/sql_class.h | 8 +++++++- sql/sql_repl.cc | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sql/sql_class.h b/sql/sql_class.h index 4fac86dc405..a96000a0598 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -159,7 +159,13 @@ typedef struct st_log_info my_off_t pos; bool fatal; // if the purge happens to give us a negative offset pthread_mutex_t lock; - st_log_info():fatal(0) { pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);} + st_log_info() + : index_file_offset(0), index_file_start_offset(0), + pos(0), fatal(0) + { + log_file_name[0] = '\0'; + pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); + } ~st_log_info() { pthread_mutex_destroy(&lock);} } LOG_INFO; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 9cc0ba7c29a..903d254db8f 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -364,7 +364,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, name=0; // Find first log linfo.index_file_offset = 0; - thd->current_linfo = &linfo; if (mysql_bin_log.find_log_pos(&linfo, name, 1)) { @@ -373,6 +372,10 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, goto err; } + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = &linfo; + pthread_mutex_unlock(&LOCK_thread_count); + if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0) { my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; @@ -1338,7 +1341,6 @@ bool mysql_show_binlog_events(THD* thd) name=0; // Find first log linfo.index_file_offset = 0; - thd->current_linfo = &linfo; if (mysql_bin_log.find_log_pos(&linfo, name, 1)) { @@ -1346,6 +1348,10 @@ bool mysql_show_binlog_events(THD* thd) goto err; } + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = &linfo; + pthread_mutex_unlock(&LOCK_thread_count); + if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0) goto err; From d0b076b66cef0335a884fa96c1c636bbef31a9db Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Oct 2007 13:06:01 +0500 Subject: [PATCH 23/43] Bug#29323 mysql client only accetps ANSI encoded files Fix: ignore BOM marker in the first line. client/mysql.cc: Skip BOM marker in the very first line. mysql-test/r/mysql.result: Adding test mysql-test/t/mysql.test: Adding test --- client/mysql.cc | 11 +++++++++++ mysql-test/r/mysql.result | 2 ++ mysql-test/t/mysql.test | 9 +++++++++ 3 files changed, 22 insertions(+) diff --git a/client/mysql.cc b/client/mysql.cc index 8e1b6c2a9b4..3cc7f2ad090 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1042,6 +1042,17 @@ static int read_and_execute(bool interactive) if (!interactive) { line=batch_readline(status.line_buff); + /* + Skip UTF8 Byte Order Marker (BOM) 0xEFBBBF. + Editors like "notepad" put this marker in + the very beginning of a text file when + you save the file using "Unicode UTF-8" format. + */ + if (!line_number && + (uchar) line[0] == 0xEF && + (uchar) line[1] == 0xBB && + (uchar) line[2] == 0xBF) + line+= 3; line_number++; if (!glob_buffer.length()) status.query_start_line=line_number; diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index c6e589a5fb7..eded1a3fc3b 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -178,4 +178,6 @@ ERROR at line 1: DELIMITER cannot contain a backslash character 1 1 1 +This is a file starting with UTF8 BOM 0xEFBBBF +This is a file starting with UTF8 BOM 0xEFBBBF End of 5.0 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 6e97d0faede..182b292c817 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -281,4 +281,13 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug21412.sql; # --exec $MYSQL test -e "/*! \C latin1 */ select 1;" +# +# Bug#29323 mysql client only accetps ANSI encoded files +# +--write_file $MYSQLTEST_VARDIR/tmp/bug29323.sql +select "This is a file starting with UTF8 BOM 0xEFBBBF"; +EOF +--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug29323.sql 2>&1 +remove_file $MYSQLTEST_VARDIR/tmp/bug29323.sql; + --echo End of 5.0 tests From 0f0e0e1aafcc2d0d467ce5de560d7d6f7151d384 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Oct 2007 13:13:04 +0300 Subject: [PATCH 24/43] manual merge sql/log.h: manual merge: moving 5.0 hunk into the correct file. --- sql/log.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/log.h b/sql/log.h index e597c986794..afcb1d1adf4 100644 --- a/sql/log.h +++ b/sql/log.h @@ -130,7 +130,13 @@ typedef struct st_log_info my_off_t pos; bool fatal; // if the purge happens to give us a negative offset pthread_mutex_t lock; - st_log_info():fatal(0) { pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);} + st_log_info() + : index_file_offset(0), index_file_start_offset(0), + pos(0), fatal(0) + { + log_file_name[0] = '\0'; + pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); + } ~st_log_info() { pthread_mutex_destroy(&lock);} } LOG_INFO; From bf8a85aa56fe755a1712a08b45667734765d45c8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 4 Oct 2007 18:46:31 +0300 Subject: [PATCH 25/43] Bug #29309 Incorrect "Seconds_Behind_Master" value in SHOW SLAVE STATUS after FLUSH LOGS Report claims that Seconds_behind_master behaves unexpectedly. Code analysis shows that there is an evident flaw in that treating of FormatDescription event is wrong so that after FLUSH LOGS on slave the Seconds_behind_master's calculation slips and incorrect value can be reported to SHOW SLAVE STATUS. Even worse is that the gap between the correct and incorrect deltas grows with time. Fixed with prohibiting changes to rpl->last_master_timestamp by artifical events (any kind of). suggestion as comments is added how to fight with lack of info on the slave side by means of new heartbeat feature coming. The test can not be done ealily fully determistic. sql/log_event.cc: changing timestamp is affirmed only by non-artificial events. Artifical FD won't change it anymore. The simulation code is off unless server is started with the args from the opt-file. The simulation code assumes that it will execute specific schedule generated by rpl_replication_delay.test. sql/slave.cc: Comments are changed to announce a new possibility to cope with Seconds_behind_master jumping due to EOF special treatment (reset of the timestamp) mysql-test/suite/manual/r/rpl_replication_delay.result: result are not deterministic though there are comments saying the most probable expected value for Seconds_behind_master mysql-test/suite/manual/t/rpl_replication_delay-slave.opt: bug emulation mysql-test/suite/manual/t/rpl_replication_delay.test: specic test for bug#29309. It's hard to make it reliable as it deals with timestamps. (a way to automate the test like this is to have I_S table for show slave status' fields) A possible way to check results is to run grep -i 'show\|seconds' < suite/manual/r/rpl_replication_delay.reject and to get the lines like these: show slave status /* Second_behind reports 0 */;; Seconds_Behind_Master 0 show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */;; Seconds_Behind_Master 9 show slave status /* reports the correct diff with master query time about 3+3 secs */;; Seconds_Behind_Master 6 Due to time discreteness of time the reported numbers may slightly vary. That's why the test is not reliable. --- .../manual/r/rpl_replication_delay.result | 121 ++++++++++++++++++ .../manual/t/rpl_replication_delay-slave.opt | 1 + .../suite/manual/t/rpl_replication_delay.test | 71 ++++++++++ sql/log_event.cc | 32 ++++- sql/slave.cc | 11 +- 5 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 mysql-test/suite/manual/r/rpl_replication_delay.result create mode 100644 mysql-test/suite/manual/t/rpl_replication_delay-slave.opt create mode 100644 mysql-test/suite/manual/t/rpl_replication_delay.test diff --git a/mysql-test/suite/manual/r/rpl_replication_delay.result b/mysql-test/suite/manual/r/rpl_replication_delay.result new file mode 100644 index 00000000000..22447a30cba --- /dev/null +++ b/mysql-test/suite/manual/r/rpl_replication_delay.result @@ -0,0 +1,121 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +show slave status /* Second_behind reports 0 */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 98 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 98 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 0 +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' +create table t1 (f1 int); +flush logs /* contaminate rli->last_master_timestamp */; +lock table t1 write; +insert into t1 values (1); +show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 359 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 271 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 10 +unlock tables; +flush logs /* this time rli->last_master_timestamp is not affected */; +lock table t1 write; +insert into t1 values (2); +show slave status /* reports the correct diff with master query time about 3+3 secs */;; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port 9306 +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 447 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos 359 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master 6 +unlock tables; +drop table t1; diff --git a/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt b/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt new file mode 100644 index 00000000000..24a4c5952fe --- /dev/null +++ b/mysql-test/suite/manual/t/rpl_replication_delay-slave.opt @@ -0,0 +1 @@ +--loose-debug=d,let_first_flush_log_change_timestamp diff --git a/mysql-test/suite/manual/t/rpl_replication_delay.test b/mysql-test/suite/manual/t/rpl_replication_delay.test new file mode 100644 index 00000000000..8230698c8f9 --- /dev/null +++ b/mysql-test/suite/manual/t/rpl_replication_delay.test @@ -0,0 +1,71 @@ +# +# Testing replication delay reporting (bug#29309) +# there is an unavoidable non-determinism in the test +# please compare the results with the comments +# + + +source include/master-slave.inc; + +connection master; +#connection slave; +sync_slave_with_master; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* Second_behind reports 0 */; +sleep 3; + +### bug emulation + +connection master; +drop table if exists t1; +create table t1 (f1 int); +sleep 3; + +#connection slave; +sync_slave_with_master; +flush logs /* contaminate rli->last_master_timestamp */; + +connection slave; +lock table t1 write; + +connection master; +insert into t1 values (1); + +sleep 3; + +connection slave; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* bug emulated: reports slave threads starting time about 3*3 not 3 secs */; +unlock tables; + +connection master; +sync_slave_with_master; + +### bugfix + + +connection slave; +flush logs /* this time rli->last_master_timestamp is not affected */; +lock table t1 write; + +connection master; +insert into t1 values (2); +sleep 3; + +connection slave; +--replace_result $DEFAULT_MASTER_PORT DEFAULT_MASTER_PORT +--replace_column 1 # 8 # 9 # 23 # +--query_vertical show slave status /* reports the correct diff with master query time about 3+3 secs */; +unlock tables; + +connection master; +drop table t1; + +#connection slave; +sync_slave_with_master; + + +# End of tests + diff --git a/sql/log_event.cc b/sql/log_event.cc index 1ef765f607f..3899e772bf8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -27,6 +27,10 @@ #define log_cs &my_charset_latin1 +#ifndef DBUG_OFF +uint debug_not_change_ts_if_art_event= 1; // bug#29309 simulation +#endif + /* pretty_print_str() */ @@ -481,6 +485,18 @@ int Log_event::exec_event(struct st_relay_log_info* rli) rli->inc_event_relay_log_pos(); else { + /* + bug#29309 simulation: resetting the flag to force + wrong behaviour of artificial event to update + rli->last_master_timestamp for only one time - + the first FLUSH LOGS in the test. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 1 + && is_artificial_event()) + { + debug_not_change_ts_if_art_event= 0; + }); rli->inc_group_relay_log_pos(log_pos); flush_relay_log_info(rli); /* @@ -491,7 +507,21 @@ int Log_event::exec_event(struct st_relay_log_info* rli) rare cases, only consequence is that value may take some time to display in Seconds_Behind_Master - not critical). */ - rli->last_master_timestamp= when; +#ifndef DBUG_OFF + if (!(is_artificial_event() && debug_not_change_ts_if_art_event > 0)) +#else + if (!is_artificial_event()) +#endif + rli->last_master_timestamp= when; + /* + The flag is set back to be positive so that + any further FLUSH LOGS will be handled as prescribed. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 0) + { + debug_not_change_ts_if_art_event= 2; + }); } } DBUG_RETURN(0); diff --git a/sql/slave.cc b/sql/slave.cc index 57f6e64ce03..0bc4bf7b32f 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4931,7 +4931,16 @@ Log_event* next_event(RELAY_LOG_INFO* rli) a new event and is queuing it; the false "0" will exist until SQL finishes executing the new event; it will be look abnormal only if the events have old timestamps (then you get "many", 0, "many"). - Transient phases like this can't really be fixed. + + Transient phases like this can be fixed with implemeting + Heartbeat event which provides the slave the status of the + master at time the master does not have any new update to send. + Seconds_Behind_Master would be zero only when master has no + more updates in binlog for slave. The heartbeat can be sent + in a (small) fraction of slave_net_timeout. Until it's done + rli->last_master_timestamp is temporarely (for time of + waiting for the following event) reset whenever EOF is + reached. */ time_t save_timestamp= rli->last_master_timestamp; rli->last_master_timestamp= 0; From 64b19133820078a555e73ed1ff429984e82d1041 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 5 Oct 2007 12:15:11 +0500 Subject: [PATCH 26/43] Bug#31081 server crash in regexp function Problem: The "regex" library written by Henry Spencer does not support tricky character sets like UCS2. Fix: convert tricky character sets to UTF8 before calling regex functions. mysql-test/r/ctype_uca.result: Adding tests mysql-test/r/ctype_ucs.result: Adding tests mysql-test/r/ctype_utf8.result: Adding tests mysql-test/r/func_regexp.result: Adding tests mysql-test/t/ctype_uca.test: Adding tests mysql-test/t/ctype_ucs.test: Adding tests mysql-test/t/ctype_utf8.test: Adding tests mysql-test/t/func_regexp.test: Adding tests sql/item_cmpfunc.cc: - Adding new method Item_func_regex::regcomp() to share more code between fix_fields() and val_int() - Adding conversion from ASCII-incompatible charsets like UCS2 to UTF8, because the "regexp" does not support these charsets - Additional optimization: calculate flags for regcomp only once in fix_fields, instead of every regcomp() sql/item_cmpfunc.h: Adding prototypes for new members and methods mysql-test/include/ctype_regex.inc: New BitKeeper file ``mysql-test/include/ctype_regex.inc'' Moving common regular expression tests into a separate file and uncluding it into func_regexp and into many ctype_xxx tests. --- mysql-test/include/ctype_regex.inc | 42 ++++++++++ mysql-test/r/ctype_uca.result | 45 +++++++++++ mysql-test/r/ctype_ucs.result | 45 +++++++++++ mysql-test/r/ctype_utf8.result | 45 +++++++++++ mysql-test/r/func_regexp.result | 14 +++- mysql-test/t/ctype_uca.test | 4 + mysql-test/t/ctype_ucs.test | 4 + mysql-test/t/ctype_utf8.test | 7 ++ mysql-test/t/func_regexp.test | 23 +----- sql/item_cmpfunc.cc | 122 +++++++++++++++++------------ sql/item_cmpfunc.h | 4 + 11 files changed, 283 insertions(+), 72 deletions(-) create mode 100644 mysql-test/include/ctype_regex.inc diff --git a/mysql-test/include/ctype_regex.inc b/mysql-test/include/ctype_regex.inc new file mode 100644 index 00000000000..0e6b4c41607 --- /dev/null +++ b/mysql-test/include/ctype_regex.inc @@ -0,0 +1,42 @@ +# +# To test a desired collation, set session.collation_connection to +# this collation before including this file +# + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# Create a table with two varchar(64) null-able column, +# using current values of +# @@character_set_connection and @@collation_connection. +# + +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +delete from t1; + +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); + +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); + +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); + +select HIGH_PRIORITY s1 regexp s2 from t1; + +drop table t1; diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 889702e380c..ada7ace9696 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2754,4 +2754,49 @@ a c ch drop table t1; +set collation_connection=ucs2_unicode_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL, + `s2` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names utf8; End for 5.0 tests diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 023267c227c..954fdab7699 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -922,4 +922,49 @@ ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_gen select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0); ERROR HY000: Illegal mix of collations (ascii_general_ci,IMPLICIT) and (ucs2_general_ci,COERCIBLE) for operation '=' drop table t1; +set collation_connection=ucs2_general_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set ucs2 default NULL, + `s2` varchar(64) character set ucs2 default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names latin1; End of 5.0 tests diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 710cac388a5..7cdc5c265d7 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -267,6 +267,51 @@ b select * from t1 where a = 'b' and a != 'b'; a drop table t1; +set collation_connection=utf8_general_ci; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) character set utf8 default NULL, + `s2` varchar(64) character set utf8 default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; +insert into t1 values('aaa','aaa'); +insert into t1 values('aaa|qqq','qqq'); +insert into t1 values('gheis','^[^a-dXYZ]+$'); +insert into t1 values('aab','^aa?b'); +insert into t1 values('Baaan','^Ba*n'); +insert into t1 values('aaa','qqq|aaa'); +insert into t1 values('qqq','qqq|aaa'); +insert into t1 values('bbb','qqq|aaa'); +insert into t1 values('bbb','qqq'); +insert into t1 values('aaa','aba'); +insert into t1 values(null,'abc'); +insert into t1 values('def',null); +insert into t1 values(null,null); +insert into t1 values('ghi','ghi['); +select HIGH_PRIORITY s1 regexp s2 from t1; +s1 regexp s2 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +NULL +NULL +NULL +NULL +drop table t1; +set names utf8; set names utf8; select 'вася' rlike '[[:<:]]вася[[:>:]]'; 'вася' rlike '[[:<:]]вася[[:>:]]' diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result index 584c8a9b820..752ec3a5810 100644 --- a/mysql-test/r/func_regexp.result +++ b/mysql-test/r/func_regexp.result @@ -1,5 +1,17 @@ drop table if exists t1; -create table t1 (s1 char(64),s2 char(64)); +set names latin1; +drop table if exists t1; +create table t1 as +select repeat(' ', 64) as s1, repeat(' ',64) as s2 +union +select null, null; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `s1` varchar(64) default NULL, + `s2` varchar(64) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +delete from t1; insert into t1 values('aaa','aaa'); insert into t1 values('aaa|qqq','qqq'); insert into t1 values('gheis','^[^a-dXYZ]+$'); diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 17632e7c8fc..bac3ef7d63c 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -538,4 +538,8 @@ alter table t1 convert to character set ucs2 collate ucs2_czech_ci; select * from t1 where a like 'c%'; drop table t1; +set collation_connection=ucs2_unicode_ci; +--source include/ctype_regex.inc +set names utf8; + -- echo End for 5.0 tests diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index bca3a9c3a96..3779dd50260 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -651,4 +651,8 @@ select * from t1 where a=if(b<10,_ucs2 0x00C0,_ucs2 0x0062); select * from t1 where a=if(b<10,_ucs2 0x0062,_ucs2 0x00C0); drop table t1; +set collation_connection=ucs2_general_ci; +--source include/ctype_regex.inc +set names latin1; + --echo End of 5.0 tests diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index f8eed0bae9a..927794f2d5a 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -185,6 +185,13 @@ select * from t1 where a = 'b' and a = 'b'; select * from t1 where a = 'b' and a != 'b'; drop table t1; +# +# Testing regexp +# +set collation_connection=utf8_general_ci; +--source include/ctype_regex.inc +set names utf8; + # # Bug #3928 regexp [[:>:]] and UTF-8 # diff --git a/mysql-test/t/func_regexp.test b/mysql-test/t/func_regexp.test index 23070c71fe9..f34830f6100 100644 --- a/mysql-test/t/func_regexp.test +++ b/mysql-test/t/func_regexp.test @@ -6,28 +6,9 @@ drop table if exists t1; --enable_warnings -create table t1 (s1 char(64),s2 char(64)); +set names latin1; +--source include/ctype_regex.inc -insert into t1 values('aaa','aaa'); -insert into t1 values('aaa|qqq','qqq'); -insert into t1 values('gheis','^[^a-dXYZ]+$'); -insert into t1 values('aab','^aa?b'); -insert into t1 values('Baaan','^Ba*n'); -insert into t1 values('aaa','qqq|aaa'); -insert into t1 values('qqq','qqq|aaa'); - -insert into t1 values('bbb','qqq|aaa'); -insert into t1 values('bbb','qqq'); -insert into t1 values('aaa','aba'); - -insert into t1 values(null,'abc'); -insert into t1 values('def',null); -insert into t1 values(null,null); -insert into t1 values('ghi','ghi['); - -select HIGH_PRIORITY s1 regexp s2 from t1; - -drop table t1; # # This test a bug in regexp on Alpha diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 86eb10d50b0..51b3e8cda6b 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4225,6 +4225,51 @@ void Item_func_like::cleanup() #ifdef USE_REGEX +bool +Item_func_regex::regcomp(bool send_error) +{ + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff),&my_charset_bin); + String *res= args[1]->val_str(&tmp); + int error; + + if (args[1]->null_value) + return TRUE; + + if (regex_compiled) + { + if (!stringcmp(res, &prev_regexp)) + return FALSE; + prev_regexp.copy(*res); + my_regfree(&preg); + regex_compiled= 0; + } + + if (cmp_collation.collation != regex_lib_charset) + { + /* Convert UCS2 strings to UTF8 */ + uint dummy_errors; + if (conv.copy(res->ptr(), res->length(), res->charset(), + regex_lib_charset, &dummy_errors)) + return TRUE; + res= &conv; + } + + if ((error= my_regcomp(&preg, res->c_ptr(), + regex_lib_flags, regex_lib_charset))) + { + if (send_error) + { + (void) my_regerror(error, &preg, buff, sizeof(buff)); + my_error(ER_REGEXP_ERROR, MYF(0), buff); + } + return TRUE; + } + regex_compiled= 1; + return FALSE; +} + + bool Item_func_regex::fix_fields(THD *thd, Item **ref) { @@ -4241,34 +4286,33 @@ Item_func_regex::fix_fields(THD *thd, Item **ref) if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1)) return TRUE; + regex_lib_flags= (cmp_collation.collation->state & + (MY_CS_BINSORT | MY_CS_CSSORT)) ? + REG_EXTENDED | REG_NOSUB : + REG_EXTENDED | REG_NOSUB | REG_ICASE; + /* + If the case of UCS2 and other non-ASCII character sets, + we will convert patterns and strings to UTF8. + */ + regex_lib_charset= (cmp_collation.collation->mbminlen > 1) ? + &my_charset_utf8_general_ci : + cmp_collation.collation; + used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); not_null_tables_cache= (args[0]->not_null_tables() | args[1]->not_null_tables()); const_item_cache=args[0]->const_item() && args[1]->const_item(); if (!regex_compiled && args[1]->const_item()) { - char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff),&my_charset_bin); - String *res=args[1]->val_str(&tmp); if (args[1]->null_value) { // Will always return NULL maybe_null=1; return FALSE; } - int error; - if ((error= my_regcomp(&preg,res->c_ptr(), - ((cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE), - cmp_collation.collation))) - { - (void) my_regerror(error,&preg,buff,sizeof(buff)); - my_error(ER_REGEXP_ERROR, MYF(0), buff); + if (regcomp(TRUE)) return TRUE; - } - regex_compiled=regex_is_const=1; - maybe_null=args[0]->maybe_null; + regex_is_const= 1; + maybe_null= args[0]->maybe_null; } else maybe_null=1; @@ -4281,47 +4325,25 @@ longlong Item_func_regex::val_int() { DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; - String *res, tmp(buff,sizeof(buff),&my_charset_bin); + String tmp(buff,sizeof(buff),&my_charset_bin); + String *res= args[0]->val_str(&tmp); - res=args[0]->val_str(&tmp); - if (args[0]->null_value) - { - null_value=1; + if ((null_value= (args[0]->null_value || + (!regex_is_const && regcomp(FALSE))))) return 0; - } - if (!regex_is_const) - { - char buff2[MAX_FIELD_WIDTH]; - String *res2, tmp2(buff2,sizeof(buff2),&my_charset_bin); - res2= args[1]->val_str(&tmp2); - if (args[1]->null_value) + if (cmp_collation.collation != regex_lib_charset) + { + /* Convert UCS2 strings to UTF8 */ + uint dummy_errors; + if (conv.copy(res->ptr(), res->length(), res->charset(), + regex_lib_charset, &dummy_errors)) { - null_value=1; + null_value= 1; return 0; } - if (!regex_compiled || stringcmp(res2,&prev_regexp)) - { - prev_regexp.copy(*res2); - if (regex_compiled) - { - my_regfree(&preg); - regex_compiled=0; - } - if (my_regcomp(&preg,res2->c_ptr_safe(), - ((cmp_collation.collation->state & - (MY_CS_BINSORT | MY_CS_CSSORT)) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE), - cmp_collation.collation)) - { - null_value=1; - return 0; - } - regex_compiled=1; - } + res= &conv; } - null_value=0; return my_regexec(&preg,res->c_ptr_safe(),0,(my_regmatch_t*) 0,0) ? 0 : 1; } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8410c66b034..11851e9a4e4 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1313,6 +1313,10 @@ class Item_func_regex :public Item_bool_func bool regex_is_const; String prev_regexp; DTCollation cmp_collation; + CHARSET_INFO *regex_lib_charset; + int regex_lib_flags; + String conv; + bool regcomp(bool send_error); public: Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b), regex_compiled(0),regex_is_const(0) {} From 4c21617d4a188de89833ceb0714de0c70fa963da Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 9 Oct 2007 13:53:39 +0500 Subject: [PATCH 27/43] Bug#27287 extractvalue() (and updatexml()) extremely slow for large XML Performance improvements made. ExtractValue for large XML values is now much faster (about 2000 times faster of 1Mb-long XML values). sql/item_xmlfunc.cc: Performance improvement for huge XML values: 1. Avoid reallocs - reserve extra memory: using String::reserve() + String::q_append() instead of String::append() 2. Parent is now not searched through the all previous nodes in backward direction. Instead, we do the following: - we introduce data->parent - a new member in MY_XML_USER_DATA - when entering a new tag/attribute node, we remember offset of the current node in data->parent - when leaving a tag/attribute node, we change data->parent to offset of the parent of the current node. --- sql/item_xmlfunc.cc | 60 ++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 15be9c97b6e..d0dbab16b1c 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2611,35 +2611,27 @@ typedef struct uint level; String *pxml; // parsed XML uint pos[MAX_LEVEL]; // Tag position stack + uint parent; // Offset of the parent of the current node } MY_XML_USER_DATA; -/* - Find the parent node - - SYNOPSYS - Find the parent node, i.e. a tag or attrubute node on the given level. - - RETURN - 1 - success - 0 - failure -*/ -static uint xml_parent_tag(MY_XML_NODE *items, uint nitems, uint level) +static bool +append_node(String *str, MY_XML_NODE *node) { - if (!nitems) - return 0; - - MY_XML_NODE *p, *last= &items[nitems-1]; - for (p= last; p >= items; p--) - { - if (p->level == level && - (p->type == MY_XML_NODE_TAG || - p->type == MY_XML_NODE_ATTR)) - { - return p - items; - } - } - return 0; + /* + If "str" doesn't have space for a new node, + it will allocate two times more space that it has had so far. + (2*len+512) is a heuristic value, + which gave the best performance during tests. + The ideas behind this formula are: + - It allows to have a very small number of reallocs: + about 10 reallocs on a 1Mb-long XML value. + - At the same time, it avoids excessive memory use. + */ + if (str->reserve(sizeof(MY_XML_NODE), 2 * str->length() + 512)) + return TRUE; + str->q_append((const char*) node, sizeof(MY_XML_NODE)); + return FALSE; } @@ -2661,19 +2653,17 @@ extern "C" int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len); int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len) { MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data; - MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE); - uint parent= xml_parent_tag(nodes, numnodes, data->level - 1); MY_XML_NODE node; + node.parent= data->parent; // Set parent for the new node to old parent + data->parent= numnodes; // Remember current node as new parent data->pos[data->level]= numnodes; node.level= data->level++; node.type= st->current_node_type; // TAG or ATTR node.beg= attr; node.end= attr + len; - node.parent= parent; - data->pxml->append((const char*) &node, sizeof(MY_XML_NODE)); - return MY_XML_OK; + return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK; } @@ -2694,18 +2684,14 @@ extern "C" int xml_value(MY_XML_PARSER *st,const char *attr, size_t len); int xml_value(MY_XML_PARSER *st,const char *attr, size_t len) { MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data; - MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); - uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE); - uint parent= xml_parent_tag(nodes, numnodes, data->level - 1); MY_XML_NODE node; + node.parent= data->parent; // Set parent for the new text node to old parent node.level= data->level; node.type= MY_XML_NODE_TEXT; node.beg= attr; node.end= attr + len; - node.parent= parent; - data->pxml->append((const char*) &node, sizeof(MY_XML_NODE)); - return MY_XML_OK; + return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK; } @@ -2730,6 +2716,7 @@ int xml_leave(MY_XML_PARSER *st,const char *attr, size_t len) data->level--; MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr(); + data->parent= nodes[data->parent].parent; nodes+= data->pos[data->level]; nodes->tagend= st->cur; @@ -2760,6 +2747,7 @@ String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf) p.flags= MY_XML_FLAG_RELATIVE_NAMES | MY_XML_FLAG_SKIP_TEXT_NORMALIZATION; user_data.level= 0; user_data.pxml= parsed_xml_buf; + user_data.parent= 0; my_xml_set_enter_handler(&p, xml_enter); my_xml_set_value_handler(&p, xml_value); my_xml_set_leave_handler(&p, xml_leave); From e8e20954e6dd610cb1400eb411195861e652f67e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 10 Oct 2007 18:10:54 +0200 Subject: [PATCH 28/43] BUG#29046: rpl_stm_mystery22 unstable Problem: rpl_stm_mystery22 is unstable. Reason: At one place, the test case *should* wait until the SQL thread on the slave receives an error, but instead it waits until the SQL thread stops. The SQL thread may stop before the error flag is set, so that when the test case continues to execute, the error flag is not set. Fix: Introduce the subroutine mysql-test/include/wait_for_slave_sql_error.inc, which waits until there is an error in the sql thread of the slave. Re-commit: fixed one logical error and two smaller things noted by Mats. mysql-test/suite/rpl/t/rpl_stm_mystery22.test: Use the new wait_for_slave_sql_error.inc instead of wait_for_slave_to_stop. There may be a delay from when the slave stops to when Last_SQL_Errno is set, so it is not safe to merely wait until the slave stops. mysql-test/include/wait_for_slave_sql_error.inc: New BitKeeper file ``mysql-test/include/wait_for_slave_sql_error.inc'' This is a subroutine that waits until the sql thread on the slave receives an error, as indicated by Last_SQL_Errno in "SHOW SLAVE STATUS". --- .../include/wait_for_slave_sql_error.inc | 33 +++++++++++++++++++ mysql-test/suite/rpl/t/rpl_stm_mystery22.test | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 mysql-test/include/wait_for_slave_sql_error.inc diff --git a/mysql-test/include/wait_for_slave_sql_error.inc b/mysql-test/include/wait_for_slave_sql_error.inc new file mode 100644 index 00000000000..6780edbe2f0 --- /dev/null +++ b/mysql-test/include/wait_for_slave_sql_error.inc @@ -0,0 +1,33 @@ +################################################### +#Author: Sven +#Date: 2007-10-09 +#Purpose: Wait until the slave has an error in the +# sql thread, as indicated by +# "SHOW SLAVE STATUS", or at most 30 +# seconds. +#Details: +# 1) Fill in and setup variables +# 2) loop, looking for sql error on slave +# 3) If it loops too long, die. +#################################################### +connection slave; +let $row_number= 1; +let $run= 1; +let $counter= 300; + +while ($run) +{ + let $sql_result= query_get_value("SHOW SLAVE STATUS", Last_SQL_Errno, $row_number); + let $run= `SELECT '$sql_result' = '0'`; + if ($run) { + real_sleep 0.1; + if (!$counter){ + --echo "Failed while waiting for slave to produce an error in its sql thread" + --replace_result $MASTER_MYPORT MASTER_PORT + --replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 # + query_vertical SHOW SLAVE STATUS; + exit; + } + dec $counter; + } +} diff --git a/mysql-test/suite/rpl/t/rpl_stm_mystery22.test b/mysql-test/suite/rpl/t/rpl_stm_mystery22.test index 017593fdfba..b43a734fffc 100644 --- a/mysql-test/suite/rpl/t/rpl_stm_mystery22.test +++ b/mysql-test/suite/rpl/t/rpl_stm_mystery22.test @@ -28,7 +28,7 @@ insert into t1 values(NULL,'new'); save_master_pos; connection slave; # wait until the slave tries to run the query, fails and aborts slave thread -wait_for_slave_to_stop; +source include/wait_for_slave_sql_error.inc; select * from t1 order by n; delete from t1 where n = 2; --disable_warnings From 06fb8c2d1009fe6d285fd29ab9080b2b040a3d60 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 Oct 2007 18:18:05 +0200 Subject: [PATCH 29/43] BUG#29549 (Endians: test failures on Solaris): Refactoring code to add parameter to pack() and unpack() functions with purpose of indicating if data should be packed in little-endian or native order. Using new functions to always pack data for binary log in little-endian order. The purpose of this refactoring is to allow proper implementation of endian-agnostic pack() and unpack() functions. Eliminating several versions of virtual pack() and unpack() functions in favor for one single virtual function which is overridden in subclasses. Implementing pack() and unpack() functions for some field types that packed data in native format regardless of the value of the st_table_share::db_low_byte_first flag. The field types that were packed in native format regardless are: Field_real, Field_decimal, Field_tiny, Field_short, Field_medium, Field_long, Field_longlong, and Field_blob. Before the patch, row-based logging wrote the rows incorrectly on big-endian machines where the storage engine defined its own low_byte_first() to be FALSE on big-endian machines (the default is TRUE), while little-endian machines wrote the fields in correct order. The only known storage engine that does this is NDB. In effect, this means that row-based replication from or to a big-endian machine where the table was using NDB as storage engine failed if the other engine was either non-NDB or on a little-endian machine. With this patch, row-based logging is now always done in little-endian order, while ORDER BY uses the native order if the storage engine defines low_byte_first() to return FALSE for big-endian machines. In addition, the max_data_length() function available in Field_blob was generalized to the entire Field hierarchy to give the maximum number of bytes that Field::pack() will write. mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test: Sorting by columns that produces deterministic order. mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result: Result change. mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result: Result change. mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result: Result change. mysql-test/suite/rpl/t/disabled.def: Enabling tests. mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test: Adding missing sync_slave_with_master causing slave to keep tables after shutdown. mysql-test/suite/rpl_ndb/t/disabled.def: Enabling tests. mysql-test/suite/rpl_ndb/t/rpl_ndb_innodb2ndb-slave.opt: Adding --new option mysql-test/suite/rpl_ndb/t/rpl_ndb_innodb2ndb.test: Adding have_log_bin. mysql-test/suite/rpl_ndb/t/rpl_ndb_myisam2ndb-slave.opt: Adding --new option mysql-test/suite/rpl_ndb/t/rpl_ndb_myisam2ndb.test: Adding have_log_bin mysql-test/t/partition.test: Adding have_archive, since that is used in the test. sql/field.cc: Eliminating all two-argument pack() and unpack() functions and moving functionality into the four-argument version. The four argument version is introduced so that it is possible to avoid using the storage engine default when writing and reading the packed format (the unpacked format still uses the storage engine's default). This is used by row-based replication to write the fields in a storage engine- and endian-agnostic format. Packing integral and floating-point numbers in little-endian format (if requested). Using pad_char for the field instead of spaces (0x20) when unpacking. Adding some Doxygen documentation. --- Adding max_data_length() to denote the maximum number of bytes that pack() will write. Adding casts to remove warnings for debug printouts. sql/field.h: Eliminating all virtual pack() and unpack() functions except the four- argument version, which now is the function that shall be overridden. The two-argument versions are convenience functions, to prevent changes to code that uses these. Adding code to pack integer numbers and floating-point numbers in little-endian format, if requested. --- Adding max_data_length() to denote the maximum number of bytes that pack() will write. sql/log.cc: Removing debug printout causing crash when starting NDB on Solaris. sql/log_event.cc: Adding missing #ifndef causing compile failure. Adding debug printouts. sql/rpl_record.cc: Debriding code. Using new pack() and unpack() functions to always pack fields little-endian. Adding debug printouts. --- Using max_data_length() when packing field into row. Adding casts to debug printouts. sql/sql_show.cc: Adding code that causes crash on Solaris machines since printf() cannot handle NULL values for strings properly. mysql-test/suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result: New BitKeeper file ``mysql-test/suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result'' mysql-test/suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result: New BitKeeper file ``mysql-test/suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result'' --- .../extra/rpl_tests/rpl_extraMaster_Col.test | 2 +- .../rpl/r/rpl_extraColmaster_innodb.result | Bin 38226 -> 38226 bytes .../rpl/r/rpl_extraColmaster_myisam.result | Bin 38226 -> 38226 bytes .../rpl/r/rpl_row_extraColmaster_ndb.result | Bin 19129 -> 19129 bytes mysql-test/suite/rpl/t/disabled.def | 1 - .../suite/rpl/t/rpl_row_mysqlbinlog.test | 1 + .../suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result | 855 ++++++++++++++++++ .../suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result | 855 ++++++++++++++++++ mysql-test/suite/rpl_ndb/t/disabled.def | 2 - .../rpl_ndb/t/rpl_ndb_innodb2ndb-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_innodb2ndb.test | 10 +- .../rpl_ndb/t/rpl_ndb_myisam2ndb-slave.opt | 2 +- .../suite/rpl_ndb/t/rpl_ndb_myisam2ndb.test | 7 +- mysql-test/t/partition.test | 3 +- sql/field.cc | 407 ++++++--- sql/field.h | 271 +++++- sql/log.cc | 3 - sql/log_event.cc | 4 + sql/rpl_record.cc | 54 +- sql/sql_show.cc | 6 +- 20 files changed, 2251 insertions(+), 234 deletions(-) create mode 100644 mysql-test/suite/rpl_ndb/r/rpl_ndb_innodb2ndb.result create mode 100644 mysql-test/suite/rpl_ndb/r/rpl_ndb_myisam2ndb.result diff --git a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test index 26b1e6d5ba0..a03aa337c2b 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraMaster_Col.test @@ -466,7 +466,7 @@ binary data'; select * from t2 order by f1; select * from t3 order by f1; select * from t4 order by f1; - select * from t31 order by f1; + select * from t31 order by f3; connection master; diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_innodb.result index 189066179255c33b7d56e0fdfd8a3893dda3535c..ef6e2a6de25a11ce8c9b48e9bd4a0ab8e0380089 100644 GIT binary patch delta 27 dcmcb#is{lSrVXZUlVyXYHwU=6c|jQqSpb}X3M&8r delta 27 ecmcb#is{lSrVXZUlW+A)Zw_#C^MW!KvH$?ISqvQj diff --git a/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result b/mysql-test/suite/rpl/r/rpl_extraColmaster_myisam.result index 5bc1a13b1078a054d99dfef348ad74e85295e302..475ea4cdcbaab56b53f74844b68bcae4aaa0d753 100644 GIT binary patch delta 27 dcmcb#is{lSrVXZUlVyXYHwU=6c|jQqSpb}X3M&8r delta 27 ecmcb#is{lSrVXZUlW+A)Zw_#C^MW!KvH$?ISqvQj diff --git a/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result b/mysql-test/suite/rpl/r/rpl_row_extraColmaster_ndb.result index 0b1f2e6c8bf9514ef53ef326dde109d3a78bdea8..fb83c5088e502338e8db678565120f65b47dcba1 100644 GIT binary patch delta 82 zcmdlvm2u}(#tna6C;ySTNkkg2>I5jyxFNF)lG3G4E$Si`eO*qr?ON&Y} Xz!IjMX_;wIwi#z}X2s@Uw=@<2Nf{Ui delta 86 zcmdlvm2u}(#tna6Cm(Yab~fcq%Slow_byte_first is dependent on how the + packed data is going to be used: for local use, e.g., temporary + store on disk or in memory, use the native format since that is + faster. For data that is going to be transfered to other machines + (e.g., when writing data to the binary log), data should always be + stored in little-endian format. + + @note The default method for packing fields just copy the raw bytes + of the record into the destination, but never more than + max_length characters. + + @param to + Pointer to memory area where representation of field should be put. + + @param from + Pointer to memory area where record representation of field is + stored. + + @param max_length + Maximum length of the field, as given in the column definition. For + example, for CHAR(1000), the max_length + is 1000. This information is sometimes needed to decide how to pack + the data. + + @param low_byte_first + @c TRUE if integers should be stored little-endian, @c FALSE if + native format should be used. Note that for little-endian machines, + the value of this flag is a moot point since the native format is + little-endian. +*/ +uchar * +Field::pack(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) +{ + uint32 length= pack_length(); + set_if_smaller(length, max_length); + memcpy(to, from, length); + return to+length; +} + /** Unpack a field from row data. - This method is used to unpack a field from a master whose size - of the field is less than that of the slave. - + This method is used to unpack a field from a master whose size of + the field is less than that of the slave. + + The param_data parameter is a two-byte integer (stored + in the least significant 16 bits of the unsigned integer) usually + consisting of two parts: the real type in the most significant byte + and a original pack length in the least significant byte. + + The exact layout of the param_data field is given by + the Table_map_log_event::save_field_metadata(). + + This is the default method for unpacking a field. It just copies + the memory block in byte order (of original pack length bytes or + length of field, whichever is smaller). + @param to Destination of the data @param from Source of the data - @param param_data Pack length of the field data + @param param_data Real type and original pack length of the field + data + + @param low_byte_first + If this flag is @c true, all composite entities (e.g., lengths) + should be unpacked in little-endian format; otherwise, the entities + are unpacked in native order. @return New pointer into memory based on from + length of the data */ -const uchar *Field::unpack(uchar* to, - const uchar *from, - uint param_data) +const uchar * +Field::unpack(uchar* to, const uchar *from, uint param_data, + bool low_byte_first __attribute__((unused))) { uint length=pack_length(); int from_type= 0; @@ -1399,19 +1464,18 @@ const uchar *Field::unpack(uchar* to, from_type= (param_data & 0xff00) >> 8U; // real_type. param_data= param_data & 0x00ff; // length. } + + if ((param_data == 0) || + (length == param_data) || + (from_type != real_type())) + { + memcpy(to, from, length); + return from+length; + } + uint len= (param_data && (param_data < length)) ? param_data : length; - /* - If the length is the same, use old unpack method. - If the param_data is 0, use the old unpack method. - This is possible if the table map was generated from a down-level - master or if the data was not available on the master. - If the real_types are not the same, use the old unpack method. - */ - if ((length == param_data) || - (param_data == 0) || - (from_type != real_type())) - return(unpack(to, from)); + memcpy(to, from, param_data > length ? length : len); return from+len; } @@ -2714,10 +2778,15 @@ uint Field_new_decimal::is_equal(Create_field *new_field) @return New pointer into memory based on from + length of the data */ -const uchar *Field_new_decimal::unpack(uchar* to, - const uchar *from, - uint param_data) +const uchar * +Field_new_decimal::unpack(uchar* to, + const uchar *from, + uint param_data, + bool low_byte_first) { + if (param_data == 0) + return Field::unpack(to, from, param_data, low_byte_first); + uint from_precision= (param_data & 0xff00) >> 8U; uint from_decimal= param_data & 0x00ff; uint length=pack_length(); @@ -3857,6 +3926,49 @@ void Field_longlong::sql_type(String &res) const } +/* + Floating-point numbers + */ + +uchar * +Field_real::pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first) +{ + DBUG_ENTER("Field_real::pack"); + DBUG_ASSERT(max_length >= pack_length()); + DBUG_PRINT("debug", ("pack_length(): %u", pack_length())); +#ifdef WORDS_BIGENDIAN + if (low_byte_first != table->s->db_low_byte_first) + { + const uchar *dptr= from + pack_length(); + while (dptr-- > from) + *to++ = *dptr; + DBUG_RETURN(to); + } + else +#endif + DBUG_RETURN(Field::pack(to, from, max_length, low_byte_first)); +} + +const uchar * +Field_real::unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first) +{ + DBUG_ENTER("Field_real::unpack"); + DBUG_PRINT("debug", ("pack_length(): %u", pack_length())); +#ifdef WORDS_BIGENDIAN + if (low_byte_first != table->s->db_low_byte_first) + { + const uchar *dptr= from + pack_length(); + while (dptr-- > from) + *to++ = *dptr; + DBUG_RETURN(from + pack_length()); + } + else +#endif + DBUG_RETURN(Field::unpack(to, from, param_data, low_byte_first)); +} + /**************************************************************************** single precision float ****************************************************************************/ @@ -6211,6 +6323,11 @@ int Field_longstr::store_decimal(const my_decimal *d) return store(str.ptr(), str.length(), str.charset()); } +uint32 Field_longstr::max_data_length() const +{ + return field_length + (field_length > 255 ? 2 : 1); +} + double Field_string::val_real(void) { @@ -6355,7 +6472,9 @@ void Field_string::sql_type(String &res) const } -uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_string::pack(uchar *to, const uchar *from, + uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= min(field_length,max_length); uint local_char_length= max_length/field_charset->mbmaxlen; @@ -6363,11 +6482,15 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) local_char_length= my_charpos(field_charset, from, from+length, local_char_length); set_if_smaller(length, local_char_length); - while (length && from[length-1] == ' ') + while (length && from[length-1] == field_charset->pad_char) length--; + + // Length always stored little-endian *to++= (uchar) length; if (field_length > 255) *to++= (uchar) (length >> 8); + + // Store the actual bytes of the string memcpy(to, from, length); return to+length; } @@ -6389,34 +6512,27 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length) @return New pointer into memory based on from + length of the data */ -const uchar *Field_string::unpack(uchar *to, - const uchar *from, - uint param_data) -{ - uint from_len= param_data & 0x00ff; // length. - uint length= 0; - uint f_length; - f_length= (from_len < field_length) ? from_len : field_length; - DBUG_ASSERT(f_length <= 255); - length= (uint) *from++; - bitmap_set_bit(table->write_set,field_index); - store((const char *)from, length, system_charset_info); - return from+length; -} - - -const uchar *Field_string::unpack(uchar *to, const uchar *from) +const uchar * +Field_string::unpack(uchar *to, + const uchar *from, + uint param_data, + bool low_byte_first __attribute__((unused))) { + uint from_length= + param_data ? min(param_data & 0x00ff, field_length) : field_length; uint length; - if (field_length > 255) + + if (from_length > 255) { length= uint2korr(from); from+= 2; } else length= (uint) *from++; - memcpy(to, from, (int) length); - bfill(to+length, field_length - length, ' '); + + memcpy(to, from, length); + // Pad the string with the pad character of the fields charset + bfill(to + length, field_length - length, field_charset->pad_char); return from+length; } @@ -6796,22 +6912,30 @@ uint32 Field_varstring::data_length() Here the number of length bytes are depending on the given max_length */ -uchar *Field_varstring::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_varstring::pack(uchar *to, const uchar *from, + uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= length_bytes == 1 ? (uint) *from : uint2korr(from); set_if_smaller(max_length, field_length); if (length > max_length) length=max_length; - *to++= (char) (length & 255); + + /* Length always stored little-endian */ + *to++= length & 0xFF; if (max_length > 255) - *to++= (char) (length >> 8); - if (length) + *to++= (length >> 8) & 0xFF; + + /* Store bytes of string */ + if (length > 0) memcpy(to, from+length_bytes, length); return to+length; } -uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) +uchar * +Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length, + bool low_byte_first __attribute__((unused))) { uint length= length_bytes == 1 ? (uint) *key : uint2korr(key); uint local_char_length= ((field_charset->mbmaxlen > 1) ? @@ -6850,8 +6974,9 @@ uchar *Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length) Pointer to end of 'key' (To the next key part if multi-segment key) */ -const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key, - uint max_length) +const uchar * +Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length, + bool low_byte_first __attribute__((unused))) { /* get length of the blob key */ uint32 length= *key++; @@ -6880,8 +7005,9 @@ const uchar *Field_varstring::unpack_key(uchar *to, const uchar *key, end of key storage */ -uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, - uint max_length) +uchar * +Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { /* Key length is always stored as 2 bytes */ uint length= uint2korr(from); @@ -6901,6 +7027,9 @@ uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, This method is used to unpack a varstring field from a master whose size of the field is less than that of the slave. + + @note + The string length is always packed little-endian. @param to Destination of the data @param from Source of the data @@ -6908,9 +7037,10 @@ uchar *Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from, @return New pointer into memory based on from + length of the data */ -const uchar *Field_varstring::unpack(uchar *to, - const uchar *from, - uint param_data) +const uchar * +Field_varstring::unpack(uchar *to, const uchar *from, + uint param_data, + bool low_byte_first __attribute__((unused))) { uint length; uint l_bytes= (param_data && (param_data < field_length)) ? @@ -6922,28 +7052,7 @@ const uchar *Field_varstring::unpack(uchar *to, if (length_bytes == 2) to[1]= 0; } - else - { - length= uint2korr(from); - to[0]= *from++; - to[1]= *from++; - } - if (length) - memcpy(to+ length_bytes, from, length); - return from+length; -} - - -/* - unpack field packed with Field_varstring::pack() -*/ - -const uchar *Field_varstring::unpack(uchar *to, const uchar *from) -{ - uint length; - if (length_bytes == 1) - length= (uint) (*to= *from++); - else + else /* l_bytes == 2 */ { length= uint2korr(from); to[0]= *from++; @@ -7192,9 +7301,9 @@ void Field_blob::store_length(uchar *i_ptr, } -uint32 Field_blob::get_length(const uchar *pos, bool low_byte_first) +uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg, bool low_byte_first) { - switch (packlength) { + switch (packlength_arg) { case 1: return (uint32) pos[0]; case 2: @@ -7608,28 +7717,37 @@ void Field_blob::sql_type(String &res) const } } - -uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) +uchar *Field_blob::pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first) { + DBUG_ENTER("Field_blob::pack"); + DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;" + " max_length: %u; low_byte_first: %d", + (ulong) to, (ulong) from, + max_length, low_byte_first)); + DBUG_DUMP("record", from, table->s->reclength); uchar *save= ptr; ptr= (uchar*) from; uint32 length=get_length(); // Length of from string - if (length > max_length) - { - ptr=to; - length=max_length; - store_length(length); // Store max length - ptr= (uchar*) from; - } - else - memcpy(to,from,packlength); // Copy length - if (length) + + /* + Store max length, which will occupy packlength bytes. If the max + length given is smaller than the actual length of the blob, we + just store the initial bytes of the blob. + */ + store_length(to, packlength, min(length, max_length), low_byte_first); + + /* + Store the actual blob data, which will occupy 'length' bytes. + */ + if (length > 0) { get_ptr((uchar**) &from); memcpy(to+packlength, from,length); } ptr=save; // Restore org row pointer - return to+packlength+length; + DBUG_DUMP("packed", to, packlength + length); + DBUG_RETURN(to+packlength+length); } @@ -7644,28 +7762,26 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length) @param to Destination of the data @param from Source of the data - @param param_data @return New pointer into memory based on from + length of the data */ const uchar *Field_blob::unpack(uchar *to, const uchar *from, - uint param_data) + uint param_data, + bool low_byte_first) { - return unpack(to, from); -} - - -const uchar *Field_blob::unpack(uchar *to, const uchar *from) -{ - memcpy(to,from,packlength); - uint32 length=get_length(from); - from+=packlength; - if (length) - memcpy_fixed(to+packlength, &from, sizeof(from)); - else - bzero(to+packlength,sizeof(from)); - return from+length; + DBUG_ENTER("Field_blob::unpack"); + DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx;" + " param_data: %u; low_byte_first: %d", + (ulong) to, (ulong) from, param_data, low_byte_first)); + uint const master_packlength= + param_data > 0 ? param_data & 0xFF : packlength; + uint32 const length= get_length(from, master_packlength, low_byte_first); + DBUG_DUMP("packed", from, length + master_packlength); + store(reinterpret_cast(from) + master_packlength, + length, field_charset); + DBUG_DUMP("record", to, table->s->reclength); + DBUG_RETURN(from + master_packlength + length); } /* Keys for blobs are like keys on varchars */ @@ -7715,7 +7831,9 @@ int Field_blob::pack_cmp(const uchar *b, uint key_length_arg, /* Create a packed key that will be used for storage from a MySQL row */ -uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) +uchar * +Field_blob::pack_key(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { uchar *save= ptr; ptr= (uchar*) from; @@ -7760,8 +7878,9 @@ uchar *Field_blob::pack_key(uchar *to, const uchar *from, uint max_length) Pointer into 'from' past the last byte copied from packed key. */ -const uchar *Field_blob::unpack_key(uchar *to, const uchar *from, - uint max_length) +const uchar * +Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { /* get length of the blob key */ uint32 length= *from++; @@ -7784,8 +7903,9 @@ const uchar *Field_blob::unpack_key(uchar *to, const uchar *from, /* Create a packed key that will be used for storage from a MySQL key */ -uchar *Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, - uint max_length) +uchar * +Field_blob::pack_key_from_key_image(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { uint length=uint2korr(from); if (length > max_length) @@ -8672,9 +8792,11 @@ void Field_bit::sql_type(String &res) const } -uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length) +uchar * +Field_bit::pack(uchar *to, const uchar *from, uint max_length, + bool low_byte_first __attribute__((unused))) { - DBUG_ASSERT(max_length); + DBUG_ASSERT(max_length > 0); uint length; if (bit_len > 0) { @@ -8709,28 +8831,44 @@ uchar *Field_bit::pack(uchar *to, const uchar *from, uint max_length) /** Unpack a bit field from row data. - This method is used to unpack a bit field from a master whose size + This method is used to unpack a bit field from a master whose size of the field is less than that of the slave. - + @param to Destination of the data @param from Source of the data @param param_data Bit length (upper) and length (lower) values @return New pointer into memory based on from + length of the data */ -const uchar *Field_bit::unpack(uchar *to, - const uchar *from, - uint param_data) +const uchar * +Field_bit::unpack(uchar *to, const uchar *from, uint param_data, + bool low_byte_first __attribute__((unused))) { uint const from_len= (param_data >> 8U) & 0x00ff; uint const from_bit_len= param_data & 0x00ff; /* - If the master and slave have the same sizes, then use the old - unpack() method. + If the parameter data is zero (i.e., undefined), or if the master + and slave have the same sizes, then use the old unpack() method. */ - if ((from_bit_len == bit_len) && - (from_len == bytes_in_rec)) - return(unpack(to, from)); + if (param_data == 0 || + (from_bit_len == bit_len) && (from_len == bytes_in_rec)) + { + if (bit_len > 0) + { + /* + set_rec_bits is a macro, don't put the post-increment in the + argument since that might cause strange side-effects. + + For the choice of the second argument, see the explanation for + Field_bit::pack(). + */ + set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len); + from++; + } + memcpy(to, from, bytes_in_rec); + return from + bytes_in_rec; + } + /* We are converting a smaller bit field to a larger one here. To do that, we first need to construct a raw value for the original @@ -8758,25 +8896,6 @@ const uchar *Field_bit::unpack(uchar *to, } -const uchar *Field_bit::unpack(uchar *to, const uchar *from) -{ - if (bit_len > 0) - { - /* - set_rec_bits is a macro, don't put the post-increment in the - argument since that might cause strange side-effects. - - For the choice of the second argument, see the explanation for - Field_bit::pack(). - */ - set_rec_bits(*from, bit_ptr + (to - ptr), bit_ofs, bit_len); - from++; - } - memcpy(to, from, bytes_in_rec); - return from + bytes_in_rec; -} - - void Field_bit::set_default() { if (bit_len > 0) diff --git a/sql/field.h b/sql/field.h index 60f6fc19d76..37a0cdae070 100644 --- a/sql/field.h +++ b/sql/field.h @@ -157,6 +157,17 @@ public: */ virtual uint32 data_length() { return pack_length(); } virtual uint32 sort_length() const { return pack_length(); } + + /** + Get the maximum size of the data in packed format. + + @return Maximum data length of the field when packed using the + Field::pack() function. + */ + virtual uint32 max_data_length() const { + return pack_length(); + }; + virtual int reset(void) { bzero(ptr,pack_length()); return 0; } virtual void reset_fields() {} virtual void set_default() @@ -339,32 +350,45 @@ public: return str; } virtual bool send_binary(Protocol *protocol); - virtual uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0) + + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + /** + @overload Field::pack(uchar*, const uchar*, uint, bool) + */ + uchar *pack(uchar *to, const uchar *from) { - uint32 length=pack_length(); - memcpy(to,from,length); - return to+length; + DBUG_ENTER("Field::pack"); + uchar *result= this->pack(to, from, UINT_MAX, table->s->db_low_byte_first); + DBUG_RETURN(result); } - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - virtual const uchar *unpack(uchar* to, const uchar *from) + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + /** + @overload Field::unpack(uchar*, const uchar*, uint, bool) + */ + const uchar *unpack(uchar* to, const uchar *from) { - uint length=pack_length(); - memcpy(to,from,length); - return from+length; + DBUG_ENTER("Field::unpack"); + const uchar *result= unpack(to, from, 0U, table->s->db_low_byte_first); + DBUG_RETURN(result); } - virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length) + + virtual uchar *pack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) { - return pack(to,from,max_length); + return pack(to, from, max_length, low_byte_first); } virtual uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length) + uint max_length, bool low_byte_first) { - return pack(to,from,max_length); + return pack(to, from, max_length, low_byte_first); } virtual const uchar *unpack_key(uchar* to, const uchar *from, - uint max_length) + uint max_length, bool low_byte_first) { - return unpack(to,from); + return unpack(to, from, max_length, low_byte_first); } virtual uint packed_col_length(const uchar *to, uint length) { return length;} @@ -536,6 +560,7 @@ public: {} int store_decimal(const my_decimal *d); + uint32 max_data_length() const; }; /* base class for float and double and decimal (old one) */ @@ -556,6 +581,10 @@ public: int truncate(double *nr, double max_length); uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); }; @@ -584,6 +613,16 @@ public: void overflow(bool negative); bool zero_pack() const { return 0; } void sql_type(String &str) const; + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + return Field::unpack(to, from, param_data, low_byte_first); + } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + return Field::pack(to, from, max_length, low_byte_first); + } }; @@ -629,7 +668,8 @@ public: uint size_of() const { return sizeof(*this); } uint32 pack_length() const { return (uint32) bin_size; } uint is_equal(Create_field *new_field); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); }; @@ -660,6 +700,20 @@ public: uint32 pack_length() const { return 1; } void sql_type(String &str) const; uint32 max_display_length() { return 4; } + + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + *to= *from; + return to + 1; + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + *to= *from; + return from + 1; + } }; @@ -695,8 +749,47 @@ public: uint32 pack_length() const { return 2; } void sql_type(String &str) const; uint32 max_display_length() { return 6; } -}; + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int16 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint2korr(from); + else +#endif + shortget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int2store(to, val); + else +#endif + shortstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int16 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint2korr(from); + else +#endif + shortget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int2store(to, val); + else +#endif + shortstore(to, val); + return from + sizeof(val); + } +}; class Field_medium :public Field_num { public: @@ -725,6 +818,18 @@ public: uint32 pack_length() const { return 3; } void sql_type(String &str) const; uint32 max_display_length() { return 8; } + + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + return Field::pack(to, from, max_length, low_byte_first); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + return Field::unpack(to, from, param_data, low_byte_first); + } }; @@ -760,6 +865,45 @@ public: uint32 pack_length() const { return 4; } void sql_type(String &str) const; uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int32 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint4korr(from); + else +#endif + longget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int4store(to, val); + else +#endif + longstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int32 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint4korr(from); + else +#endif + longget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int4store(to, val); + else +#endif + longstore(to, val); + return from + sizeof(val); + } }; @@ -802,6 +946,45 @@ public: void sql_type(String &str) const; bool can_be_compared_as_longlong() const { return TRUE; } uint32 max_display_length() { return 20; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length, bool low_byte_first) + { + int64 val; +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + val = sint8korr(from); + else +#endif + longlongget(val, from); + +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + int8store(to, val); + else +#endif + longlongstore(to, val); + return to + sizeof(val); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first) + { + int64 val; +#ifdef WORDS_BIGENDIAN + if (low_byte_first) + val = sint8korr(from); + else +#endif + longlongget(val, from); + +#ifdef WORDS_BIGENDIAN + if (table->s->db_low_byte_first) + int8store(to, val); + else +#endif + longlongstore(to, val); + return from + sizeof(val); + } }; #endif @@ -1176,9 +1359,10 @@ public: int cmp(const uchar *,const uchar *); void sort_string(uchar *buff,uint length); void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); int pack_cmp(const uchar *a,const uchar *b,uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b,uint key_length,my_bool insert_or_update); @@ -1250,13 +1434,15 @@ public: uint get_key_image(uchar *buff,uint length, imagetype type); void set_key_image(const uchar *buff,uint length); void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - uchar *pack_key(uchar *to, const uchar *from, uint max_length); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + uchar *pack_key(uchar *to, const uchar *from, uint max_length, bool low_byte_first); uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length); - virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); - const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar* to, const uchar *from, + uint param_data, bool low_byte_first); + const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); int pack_cmp(const uchar *a, const uchar *b, uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); @@ -1346,7 +1532,7 @@ public: uint32 pack_length_no_ptr() const { return (uint32) (packlength); } uint32 sort_length() const; - inline uint32 max_data_length() const + virtual uint32 max_data_length() const { return (uint32) (((ulonglong) 1 << (packlength*8)) -1); } @@ -1374,13 +1560,13 @@ public: @retval The length in the row plus the size of the data. */ uint32 get_packed_size(const uchar *ptr_arg, bool low_byte_first) - {return packlength + get_length(ptr_arg, low_byte_first);} + {return packlength + get_length(ptr_arg, packlength, low_byte_first);} inline uint32 get_length(uint row_offset= 0) - { return get_length(ptr+row_offset, table->s->db_low_byte_first); } - uint32 get_length(const uchar *ptr, bool low_byte_first); + { return get_length(ptr+row_offset, this->packlength, table->s->db_low_byte_first); } + uint32 get_length(const uchar *ptr, uint packlength, bool low_byte_first); uint32 get_length(const uchar *ptr_arg) - { return get_length(ptr_arg, table->s->db_low_byte_first); } + { return get_length(ptr_arg, this->packlength, table->s->db_low_byte_first); } void put_length(uchar *pos, uint32 length); inline void get_ptr(uchar **str) { @@ -1421,13 +1607,16 @@ public: memcpy_fixed(ptr+packlength,&tmp,sizeof(char*)); return 0; } - uchar *pack(uchar *to, const uchar *from, uint max_length= ~(uint) 0); - uchar *pack_key(uchar *to, const uchar *from, uint max_length); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + uchar *pack_key(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); uchar *pack_key_from_key_image(uchar* to, const uchar *from, - uint max_length); - virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); - const uchar *unpack(uchar *to, const uchar *from); - const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first); + const uchar *unpack_key(uchar* to, const uchar *from, + uint max_length, bool low_byte_first); int pack_cmp(const uchar *a, const uchar *b, uint key_length, my_bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,my_bool insert_or_update); @@ -1572,6 +1761,7 @@ public: enum_field_types type() const { return MYSQL_TYPE_BIT; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } uint32 key_length() const { return (uint32) (field_length + 7) / 8; } + uint32 max_data_length() const { return (field_length + 7) / 8; } uint32 max_display_length() { return field_length; } uint size_of() const { return sizeof(*this); } Item_result result_type () const { return INT_RESULT; } @@ -1602,9 +1792,10 @@ public: uint32 pack_length() const { return (uint32) (field_length + 7) / 8; } uint32 pack_length_in_rec() const { return bytes_in_rec; } void sql_type(String &str) const; - uchar *pack(uchar *to, const uchar *from, uint max_length=~(uint) 0); - virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); - const uchar *unpack(uchar* to, const uchar *from); + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length, bool low_byte_first); + virtual const uchar *unpack(uchar *to, const uchar *from, + uint param_data, bool low_byte_first); virtual void set_default(); Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, diff --git a/sql/log.cc b/sql/log.cc index dcf27161f1a..4d1ef9eed9f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3571,9 +3571,6 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) (!binlog_filter->db_ok(local_db))) { VOID(pthread_mutex_unlock(&LOCK_log)); - DBUG_PRINT("info",("OPTION_BIN_LOG is %s, db_ok('%s') == %d", - (thd->options & OPTION_BIN_LOG) ? "set" : "clear", - local_db, binlog_filter->db_ok(local_db))); DBUG_RETURN(0); } #endif /* HAVE_REPLICATION */ diff --git a/sql/log_event.cc b/sql/log_event.cc index cfac7df21a8..cf4bb229b2f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5697,7 +5697,9 @@ Rows_log_event::Rows_log_event(const char *buf, uint event_len, *description_event) : Log_event(buf, description_event), m_row_count(0), +#ifndef MYSQL_CLIENT m_table(NULL), +#endif m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_curr_row(NULL), m_curr_row_end(NULL), m_key(NULL) @@ -6168,6 +6170,8 @@ int Rows_log_event::do_apply_event(RELAY_LOG_INFO const *rli) unpack_current_row(rli); // at this moment m_curr_row_end should be set + DBUG_PRINT("debug", ("m_curr_row_end: 0x%lx; m_curr_row: 0x%lx; m_rows_end: 0x%lx", + m_curr_row_end, m_curr_row, m_rows_end)); DBUG_ASSERT(error || m_curr_row_end != NULL); DBUG_ASSERT(error || m_curr_row < m_curr_row_end); DBUG_ASSERT(error || m_curr_row_end <= m_rows_end); diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index de4f6e0c337..dbfe7902ee9 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -65,6 +65,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, my_ptrdiff_t const rec_offset= record - table->record[0]; my_ptrdiff_t const def_offset= table->s->default_values - table->record[0]; + DBUG_ENTER("pack_row"); + /* We write the null bits and the packed records using one pass through all the fields. The null bytes are written little-endian, @@ -96,26 +98,14 @@ pack_row(TABLE *table, MY_BITMAP const* cols, For big-endian machines, we have to make sure that the length is stored in little-endian format, since this is the format used for the binlog. - - We do this by setting the db_low_byte_first, which is used - inside some store_length() to decide what order to write the - bytes in. - - In reality, db_log_byte_first is only set for legacy table - type Isam, but in the event of a bug, we need to guarantee - the endianess when writing to the binlog. - - This is currently broken for NDB due to BUG#29549, so we - will fix it when NDB has fixed their way of handling BLOBs. */ -#if 0 - bool save= table->s->db_low_byte_first; - table->s->db_low_byte_first= TRUE; -#endif - pack_ptr= field->pack(pack_ptr, field->ptr + offset); -#if 0 - table->s->db_low_byte_first= save; -#endif + const uchar *old_pack_ptr= pack_ptr; + pack_ptr= field->pack(pack_ptr, field->ptr + offset, + field->max_data_length(), TRUE); + DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" + " pack_ptr':0x%lx; bytes: %d", + field->field_name, (ulong) old_pack_ptr, + (ulong) pack_ptr, pack_ptr - old_pack_ptr)); } null_mask <<= 1; @@ -143,8 +133,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, packed data. If it doesn't, something is very wrong. */ DBUG_ASSERT(null_ptr == row_data + null_byte_count); - - return static_cast(pack_ptr - row_data); + DBUG_DUMP("row_data", row_data, pack_ptr - row_data); + DBUG_RETURN(static_cast(pack_ptr - row_data)); } #endif @@ -242,18 +232,14 @@ unpack_row(RELAY_LOG_INFO const *rli, Use the master's size information if available else call normal unpack operation. */ -#if 0 - bool save= table->s->db_low_byte_first; - table->s->db_low_byte_first= TRUE; -#endif uint16 const metadata= tabledef->field_metadata(i); - if (tabledef && metadata) - pack_ptr= f->unpack(f->ptr, pack_ptr, metadata); - else - pack_ptr= f->unpack(f->ptr, pack_ptr); -#if 0 - table->s->db_low_byte_first= save; -#endif + uchar const *const old_pack_ptr= pack_ptr; + pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE); + DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" + " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", + f->field_name, metadata, + (ulong) old_pack_ptr, (ulong) pack_ptr, + pack_ptr - old_pack_ptr)); } null_mask <<= 1; @@ -265,6 +251,7 @@ unpack_row(RELAY_LOG_INFO const *rli, throw away master's extra fields */ uint max_cols= min(tabledef->size(), cols->n_bits); + DBUG_PRINT("debug", ("Master has %u fields, slave %u", tabledef->size(), cols->n_bits)); for (; i < max_cols; i++) { if (bitmap_is_set(cols, i)) @@ -279,6 +266,7 @@ unpack_row(RELAY_LOG_INFO const *rli, if (!((null_bits & null_mask) && tabledef->maybe_null(i))) pack_ptr+= tabledef->calc_field_size(i, (uchar *) pack_ptr); + DBUG_PRINT("debug", ("pack_ptr: 0x%lx", (ulong) pack_ptr)); null_mask <<= 1; } } @@ -289,6 +277,8 @@ unpack_row(RELAY_LOG_INFO const *rli, */ DBUG_ASSERT(null_ptr == row_data + master_null_byte_count); + DBUG_DUMP("row_data", row_data, pack_ptr - row_data); + *row_end = pack_ptr; if (master_reclength) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bb4f5107df8..49910e75286 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -29,6 +29,8 @@ #include "event_data_objects.h" #include +#define STR_OR_NIL(S) ((S) ? (S) : "") + #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" #endif @@ -3096,8 +3098,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) schema_table_idx= get_schema_table_idx(schema_table); get_lookup_field_values(thd, cond, tables, &lookup_field_vals); DBUG_PRINT("INDEX VALUES",("db_name='%s', table_name='%s'", - lookup_field_vals.db_value.str, - lookup_field_vals.table_value.str)); + STR_OR_NIL(lookup_field_vals.db_value.str), + STR_OR_NIL(lookup_field_vals.table_value.str))); if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value) { From b3b01cf48b6ab3139ee782ac91cf804a3efb7f2a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 12 Oct 2007 18:22:31 +0200 Subject: [PATCH 30/43] BUG#29549 (Endians: rpl_ndb_myisam2ndb,rpl_ndb_innodb2ndb and rpl_ndb_mix_innodb failed on): Post-merge fixes. Setting write bit before calling Field::store() since the function asserts that the write bit has been set. sql/field.cc: Setting bit in write set to prevent assertion from throwing when calling Field::store(). --- sql/field.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/field.cc b/sql/field.cc index a872beab726..29a4fcc1947 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7962,6 +7962,7 @@ const uchar *Field_blob::unpack(uchar *to, param_data > 0 ? param_data & 0xFF : packlength; uint32 const length= get_length(from, master_packlength, low_byte_first); DBUG_DUMP("packed", from, length + master_packlength); + bitmap_set_bit(table->write_set, field_index); store(reinterpret_cast(from) + master_packlength, length, field_charset); DBUG_DUMP("record", to, table->s->reclength); From c8b6d1050933f0b9b18367c421702c9f16907de5 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 Oct 2007 15:49:42 +0300 Subject: [PATCH 31/43] Bug #29136 erred multi-delete on trans table does not rollback the statement similar to bug_27716, but it was stressed on in the synopsis on that there is another side of the artifact affecting behaviour in transaction. Fixed with deploying multi_delete::send_error() - otherwise never called - and refining its logic to perform binlogging job if needed. The changeset includes the following side effects: - added tests to check bug_23333's scenarios on the mixture of tables for multi_update; - fixes bug@30763 with two-liner patch and a test coinciding to one added for bug_23333. mysql-test/r/innodb.result: results changed mysql-test/r/mix_innodb_myisam_binlog.result: results changed mysql-test/r/multi_update.result: results changed mysql-test/t/innodb.test: trans table specific test added mysql-test/t/mix_innodb_myisam_binlog.test: multi-update and multi-delete of mixure of ta and not-ta tables tests added (relates to bug_23333). mysql-test/t/multi_update.test: testing another branch of mult-delete: send_eof() (binloggin there), send_error (early return) sql/sql_class.h: a new flag to designate the fact the statement's error has been handled. The flag is checked by ::send_error() methods (multi_update and _delete classes) sql/sql_delete.cc: expanding multi_delete::send_error to 1. early return if error_handled == t 2. binlogging locally if there was a non-trans table modified side effect sql/sql_parse.cc: adding multi_update::send_error which can perform binlogging and rollback job in needed sql/sql_update.cc: issues relating to 1. bug_27716 with zeroing of `updated' to serve as the flag of early return from send_error(). The flag is changed to be a new member error_handled; also moved outside binlogging branch. The reason for this change is that bug_23333 fixes were pushed after the bug_27716's and they left this flaw (also no test coverage). 2. bug_30763 with assertion on trans_safe. I decide to make 2 liner fix for that bug here instead of to remove those two assertions. This new bug test case is the same as for multi-update on the mixure of tables. The rational for this fix: presumption for mutli_update::trans_safe to be set to zero at multi_update::multi_update or multi_update::initialize_tables() is incorrect. trans_safe := false should happen only when a non-transactional table gets modified. Therefore, at initialization the member must be be set to true. --- mysql-test/r/innodb.result | 17 ++++- mysql-test/r/mix_innodb_myisam_binlog.result | 52 ++++++++++++-- mysql-test/r/multi_update.result | 24 ++++++- mysql-test/t/innodb.test | 32 +++++++++ mysql-test/t/mix_innodb_myisam_binlog.test | 76 ++++++++++++++++++-- mysql-test/t/multi_update.test | 34 +++++++++ sql/sql_class.h | 10 +++ sql/sql_delete.cc | 29 ++++++-- sql/sql_parse.cc | 7 ++ sql/sql_update.cc | 22 +++--- 10 files changed, 274 insertions(+), 29 deletions(-) diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 6082a30bce3..38b26425ec8 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1119,6 +1119,19 @@ show master status /* there must be no UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 98 drop table t1, t2; +drop table if exists t1, t2; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); +delete t2 from t2; +ERROR 23000: Duplicate entry '1' for key 1 +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; +count(*) +2 +drop table t1, t2; create table t1 (a int, b int) engine=innodb; insert into t1 values(20,null); select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on @@ -1792,10 +1805,10 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 72 +Innodb_rows_deleted 73 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 29732 +Innodb_rows_inserted 29734 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 29532 diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 5d5726c9689..89ee82e9655 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -351,7 +351,7 @@ drop function if exists bug27417; drop table if exists t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); -create function bug27417(n int) +create function bug27417(n int) RETURNS int(11) begin insert into t1 values (null); @@ -393,7 +393,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -427,6 +429,31 @@ master-bin.000001 190 select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 301 +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 1 +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -443,6 +470,23 @@ master-bin.000001 246 select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 1 +show master status /* the offset must denote there is the query */; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 274 +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -458,7 +502,7 @@ count(*) show master status /* the offset must denote there is the query */; File Position Binlog_Do_DB Binlog_Ignore_DB master-bin.000001 376 -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; end of tests diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 0f624e3ee8d..d95036090a5 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -545,7 +545,7 @@ a b 4 4 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 189 +master-bin.000001 260 delete from t1; delete from t2; insert into t1 values (1,2),(3,4),(4,4); @@ -555,6 +555,26 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; ERROR 23000: Duplicate entry '4' for key 1 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 204 +master-bin.000001 275 drop table t1, t2; +drop table if exists t1, t2, t3; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; +delete t3.* from t2,t3 where t2.a=t3.a; +ERROR 23000: Duplicate entry '1' for key 1 +select count(*) from t1 /* must be 1 */; +count(*) +1 +select count(*) from t3 /* must be 1 */; +count(*) +1 +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 # use `test`; delete t3.* from t2,t3 where t2.a=t3.a +drop table t1, t2, t3; end of tests diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 04dfa1d0836..d045bad39f7 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -792,6 +792,38 @@ show master status /* there must be no UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +# +# Bug #29136 erred multi-delete on trans table does not rollback +# + +# prepare +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); + + +# exec cases A, B - see multi_update.test + +# A. send_error() w/o send_eof() branch + +--error ER_DUP_ENTRY +delete t2 from t2; + +# check + +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; + +# cleanup bug#29136 + +drop table t1, t2; + + # # Testing of IFNULL # diff --git a/mysql-test/t/mix_innodb_myisam_binlog.test b/mysql-test/t/mix_innodb_myisam_binlog.test index e1740bda03e..e0ce802254a 100644 --- a/mysql-test/t/mix_innodb_myisam_binlog.test +++ b/mysql-test/t/mix_innodb_myisam_binlog.test @@ -347,7 +347,7 @@ CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); delimiter |; -create function bug27417(n int) +create function bug27417(n int) RETURNS int(11) begin insert into t1 values (null); @@ -385,13 +385,17 @@ drop table t1,t2; # # Bug#23333 using the patch (and the test) for bug#27471 +# # throughout the bug tests # t1 - non-trans side effects gatherer; # t2 - transactional table; # + CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; # @@ -434,7 +438,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); select count(*) from t1 /* must be 2 */; # -# UPDATE (multi-update see bug#27716) +# UPDATE inc multi-update # # prepare @@ -450,9 +454,48 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); show master status /* the offset must denote there is the query */; select count(*) from t1 /* must be 2 */; +## multi_update::send_eof() branch + +# prepare + delete from t3; + delete from t4; + insert into t3 values (1,1); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 4 */; + +## send_error() branch of multi_update + +# prepare + delete from t1; + delete from t3; + delete from t4; + insert into t3 values (1,1),(2,2); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); + +# check + select count(*) from t1 /* must be 1 */; + +# cleanup + drop table t4; + # -# DELETE (for multi-delete see Bug #29136) +# DELETE incl multi-delete # # prepare @@ -472,6 +515,27 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); show master status /* the offset must denote there is the query */; select count(*) from t1 /* must be 1 */; +# cleanup + drop trigger trg_del; + +# prepare + delete from t1; + delete from t2; + delete from t5; + create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); + insert into t2 values (2),(3); + insert into t5 values (1),(2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete t2.* from t2,t5 where t2.a=t5.a + 1; + +# check + show master status /* the offset must denote there is the query */; + select count(*) from t1 /* must be 1 */; + # # LOAD DATA @@ -496,8 +560,8 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 84e6a444d47..37cdfcf5f26 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -574,4 +574,38 @@ show master status /* there must be the UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +# +# Bug #29136 erred multi-delete on trans table does not rollback +# + +# prepare +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); + +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; + +# exec cases B, A - see innodb.test + +# B. send_eof() and send_error() afterward + +--error ER_DUP_ENTRY +delete t3.* from t2,t3 where t2.a=t3.a; + +# check +select count(*) from t1 /* must be 1 */; +select count(*) from t3 /* must be 1 */; +# the query must be in binlog (no surprise though) +source include/show_binlog_events.inc; + +# cleanup bug#29136 +drop table t1, t2, t3; + + --echo end of tests diff --git a/sql/sql_class.h b/sql/sql_class.h index a96000a0598..457c8c87fc8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2356,6 +2356,11 @@ class multi_delete :public select_result_interceptor /* True if at least one table we delete from is not transactional */ bool normal_tables; bool delete_while_scanning; + /* + error handling (rollback and binlogging) can happen in send_eof() + so that afterward send_error() needs to find out that. + */ + bool error_handled; public: multi_delete(TABLE_LIST *dt, uint num_of_tables); @@ -2391,6 +2396,11 @@ class multi_update :public select_result_interceptor /* True if the update operation has made a change in a transactional table */ bool transactional_tables; bool ignore; + /* + error handling (rollback and binlogging) can happen in send_eof() + so that afterward send_error() needs to find out that. + */ + bool error_handled; public: multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list, diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7555219f5d8..add37c8c552 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -504,7 +504,7 @@ bool mysql_multi_delete_prepare(THD *thd) multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg) : delete_tables(dt), deleted(0), found(0), num_of_tables(num_of_tables_arg), error(0), - do_delete(0), transactional_tables(0), normal_tables(0) + do_delete(0), transactional_tables(0), normal_tables(0), error_handled(0) { tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables); } @@ -685,12 +685,14 @@ void multi_delete::send_error(uint errcode,const char *err) /* First send error what ever it is ... */ my_message(errcode, err, MYF(0)); - /* If nothing deleted return */ - if (!deleted) + /* the error was handled or nothing deleted and no side effects return */ + if (error_handled || + !thd->transaction.stmt.modified_non_trans_table && !deleted) DBUG_VOID_RETURN; /* Something already deleted so we have to invalidate cache */ - query_cache_invalidate3(thd, delete_tables, 1); + if (deleted) + query_cache_invalidate3(thd, delete_tables, 1); /* If rows from the first table only has been deleted and it is @@ -710,12 +712,29 @@ void multi_delete::send_error(uint errcode,const char *err) */ error= 1; send_eof(); + DBUG_ASSERT(error_handled); + DBUG_VOID_RETURN; + } + + if (thd->transaction.stmt.modified_non_trans_table) + { + /* + there is only side effects; to binlog with the error + */ + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length, + transactional_tables, FALSE); + mysql_bin_log.write(&qinfo); + } + thd->transaction.all.modified_non_trans_table= true; } DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); DBUG_VOID_RETURN; } + /* Do delete from other tables. Returns values: @@ -832,6 +851,8 @@ bool multi_delete::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + if (local_error != 0) + error_handled= TRUE; // to force early leave from ::send_error() /* Commit or rollback the current SQL statement */ if (transactional_tables) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f4ee2ffc0f7..77695f47b1f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3701,6 +3701,13 @@ end_with_restore_list: SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | OPTION_SETUP_TABLES_DONE, del_result, unit, select_lex); + res|= thd->net.report_error; + if (unlikely(res)) + { + /* If we had a another error reported earlier then this will be ignored */ + del_result->send_error(ER_UNKNOWN_ERROR, "Execution of the query failed"); + del_result->abort(); + } delete del_result; } else diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 3f38ad8b33c..f3695976508 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -994,8 +994,8 @@ multi_update::multi_update(TABLE_LIST *table_list, :all_tables(table_list), leaves(leaves_list), update_tables(0), tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), - handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0), - transactional_tables(1), ignore(ignore_arg) + handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1), + transactional_tables(1), ignore(ignore_arg), error_handled(0) {} @@ -1202,7 +1202,6 @@ multi_update::initialize_tables(JOIN *join) if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join)) DBUG_RETURN(1); main_table=join->join_tab->table; - trans_safe= transactional_tables= main_table->file->has_transactions(); table_to_update= 0; /* Any update has at least one pair (field, value) */ @@ -1484,12 +1483,14 @@ void multi_update::send_error(uint errcode,const char *err) /* First send error what ever it is ... */ my_error(errcode, MYF(0), err); - /* If nothing updated return */ - if (updated == 0) /* the counter might be reset in send_eof */ - return; /* and then the query has been binlogged */ + /* the error was handled or nothing deleted and no side effects return */ + if (error_handled || + !thd->transaction.stmt.modified_non_trans_table && !updated) + return; /* Something already updated so we have to invalidate cache */ - query_cache_invalidate3(thd, update_tables, 1); + if (updated) + query_cache_invalidate3(thd, update_tables, 1); /* If all tables that has been updated are trans safe then just do rollback. If not attempt to do remaining updates. @@ -1525,8 +1526,7 @@ void multi_update::send_error(uint errcode,const char *err) transactional_tables, FALSE); mysql_bin_log.write(&qinfo); } - if (!trans_safe) - thd->transaction.all.modified_non_trans_table= TRUE; + thd->transaction.all.modified_non_trans_table= TRUE; } DBUG_ASSERT(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table); @@ -1739,8 +1739,6 @@ bool multi_update::send_eof() { if (local_error == 0) thd->clear_error(); - else - updated= 0; /* if there's an error binlog it here not in ::send_error */ Query_log_event qinfo(thd, thd->query, thd->query_length, transactional_tables, FALSE); if (mysql_bin_log.write(&qinfo) && trans_safe) @@ -1749,6 +1747,8 @@ bool multi_update::send_eof() if (thd->transaction.stmt.modified_non_trans_table) thd->transaction.all.modified_non_trans_table= TRUE; } + if (local_error != 0) + error_handled= TRUE; // to force early leave from ::send_error() if (transactional_tables) { From bf9eb0f0d71f741d1ab9ff5375892d93b53c01d4 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 13 Oct 2007 23:12:50 +0300 Subject: [PATCH 32/43] manual merge for bug_29136, bug#29309. mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test: manual merge from 5.0 mysql-test/r/innodb.result: results changed mysql-test/r/multi_update.result: results changed mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: manual merge: results re-recorded mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: results changed mysql-test/suite/manual/r/rpl_replication_delay.result: results recorded for 5.1 mysql-test/t/innodb.test: removing bug27716 regression test as one exists in binlog suite already. mysql-test/t/multi_update.test: manual merge plus refining for execution in both binlog_format. sql/log_event.cc: bloody manual merge; the fact that an event is artificial is encode with setting timestamp argument to zero. rli's last_master_timestamp won't be updated in stmt_done in such case. sql/rpl_rli.cc: simulation and the real fixing code. Don't update last_master_timestamp with zero. sql/sql_delete.cc: manual merge --- .../mix_innodb_myisam_side_effects.test | 74 +++++++++++++++++-- mysql-test/r/innodb.result | 17 ++++- mysql-test/r/multi_update.result | 23 +++++- .../r/binlog_row_mix_innodb_myisam.result | 59 +++++++++++++-- .../r/binlog_stm_mix_innodb_myisam.result | 59 +++++++++++++-- .../manual/r/rpl_replication_delay.result | 31 ++++++-- mysql-test/t/innodb.test | 39 ---------- mysql-test/t/multi_update.test | 8 +- sql/log_event.cc | 28 ++++++- sql/rpl_rli.cc | 10 ++- sql/sql_delete.cc | 6 +- 11 files changed, 278 insertions(+), 76 deletions(-) diff --git a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test index 6c961c4694d..03514bfdb55 100644 --- a/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test +++ b/mysql-test/extra/binlog_tests/mix_innodb_myisam_side_effects.test @@ -126,7 +126,9 @@ drop table t1,t2; # CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; # @@ -169,7 +171,7 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); select count(*) from t1 /* must be 2 */; # -# UPDATE (multi-update see bug#27716) +# UPDATE inc multi-update # # prepare @@ -185,9 +187,48 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 2 */; +## multi_update::send_eof() branch + +# prepare + delete from t3; + delete from t4; + insert into t3 values (1,1); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; + +# check + source include/show_binlog_events.inc; # the offset must denote there is the query + select count(*) from t1 /* must be 4 */; + +## send_error() branch of multi_update + +# prepare + delete from t1; + delete from t3; + delete from t4; + insert into t3 values (1,1),(2,2); + insert into t4 values (1,1),(2,2); + + reset master; + +# execute + --error ER_DUP_ENTRY + UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); + +# check + select count(*) from t1 /* must be 1 */; + +# cleanup + drop table t4; + # -# DELETE (for multi-delete see Bug #29136) +# DELETE incl multi-delete # # prepare @@ -203,6 +244,27 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # execute --error ER_DUP_ENTRY delete from t2; +# check + source include/show_binlog_events.inc; # the offset must denote there is the query + select count(*) from t1 /* must be 1 */; + +# cleanup + drop trigger trg_del; + +# prepare + delete from t1; + delete from t2; + delete from t5; + create trigger trg_del_t2 after delete on t2 for each row + insert into t1 values (1); + insert into t2 values (2),(3); + insert into t5 values (1),(2); + reset master; + +# execute + --error ER_DUP_ENTRY + delete t2.* from t2,t5 where t2.a=t5.a + 1; + # check source include/show_binlog_events.inc; # must be events of the query select count(*) from t1 /* must be 1 */; @@ -229,6 +291,8 @@ CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); # # bug#23333 cleanup # -drop trigger trg_del; -drop table t1,t2,t3,t4; + + +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index d0b67e90afb..e1cc365f5c3 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1086,6 +1086,19 @@ n d 1 30 2 20 drop table t1,t2; +drop table if exists t1, t2; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t1 values (1); +insert into t2 values (1),(2); +delete t2 from t2; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; +count(*) +2 +drop table t1, t2; create table t1 (a int, b int) engine=innodb; insert into t1 values(20,null); select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on @@ -1751,10 +1764,10 @@ Variable_name Value Innodb_page_size 16384 show status like "Innodb_rows_deleted"; Variable_name Value -Innodb_rows_deleted 70 +Innodb_rows_deleted 71 show status like "Innodb_rows_inserted"; Variable_name Value -Innodb_rows_inserted 1083 +Innodb_rows_inserted 1085 show status like "Innodb_rows_updated"; Variable_name Value Innodb_rows_updated 886 diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result index 55e47756312..0bc01e95d2d 100644 --- a/mysql-test/r/multi_update.result +++ b/mysql-test/r/multi_update.result @@ -614,6 +614,7 @@ CREATE TABLE `t2` ( `b` int(11) default NULL, PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; +set @sav_binlog_format= @@session.binlog_format; set @@session.binlog_format= mixed; insert into t1 values (1,1),(2,2); insert into t2 values (1,1),(4,4); @@ -626,7 +627,7 @@ a b 4 4 show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 197 +master-bin.000001 268 delete from t1; delete from t2; insert into t1 values (1,2),(3,4),(4,4); @@ -636,6 +637,24 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; ERROR 23000: Duplicate entry '4' for key 'PRIMARY' show master status /* there must be the UPDATE query event */; File Position Binlog_Do_DB Binlog_Ignore_DB -master-bin.000001 212 +master-bin.000001 283 drop table t1, t2; +set @@session.binlog_format= @sav_binlog_format; +drop table if exists t1, t2, t3; +CREATE TABLE t1 (a int, PRIMARY KEY (a)); +CREATE TABLE t2 (a int, PRIMARY KEY (a)); +CREATE TABLE t3 (a int, PRIMARY KEY (a)) ENGINE=MyISAM; +create trigger trg_del_t3 before delete on t3 for each row insert into t1 values (1); +insert into t2 values (1),(2); +insert into t3 values (1),(2); +reset master; +delete t3.* from t2,t3 where t2.a=t3.a; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +select count(*) from t3 /* must be 1 */; +count(*) +1 +drop table t1, t2, t3; end of tests diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 8022f2b1e10..f69d5717a1f 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -520,7 +520,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -559,6 +561,33 @@ master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */ +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -571,12 +600,30 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Intvar # # INSERT_ID=9 master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -591,11 +638,11 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index 9c580b2312e..c15478bc826 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -494,7 +494,9 @@ count(*) drop table t1,t2; CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique); +CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM; +CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb; +CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; insert into t2 values (1); reset master; insert into t2 values (bug27417(1)); @@ -533,6 +535,33 @@ master-bin.000001 # Query # # use `test`; update t3 set b=b+bug27417(1) select count(*) from t1 /* must be 2 */; count(*) 2 +delete from t3; +delete from t4; +insert into t3 values (1,1); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */; +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Query # # use `test`; UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */ +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 4 */; +count(*) +4 +delete from t1; +delete from t3; +delete from t4; +insert into t3 values (1,1),(2,2); +insert into t4 values (1,1),(2,2); +reset master; +UPDATE t3,t4 SET t3.a=t4.a + bug27417(1); +ERROR 23000: Duplicate entry '2' for key 'PRIMARY' +select count(*) from t1 /* must be 1 */; +count(*) +1 +drop table t4; delete from t1; delete from t2; delete from t3; @@ -545,12 +574,30 @@ delete from t2; ERROR 23000: Duplicate entry '1' for key 'PRIMARY' show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=6 +master-bin.000001 # Intvar # # INSERT_ID=9 master-bin.000001 # Query # # use `test`; delete from t2 master-bin.000001 # Query # # use `test`; ROLLBACK select count(*) from t1 /* must be 1 */; count(*) 1 +drop trigger trg_del; +delete from t1; +delete from t2; +delete from t5; +create trigger trg_del_t2 after delete on t2 for each row +insert into t1 values (1); +insert into t2 values (2),(3); +insert into t5 values (1),(2); +reset master; +delete t2.* from t2,t5 where t2.a=t5.a + 1; +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +show binlog events from ; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1 +master-bin.000001 # Query # # use `test`; ROLLBACK +select count(*) from t1 /* must be 1 */; +count(*) +1 delete from t1; create table t4 (a int default 0, b int primary key) engine=innodb; insert into t4 values (0, 17); @@ -565,13 +612,13 @@ count(*) 2 show binlog events from ; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Begin_load_query # # ;file_id=1;block_len=12 -master-bin.000001 # Intvar # # INSERT_ID=7 +master-bin.000001 # Intvar # # INSERT_ID=10 master-bin.000001 # Execute_load_query # # use `test`; load data infile '../std_data_ln/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=1 master-bin.000001 # Query # # use `test`; ROLLBACK -drop trigger trg_del; -drop table t1,t2,t3,t4; +drop trigger trg_del_t2; +drop table t1,t2,t3,t4,t5; drop function bug27417; set @@session.binlog_format=@@global.binlog_format; end of tests diff --git a/mysql-test/suite/manual/r/rpl_replication_delay.result b/mysql-test/suite/manual/r/rpl_replication_delay.result index 22447a30cba..a8fa6ce8265 100644 --- a/mysql-test/suite/manual/r/rpl_replication_delay.result +++ b/mysql-test/suite/manual/r/rpl_replication_delay.result @@ -11,7 +11,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 98 +Read_Master_Log_Pos 106 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -26,7 +26,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 98 +Exec_Master_Log_Pos 106 Relay_Log_Space # Until_Condition None Until_Log_File @@ -38,6 +38,11 @@ Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master 0 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error drop table if exists t1; Warnings: Note 1051 Unknown table 't1' @@ -52,7 +57,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 359 +Read_Master_Log_Pos 367 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -67,7 +72,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 271 +Exec_Master_Log_Pos 279 Relay_Log_Space # Until_Condition None Until_Log_File @@ -78,7 +83,12 @@ Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -Seconds_Behind_Master 10 +Seconds_Behind_Master 9 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error unlock tables; flush logs /* this time rli->last_master_timestamp is not affected */; lock table t1 write; @@ -90,7 +100,7 @@ Master_User root Master_Port 9306 Connect_Retry 1 Master_Log_File master-bin.000001 -Read_Master_Log_Pos 447 +Read_Master_Log_Pos 455 Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 @@ -105,7 +115,7 @@ Replicate_Wild_Ignore_Table Last_Errno 0 Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 359 +Exec_Master_Log_Pos 367 Relay_Log_Space # Until_Condition None Until_Log_File @@ -116,6 +126,11 @@ Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key -Seconds_Behind_Master 6 +Seconds_Behind_Master 7 +Master_SSL_Verify_Server_Cert No +Last_IO_Errno 0 +Last_IO_Error +Last_SQL_Errno 0 +Last_SQL_Error unlock tables; drop table t1; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 63682ab96eb..c7fe033fd36 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -753,45 +753,6 @@ select * from t1; select * from t2; drop table t1,t2; -# -# Bug#27716 multi-update did partially and has not binlogged -# - -CREATE TABLE `t1` ( - `a` int(11) NOT NULL auto_increment, - `b` int(11) default NULL, - PRIMARY KEY (`a`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; - -CREATE TABLE `t2` ( - `a` int(11) NOT NULL auto_increment, - `b` int(11) default NULL, - PRIMARY KEY (`a`) -) ENGINE=INNODB DEFAULT CHARSET=latin1 ; - -# A. testing multi_update::send_eof() execution branch -insert into t1 values (1,1),(2,2); -insert into t2 values (1,1),(4,4); -reset master; ---error ER_DUP_ENTRY -UPDATE t2,t1 SET t2.a=t1.a+2; -# check -select * from t2 /* must be (3,1), (4,4) */; -show master status /* there must no UPDATE in binlog */; - -# B. testing multi_update::send_error() execution branch -delete from t1; -delete from t2; -insert into t1 values (1,2),(3,4),(4,4); -insert into t2 values (1,2),(3,4),(4,4); -reset master; ---error ER_DUP_ENTRY -UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a; -show master status /* there must be no UPDATE query event */; - -# cleanup bug#27716 -drop table t1, t2; - # # Bug #29136 erred multi-delete on trans table does not rollback # diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index 8b8132df84a..331663dceb5 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -588,6 +588,7 @@ CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 ; # as the test is about to see erroed queries in binlog +set @sav_binlog_format= @@session.binlog_format; set @@session.binlog_format= mixed; @@ -614,6 +615,7 @@ show master status /* there must be the UPDATE query event */; # cleanup bug#27716 drop table t1, t2; +set @@session.binlog_format= @sav_binlog_format; # # Bug #29136 erred multi-delete on trans table does not rollback @@ -642,11 +644,13 @@ delete t3.* from t2,t3 where t2.a=t3.a; # check select count(*) from t1 /* must be 1 */; select count(*) from t3 /* must be 1 */; -# the query must be in binlog (no surprise though) -source include/show_binlog_events.inc; # cleanup bug#29136 drop table t1, t2, t3; +# +# Add further tests from here +# + --echo end of tests diff --git a/sql/log_event.cc b/sql/log_event.cc index 31309694c1a..ec4d6820cca 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -558,8 +558,32 @@ int Log_event::do_update_pos(Relay_log_info *rli) Matz: I don't think we will need this check with this refactoring. */ if (rli) - rli->stmt_done(log_pos, when); - + { + /* + bug#29309 simulation: resetting the flag to force + wrong behaviour of artificial event to update + rli->last_master_timestamp for only one time - + the first FLUSH LOGS in the test. + */ + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 1 + && is_artificial_event()) + { + debug_not_change_ts_if_art_event= 0; + }); +#ifndef DBUG_OFF + rli->stmt_done(log_pos, + is_artificial_event() && + debug_not_change_ts_if_art_event > 0 ? 0 : when); +#else + rli->stmt_done(log_pos, is_artificial_event()? 0 : when); +#endif + DBUG_EXECUTE_IF("let_first_flush_log_change_timestamp", + if (debug_not_change_ts_if_art_event == 0) + { + debug_not_change_ts_if_art_event= 2; + }); + } return 0; // Cannot fail currently } diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 867d55a60a3..15d7d97affd 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1082,6 +1082,9 @@ bool Relay_log_info::cached_charset_compare(char *charset) const void Relay_log_info::stmt_done(my_off_t event_master_log_pos, time_t event_creation_time) { +#ifndef DBUG_OFF + extern uint debug_not_change_ts_if_art_event; +#endif clear_flag(IN_STMT); /* @@ -1121,7 +1124,12 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, is that value may take some time to display in Seconds_Behind_Master - not critical). */ - last_master_timestamp= event_creation_time; +#ifndef DBUG_OFF + if (!(event_creation_time == 0 && debug_not_change_ts_if_art_event > 0)) +#else + if (event_creation_time != 0) +#endif + last_master_timestamp= event_creation_time; } } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index aad0514b10b..b4b877b9a37 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -758,9 +758,9 @@ void multi_delete::send_error(uint errcode,const char *err) */ if (mysql_bin_log.is_open()) { - Query_log_event qinfo(thd, thd->query, thd->query_length, - transactional_tables, FALSE); - mysql_bin_log.write(&qinfo); + thd->binlog_query(THD::ROW_QUERY_TYPE, + thd->query, thd->query_length, + transactional_tables, FALSE); } thd->transaction.all.modified_non_trans_table= true; } From 1590fa13ff044c1c779a11b716394fc76453424e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 Oct 2007 15:22:44 +0500 Subject: [PATCH 33/43] After merge fix: Adjusting SHOW CREATE TABLE output from 5.0 to 5.1 format mysql-test/r/ctype_uca.result: Adjusting SHOW CREATE TABLE output mysql-test/r/ctype_ucs.result: Adjusting SHOW CREATE TABLE output mysql-test/r/ctype_utf8.result: Adjusting SHOW CREATE TABLE output mysql-test/r/func_regexp.result: Adjusting SHOW CREATE TABLE output --- mysql-test/r/ctype_uca.result | 4 ++-- mysql-test/r/ctype_ucs.result | 4 ++-- mysql-test/r/ctype_utf8.result | 4 ++-- mysql-test/r/func_regexp.result | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index ada7ace9696..4980b179c4b 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -2763,8 +2763,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL, - `s2` varchar(64) character set ucs2 collate ucs2_unicode_ci default NULL + `s1` varchar(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci DEFAULT NULL, + `s2` varchar(64) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 709a097d823..dab49cdd8bb 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -931,8 +931,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set ucs2 default NULL, - `s2` varchar(64) character set ucs2 default NULL + `s1` varchar(64) CHARACTER SET ucs2 DEFAULT NULL, + `s2` varchar(64) CHARACTER SET ucs2 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 0981f72b0c1..3575a07d83c 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -276,8 +276,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) character set utf8 default NULL, - `s2` varchar(64) character set utf8 default NULL + `s1` varchar(64) CHARACTER SET utf8 DEFAULT NULL, + `s2` varchar(64) CHARACTER SET utf8 DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); diff --git a/mysql-test/r/func_regexp.result b/mysql-test/r/func_regexp.result index c3851e51207..dca73244780 100644 --- a/mysql-test/r/func_regexp.result +++ b/mysql-test/r/func_regexp.result @@ -8,8 +8,8 @@ select null, null; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `s1` varchar(64) default NULL, - `s2` varchar(64) default NULL + `s1` varchar(64) DEFAULT NULL, + `s2` varchar(64) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 delete from t1; insert into t1 values('aaa','aaa'); From 828801bbaa670ab141ffc4bcb437e17d88097a99 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 16 Oct 2007 23:19:39 +0400 Subject: [PATCH 34/43] Fix for non-deterministic behavior of SELECTs and VIEWs mysql-test/suite/rpl/include/rpl_mixed_check_select.inc: Added ORDER BY for SELECT mysql-test/suite/rpl/include/rpl_mixed_check_view.inc: Added ORDER BY for VIEW mysql-test/suite/rpl/include/rpl_mixed_dml.inc: Added ORDER BY for SELECT mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result: Updated result file --- .../rpl/include/rpl_mixed_check_select.inc | 8 +- .../rpl/include/rpl_mixed_check_view.inc | 4 +- .../suite/rpl/include/rpl_mixed_dml.inc | 8 +- .../suite/rpl/r/rpl_innodb_mixed_dml.result | 152 +++++++++--------- 4 files changed, 86 insertions(+), 86 deletions(-) diff --git a/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc b/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc index 5d3b80e077b..b3e0cefbbd7 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_check_select.inc @@ -7,15 +7,15 @@ --echo ==========MASTER========== SELECT COUNT(*) FROM t1; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; SELECT COUNT(*) FROM t2; -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; sync_slave_with_master; --echo ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; SELECT COUNT(*) FROM t2; -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; connection master; diff --git a/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc b/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc index 43feedfe64a..a9f7ad8cd68 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_check_view.inc @@ -7,11 +7,11 @@ --echo ==========MASTER========== SHOW CREATE VIEW v1; -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; sync_slave_with_master; --echo ==========SLAVE=========== USE test_rpl; SHOW CREATE VIEW v1; -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; connection master; diff --git a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc index 96dfdbed541..d596df31b99 100644 --- a/mysql-test/suite/rpl/include/rpl_mixed_dml.inc +++ b/mysql-test/suite/rpl/include/rpl_mixed_dml.inc @@ -54,7 +54,7 @@ DELETE FROM t2 WHERE a = 2; --exec cp ./suite/rpl/data/rpl_mixed.dat $MYSQLTEST_VARDIR/tmp/ LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ; --exec rm $MYSQLTEST_VARDIR/tmp/rpl_mixed.dat -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; --source suite/rpl/include/rpl_mixed_check_select.inc --source suite/rpl/include/rpl_mixed_clear_tables.inc @@ -75,7 +75,7 @@ DELETE FROM t1 WHERE a = 2; --echo --echo ******************** SELECT ******************** INSERT INTO t1 VALUES(1, 't1, text 1'); -SELECT * FROM t1 WHERE b <> UUID(); +SELECT * FROM t1 WHERE b <> UUID() ORDER BY a; --source suite/rpl/include/rpl_mixed_clear_tables.inc # JOIN @@ -85,8 +85,8 @@ INSERT INTO t1 VALUES(1, 'CCC'); INSERT INTO t1 VALUES(2, 'DDD'); INSERT INTO t2 VALUES(1, 'DDD'); INSERT INTO t2 VALUES(2, 'CCC'); -SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a; -SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a ORDER BY t1.a,t2.a; +SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b ORDER BY t1.a,t2.a; --source suite/rpl/include/rpl_mixed_clear_tables.inc # UNION diff --git a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result index 19c5299df25..0e11d132cc4 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result @@ -41,26 +41,26 @@ DELETE FROM t2 WHERE b <> UUID(); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 2 t1, text 2 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 2 t1, text 2 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -76,13 +76,13 @@ DELETE FROM t2 WHERE a = 2; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 ==========SLAVE=========== @@ -90,13 +90,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 DELETE FROM t1; @@ -104,7 +104,7 @@ DELETE FROM t2; ******************** LOAD DATA INFILE ******************** LOAD DATA INFILE '../tmp/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ; -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -113,7 +113,7 @@ a b SELECT COUNT(*) FROM t1; COUNT(*) 3 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -121,14 +121,14 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 3 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 10 line A 20 line B @@ -136,7 +136,7 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -153,35 +153,35 @@ DELETE FROM t1 WHERE a = 2; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 11 3 t1, text 33 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 11 3 t1, text 33 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; ******************** SELECT ******************** INSERT INTO t1 VALUES(1, 't1, text 1'); -SELECT * FROM t1 WHERE b <> UUID(); +SELECT * FROM t1 WHERE b <> UUID() ORDER BY a; a b 1 t1, text 1 DELETE FROM t1; @@ -192,11 +192,11 @@ INSERT INTO t1 VALUES(1, 'CCC'); INSERT INTO t1 VALUES(2, 'DDD'); INSERT INTO t2 VALUES(1, 'DDD'); INSERT INTO t2 VALUES(2, 'CCC'); -SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a ORDER BY t1.a,t2.a; a b a b 1 CCC 1 DDD 2 DDD 2 CCC -SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b; +SELECT * FROM t1 INNER JOIN t2 ON t1.b = t2.b ORDER BY t1.a,t2.a; a b a b 1 CCC 2 CCC 2 DDD 1 DDD @@ -219,50 +219,50 @@ INSERT INTO t1 VALUES(1, 't1, text 1'); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b TRUNCATE t1; ==========MASTER========== SELECT COUNT(*) FROM t1; COUNT(*) 0 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 0 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -275,13 +275,13 @@ UPDATE t1 SET b = 't1, text 1 updated' WHERE a = 1; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 updated SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 ==========SLAVE=========== @@ -289,13 +289,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 t1, text 1 updated SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 t2, text 1 UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test'; @@ -303,13 +303,13 @@ UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test'; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test ==========SLAVE=========== @@ -317,13 +317,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test DELETE FROM t1; @@ -349,26 +349,26 @@ COMMIT; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (2, 'rollback'); @@ -377,26 +377,26 @@ ROLLBACK; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (3, 'before savepoint s1'); @@ -407,27 +407,27 @@ ROLLBACK TO SAVEPOINT s1; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b START TRANSACTION; INSERT INTO t1 VALUES (5, 'before savepoint s2'); @@ -441,7 +441,7 @@ DELETE FROM t1 WHERE a = 7; SELECT COUNT(*) FROM t1; COUNT(*) 4 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 @@ -450,14 +450,14 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 4 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 start 3 before savepoint s1 @@ -466,7 +466,7 @@ a b SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DELETE FROM t1; DELETE FROM t2; @@ -610,28 +610,28 @@ DELETE FROM t1 WHERE a = 202; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 100 test 201 test SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 2 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 100 test 201 test SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ALTER PROCEDURE p1 COMMENT 'p1'; DROP PROCEDURE p1; @@ -649,13 +649,13 @@ INSERT INTO t1 VALUES (1, 'test'); SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test ==========SLAVE=========== @@ -663,13 +663,13 @@ USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test SELECT COUNT(*) FROM t2; COUNT(*) 1 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b 1 test DELETE FROM t1; @@ -694,51 +694,51 @@ test_rpl e1 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========MASTER========== SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ALTER EVENT e1 RENAME TO e2; ==========MASTER========== @@ -754,26 +754,26 @@ test_rpl e2 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b ==========SLAVE=========== USE test_rpl; SELECT COUNT(*) FROM t1; COUNT(*) 1 -SELECT * FROM t1; +SELECT * FROM t1 ORDER BY a; a b 1 test1 SELECT COUNT(*) FROM t2; COUNT(*) 0 -SELECT * FROM t2; +SELECT * FROM t2 ORDER BY a; a b DROP EVENT e2; ==========MASTER========== @@ -795,7 +795,7 @@ CREATE VIEW v2 AS SELECT * FROM t1 WHERE b <> UUID(); SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 1) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 1 test1 ==========SLAVE=========== @@ -803,7 +803,7 @@ USE test_rpl; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 1) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 1 test1 ALTER VIEW v1 AS SELECT * FROM t1 WHERE a = 2; @@ -811,7 +811,7 @@ ALTER VIEW v1 AS SELECT * FROM t1 WHERE a = 2; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 2) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 2 test2 ==========SLAVE=========== @@ -819,7 +819,7 @@ USE test_rpl; SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where (`t1`.`a` = 2) latin1 latin1_swedish_ci -SELECT * FROM v1; +SELECT * FROM v1 ORDER BY a; a b 2 test2 DROP VIEW v1; From f3cd8a91b0f5da08e4e68bf819acf604f46d4c93 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Oct 2007 06:50:03 +0200 Subject: [PATCH 35/43] Eliminating some valgrind warnings resulting from that some storage engines do not set the unused null bits (i.e., the filler bits and the X bit) correctly. Also adding some casts to debug printouts to eliminate compiler warnings. sql/ha_ndbcluster.cc: Changing debug enter names to use full names for member functions. sql/records.cc: Emptying records before starting to read records since some engines do not set the unused null bits, leading to valgrind errors. sql/rpl_record.cc: Adding casts to debug printouts to eliminate compiler warnings. --- sql/ha_ndbcluster.cc | 110 +++++++++++++++++++++---------------------- sql/records.cc | 2 + sql/rpl_record.cc | 5 +- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b2152fbb906..21267f4901a 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -411,7 +411,7 @@ Ndb *ha_ndbcluster::get_ndb() void ha_ndbcluster::set_rec_per_key() { - DBUG_ENTER("ha_ndbcluster::get_status_const"); + DBUG_ENTER("ha_ndbcluster::set_rec_per_key"); for (uint i=0 ; i < table_share->keys ; i++) { table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]= 1; @@ -558,7 +558,7 @@ int ha_ndbcluster::ndb_err(NdbTransaction *trans) THD *thd= current_thd; int res; NdbError err= trans->getNdbError(); - DBUG_ENTER("ndb_err"); + DBUG_ENTER("ha_ndbcluster::ndb_err"); set_ndb_err(thd, err); @@ -695,7 +695,7 @@ static bool field_type_forces_var_part(enum_field_types type) bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op, uint fieldnr, const uchar *field_ptr) { - DBUG_ENTER("set_hidden_key"); + DBUG_ENTER("ha_ndbcluster::set_hidden_key"); DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr) != 0); } @@ -708,7 +708,7 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, uint fieldnr, const uchar *field_ptr) { uint32 pack_len= field->pack_length(); - DBUG_ENTER("set_ndb_key"); + DBUG_ENTER("ha_ndbcluster::set_ndb_key"); DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d", fieldnr, field->field_name, field->type(), pack_len)); @@ -731,7 +731,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, { const uchar* field_ptr= field->ptr + row_offset; uint32 pack_len= field->pack_length(); - DBUG_ENTER("set_ndb_value"); + DBUG_ENTER("ha_ndbcluster::set_ndb_value"); DBUG_PRINT("enter", ("%d: %s type: %u len=%d is_null=%s", fieldnr, field->field_name, field->type(), pack_len, field->is_null(row_offset) ? "Y" : "N")); @@ -934,7 +934,7 @@ int get_ndb_blobs_value(TABLE* table, NdbValue* value_array, int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, uint fieldnr, uchar* buf) { - DBUG_ENTER("get_ndb_value"); + DBUG_ENTER("ha_ndbcluster::get_ndb_value"); DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr, (int)(field != NULL ? field->flags : 0))); @@ -985,7 +985,7 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, */ int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op) { - DBUG_ENTER("get_ndb_partition_id"); + DBUG_ENTER("ha_ndbcluster::get_ndb_partition_id"); DBUG_RETURN(ndb_op->getValue(NdbDictionary::Column::FRAGMENT, (char *)&m_part_id) == NULL); } @@ -1044,7 +1044,7 @@ int ha_ndbcluster::get_metadata(const char *path) NDBDICT *dict= ndb->getDictionary(); const NDBTAB *tab; int error; - DBUG_ENTER("get_metadata"); + DBUG_ENTER("ha_ndbcluster::get_metadata"); DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path)); DBUG_ASSERT(m_table == NULL); @@ -1463,7 +1463,7 @@ void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb) { uint i; - DBUG_ENTER("release_metadata"); + DBUG_ENTER("ha_ndbcluster::release_metadata"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); NDBDICT *dict= ndb->getDictionary(); @@ -1604,7 +1604,7 @@ int ha_ndbcluster::set_primary_key(NdbOperation *op, const uchar *key) KEY* key_info= table->key_info + table_share->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("set_primary_key"); + DBUG_ENTER("ha_ndbcluster::set_primary_key"); for (; key_part != end; key_part++) { @@ -1626,7 +1626,7 @@ int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const uchar *re KEY* key_info= table->key_info + table_share->primary_key; KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; - DBUG_ENTER("set_primary_key_from_record"); + DBUG_ENTER("ha_ndbcluster::set_primary_key_from_record"); for (; key_part != end; key_part++) { @@ -1645,7 +1645,7 @@ int ha_ndbcluster::set_index_key_from_record(NdbOperation *op, KEY_PART_INFO* key_part= key_info->key_part; KEY_PART_INFO* end= key_part+key_info->key_parts; uint i; - DBUG_ENTER("set_index_key_from_record"); + DBUG_ENTER("ha_ndbcluster::set_index_key_from_record"); for (i= 0; key_part != end; key_part++, i++) { @@ -1684,7 +1684,7 @@ inline int ha_ndbcluster::define_read_attrs(uchar* buf, NdbOperation* op) { uint i; - DBUG_ENTER("define_read_attrs"); + DBUG_ENTER("ha_ndbcluster::define_read_attrs"); // Define attributes to read for (i= 0; i < table_share->fields; i++) @@ -1731,7 +1731,7 @@ int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf, NdbOperation *op; int res; - DBUG_ENTER("pk_read"); + DBUG_ENTER("ha_ndbcluster::pk_read"); DBUG_PRINT("enter", ("key_len: %u", key_len)); DBUG_DUMP("key", key, key_len); m_write_op= FALSE; @@ -1798,7 +1798,7 @@ int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data, uint no_fields= table_share->fields, i; NdbTransaction *trans= m_active_trans; NdbOperation *op; - DBUG_ENTER("complemented_read"); + DBUG_ENTER("ha_ndbcluster::complemented_read"); m_write_op= FALSE; if (bitmap_is_set_all(table->read_set)) @@ -1964,7 +1964,7 @@ int ha_ndbcluster::peek_indexed_rows(const uchar *record, const NdbOperation *first, *last; uint i; int res; - DBUG_ENTER("peek_indexed_rows"); + DBUG_ENTER("ha_ndbcluster::peek_indexed_rows"); NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -2104,7 +2104,7 @@ int ha_ndbcluster::unique_index_read(const uchar *key, inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) { - DBUG_ENTER("fetch_next"); + DBUG_ENTER("ha_ndbcluster::fetch_next"); int local_check; NdbTransaction *trans= m_active_trans; @@ -2213,7 +2213,7 @@ inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor) inline int ha_ndbcluster::next_result(uchar *buf) { int res; - DBUG_ENTER("next_result"); + DBUG_ENTER("ha_ndbcluster::next_result"); if (!m_active_cursor) DBUG_RETURN(HA_ERR_END_OF_FILE); @@ -2256,7 +2256,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, uint tot_len; uint i, j; - DBUG_ENTER("set_bounds"); + DBUG_ENTER("ha_ndbcluster::set_bounds"); DBUG_PRINT("info", ("key_parts=%d", key_parts)); for (j= 0; j <= 1; j++) @@ -2543,7 +2543,7 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info, NdbTransaction *trans= m_active_trans; part_id_range part_spec; - DBUG_ENTER("unique_index_scan"); + DBUG_ENTER("ha_ndbcluster::unique_index_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); NdbOperation::LockMode lm= @@ -2617,7 +2617,7 @@ int ha_ndbcluster::full_table_scan(uchar *buf) NdbTransaction *trans= m_active_trans; part_id_range part_spec; - DBUG_ENTER("full_table_scan"); + DBUG_ENTER("ha_ndbcluster::full_table_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); m_write_op= FALSE; @@ -2950,7 +2950,7 @@ int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data) longlong func_value; bool pk_update= (table_share->primary_key != MAX_KEY && key_cmp(table_share->primary_key, old_data, new_data)); - DBUG_ENTER("update_row"); + DBUG_ENTER("ha_ndbcluster::update_row"); m_write_op= TRUE; /* @@ -3154,7 +3154,7 @@ int ha_ndbcluster::delete_row(const uchar *record) NdbOperation *op; uint32 part_id; int error; - DBUG_ENTER("delete_row"); + DBUG_ENTER("ha_ndbcluster::delete_row"); m_write_op= TRUE; ha_statistic_increment(&SSV::ha_delete_count); @@ -3434,7 +3434,7 @@ void ha_ndbcluster::unpack_record(uchar *buf) void ha_ndbcluster::print_results() { - DBUG_ENTER("print_results"); + DBUG_ENTER("ha_ndbcluster::print_results"); #ifndef DBUG_OFF @@ -3701,7 +3701,7 @@ int ha_ndbcluster::read_range_next() int ha_ndbcluster::rnd_init(bool scan) { NdbScanOperation *cursor= m_active_cursor; - DBUG_ENTER("rnd_init"); + DBUG_ENTER("ha_ndbcluster::rnd_init"); DBUG_PRINT("enter", ("scan: %d", scan)); // Check if scan is to be restarted if (cursor) @@ -3721,7 +3721,7 @@ int ha_ndbcluster::rnd_init(bool scan) int ha_ndbcluster::close_scan() { NdbTransaction *trans= m_active_trans; - DBUG_ENTER("close_scan"); + DBUG_ENTER("ha_ndbcluster::close_scan"); m_multi_cursor= 0; if (!m_active_cursor && !m_multi_cursor) @@ -3770,14 +3770,14 @@ int ha_ndbcluster::close_scan() int ha_ndbcluster::rnd_end() { - DBUG_ENTER("rnd_end"); + DBUG_ENTER("ha_ndbcluster::rnd_end"); DBUG_RETURN(close_scan()); } int ha_ndbcluster::rnd_next(uchar *buf) { - DBUG_ENTER("rnd_next"); + DBUG_ENTER("ha_ndbcluster::rnd_next"); ha_statistic_increment(&SSV::ha_read_rnd_next_count); if (!m_active_cursor) @@ -3795,7 +3795,7 @@ int ha_ndbcluster::rnd_next(uchar *buf) int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos) { - DBUG_ENTER("rnd_pos"); + DBUG_ENTER("ha_ndbcluster::rnd_pos"); ha_statistic_increment(&SSV::ha_read_rnd_count); // The primary key for the record is stored in pos // Perform a pk_read using primary key "index" @@ -3847,7 +3847,7 @@ void ha_ndbcluster::position(const uchar *record) uchar *buff; uint key_length; - DBUG_ENTER("position"); + DBUG_ENTER("ha_ndbcluster::position"); if (table_share->primary_key != MAX_KEY) { @@ -3931,7 +3931,7 @@ void ha_ndbcluster::position(const uchar *record) int ha_ndbcluster::info(uint flag) { int result= 0; - DBUG_ENTER("info"); + DBUG_ENTER("ha_ndbcluster::info"); DBUG_PRINT("enter", ("flag: %d", flag)); if (flag & HA_STATUS_POS) @@ -4032,7 +4032,7 @@ void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info, int ha_ndbcluster::extra(enum ha_extra_function operation) { - DBUG_ENTER("extra"); + DBUG_ENTER("ha_ndbcluster::extra"); switch (operation) { case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/ DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY")); @@ -4125,7 +4125,7 @@ void ha_ndbcluster::start_bulk_insert(ha_rows rows) int bytes, batch; const NDBTAB *tab= m_table; - DBUG_ENTER("start_bulk_insert"); + DBUG_ENTER("ha_ndbcluster::start_bulk_insert"); DBUG_PRINT("enter", ("rows: %d", (int)rows)); m_rows_inserted= (ha_rows) 0; @@ -4174,7 +4174,7 @@ int ha_ndbcluster::end_bulk_insert() { int error= 0; - DBUG_ENTER("end_bulk_insert"); + DBUG_ENTER("ha_ndbcluster::end_bulk_insert"); // Check if last inserts need to be flushed if (m_bulk_insert_not_flushed) { @@ -4215,7 +4215,7 @@ int ha_ndbcluster::end_bulk_insert() int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size) { - DBUG_ENTER("extra_opt"); + DBUG_ENTER("ha_ndbcluster::extra_opt"); DBUG_PRINT("enter", ("cache_size: %lu", cache_size)); DBUG_RETURN(extra(operation)); } @@ -4257,7 +4257,7 @@ THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) { - DBUG_ENTER("store_lock"); + DBUG_ENTER("ha_ndbcluster::store_lock"); if (lock_type != TL_IGNORE && m_lock.type == TL_UNLOCK) { @@ -4375,7 +4375,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) { int error=0; NdbTransaction* trans= NULL; - DBUG_ENTER("external_lock"); + DBUG_ENTER("ha_ndbcluster::external_lock"); /* Check that this handler instance has a connection @@ -4591,7 +4591,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) void ha_ndbcluster::unlock_row() { - DBUG_ENTER("unlock_row"); + DBUG_ENTER("ha_ndbcluster::unlock_row"); DBUG_PRINT("info", ("Unlocking row")); m_lock_tuple= FALSE; @@ -4609,7 +4609,7 @@ void ha_ndbcluster::unlock_row() int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type) { int error=0; - DBUG_ENTER("start_stmt"); + DBUG_ENTER("ha_ndbcluster::start_stmt"); PRINT_OPTION_FLAGS(thd); Thd_ndb *thd_ndb= get_thd_ndb(thd); @@ -5446,7 +5446,7 @@ int ha_ndbcluster::create_handler_files(const char *file, size_t length, pack_length; int error= 0; - DBUG_ENTER("create_handler_files"); + DBUG_ENTER("ha_ndbcluster::create_handler_files"); if (action_flag != CHF_INDEX_FLAG) { @@ -6131,7 +6131,7 @@ void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment, { int cache_size; Uint64 auto_value; - DBUG_ENTER("get_auto_increment"); + DBUG_ENTER("ha_ndbcluster::get_auto_increment"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); Ndb *ndb= get_ndb(); @@ -6238,7 +6238,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg): { int i; - DBUG_ENTER("ha_ndbcluster"); + DBUG_ENTER("ha_ndbcluster::ha_ndbcluster"); m_tabname[0]= '\0'; m_dbname[0]= '\0'; @@ -6271,7 +6271,7 @@ ha_ndbcluster::~ha_ndbcluster() { THD *thd= current_thd; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; - DBUG_ENTER("~ha_ndbcluster"); + DBUG_ENTER("ha_ndbcluster::~ha_ndbcluster"); if (m_share) { @@ -6426,7 +6426,7 @@ void ha_ndbcluster::set_part_info(partition_info *part_info) int ha_ndbcluster::close(void) { - DBUG_ENTER("close"); + DBUG_ENTER("ha_ndbcluster::close"); THD *thd= table->in_use; Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb; /* ndb_share reference handler free */ @@ -6442,7 +6442,7 @@ int ha_ndbcluster::close(void) Thd_ndb* ha_ndbcluster::seize_thd_ndb() { Thd_ndb *thd_ndb; - DBUG_ENTER("seize_thd_ndb"); + DBUG_ENTER("ha_ndbcluster::seize_thd_ndb"); thd_ndb= new Thd_ndb(); if (thd_ndb == NULL) @@ -6468,7 +6468,7 @@ Thd_ndb* ha_ndbcluster::seize_thd_ndb() void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb) { - DBUG_ENTER("release_thd_ndb"); + DBUG_ENTER("ha_ndbcluster::release_thd_ndb"); delete thd_ndb; DBUG_VOID_RETURN; } @@ -6498,7 +6498,7 @@ Ndb* check_ndb_in_thd(THD* thd) int ha_ndbcluster::check_ndb_connection(THD* thd) { Ndb *ndb; - DBUG_ENTER("check_ndb_connection"); + DBUG_ENTER("ha_ndbcluster::check_ndb_connection"); if (!(ndb= check_ndb_in_thd(thd))) DBUG_RETURN(HA_ERR_NO_CONNECTION); @@ -7549,7 +7549,7 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key, uint key_length= key_info->key_length; NDB_INDEX_TYPE idx_type= get_index_type(inx); - DBUG_ENTER("records_in_range"); + DBUG_ENTER("ha_ndbcluster::records_in_range"); // Prevent partial read of hash indexes by returning HA_POS_ERROR if ((idx_type == UNIQUE_INDEX || idx_type == PRIMARY_KEY_INDEX) && ((min_key && min_key->length < key_length) || @@ -8509,7 +8509,7 @@ int ha_ndbcluster::write_ndb_file(const char *name) bool error=1; char path[FN_REFLEN]; - DBUG_ENTER("write_ndb_file"); + DBUG_ENTER("ha_ndbcluster::write_ndb_file"); DBUG_PRINT("enter", ("name: %s", name)); (void)strxnmov(path, FN_REFLEN-1, @@ -8553,7 +8553,7 @@ ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges, KEY_MULTI_RANGE *end_range, HANDLER_BUFFER *buffer) { - DBUG_ENTER("null_value_index_search"); + DBUG_ENTER("ha_ndbcluster::null_value_index_search"); KEY* key_info= table->key_info + active_index; KEY_MULTI_RANGE *range= ranges; ulong reclength= table->s->reclength; @@ -8948,7 +8948,7 @@ found_next: int ha_ndbcluster::setup_recattr(const NdbRecAttr* curr) { - DBUG_ENTER("setup_recattr"); + DBUG_ENTER("ha_ndbcluster::setup_recattr"); Field **field, **end; NdbValue *value= m_value; @@ -9319,7 +9319,7 @@ const COND* ha_ndbcluster::cond_push(const COND *cond) { - DBUG_ENTER("cond_push"); + DBUG_ENTER("ha_ndbcluster::cond_push"); if (!m_cond) m_cond= new ha_ndbcluster_cond; if (!m_cond) @@ -9554,7 +9554,7 @@ int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info) uint i; int error= 0; bool unsigned_flag= part_info->part_expr->unsigned_flag; - DBUG_ENTER("set_range_data"); + DBUG_ENTER("ha_ndbcluster::set_range_data"); if (!range_data) { @@ -9593,7 +9593,7 @@ int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info) uint32 *part_id, i; int error= 0; bool unsigned_flag= part_info->part_expr->unsigned_flag; - DBUG_ENTER("set_list_data"); + DBUG_ENTER("ha_ndbcluster::set_list_data"); if (!list_data) { @@ -9924,7 +9924,7 @@ int ndbcluster_alter_tablespace(handlerton *hton, int error; const char *errmsg; Ndb *ndb; - DBUG_ENTER("ha_ndbcluster::alter_tablespace"); + DBUG_ENTER("alter_tablespace"); LINT_INIT(errmsg); ndb= check_ndb_in_thd(thd); diff --git a/sql/records.cc b/sql/records.cc index 81c26da4b4d..0bf815e4073 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -55,6 +55,7 @@ static int rr_index(READ_RECORD *info); void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, bool print_error, uint idx) { + empty_record(table); bzero((char*) info,sizeof(*info)); info->table= table; info->file= table->file; @@ -161,6 +162,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, } else { + empty_record(table); info->record= table->record[0]; info->ref_length= table->file->ref_length; } diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 71cc431890b..061f931436f 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -105,7 +105,8 @@ pack_row(TABLE *table, MY_BITMAP const* cols, DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" " pack_ptr':0x%lx; bytes: %d", field->field_name, (ulong) old_pack_ptr, - (ulong) pack_ptr, pack_ptr - old_pack_ptr)); + (ulong) pack_ptr, + (int) (pack_ptr - old_pack_ptr))); } null_mask <<= 1; @@ -239,7 +240,7 @@ unpack_row(Relay_log_info const *rli, " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", f->field_name, metadata, (ulong) old_pack_ptr, (ulong) pack_ptr, - pack_ptr - old_pack_ptr)); + (int) (pack_ptr - old_pack_ptr))); } null_mask <<= 1; From 3f284594be3988a8e24d579444033f3884b8ead5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 17 Oct 2007 09:29:11 +0200 Subject: [PATCH 36/43] Removing debug variables from non-debug builds. sql/rpl_record.cc: Turning of declaration of debug variables in non-debug builds. --- sql/rpl_record.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 061f931436f..ed0dc82cf01 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -99,7 +99,9 @@ pack_row(TABLE *table, MY_BITMAP const* cols, length is stored in little-endian format, since this is the format used for the binlog. */ +#ifndef DBUG_OFF const uchar *old_pack_ptr= pack_ptr; +#endif pack_ptr= field->pack(pack_ptr, field->ptr + offset, field->max_data_length(), TRUE); DBUG_PRINT("debug", ("field: %s; pack_ptr: 0x%lx;" @@ -234,7 +236,9 @@ unpack_row(Relay_log_info const *rli, normal unpack operation. */ uint16 const metadata= tabledef->field_metadata(i); +#ifndef DBUG_OFF uchar const *const old_pack_ptr= pack_ptr; +#endif pack_ptr= f->unpack(f->ptr, pack_ptr, metadata, TRUE); DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", From 74ef292dc2480e617a6fde4feea7e6595ddbc837 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 19 Oct 2007 14:18:41 +0200 Subject: [PATCH 37/43] BUG#28618 (Skipping into the middle of a group with SQL_SLAVE_SKIP_COUNTER is possible): When skipping the beginning of a transaction starting with BEGIN, the OPTION_BEGIN flag was not set correctly, which caused the slave to not recognize that it was inside a group. This patch sets the OPTION_BEGIN flag for BEGIN, COMMIT, ROLLBACK, and XID events. It also adds checks if inside a group before decreasing the slave skip counter to zero. Begin_query_log_event was not marked that it could not end a group, which is now corrected. mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test: Correcting slave skip counter to get the correct behaviour. mysql-test/suite/rpl/r/rpl_slave_skip.result: Result change. mysql-test/suite/rpl/t/rpl_slave_skip.test: Adding tests to check that skipping works for transactions: - Skipping one group with BEGIN first - Skipping two groups with BEGIN first - Skipping one group without BEGIN first but with AUTOCOMMIT=0 - LOAD DATA INFILE under statement-based replication mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result: Result change. sql/log_event.cc: Adding checks if we're in a group when the slave skip counter is 1. In that case, we should keep going. Adding helping member function Log_event::continue_group() denoting that this event cannot end a group, and if the skip counter indicates that the group ends after this event, it should not decrease the skip counter. Query_log_event will change the OPTION_BEGIN flag for BEGIN, COMMIT, and ROLLBACK, even when skipping because of a positive skip count, and Xid_log_event will also affect the OPTION_BEGIN flag, even when being skipped. Begin_load_query_log_event cannot end a group, so it is marked to continue the group. sql/log_event.h: Adding helper function Log_event::continue_group(). sql/rpl_rli.h: Adding Relay_log_info::get_flag() to get the value of a replication flag. sql/slave.cc: Adding debug output and changing debug message. mysql-test/suite/rpl/data/rpl_bug28618.dat: New BitKeeper file ``mysql-test/suite/rpl/data/rpl_bug28618.dat'' mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt: New BitKeeper file ``mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt'' --- .../extra/rpl_tests/rpl_extraSlave_Col.test | 4 +- mysql-test/suite/rpl/data/rpl_bug28618.dat | 3 + mysql-test/suite/rpl/r/rpl_slave_skip.result | 208 +++++++++++++++ .../suite/rpl/t/rpl_slave_skip-slave.opt | 1 + mysql-test/suite/rpl/t/rpl_slave_skip.test | 239 ++++++++++++++++++ .../suite/rpl_ndb/r/rpl_ndb_extraCol.result | 2 +- sql/log_event.cc | 81 ++++-- sql/log_event.h | 25 ++ sql/rpl_rli.h | 12 + sql/slave.cc | 5 +- 10 files changed, 560 insertions(+), 20 deletions(-) create mode 100644 mysql-test/suite/rpl/data/rpl_bug28618.dat create mode 100644 mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt diff --git a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test index a4ac55cc2e8..72013fe7ce8 100644 --- a/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test +++ b/mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test @@ -736,7 +736,7 @@ connection slave; --replace_result $MASTER_MYPORT MASTER_PORT --replace_column 1 # 4 # 7 # 8 # 9 # 16 # 22 # 23 # 33 # 35 # 36 # --query_vertical SHOW SLAVE STATUS -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; --echo *** Try to insert in master **** @@ -744,6 +744,8 @@ connection master; INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); SELECT * FROM t15 ORDER BY c1; +#SHOW BINLOG EVENTS; + --echo *** Try to select from slave **** sync_slave_with_master; --replace_column 7 CURRENT_TIMESTAMP diff --git a/mysql-test/suite/rpl/data/rpl_bug28618.dat b/mysql-test/suite/rpl/data/rpl_bug28618.dat new file mode 100644 index 00000000000..b800c4dd39d --- /dev/null +++ b/mysql-test/suite/rpl/data/rpl_bug28618.dat @@ -0,0 +1,3 @@ +1|master only +2|master only +3|master only diff --git a/mysql-test/suite/rpl/r/rpl_slave_skip.result b/mysql-test/suite/rpl/r/rpl_slave_skip.result index 8e492fe4732..f89fa34e319 100644 --- a/mysql-test/suite/rpl/r/rpl_slave_skip.result +++ b/mysql-test/suite/rpl/r/rpl_slave_skip.result @@ -142,3 +142,211 @@ Last_SQL_Errno 0 Last_SQL_Error **** On Master **** DROP TABLE t1, t2; +SET SESSION BINLOG_FORMAT=ROW; +SET AUTOCOMMIT=0; +CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam; +INSERT INTO t1 VALUES (1,'master/slave'); +INSERT INTO t2 VALUES (1,'master/slave'); +INSERT INTO t3 VALUES (1,'master/slave'); +CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW +BEGIN +INSERT INTO t2 VALUES (NEW.a,NEW.b); +DELETE FROM t2 WHERE a < NEW.a; +END| +CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW +BEGIN +UPDATE t3 SET a =2, b = 'master only'; +END| +**** On Slave **** +STOP SLAVE; +**** On Master **** +UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1; +DROP TRIGGER tr1; +DROP TRIGGER tr2; +INSERT INTO t1 VALUES (3,'master/slave'); +INSERT INTO t2 VALUES (3,'master/slave'); +INSERT INTO t3 VALUES (3,'master/slave'); +SELECT * FROM t1 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t2 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t3 ORDER BY a; +a b +2 master only +3 master/slave +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t1 ORDER BY a; +a b +1 master/slave +3 master/slave +SELECT * FROM t2 ORDER BY a; +a b +1 master/slave +3 master/slave +SELECT * FROM t3 ORDER BY a; +a b +1 master/slave +3 master/slave +DROP TABLE t1, t2, t3; +**** Case 2: Row binlog format and transactional tables **** +*** On Master *** +CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb; +**** On Slave **** +STOP SLAVE; +*** On Master *** +BEGIN; +INSERT INTO t4 VALUES (2, 'master only'); +INSERT INTO t5 VALUES (2, 'master only'); +INSERT INTO t6 VALUES (2, 'master only'); +COMMIT; +BEGIN; +INSERT INTO t4 VALUES (3, 'master/slave'); +INSERT INTO t5 VALUES (3, 'master/slave'); +INSERT INTO t6 VALUES (3, 'master/slave'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +**** On Slave **** +STOP SLAVE; +*** On Master *** +BEGIN; +INSERT INTO t4 VALUES (6, 'master only'); +INSERT INTO t5 VALUES (6, 'master only'); +INSERT INTO t6 VALUES (6, 'master only'); +COMMIT; +BEGIN; +INSERT INTO t4 VALUES (7, 'master only'); +INSERT INTO t5 VALUES (7, 'master only'); +INSERT INTO t6 VALUES (7, 'master only'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +6 master only +7 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=10; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +STOP SLAVE; +SET AUTOCOMMIT=0; +INSERT INTO t4 VALUES (4, 'master only'); +INSERT INTO t5 VALUES (4, 'master only'); +INSERT INTO t6 VALUES (4, 'master only'); +COMMIT; +INSERT INTO t4 VALUES (5, 'master/slave'); +INSERT INTO t5 VALUES (5, 'master/slave'); +INSERT INTO t6 VALUES (5, 'master/slave'); +COMMIT; +SELECT * FROM t4 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +SELECT * FROM t5 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +SELECT * FROM t6 ORDER BY a; +a b +2 master only +3 master/slave +4 master only +5 master/slave +6 master only +7 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t4 ORDER BY a; +a b +3 master/slave +5 master/slave +SELECT * FROM t5 ORDER BY a; +a b +3 master/slave +5 master/slave +SELECT * FROM t6 ORDER BY a; +a b +3 master/slave +5 master/slave +DROP TABLE t4, t5, t6; +**** Case 3: Statement logging format and LOAD DATA with non-transactional table **** +*** On Master *** +CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam; +*** On Slave *** +STOP SLAVE; +*** On Master *** +SET SESSION BINLOG_FORMAT=STATEMENT; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|'; +SELECT * FROM t10 ORDER BY a; +a b +1 master only +2 master only +3 master only +*** On Slave *** +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +SELECT * FROM t10 ORDER BY a; +a b +DROP TABLE t10; diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt b/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_slave_skip-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/suite/rpl/t/rpl_slave_skip.test b/mysql-test/suite/rpl/t/rpl_slave_skip.test index b19d6a2730b..6783098fd7c 100644 --- a/mysql-test/suite/rpl/t/rpl_slave_skip.test +++ b/mysql-test/suite/rpl/t/rpl_slave_skip.test @@ -1,7 +1,9 @@ source include/master-slave.inc; +source include/have_innodb.inc; --echo **** On Slave **** connection slave; +source include/have_innodb.inc; STOP SLAVE; --echo **** On Master **** @@ -69,3 +71,240 @@ query_vertical SHOW SLAVE STATUS; connection master; DROP TABLE t1, t2; sync_slave_with_master; + +# +# More tests for BUG#28618 +# +# Case 1. +# ROW binlog format and non-transactional tables. +# Create the group of events via triggers and try to skip +# some items of that group. +# + +connection master; +SET SESSION BINLOG_FORMAT=ROW; +SET AUTOCOMMIT=0; + +CREATE TABLE t1 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t2 (a INT, b VARCHAR(20)) ENGINE=myisam; +CREATE TABLE t3 (a INT, b VARCHAR(20)) ENGINE=myisam; + +INSERT INTO t1 VALUES (1,'master/slave'); +INSERT INTO t2 VALUES (1,'master/slave'); +INSERT INTO t3 VALUES (1,'master/slave'); + +DELIMITER |; + +CREATE TRIGGER tr1 AFTER UPDATE on t1 FOR EACH ROW +BEGIN + INSERT INTO t2 VALUES (NEW.a,NEW.b); + DELETE FROM t2 WHERE a < NEW.a; +END| + +CREATE TRIGGER tr2 AFTER INSERT on t2 FOR EACH ROW +BEGIN + UPDATE t3 SET a =2, b = 'master only'; +END| + +DELIMITER ;| + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 2, b = 'master only' WHERE a = 1; +DROP TRIGGER tr1; +DROP TRIGGER tr2; +INSERT INTO t1 VALUES (3,'master/slave'); +INSERT INTO t2 VALUES (3,'master/slave'); +INSERT INTO t3 VALUES (3,'master/slave'); + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +connection master; +DROP TABLE t1, t2, t3; +sync_slave_with_master; + +--echo **** Case 2: Row binlog format and transactional tables **** + +# Create the transaction and try to skip some +# queries from one. + +--echo *** On Master *** +connection master; +CREATE TABLE t4 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t5 (a INT, b VARCHAR(20)) ENGINE=innodb; +CREATE TABLE t6 (a INT, b VARCHAR(20)) ENGINE=innodb; + +--echo **** On Slave **** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +BEGIN; +INSERT INTO t4 VALUES (2, 'master only'); +INSERT INTO t5 VALUES (2, 'master only'); +INSERT INTO t6 VALUES (2, 'master only'); +COMMIT; + +BEGIN; +INSERT INTO t4 VALUES (3, 'master/slave'); +INSERT INTO t5 VALUES (3, 'master/slave'); +INSERT INTO t6 VALUES (3, 'master/slave'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +# Test skipping two groups + +--echo **** On Slave **** +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +BEGIN; +INSERT INTO t4 VALUES (6, 'master only'); +INSERT INTO t5 VALUES (6, 'master only'); +INSERT INTO t6 VALUES (6, 'master only'); +COMMIT; + +BEGIN; +INSERT INTO t4 VALUES (7, 'master only'); +INSERT INTO t5 VALUES (7, 'master only'); +INSERT INTO t6 VALUES (7, 'master only'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=10; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +# +# And the same, but with autocommit = 0 +# +connection slave; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +connection master; +SET AUTOCOMMIT=0; + +INSERT INTO t4 VALUES (4, 'master only'); +INSERT INTO t5 VALUES (4, 'master only'); +INSERT INTO t6 VALUES (4, 'master only'); +COMMIT; + +INSERT INTO t4 VALUES (5, 'master/slave'); +INSERT INTO t5 VALUES (5, 'master/slave'); +INSERT INTO t6 VALUES (5, 'master/slave'); +COMMIT; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t4 ORDER BY a; +SELECT * FROM t5 ORDER BY a; +SELECT * FROM t6 ORDER BY a; + +connection master; +DROP TABLE t4, t5, t6; +sync_slave_with_master; + +--echo **** Case 3: Statement logging format and LOAD DATA with non-transactional table **** + +# LOAD DATA creates two events in binary log for statement binlog format. +# Try to skip the first. + +--echo *** On Master *** +connection master; +CREATE TABLE t10 (a INT, b VARCHAR(20)) ENGINE=myisam; + +--echo *** On Slave *** +sync_slave_with_master; +STOP SLAVE; +source include/wait_for_slave_to_stop.inc; + +--echo *** On Master *** +connection master; +SET SESSION BINLOG_FORMAT=STATEMENT; +exec cp ./suite/rpl/data/rpl_bug28618.dat $MYSQLTEST_VARDIR/tmp/; +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat' INTO TABLE t10 FIELDS TERMINATED BY '|'; +remove_file $MYSQLTEST_VARDIR/tmp/rpl_bug28618.dat; + +SELECT * FROM t10 ORDER BY a; + +save_master_pos; + +--echo *** On Slave *** +connection slave; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; +START SLAVE; +source include/wait_for_slave_to_start.inc; +sync_with_master; + +SELECT * FROM t10 ORDER BY a; + +connection master; +DROP TABLE t10; +sync_slave_with_master; + diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result index 2327dc7ee81..6f040d2e6ad 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); diff --git a/sql/log_event.cc b/sql/log_event.cc index 7e5cfd6a7a4..0e877252ce8 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -570,7 +570,8 @@ Log_event::do_shall_skip(Relay_log_info *rli) (ulong) server_id, (ulong) ::server_id, rli->replicate_same_server_id, rli->slave_skip_counter)); - if (server_id == ::server_id && !rli->replicate_same_server_id) + if (server_id == ::server_id && !rli->replicate_same_server_id || + rli->slave_skip_counter == 1 && rli->is_in_group()) return EVENT_SKIP_IGNORE; else if (rli->slave_skip_counter > 0) return EVENT_SKIP_COUNT; @@ -1227,6 +1228,16 @@ void Log_event::print_timestamp(IO_CACHE* file, time_t* ts) #endif /* MYSQL_CLIENT */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) +inline Log_event::enum_skip_reason +Log_event::continue_group(Relay_log_info *rli) +{ + if (rli->slave_skip_counter == 1) + return Log_event::EVENT_SKIP_IGNORE; + return Log_event::do_shall_skip(rli); +} +#endif + /************************************************************************** Query_log_event methods **************************************************************************/ @@ -2235,6 +2246,30 @@ int Query_log_event::do_update_pos(Relay_log_info *rli) } +Log_event::enum_skip_reason +Query_log_event::do_shall_skip(Relay_log_info *rli) +{ + DBUG_ENTER("Query_log_event::do_shall_skip"); + DBUG_PRINT("debug", ("query: %s; q_len: %d", query, q_len)); + DBUG_ASSERT(query && q_len > 0); + + if (rli->slave_skip_counter > 0) + { + if (strcmp("BEGIN", query) == 0) + { + thd->options|= OPTION_BEGIN; + DBUG_RETURN(Log_event::continue_group(rli)); + } + + if (strcmp("COMMIT", query) == 0 || strcmp("ROLLBACK", query) == 0) + { + thd->options&= ~OPTION_BEGIN; + DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); + } + } + DBUG_RETURN(Log_event::do_shall_skip(rli)); +} + #endif @@ -3871,10 +3906,7 @@ Intvar_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif @@ -3970,10 +4002,7 @@ Rand_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif /* !MYSQL_CLIENT */ @@ -4049,6 +4078,17 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli) "COMMIT /* implicit, from Xid_log_event */"); return end_trans(thd, COMMIT); } + +Log_event::enum_skip_reason +Xid_log_event::do_shall_skip(Relay_log_info *rli) +{ + DBUG_ENTER("Xid_log_event::do_shall_skip"); + if (rli->slave_skip_counter > 0) { + thd->options&= ~OPTION_BEGIN; + DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); + } + DBUG_RETURN(Log_event::do_shall_skip(rli)); +} #endif /* !MYSQL_CLIENT */ @@ -4427,10 +4467,7 @@ User_var_log_event::do_shall_skip(Relay_log_info *rli) that we do not change the value of the slave skip counter since it will be decreased by the following insert event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } #endif /* !MYSQL_CLIENT */ @@ -5366,6 +5403,19 @@ int Begin_load_query_log_event::get_create_or_append() const #endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) +Log_event::enum_skip_reason +Begin_load_query_log_event::do_shall_skip(Relay_log_info *rli) +{ + /* + If the slave skip counter is 1, then we should not start executing + on the next event. + */ + return continue_group(rli); +} +#endif + + /************************************************************************** Execute_load_query_log_event methods **************************************************************************/ @@ -6870,10 +6920,7 @@ Table_map_log_event::do_shall_skip(Relay_log_info *rli) If the slave skip counter is 1, then we should not start executing on the next event. */ - if (rli->slave_skip_counter == 1) - return Log_event::EVENT_SKIP_IGNORE; - else - return Log_event::do_shall_skip(rli); + return continue_group(rli); } int Table_map_log_event::do_update_pos(Relay_log_info *rli) diff --git a/sql/log_event.h b/sql/log_event.h index 05d4c70042f..9321860a062 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -870,6 +870,25 @@ public: protected: + /** + Helper function to ignore an event w.r.t. the slave skip counter. + + This function can be used inside do_shall_skip() for functions + that cannot end a group. If the slave skip counter is 1 when + seeing such an event, the event shall be ignored, the counter + left intact, and processing continue with the next event. + + A typical usage is: + @code + enum_skip_reason do_shall_skip(Relay_log_info *rli) { + return continue_group(rli); + } + @endcode + + @return Skip reason + */ + enum_skip_reason continue_group(Relay_log_info *rli); + /** Primitive to apply an event to the database. @@ -1086,6 +1105,7 @@ public: public: /* !!! Public in this patch to allow old usage */ #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + virtual enum_skip_reason do_shall_skip(Relay_log_info *rli); virtual int do_apply_event(Relay_log_info const *rli); virtual int do_update_pos(Relay_log_info *rli); @@ -1559,6 +1579,7 @@ class Xid_log_event: public Log_event private: #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) virtual int do_apply_event(Relay_log_info const *rli); + enum_skip_reason do_shall_skip(Relay_log_info *rli); #endif }; @@ -1937,6 +1958,10 @@ public: *description_event); ~Begin_load_query_log_event() {} Log_event_type get_type_code() { return BEGIN_LOAD_QUERY_EVENT; } +private: +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) + virtual enum_skip_reason do_shall_skip(Relay_log_info *rli); +#endif }; diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 10ecf1a43d4..a3a57ad4ce9 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -365,6 +365,18 @@ public: m_flags |= (1UL << flag); } + /** + Get the value of a replication state flag. + + @param flag Flag to get value of + + @return @c true if the flag was set, @c false otherwise. + */ + bool get_flag(enum_state_flag flag) + { + return m_flags & (1UL << flag); + } + /** Clear the value of a replication state flag. diff --git a/sql/slave.cc b/sql/slave.cc index fcbd4eb841b..570bf57d212 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1853,10 +1853,13 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) // EVENT_SKIP_NOT, "not skipped", // EVENT_SKIP_IGNORE, - "skipped because event originated from this server", + "skipped because event should be ignored", // EVENT_SKIP_COUNT "skipped because event skip counter was non-zero" }; + DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d", + thd->options & OPTION_BEGIN ? 1 : 0, + rli->get_flag(Relay_log_info::IN_STMT))); DBUG_PRINT("skip_event", ("%s event was %s", ev->get_type_str(), explain[reason])); #endif From 0b1c0f3173cd14181ece774cdbbf68dddedf35a7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 20 Oct 2007 18:19:55 +0200 Subject: [PATCH 38/43] Bug#31702 (Missing row on slave causes assertion failure under row-based replication): When replicating an update pair (before image, after image) under row-based replication, and the before image is not found on the slave, the after image was not discared, and was hence read as a before image for the next row. Eventually, this lead to an after image being read outside the block of rows in the event, causing an assertion to fire. This patch fixes this by reading the after image in the event that the row was not found on the slave, adds some extra debug assertion to catch future errors earlier, and also adds a few non-debug checks to prevent reading outside the block of the event. include/my_base.h: Adding error code HA_ERR_CORRUPT_EVENT. mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result: Result change. mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test: Adding test to try to use row-based replication to replicate an update of a row that doesn't exist on the slave. We should get an apropriate error and the slave should stop. sql/log_event.cc: Adding debug printouts. Adding code to Update_rows_log_event::do_exec_row() so that the after image is read (and ignored) in the event of an error in finding the row. This is necessary so that the second pair of images is read correctly for the next update pair. Changing logic for ignoring errors to not include update events, since a "key not found" error or a "record changed" error is not idempotent for updates, just for deletes and inserts. sql/log_event.h: Adding debug assertions to check that row reading is within the events block of rows. --- include/my_base.h | 8 ++-- .../suite/rpl/r/rpl_row_basic_11bugs.result | 31 ++++++++++++++++ .../suite/rpl/t/rpl_row_basic_11bugs.test | 37 +++++++++++++++++++ sql/log_event.cc | 27 +++++++++++--- sql/log_event.h | 24 +++++++++++- 5 files changed, 117 insertions(+), 10 deletions(-) diff --git a/include/my_base.h b/include/my_base.h index 339554979a8..e65a04bb16d 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -407,9 +407,11 @@ enum ha_base_keytype { #define HA_ERR_RECORD_IS_THE_SAME 169 /* row not actually updated : new values same as the old values */ -#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this - statement */ -#define HA_ERR_LAST 170 /*Copy last error nr.*/ +#define HA_ERR_LOGGING_IMPOSSIBLE 170 /* It is not possible to log this + statement */ +#define HA_ERR_CORRUPT_EVENT 171 /* The event was corrupt, leading to + illegal data being read */ +#define HA_ERR_LAST 171 /*Copy last error nr.*/ /* Add error numbers before HA_ERR_LAST and change it accordingly. */ #define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1) diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result index 7dc9926522b..5ad9ba7ced0 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result @@ -242,3 +242,34 @@ a b 3 1 4 4 drop table t1,t2; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +**** On Master **** +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave')); +INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave'); +**** On Slave **** +UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 slave +**** On Master **** +UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 master +**** On Slave **** +Last_SQL_Error +Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +SELECT * FROM t1 ORDER BY a; +a b +2 master,slave +5 slave +DROP TABLE t1; +**** On Master **** +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test index fb43664f121..f6180de52a4 100644 --- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test +++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test @@ -223,3 +223,40 @@ connection master; drop table t1,t2; sync_slave_with_master; + +# +# BUG#31702: Missing row on slave causes assertion failure under +# row-based replication +# + +disable_query_log; +source include/master-slave-reset.inc; +enable_query_log; + +--echo **** On Master **** +connection master; +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b SET('master','slave')); +INSERT INTO t1 VALUES (1,'master,slave'), (2,'master,slave'); +--echo **** On Slave **** +sync_slave_with_master; +UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1; +SELECT * FROM t1 ORDER BY a; +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; +save_master_pos; +SELECT * FROM t1 ORDER BY a; +--echo **** On Slave **** +connection slave; +source include/wait_for_slave_sql_error.inc; +let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); +disable_query_log; +eval SELECT "$last_error" AS Last_SQL_Error; +enable_query_log; +SELECT * FROM t1 ORDER BY a; +DROP TABLE t1; + +--echo **** On Master **** +connection master; +DROP TABLE t1; diff --git a/sql/log_event.cc b/sql/log_event.cc index ec4d6820cca..fd7e3e5db6b 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6173,14 +6173,19 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) table->in_use = old_thd; switch (error) { - /* Some recoverable errors */ - case HA_ERR_RECORD_CHANGED: - case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if - tuple does not exist */ - error= 0; case 0: break; + /* Some recoverable errors */ + case HA_ERR_RECORD_CHANGED: + case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if + tuple does not exist */ + if (get_type_code() != UPDATE_ROWS_EVENT) + { + error= 0; + break; + } + /* Fall through in the event that we have an update event */ default: rli->report(ERROR_LEVEL, thd->net.last_errno, "Error in %s event: row application failed. %s", @@ -6197,6 +6202,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) m_curr_row_end. */ + DBUG_PRINT("info", ("error: %d", error)); + DBUG_PRINT("info", ("curr_row: 0x%lu; curr_row_end: 0x%lu; rows_end: 0x%lu", + (ulong) m_curr_row, (ulong) m_curr_row_end, (ulong) m_rows_end)); + if (!m_curr_row_end && !error) unpack_current_row(rli); @@ -7931,7 +7940,15 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) int error= find_row(rli); if (error) + { + /* + We need to read the second image in the event of error to be + able to skip to the next pair of updates + */ + m_curr_row= m_curr_row_end; + unpack_current_row(rli); return error; + } /* This is the situation after locating BI: diff --git a/sql/log_event.h b/sql/log_event.h index 05d4c70042f..226ebc02712 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -37,6 +37,23 @@ #include "rpl_reporting.h" #endif +/** + Either assert or return an error. + + In debug build, the condition will be checked, but in non-debug + builds, the error code given will be returned instead. + + @param COND Condition to check + @param ERRNO Error number to return in non-debug builds +*/ +#ifdef DBUG_OFF +#define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \ + do { if (!(COND)) return ERRNO; } while (0) +#else +#define ASSERT_OR_RETURN_ERROR(COND, ERRNO) \ + DBUG_ASSERT(COND) +#endif + #define LOG_READ_EOF -1 #define LOG_READ_BOGUS -2 #define LOG_READ_IO -3 @@ -2316,8 +2333,11 @@ protected: int unpack_current_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table); - return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, - &m_curr_row_end, &m_master_reclength); + ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); + int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, + &m_curr_row_end, &m_master_reclength); + ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); + return result; } #endif From 219e6a6438a531802b331c69e697eec83ba8648c Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 20 Oct 2007 20:16:12 +0200 Subject: [PATCH 39/43] BUG#24860 (Incorrect SLAVE_TRANSACTION_RETRIES code can result in slave stuck): If a temporary error occured inside a group on an event that was not the first event of the group, the slave could get stuck because the retry counter is reset whenever an event was executed successfully. This patch only reset the retry counter when an entire group has been successfully executed, or failed with a non-transient error. sql/slave.cc: Adding debug printouts to every place where Relay_log_info::trans_retries is changed and to has_temporary_error() to print the error when returning. Adding debug variable all_errors_are_temporary_errors to make all errors for slave thread temporary errors. Adding code so that the Relay_log_info::trans_retries is only reset when an entire group was sucessfully executed, or a non-temporary error occured. mysql-test/suite/rpl/r/rpl_temporary_errors.result: New BitKeeper file ``mysql-test/suite/rpl/r/rpl_temporary_errors.result'' mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt: New BitKeeper file ``mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt'' mysql-test/suite/rpl/t/rpl_temporary_errors.test: New BitKeeper file ``mysql-test/suite/rpl/t/rpl_temporary_errors.test'' --- .../suite/rpl/r/rpl_temporary_errors.result | 81 +++++++++++++++++++ .../rpl/t/rpl_temporary_errors-slave.opt | 3 + .../suite/rpl/t/rpl_temporary_errors.test | 29 +++++++ sql/slave.cc | 26 ++++-- 4 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 mysql-test/suite/rpl/r/rpl_temporary_errors.result create mode 100644 mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt create mode 100644 mysql-test/suite/rpl/t/rpl_temporary_errors.test diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result new file mode 100644 index 00000000000..31c8930ec4f --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result @@ -0,0 +1,81 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +**** On Master **** +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +**** On Slave **** +SHOW STATUS LIKE 'Slave_retried_transactions'; +Variable_name Value +Slave_retried_transactions 0 +UPDATE t1 SET a = 5, b = 47 WHERE a = 1; +SELECT * FROM t1; +a b +5 47 +2 2 +3 3 +4 4 +**** On Master **** +UPDATE t1 SET a = 5, b = 5 WHERE a = 1; +SELECT * FROM t1; +a b +5 5 +2 2 +3 3 +4 4 +**** On Slave **** +SHOW STATUS LIKE 'Slave_retried_transactions'; +Variable_name Value +Slave_retried_transactions 2 +SELECT * FROM t1; +a b +5 47 +2 2 +3 3 +4 4 +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos 408 +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running No +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table # +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 1032 +Last_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Skip_Counter 0 +Exec_Master_Log_Pos 318 +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +Master_SSL_Verify_Server_Cert No +Last_IO_Errno # +Last_IO_Error # +Last_SQL_Errno 1032 +Last_SQL_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +DROP TABLE t1; +**** On Master **** +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt new file mode 100644 index 00000000000..80c171170f6 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors-slave.opt @@ -0,0 +1,3 @@ +--loose-debug="+d,all_errors_are_temporary_errors" --slave-transaction-retries=2 + + diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test new file mode 100644 index 00000000000..0ca515fff40 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test @@ -0,0 +1,29 @@ +source include/master-slave.inc; + +--echo **** On Master **** +connection master; +SET SESSION BINLOG_FORMAT=ROW; +CREATE TABLE t1 (a INT PRIMARY KEY, b INT); +INSERT INTO t1 VALUES (1,1), (2,2), (3,3), (4,4); +--echo **** On Slave **** +sync_slave_with_master; +SHOW STATUS LIKE 'Slave_retried_transactions'; +UPDATE t1 SET a = 5, b = 47 WHERE a = 1; +SELECT * FROM t1; +--echo **** On Master **** +connection master; +UPDATE t1 SET a = 5, b = 5 WHERE a = 1; +save_master_pos; +SELECT * FROM t1; +#SHOW BINLOG EVENTS; +--echo **** On Slave **** +connection slave; +source include/wait_for_slave_sql_to_stop.inc; +SHOW STATUS LIKE 'Slave_retried_transactions'; +SELECT * FROM t1; +source include/show_slave_status.inc; +DROP TABLE t1; + +--echo **** On Master **** +connection master; +DROP TABLE t1; diff --git a/sql/slave.cc b/sql/slave.cc index 9780ae70c5b..169cf897e6a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1714,7 +1714,14 @@ static int has_temporary_error(THD *thd) DBUG_ENTER("has_temporary_error"); if (thd->is_fatal_error) + { + DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno))); DBUG_RETURN(0); + } + + DBUG_EXECUTE_IF("all_errors_are_temporary_errors", + if (thd->net.last_errno) + thd->net.last_errno= ER_LOCK_DEADLOCK;); /* Temporary error codes: @@ -1723,7 +1730,10 @@ static int has_temporary_error(THD *thd) */ if (thd->net.last_errno == ER_LOCK_DEADLOCK || thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT) + { + DBUG_PRINT("info", ("thd->net.last_errno: %s", ER(thd->net.last_errno))); DBUG_RETURN(1); + } #ifdef HAVE_NDB_BINLOG /* @@ -1905,7 +1915,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) } if (slave_trans_retries) { - if (exec_res && has_temporary_error(thd)) + int temp_err; + if (exec_res && (temp_err= has_temporary_error(thd))) { const char *errmsg; /* @@ -1953,15 +1964,19 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) "the slave_transaction_retries variable.", slave_trans_retries); } - else if (!((thd->options & OPTION_BEGIN) && opt_using_transactions)) + else if (exec_res && !temp_err || + (opt_using_transactions && + rli->group_relay_log_pos == rli->event_relay_log_pos)) { /* - Only reset the retry counter if the event succeeded or - failed with a non-transient error. On a successful event, - the execution will proceed as usual; in the case of a + Only reset the retry counter if the entire group succeeded + or failed with a non-transient error. On a successful + event, the execution will proceed as usual; in the case of a non-transient error, the slave will stop with an error. */ rli->trans_retries= 0; // restart from fresh + DBUG_PRINT("info", ("Resetting retry counter, rli->trans_retries: %d", + rli->trans_retries)); } } DBUG_RETURN(exec_res); @@ -2450,6 +2465,7 @@ pthread_handler_t handle_slave_sql(void *arg) rli->ignore_log_space_limit= 0; pthread_mutex_unlock(&rli->log_space_lock); rli->trans_retries= 0; // start from "no error" + DBUG_PRINT("info", ("rli->trans_retries: %d", rli->trans_retries)); if (init_relay_log_pos(rli, rli->group_relay_log_name, From dcd1d492ba4b5c2e543bc1a4b3c2c10281cc7f99 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Oct 2007 10:32:35 +0200 Subject: [PATCH 40/43] Post-merge fixes. mysql-test/suite/rpl/r/rpl_extraCol_innodb.result: Result change mysql-test/suite/rpl/r/rpl_extraCol_myisam.result: Result change --- mysql-test/suite/rpl/r/rpl_extraCol_innodb.result | 3 ++- mysql-test/suite/rpl/r/rpl_extraCol_myisam.result | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result index fe5a5b28682..38e76a3c877 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_innodb.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); @@ -723,6 +723,7 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP *** DROP TABLE t15 *** DROP TABLE t15; *** Create t16 on slave *** diff --git a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result index e70a2efaf29..2228c68b271 100644 --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result @@ -707,7 +707,7 @@ Last_IO_Errno # Last_IO_Error # Last_SQL_Errno 1060 Last_SQL_Error Error 'Duplicate column name 'c6'' on query. Default database: 'test'. Query: 'ALTER TABLE t15 ADD COLUMN c6 INT AFTER c5' -SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; +SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; *** Try to insert in master **** INSERT INTO t15 () VALUES(5,2.00,'Replication Testing',@b1,'Buda',2); @@ -723,6 +723,7 @@ c1 c2 c3 c4 c5 c6 c7 1 1.00 Replication Testing Extra Col b1b1b1b1b1b1b1b1 Kyle 1 CURRENT_TIMESTAMP 2 2.00 This Test Should work b1b1b1b1b1b1b1b1 JOE 1 CURRENT_TIMESTAMP 3 3.00 If is does not, I will open a bug b1b1b1b1b1b1b1b1 QA 1 CURRENT_TIMESTAMP +5 2.00 Replication Testing b1b1b1b1b1b1b1b1 Buda 2 CURRENT_TIMESTAMP *** DROP TABLE t15 *** DROP TABLE t15; *** Create t16 on slave *** From ba7570b11099894bd6a80f4729da290c9c47b00c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Oct 2007 21:45:21 +0300 Subject: [PATCH 41/43] Bug #30594 rpl.rpl_skip_error is nondeterministic Non-determinism in the tests was due to results of SBR are different from those gained with row binlog format. Because tests effectively verify skipping only ER_DUP_ENTRY it is explicitly required to run the test on in mixed and stmt binlog format. ER_DUP_ENTRY is automatically ignored when happened in RBR because of implicit rule favoring reentrant reading from binlog rule which means that a Write_rows_log_event overwrites a slave's row if the one has the same primary key. If future we might have skipping error due to applying of row-based events. The comments added saying a new file would be needed for that: rpl_row_skip_error or smth. mysql-test/suite/rpl/r/rpl_skip_error.result: new results mysql-test/suite/rpl/t/rpl_skip_error-slave.opt: wrong error code that can not happen in the test removed. mysql-test/suite/rpl/t/rpl_skip_error.test: enforcing the test is to skip only errors due to SBR. The current test does not check anything for RBR as ignorable ER_DUP_ENTRY does make sense only for SBR. --- mysql-test/suite/rpl/r/rpl_skip_error.result | 3 +-- mysql-test/suite/rpl/t/rpl_skip_error-slave.opt | 2 +- mysql-test/suite/rpl/t/rpl_skip_error.test | 8 ++++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_skip_error.result b/mysql-test/suite/rpl/r/rpl_skip_error.result index 525909387b3..ed4c4a6b3bb 100644 --- a/mysql-test/suite/rpl/r/rpl_skip_error.result +++ b/mysql-test/suite/rpl/r/rpl_skip_error.result @@ -29,8 +29,7 @@ select * from t1; a 1 2 -3 show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master Master_SSL_Verify_Server_Cert Last_IO_Errno Last_IO_Error Last_SQL_Errno Last_SQL_Error -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 786 # # master-bin.000001 Yes Yes 0 0 786 # None 0 No # No 0 0 +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 851 # # master-bin.000001 Yes Yes 0 0 851 # None 0 No # No 0 0 drop table t1; diff --git a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt index c84171976a1..a8f5deaa30b 100644 --- a/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt +++ b/mysql-test/suite/rpl/t/rpl_skip_error-slave.opt @@ -1 +1 @@ ---slave-skip-error=1062,1582 +--slave-skip-error=1062 diff --git a/mysql-test/suite/rpl/t/rpl_skip_error.test b/mysql-test/suite/rpl/t/rpl_skip_error.test index b68b637b3b0..72d434d9c9b 100644 --- a/mysql-test/suite/rpl/t/rpl_skip_error.test +++ b/mysql-test/suite/rpl/t/rpl_skip_error.test @@ -3,6 +3,14 @@ ######################################### # Note that errors are ignored by opt file. source include/master-slave.inc; +source include/have_binlog_format_mixed_or_statement.inc; + +# +# Bug #30594 +# Skipping error due to applying Row-based repliation events +# should be checked with another test file +# consider names like rpl_row_skip_error +# create table t1 (n int not null primary key); save_master_pos; From 4a08f392145264021ad20908157072fbdc653908 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Oct 2007 16:02:37 +0200 Subject: [PATCH 42/43] BUG#31702 (Missing row on slave causes assertion failure under row-based replication): Incremental patch to enable idempotency support for update events again. The final handling of errors will be done in BUG#31609, and until then the handling of errors should be consistent between the different types of changes. mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result: Result change. mysql-test/suite/rpl/r/rpl_temporary_errors.result: Result change. mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test: Changing test to assume idempotency handling of update event. mysql-test/suite/rpl/t/rpl_temporary_errors.test: Changing test to assume idempotency handling of update event. sql/log_event.cc: Incremental patch to enable idempotency support for the update events again. The real error handling will be implemented in BUG#31609. --- mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result | 2 +- mysql-test/suite/rpl/r/rpl_temporary_errors.result | 14 +++++++------- mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test | 4 +--- mysql-test/suite/rpl/t/rpl_temporary_errors.test | 4 +--- sql/log_event.cc | 9 +++------ 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result index 5ad9ba7ced0..c3fd663fad8 100644 --- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result +++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result @@ -265,7 +265,7 @@ a b 5 master **** On Slave **** Last_SQL_Error -Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' + SELECT * FROM t1 ORDER BY a; a b 2 master,slave diff --git a/mysql-test/suite/rpl/r/rpl_temporary_errors.result b/mysql-test/suite/rpl/r/rpl_temporary_errors.result index 31c8930ec4f..5c681683b08 100644 --- a/mysql-test/suite/rpl/r/rpl_temporary_errors.result +++ b/mysql-test/suite/rpl/r/rpl_temporary_errors.result @@ -30,7 +30,7 @@ a b **** On Slave **** SHOW STATUS LIKE 'Slave_retried_transactions'; Variable_name Value -Slave_retried_transactions 2 +Slave_retried_transactions 0 SELECT * FROM t1; a b 5 47 @@ -49,17 +49,17 @@ Relay_Log_File # Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes -Slave_SQL_Running No +Slave_SQL_Running Yes Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table # Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1032 -Last_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Last_Errno 0 +Last_Error Skip_Counter 0 -Exec_Master_Log_Pos 318 +Exec_Master_Log_Pos 408 Relay_Log_Space # Until_Condition None Until_Log_File @@ -74,8 +74,8 @@ Seconds_Behind_Master # Master_SSL_Verify_Server_Cert No Last_IO_Errno # Last_IO_Error # -Last_SQL_Errno 1032 -Last_SQL_Error Error in Update_rows event: error during transaction execution on table test.t1. Can't find record in 't1' +Last_SQL_Errno 0 +Last_SQL_Error DROP TABLE t1; **** On Master **** DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test index f6180de52a4..07fe763eb3c 100644 --- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test +++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test @@ -245,11 +245,9 @@ SELECT * FROM t1 ORDER BY a; --echo **** On Master **** connection master; UPDATE t1 SET a = 5, b = 'master' WHERE a = 1; -save_master_pos; SELECT * FROM t1 ORDER BY a; --echo **** On Slave **** -connection slave; -source include/wait_for_slave_sql_error.inc; +sync_slave_with_master; let $last_error = query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1); disable_query_log; eval SELECT "$last_error" AS Last_SQL_Error; diff --git a/mysql-test/suite/rpl/t/rpl_temporary_errors.test b/mysql-test/suite/rpl/t/rpl_temporary_errors.test index 0ca515fff40..6a57f3cc167 100644 --- a/mysql-test/suite/rpl/t/rpl_temporary_errors.test +++ b/mysql-test/suite/rpl/t/rpl_temporary_errors.test @@ -13,12 +13,10 @@ SELECT * FROM t1; --echo **** On Master **** connection master; UPDATE t1 SET a = 5, b = 5 WHERE a = 1; -save_master_pos; SELECT * FROM t1; #SHOW BINLOG EVENTS; --echo **** On Slave **** -connection slave; -source include/wait_for_slave_sql_to_stop.inc; +sync_slave_with_master; SHOW STATUS LIKE 'Slave_retried_transactions'; SELECT * FROM t1; source include/show_slave_status.inc; diff --git a/sql/log_event.cc b/sql/log_event.cc index fd7e3e5db6b..5864433ec05 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -6180,12 +6180,9 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) case HA_ERR_RECORD_CHANGED: case HA_ERR_KEY_NOT_FOUND: /* Idempotency support: OK if tuple does not exist */ - if (get_type_code() != UPDATE_ROWS_EVENT) - { - error= 0; - break; - } - /* Fall through in the event that we have an update event */ + error= 0; + break; + default: rli->report(ERROR_LEVEL, thd->net.last_errno, "Error in %s event: row application failed. %s", From f8f8c0282aa2dcf37e9d0b600b0216159a181338 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 25 Oct 2007 11:58:18 +0200 Subject: [PATCH 43/43] WL#4078: Document binary format of binlog entries Documented some binlog events using doxygen. More will be done later. Also fixed typos in other comments and added remarks about dubious code. Only comments are affected, there is no change to the actual code. sql/log_event.cc: Fixed typos in some comments. Added remarks (as comments) about questionable code. sql/log_event.h: Documented the binary format of following binlog events: Log_event Query_log_event Muted_query_log_event Slave_log_event (partial) Load_log_event Intvar_log_event Rand_log_event Rotate_log_event (partial) sql/sql_class.h: Fixed typo in comment. --- sql/log_event.cc | 29 +- sql/log_event.h | 989 +++++++++++++++++++++++++++++++++++++++++------ sql/sql_class.h | 12 +- 3 files changed, 898 insertions(+), 132 deletions(-) diff --git a/sql/log_event.cc b/sql/log_event.cc index c0fbfb1000d..e5a26d48af9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1328,6 +1328,11 @@ static void write_str_with_code_and_len(char **dst, const char *src, bool Query_log_event::write(IO_CACHE* file) { + /** + @todo if catalog can be of length FN_REFLEN==512, then we are not + replicating it correctly, since the length is stored in a byte + /sven + */ uchar buf[QUERY_HEADER_LEN+ 1+4+ // code of flags2 and flags2 1+8+ // code of sql_mode and sql_mode @@ -1554,6 +1559,10 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, time(&end_time); exec_time = (ulong) (end_time - thd_arg->start_time); + /** + @todo this means that if we have no catalog, then it is replicated + as an existing catalog of length zero. is that safe? /sven + */ catalog_len = (catalog) ? (uint32) strlen(catalog) : 0; /* status_vars_len is set just before writing the event */ db_len = (db) ? (uint32) strlen(db) : 0; @@ -1563,7 +1572,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, /* If we don't use flags2 for anything else than options contained in thd_arg->options, it would be more efficient to flags2=thd_arg->options - (OPTIONS_WRITTEN_TO_BINLOG would be used only at reading time). + (OPTIONS_WRITTEN_TO_BIN_LOG would be used only at reading time). But it's likely that we don't want to use 32 bits for 3 bits; in the future we will probably want to reclaim the 29 bits. So we need the &. */ @@ -1764,6 +1773,11 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, DBUG_VOID_RETURN; if (catalog_len) // If catalog is given { + /** + @todo we should clean up and do only copy_str_and_move; it + works for both cases. Then we can remove the catalog_nz + flag. /sven + */ if (likely(catalog_nz)) // true except if event comes from 5.0.0|1|2|3. copy_str_and_move(&catalog, &start, catalog_len); else @@ -1776,6 +1790,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len, if (time_zone_len) copy_str_and_move(&time_zone_str, &start, time_zone_len); + /** + if time_zone_len or catalog_len are 0, then time_zone and catalog + are uninitialized at this point. shouldn't they point to the + zero-length null-terminated strings we allocated space for in the + my_alloc call above? /sven + */ + /* A 2nd variable part; this is common to all versions */ memcpy((char*) start, end, data_len); // Copy db and query start[data_len]= '\0'; // End query with \0 (For safetly) @@ -2836,7 +2857,7 @@ uint Load_log_event::get_query_buffer_length() 21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" 23 + sql_ex.enclosed_len*4 + 2 + // " OPTIONALLY ENCLOSED BY 'str'" 12 + sql_ex.escaped_len*4 + 2 + // " ESCAPED BY 'str'" - 21 + sql_ex.line_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'" + 21 + sql_ex.line_term_len*4 + 2 + // " LINES TERMINATED BY 'str'" 19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'" 15 + 22 + // " IGNORE xxx LINES" 3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)" @@ -5654,6 +5675,10 @@ bool sql_ex_info::write_data(IO_CACHE* file) } else { + /** + @todo This is sensitive to field padding. We should write a + char[7], not an old_sql_ex. /sven + */ old_sql_ex old_ex; old_ex.field_term= *field_term; old_ex.enclosed= *enclosed; diff --git a/sql/log_event.h b/sql/log_event.h index f1f90aee69f..ab2424d8466 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -18,8 +18,10 @@ @{ @file - - Binary log event definitions. + + @brief Binary log event definitions. This includes generic code + common to all types of log events, as well as specific code for each + type of log event. */ @@ -411,15 +413,19 @@ struct sql_ex_info #define LOG_EVENT_BINLOG_IN_USE_F 0x1 -/* - If the query depends on the thread (for example: TEMPORARY TABLE). - Currently this is used by mysqlbinlog to know it must print - SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it - for every query but this would be slow). +/** + @def LOG_EVENT_THREAD_SPECIFIC_F + + If the query depends on the thread (for example: TEMPORARY TABLE). + Currently this is used by mysqlbinlog to know it must print + SET @@PSEUDO_THREAD_ID=xx; before the query (it would not hurt to print it + for every query but this would be slow). */ #define LOG_EVENT_THREAD_SPECIFIC_F 0x4 -/* +/** + @def LOG_EVENT_SUPPRESS_USE_F + Suppress the generation of 'USE' statements before the actual statement. This flag should be set for any events that does not need the current database set to function correctly. Most notable cases @@ -438,23 +444,26 @@ struct sql_ex_info */ #define LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F 0x10 -/* - OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must be - written to the binlog. OPTIONS_WRITTEN_TO_BINLOG could be written - into the Format_description_log_event, so that if later we don't want - to replicate a variable we did replicate, or the contrary, it's - doable. But it should not be too hard to decide once for all of what - we replicate and what we don't, among the fixed 32 bits of - thd->options. - I (Guilhem) have read through every option's usage, and it looks like - OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only ones - which alter how the query modifies the table. It's good to replicate - OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the slave may - insert data slower than the master, in InnoDB. - OPTION_BIG_SELECTS is not needed (the slave thread runs with - max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed - either, as the manual says (because a too big in-memory temp table is - automatically written to disk). +/** + @def OPTIONS_WRITTEN_TO_BIN_LOG + + OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must + be written to the binlog. OPTIONS_WRITTEN_TO_BIN_LOG could be + written into the Format_description_log_event, so that if later we + don't want to replicate a variable we did replicate, or the + contrary, it's doable. But it should not be too hard to decide once + for all of what we replicate and what we don't, among the fixed 32 + bits of thd->options. + + I (Guilhem) have read through every option's usage, and it looks + like OPTION_AUTO_IS_NULL and OPTION_NO_FOREIGN_KEYS are the only + ones which alter how the query modifies the table. It's good to + replicate OPTION_RELAXED_UNIQUE_CHECKS too because otherwise, the + slave may insert data slower than the master, in InnoDB. + OPTION_BIG_SELECTS is not needed (the slave thread runs with + max_join_size=HA_POS_ERROR) and OPTION_BIG_TABLES is not needed + either, as the manual says (because a too big in-memory temp table + is automatically written to disk). */ #define OPTIONS_WRITTEN_TO_BIN_LOG \ (OPTION_AUTO_IS_NULL | OPTION_NO_FOREIGN_KEY_CHECKS | \ @@ -469,6 +478,11 @@ struct sql_ex_info #endif #undef EXPECTED_OPTIONS /* You shouldn't use this one */ +/** + @enum Log_event_type + + Enumeration type for the different types of log events. +*/ enum Log_event_type { /* @@ -629,13 +643,90 @@ typedef struct st_print_event_info #endif -/***************************************************************************** - - Log_event class +/** + @class Log_event This is the abstract base class for binary log events. + + @section Log_event_binary_format Binary Format - ****************************************************************************/ + Any Log_event saved on disk consists of the following three + components. + + @li Common-Header + @li Post-Header + @li Body + + The Common-Header, documented below, always has the same form and + length within one version of MySQL. Each event type specifies a + form and length of the Post-Header common to all events of the type. + The Body may be of different form and length even for different + events of the same type. The binary formats of Post-Header and Body + are documented separately in each subclass. The binary format of + Common-Header is as follows. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Common-Header
NameFormat
Description
timestamp4 byte unsigned integerThe number of seconds since 1970. +
type1 byte enumerationSee enum #Log_event_type.
master_id4 byte integerServer ID of the server that created the event.
total_size4 byte integerThe total size of this event, in bytes. In other words, this + is the sum of the sizes of Common-Header, Post-Header, and Body. +
master_position4 byte integerThe position of the next event in the master binary log, in + bytes from the beginning of the file. +
flags2 byte bitfieldSee Log_event::flags.
+ + Summing up the numbers above, we see that the total size of the + common header is 19 bytes. + + @subsection Log_event_endianness_and_string_formats Endianness and String Formats + + All numbers, whether they are 16-, 32-, or 64-bit, are stored in + little endian, i.e., the least significant byte first. + + Strings are stored in various formats. The format of each string is + documented separately. +*/ class Log_event { public: @@ -709,8 +800,8 @@ public: */ uint32 server_id; - /* - Some 16 flags. Look above for LOG_EVENT_TIME_F, + /** + Some 16 flags. See the definitions above for LOG_EVENT_TIME_F, LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F, and LOG_EVENT_SUPPRESS_USE_F for notes. */ @@ -986,6 +1077,7 @@ protected: #endif }; + /* One class for each type of event. Two constructors for each class: @@ -999,13 +1091,332 @@ protected: mysqlbinlog. This constructor must be format-tolerant. */ -/***************************************************************************** +/** + @class Query_log_event + + Logs SQL queries. - Query Log Event class + @section Query_log_event_binary_format Binary format - Logs SQL queries + The Post-Header has five components: - ****************************************************************************/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Query_log_event
NameSize
Description
slave_proxy_id4 byte unsigned integerAn integer identifying the client thread, which is unique on + the server. (Note, however, that two threads on different servers + may have the same slave_proxy_id.) This is used when a client + thread creates a temporary table. Temporary tables are local to + the client, and the slave_proxy_id is used to distinguish + temporary tables belonging to different clients. +
exec_time4 byte integer???TODO
db_len1 byte integerThe length of the name of the currently selected + database. +
error_code2 byte integerError code generated by the master. If the master fails, the + slave will fail with the same error code, except for the error + codes ER_DB_CREATE_EXISTS==1007 and ER_DB_DROP_EXISTS==1008. +
status_vars_len2 byte integerThe length of the status_vars block of the Body, in bytes. See + below. +
Post-Header-For-Derived0 bytesThis field is only written by the subclass + Execute_load_query_log_event. In this base class, it takes 0 + bytes. See separate documentation for + Execute_load_query_log_event. +
+ + The Body has the following components: + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body for Query_log_event
NameSize
Description
status_varsvariable lengthZero or more status variables. Each status variable consists + of one byte identifying the variable stored, followed by the value + of the variable. The possible variables are listed separately in + the table below. MySQL always writes events in the order defined + below; however, it is capable of reading them in any order. +
dbdb_len+1The currently selected database, as a null-terminated string. + + (The trailing zero is redundant since the length is already known; + it is db_len from Post-Header.) +
queryvariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + The SQL query.
+ + The following table lists the status variables that may appear in + the status_vars field. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Status variables for Query_log_event
Status variable1-byte identifierSize
Description
flags2Q_FLAGS2_CODE == 04 byte bitfieldThe flags in thd->options, binary AND-ed with + OPTIONS_WRITTEN_TO_BIN_LOG. The thd->options bitfield contains + options for SELECT. OPTIONS_WRITTEN identifies those options that + need to be written to the binlog (not all do). Specifically, + OPTIONS_WRITTEN_TO_BIN_LOG equals (OPTION_AUTO_IS_NULL | + OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS | + OPTION_NOT_AUTOCOMMIT), or 0x0c084000 in hex. + + These flags correspond to the SQL variables SQL_AUTO_IS_NULL, + FOREIGN_KEY_CHECKS, UNIQUE_CHECKS, and AUTOCOMMIT, documented in + the "SET Syntax" section of the MySQL Manual. + + This field is always written to the binlog in version >= 5.0, and + never written in version < 5.0. +
sql_modeQ_SQL_MODE_CODE == 18 byte integerThe sql_mode variable. See the section "SQL Modes" in the + MySQL manual, and see mysql_priv.h for a list of the possible + flags. Currently (2007-10-04), the following flags are available: +
+    MODE_REAL_AS_FLOAT==0x1
+    MODE_PIPES_AS_CONCAT==0x2
+    MODE_ANSI_QUOTES==0x4
+    MODE_IGNORE_SPACE==0x8
+    MODE_NOT_USED==0x10
+    MODE_ONLY_FULL_GROUP_BY==0x20
+    MODE_NO_UNSIGNED_SUBTRACTION==0x40
+    MODE_NO_DIR_IN_CREATE==0x80
+    MODE_POSTGRESQL==0x100
+    MODE_ORACLE==0x200
+    MODE_MSSQL==0x400
+    MODE_DB2==0x800
+    MODE_MAXDB==0x1000
+    MODE_NO_KEY_OPTIONS==0x2000
+    MODE_NO_TABLE_OPTIONS==0x4000
+    MODE_NO_FIELD_OPTIONS==0x8000
+    MODE_MYSQL323==0x10000
+    MODE_MYSQL323==0x20000
+    MODE_MYSQL40==0x40000
+    MODE_ANSI==0x80000
+    MODE_NO_AUTO_VALUE_ON_ZERO==0x100000
+    MODE_NO_BACKSLASH_ESCAPES==0x200000
+    MODE_STRICT_TRANS_TABLES==0x400000
+    MODE_STRICT_ALL_TABLES==0x800000
+    MODE_NO_ZERO_IN_DATE==0x1000000
+    MODE_NO_ZERO_DATE==0x2000000
+    MODE_INVALID_DATES==0x4000000
+    MODE_ERROR_FOR_DIVISION_BY_ZERO==0x8000000
+    MODE_TRADITIONAL==0x10000000
+    MODE_NO_AUTO_CREATE_USER==0x20000000
+    MODE_HIGH_NOT_PRECEDENCE==0x40000000
+    MODE_PAD_CHAR_TO_FULL_LENGTH==0x80000000
+    
+ All these flags are replicated from the server. However, all + flags except MODE_NO_DIR_IN_CREATE are honored by the slave; the + slave always preserves its old value of MODE_NO_DIR_IN_CREATE. + For a rationale, see comment in Query_log_event::do_apply_event in + log_event.cc. + + This field is always written to the binlog. +
catalogQ_CATALOG_NZ_CODE == 6Variable-length string: the length in bytes (1 byte) followed + by the characters (at most 255 bytes) + Stores the client's current catalog. Every database belongs + to a catalog, the same way that every table belongs to a + database. Currently, there is only one catalog, 'std'. + + This field is written if the length of the catalog is > 0; + otherwise it is not written. +
auto_incrementQ_AUTO_INCREMENT == 3two 2 byte unsigned integers, totally 2+2=4 bytesThe two variables auto_increment_increment and + auto_increment_offset, in that order. For more information, see + "System variables" in the MySQL manual. + + This field is written if auto_increment>1; otherwise it is not + written. +
charsetQ_CHARSET_CODE == 4three 2-byte unsigned integers (i.e., 6 bytes)The three variables character_set_client, + collation_connection, and collation_server, in that order. + `character_set_client' is a code identifying the character set and + collation used by the client to encode the query. + `collation_connection' identifies the character set and collation + that the master converts the query to when it receives it; this is + useful when comparing literal strings. `collation_server' is the + default character set and collation used when a new database is + created. + + See also "Connection Character Sets and Collations" in the MySQL + 5.1 manual. + + All three variables are codes identifying a (character set, + collation) pair. To see which codes map to which pairs, run the + query "SELECT id, character_set_name, collation_name FROM + COLLATIONS". + + Cf. Q_CHARSET_DATABASE_NUMBER below. + + This field is always written. +
time_zoneQ_TIME_ZONE_CODE == 5Variable-length string: the length in bytes (1 byte) followed + by the characters (at most 255 bytes). + The time_zone of the master. + + See also "System Variables" and "MySQL Server Time Zone Support" + in the MySQL manual. + + This field is written if the length of the time zone string is > + 0; otherwise, it is not written. +
lc_time_names_numberQ_LC_TIME_NAMES_CODE == 72 byte integerA code identifying a table of month and day names. The + mapping from codes to languages is defined in sql_locale.cc. + + This field is written if it is != 0, i.e., if the locale is not + en_US. +
charset_database_numberQ_CHARSET_DATABASE_NUMBER == 82 byte integerThe value of the collation_database system variable (in the + source code stored in thd->variables.collation_database), which + holds the code for a (character set, collation) pair as described + above (see Q_CHARSET_CODE). + + `collation_database' was used in old versions (???WHEN). Its + value was loaded when issuing a "use db" command and could be + changed by issuing a "SET collation_database=xxx" command. It + used to affect the "LOAD DATA INFILE" and "CREATE TABLE" commands. + + In newer versions, "CREATE TABLE" has been changed to take the + character set from the database of the created table, rather than + the database of the current database. This makes a difference + when creating a table in another database than the current one. + "LOAD DATA INFILE" has not yet changed to do this, but there are + plans to eventually do it, and to make collation_database + read-only. + + This field is written if it is not 0. +
+ + @subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions + + @li Status vars were introduced in version 5.0. To read earlier + versions correctly, check the length of the Post-Header. + + @li The status variable Q_CATALOG_CODE == 2 existed in MySQL 5.0.x, + where 0<=x<=3. It was identical to Q_CATALOG_CODE, except that the + string had a trailing '\0'. The '\0' was removed in 5.0.4 since it + was redundant (the string length is stored before the string). The + Q_CATALOG_CODE will never be written by a new master, but can still + be understood by a new slave. + + @li See Q_CHARSET_DATABASE_NUMBER in the table above. + +*/ class Query_log_event: public Log_event { protected: @@ -1063,7 +1474,7 @@ public: /* 'flags2' is a second set of flags (on top of those in Log_event), for session variables. These are thd->options which is & against a mask - (OPTIONS_WRITTEN_TO_BINLOG). + (OPTIONS_WRITTEN_TO_BIN_LOG). flags2_inited helps make a difference between flags2==0 (3.23 or 4.x master, we don't know flags2, so use the slave server's global options) and flags2==0 (5.0 master, we know this has a meaning of flags all down which @@ -1133,13 +1544,16 @@ public: /* !!! Public in this patch to allow old usage */ }; -/***************************************************************************** +/** + @class Muted_query_log_event - Muted Query Log Event class + Pretends to log SQL queries, but doesn't actually do so. - Pretends to Log SQL queries, but doesn't actually do so. + @section Muted_query_log_event_binary_format Binary Format - ****************************************************************************/ + This log event is not stored, and thus the binary format is 0 bytes + long. Note that not even the Common-Header is stored. +*/ class Muted_query_log_event: public Query_log_event { public: @@ -1156,14 +1570,54 @@ public: #ifdef HAVE_REPLICATION -/***************************************************************************** +/** + @class Slave_log_event - Slave Log Event class Note that this class is currently not used at all; no code writes a - Slave_log_event (though some code in repl_failsafe.cc reads Slave_log_event). - So it's not a problem if this code is not maintained. + Slave_log_event (though some code in repl_failsafe.cc reads + Slave_log_event). So it's not a problem if this code is not + maintained. - ****************************************************************************/ + @section Slave_log_event_binary_format Binary Format + + This event type has no Post-Header. The Body has the following + four components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body for Slave_log_event
NameSize
Description
master_pos8 byte integer???TODO +
master_port2 byte integer???TODO
master_hostnull-terminated string???TODO
master_lognull-terminated string???TODO
+*/ class Slave_log_event: public Log_event { protected: @@ -1202,11 +1656,202 @@ private: #endif /* HAVE_REPLICATION */ -/***************************************************************************** +/** + @class Load_log_event - Load Log Event class + This log event corresponds to a "LOAD DATA INFILE" SQL query on the + following form: - ****************************************************************************/ + @verbatim + (1) USE db; + (2) LOAD DATA [LOCAL] INFILE 'file_name' + (3) [REPLACE | IGNORE] + (4) INTO TABLE 'table_name' + (5) [FIELDS + (6) [TERMINATED BY 'field_term'] + (7) [[OPTIONALLY] ENCLOSED BY 'enclosed'] + (8) [ESCAPED BY 'escaped'] + (9) ] + (10) [LINES + (11) [TERMINATED BY 'line_term'] + (12) [LINES STARTING BY 'line_start'] + (13) ] + (14) [IGNORE skip_lines LINES] + (15) (field_1, field_2, ..., field_n)@endverbatim + + @section Load_log_event_binary_format Binary Format + + The Post-Header consists of the following six components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Load_log_event
NameSize
Description
slave_proxy_id4 byte unsigned integerAn integer identifying the client thread, which is unique on + the server. (Note, however, that the same slave_proxy_id may + appear on different servers.) This is used when a client thread + creates a temporary table. Temporary tables are local to the + client, and the slave_proxy_id is used to distinguish temporary + tables belonging to different clients. +
exec_time4 byte unsigned integer???TODO
skip_lines4 byte unsigned integerThe number on line (14) above, if present, or 0 if line (14) + is left out. +
table_name_len1 byte unsigned integerThe length of 'table_name' on line (4) above.
db_len1 byte unsigned integerThe length of 'db' on line (1) above.
num_fields4 byte unsigned integerThe number n of fields on line (15) above.
+ + The Body contains the following components. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Body of Load_log_event
NameSize
Description
sql_exvariable lengthDescribes the part of the query on lines (3) and + (5)–(13) above. More precisely, it stores the five strings + (on lines) field_term (6), enclosed (7), escaped (8), line_term + (11), and line_start (12); as well as a bitfield indicating the + presence of the keywords REPLACE (3), IGNORE (3), and OPTIONALLY + (7). + + The data is stored in one of two formats, called "old" and "new". + The type field of Common-Header determines which of these two + formats is used: type LOAD_EVENT means that the old format is + used, and type NEW_LOAD_EVENT means that the new format is used. + When MySQL writes a Load_log_event, it uses the new format if at + least one of the five strings is two or more bytes long. + Otherwise (i.e., if all strings are 0 or 1 bytes long), the old + format is used. + + The new and old format differ in the way the five strings are + stored. + +
    +
  • In the new format, the strings are stored in the order + field_term, enclosed, escaped, line_term, line_start. Each string + consists of a length (1 byte), followed by a sequence of + characters (0-255 bytes). Finally, a boolean combination of the + following flags is stored in 1 byte: REPLACE_FLAG==0x4, + IGNORE_FLAG==0x8, and OPT_ENCLOSED_FLAG==0x2. If a flag is set, + it indicates the presence of the corresponding keyword in the SQL + query. + +
  • In the old format, we know that each string has length 0 or + 1. Therefore, only the first byte of each string is stored. The + order of the strings is the same as in the new format. These five + bytes are followed by the same 1-byte bitfield as in the new + format. Finally, a 1 byte bitfield called empty_flags is stored. + The low 5 bits of empty_flags indicate which of the five strings + have length 0. For each of the following flags that is set, the + corresponding string has length 0; for the flags that are not set, + the string has length 1: FIELD_TERM_EMPTY==0x1, + ENCLOSED_EMPTY==0x2, LINE_TERM_EMPTY==0x4, LINE_START_EMPTY==0x8, + ESCAPED_EMPTY==0x10. +
+ + Thus, the size of the new format is 6 bytes + the sum of the sizes + of the five strings. The size of the old format is always 7 + bytes. +
field_lensnum_fields 1-byte unsigned integersAn array of num_fields integers representing the length of + each field in the query. (num_fields is from the Post-Header). +
fieldsnum_fields null-terminated stringsAn array of num_fields null-terminated strings, each + representing a field in the query. (The trailing zero is + redundant, since the length are stored in the num_fields array.) + The total length of all strings equals to the sum of all + field_lens, plus num_fields bytes for all the trailing zeros. +
table_namenull-terminated string of length table_len+1 bytesThe 'table_name' from the query, as a null-terminated string. + (The trailing zero is actually redundant since the table_len is + known from Post-Header.) +
dbnull-terminated string of length db_len+1 bytesThe 'db' from the query, as a null-terminated string. + (The trailing zero is actually redundant since the db_len is known + from Post-Header.) +
file_namevariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + The 'file_name' from the query. +
+ + @subsection Load_log_event_notes_on_previous_versions Notes on Previous Versions + +*/ class Load_log_event: public Log_event { private: @@ -1313,9 +1958,8 @@ public: /* !!! Public in this patch to allow old usage */ extern char server_version[SERVER_VERSION_LENGTH]; -/***************************************************************************** - - Start Log Event_v3 class +/** + @class Start_log_event_v3 Start_log_event_v3 is the Start_log_event of binlog format 3 (MySQL 3.23 and 4.x). @@ -1325,8 +1969,8 @@ extern char server_version[SERVER_VERSION_LENGTH]; MySQL 5.0 whenever it starts sending a new binlog if the requested position is >4 (otherwise if ==4 the event will be sent naturally). - ****************************************************************************/ - + @section Start_log_event_v3_binary_format Binary Format +*/ class Start_log_event_v3: public Log_event { public: @@ -1409,10 +2053,14 @@ protected: }; -/* - For binlog version 4. - This event is saved by threads which read it, as they need it for future - use (to decode the ordinary events). +/** + @class Format_description_log_event + + For binlog version 4. + This event is saved by threads which read it, as they need it for future + use (to decode the ordinary events). + + @section Format_description_log_event_binary_format Binary Format */ class Format_description_log_event: public Start_log_event_v3 @@ -1466,13 +2114,41 @@ protected: }; -/***************************************************************************** +/** + @class Intvar_log_event - Intvar Log Event class + Logs special variables related to auto_increment values. - Logs special variables such as auto_increment values + @section Intvar_log_event_binary_format Binary Format - ****************************************************************************/ + The Post-Header has two components: + + + + + + + + + + + + + + + + + + + + + + +
Post-Header for Intvar_log_event
NameSize
Description
Type1 byte enumerationOne byte identifying the type of variable stored. Currently, + two identifiers are supported: LAST_INSERT_ID_EVENT==1 and + INSERT_ID_EVENT==2. +
value8 byte unsigned integerThe value of the variable.
+*/ class Intvar_log_event: public Log_event { @@ -1511,16 +2187,24 @@ private: }; -/***************************************************************************** - - Rand Log Event class +/** + @class Rand_log_event Logs random seed used by the next RAND(), and by PASSWORD() in 4.1.0. 4.1.1 does not need it (it's repeatable again) so this event needn't be written in 4.1.1 for PASSWORD() (but the fact that it is written is just a waste, it does not cause bugs). - ****************************************************************************/ + @section Rand_log_event_binary_format Binary Format + This event type has no Post-Header. The Body of this event type has + two components: + + @li seed1 (8 bytes): 64 bit random seed1. + @li seed2 (8 bytes): 64 bit random seed2. + + The state of the random number generation consists of 128 bits, + which are stored internally as two 64-bit numbers. +*/ class Rand_log_event: public Log_event { @@ -1557,14 +2241,14 @@ private: #endif }; -/***************************************************************************** - - Xid Log Event class +/** + @class Xid_log_event Logs xid of the transaction-to-be-committed in the 2pc protocol. Has no meaning in replication, slaves ignore it. - ****************************************************************************/ + @section Xid_log_event_binary_format Binary Format +*/ #ifdef MYSQL_CLIENT typedef ulonglong my_xid; // this line is the same as in handler.h #endif @@ -1600,14 +2284,14 @@ private: #endif }; -/***************************************************************************** - - User var Log Event class +/** + @class User_var_log_event Every time a query uses the value of a user variable, a User_var_log_event is written before the Query_log_event, to set the user variable. - ****************************************************************************/ + @section User_var_log_event_binary_format Binary Format +*/ class User_var_log_event: public Log_event { @@ -1649,11 +2333,14 @@ private: }; -/***************************************************************************** +/** + @class Stop_log_event - Stop Log Event class + @section Stop_log_event_binary_format Binary Format - ****************************************************************************/ + The Post-Header and Body for this event type are empty; it only has + the Common-Header. +*/ class Stop_log_event: public Log_event { public: @@ -1689,13 +2376,54 @@ private: #endif }; -/***************************************************************************** - - Rotate Log Event class +/** + @class Rotate_log_event This will be deprecated when we move to using sequence ids. - ****************************************************************************/ + @section Rotate_log_event_binary_format Binary Format + + The Post-Header has one component: + + + + + + + + + + + + + + + + +
Post-Header for Rotate_log_event
NameSize
Description
pos8 byte integer???TODO
+ + The Body has one component: + + + + + + + + + + + + + + + + +
Body for Rotate_log_event
NameSize
Description
new_log_identvariable length string without trailing zero, extending to the + end of the event (determined by the length field of the + Common-Header) + ???TODO
+*/ class Rotate_log_event: public Log_event { @@ -1742,9 +2470,11 @@ private: /* the classes below are for the new LOAD DATA INFILE logging */ -/***************************************************************************** - Create File Log Event class - ****************************************************************************/ +/** + @class Create_file_log_event + + @section Create_file_log_event_binary_format Binary Format +*/ class Create_file_log_event: public Load_log_event { @@ -1813,11 +2543,11 @@ private: }; -/***************************************************************************** +/** + @class Append_block_log_event - Append Block Log Event class - - ****************************************************************************/ + @section Append_block_log_event_binary_format Binary Format +*/ class Append_block_log_event: public Log_event { @@ -1868,11 +2598,11 @@ private: }; -/***************************************************************************** +/** + @class Delete_file_log_event - Delete File Log Event class - - ****************************************************************************/ + @section Delete_file_log_event_binary_format Binary Format +*/ class Delete_file_log_event: public Log_event { @@ -1909,11 +2639,11 @@ private: }; -/***************************************************************************** +/** + @class Execute_load_log_event - Execute Load Log Event class - - ****************************************************************************/ + @section Delete_file_log_event_binary_format Binary Format +*/ class Execute_load_log_event: public Log_event { @@ -1949,15 +2679,15 @@ private: }; -/*************************************************************************** - - Begin load query Log Event class +/** + @class Begin_load_query_log_event Event for the first block of file to be loaded, its only difference from Append_block event is that this event creates or truncates existing file before writing data. -****************************************************************************/ + @section Begin_load_query_log_event_binary_format Binary Format +*/ class Begin_load_query_log_event: public Append_block_log_event { public: @@ -1988,15 +2718,15 @@ private: enum enum_load_dup_handling { LOAD_DUP_ERROR= 0, LOAD_DUP_IGNORE, LOAD_DUP_REPLACE }; -/**************************************************************************** - - Execute load query Log Event class +/** + @class Execute_load_query_log_event Event responsible for LOAD DATA execution, it similar to Query_log_event but before executing the query it substitutes original filename in LOAD DATA query with name of temporary file. -****************************************************************************/ + @section Execute_load_query_log_event_binary_format Binary Format +*/ class Execute_load_query_log_event: public Query_log_event { public: @@ -2048,6 +2778,11 @@ private: #ifdef MYSQL_CLIENT +/** + @class Unknown_log_event + + @section Unknown_log_event_binary_format Binary Format +*/ class Unknown_log_event: public Log_event { public: @@ -2068,14 +2803,14 @@ public: #endif char *str_to_hex(char *to, const char *from, uint len); -/***************************************************************************** - - Table map log event class +/** + @class Table_map_log_event Create a mapping from a (database name, table name) couple to a table identifier (an integer number). - ****************************************************************************/ + @section Table_map_log_event_binary_format Binary Format +*/ class Table_map_log_event : public Log_event { public: @@ -2185,9 +2920,8 @@ private: }; -/***************************************************************************** - - Row level log event class. +/** + @class Rows_log_event Common base class for all row-containing log events. @@ -2197,7 +2931,8 @@ private: - Write data header and data body to an IO_CACHE. - Provide an interface for adding an individual row to the event. - ****************************************************************************/ + @section Rows_log_event_binary_format Binary Format +*/ class Rows_log_event : public Log_event @@ -2428,15 +3163,15 @@ private: friend class Old_rows_log_event; }; -/***************************************************************************** - - Write row log event class +/** + @class Write_rows_log_event Log row insertions and updates. The event contain several insert/update rows for a table. Note that each event contains only rows for one table. - ****************************************************************************/ + @section Write_rows_log_event_binary_format Binary Format +*/ class Write_rows_log_event : public Rows_log_event { public: @@ -2483,9 +3218,8 @@ private: }; -/***************************************************************************** - - Update rows log event class +/** + @class Update_rows_log_event Log row updates with a before image. The event contain several update rows for a table. Note that each event contains only rows for @@ -2494,7 +3228,8 @@ private: Also note that the row data consists of pairs of row data: one row for the old data and one row for the new data. - ****************************************************************************/ + @section Update_rows_log_event_binary_format Binary Format +*/ class Update_rows_log_event : public Rows_log_event { public: @@ -2556,9 +3291,8 @@ protected: #endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */ }; -/***************************************************************************** - - Delete rows log event class. +/** + @class Delete_rows_log_event Log row deletions. The event contain several delete rows for a table. Note that each event contains only rows for one table. @@ -2575,7 +3309,8 @@ protected: Row_reader Extract the rows from the event. - ****************************************************************************/ + @section Delete_rows_log_event_binary_format Binary Format +*/ class Delete_rows_log_event : public Rows_log_event { public: @@ -2625,6 +3360,8 @@ protected: #include "log_event_old.h" /** + @class Incident_log_event + Class representing an incident, an occurance out of the ordinary, that happened on the master. @@ -2636,7 +3373,7 @@ protected: Incident event format Symbol - Size
(bytes) + Size
(bytes) Description @@ -2655,7 +3392,9 @@ protected: The message, if present. Not null terminated. - */ + + @section Delete_rows_log_event_binary_format Binary Format +*/ class Incident_log_event : public Log_event { public: #ifndef MYSQL_CLIENT diff --git a/sql/sql_class.h b/sql/sql_class.h index 1b07ab08d32..2084fbcb7ed 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1263,14 +1263,16 @@ public: We follow this logic: - when stmt starts, first_successful_insert_id_in_prev_stmt contains the first insert id successfully inserted by the previous stmt. - - as stmt makes progress, handler::insert_id_for_cur_row changes; every - time get_auto_increment() is called, auto_inc_intervals_for_binlog is - augmented with the reserved interval (if statement-based binlogging). + - as stmt makes progress, handler::insert_id_for_cur_row changes; + every time get_auto_increment() is called, + auto_inc_intervals_in_cur_stmt_for_binlog is augmented with the + reserved interval (if statement-based binlogging). - at first successful insertion of an autogenerated value, first_successful_insert_id_in_cur_stmt is set to handler::insert_id_for_cur_row. - - when stmt goes to binlog, auto_inc_intervals_for_binlog is - binlogged if non-empty. + - when stmt goes to binlog, + auto_inc_intervals_in_cur_stmt_for_binlog is binlogged if + non-empty. - when stmt ends, first_successful_insert_id_in_prev_stmt is set to first_successful_insert_id_in_cur_stmt. */