From: Martin Skold Date: November 1 2012 3:38pm Subject: bzr push into mysql-5.1-telco-7.1 branch (Martin.Skold:4637 to 4640) Bug#14615095 List-Archive: http://lists.mysql.com/commits/145184 X-Bug: 14615095 Message-Id: <20121101153837.B7FE79F8259@quadfish> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4640 Martin Skold 2012-11-01 Bug#14615095 ERROR 839 'ILLEGAL NULL ATTRIBUTE' WHEN REPLAYING BINLOG: Added IgnoreError option when committing transactions during application of binlog statements to achieve same behavior as in the slave applier thread, added test cases modified: mysql-test/suite/ndb_binlog/r/ndb_binlog_variants.result mysql-test/suite/ndb_binlog/t/ndb_binlog_variants.test 4639 Martin Skold 2012-11-01 Added option to specify specific binlog_file to wait for modified: mysql-test/include/wait_for_binlog_event.inc 4638 Martin Skold 2012-11-01 Bug#14615095 ERROR 839 'ILLEGAL NULL ATTRIBUTE' WHEN REPLAYING BINLOG: Added IgnoreError option when committing transactions during application of binlog statements to achieve same behavior as in the slave applier thread modified: sql/ha_ndbcluster.cc sql/ha_ndbcluster.h 4637 Maitrayi Sabaratnam 2012-11-01 [merge] Merge 7.0->7.1 modified: storage/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp === modified file 'mysql-test/include/wait_for_binlog_event.inc' --- a/mysql-test/include/wait_for_binlog_event.inc 2010-05-24 13:54:08 +0000 +++ b/mysql-test/include/wait_for_binlog_event.inc 2012-11-01 14:54:48 +0000 @@ -7,6 +7,7 @@ # USAGE # # let $wait_binlog_event= DROP; +# [let $binlog_file= master-bin.000001;] # --source include/wait_for_binlog_event.inc let $_loop_count= 300; @@ -22,12 +23,26 @@ while (`SELECT INSTR("$_last_event","$wa --die ERROR: failed while waiting for $wait_binlog_event in binlog } real_sleep 0.1; - let $_event= query_get_value(SHOW BINLOG EVENTS, Info, $_event_pos); + if (!$binlog_file) + { + let $_event= query_get_value(SHOW BINLOG EVENTS, Info, $_event_pos); + } + if ($binlog_file) + { + let $_event= query_get_value(SHOW BINLOG EVENTS IN '$binlog_file', Info, $_event_pos); + } let $_last_event= $_event; while (`SELECT "$_event" != "No such row"`) { inc $_event_pos; let $_last_event= $_event; - let $_event= query_get_value(SHOW BINLOG EVENTS, Info, $_event_pos); + if (!$binlog_file) + { + let $_event= query_get_value(SHOW BINLOG EVENTS, Info, $_event_pos); + } + if ($binlog_file) + { + let $_event= query_get_value(SHOW BINLOG EVENTS IN '$binlog_file', Info, $_event_pos); + } } } === modified file 'mysql-test/suite/ndb_binlog/r/ndb_binlog_variants.result' --- a/mysql-test/suite/ndb_binlog/r/ndb_binlog_variants.result 2009-10-07 17:16:52 +0000 +++ b/mysql-test/suite/ndb_binlog/r/ndb_binlog_variants.result 2012-11-01 14:55:35 +0000 @@ -101,3 +101,82 @@ select * from bah order by tst; tst cvy sqs 1 2 1 drop table bah; +reset master; +show variables like '%log_update%'; +Variable_name Value +ndb_log_update_as_write ON +ndb_log_updated_only ON +sql_log_update ON +CREATE TABLE `t1` ( +`charId` varchar(60) NOT NULL, +`enumId` enum('A','B','C') NOT NULL, +`val` bigint(20) NOT NULL, +`version` int(11) NOT NULL, +PRIMARY KEY (`charId`,`enumId`) +) ENGINE=ndbcluster DEFAULT CHARSET=latin1; +INSERT INTO t1 VALUES ('', 'A', 0, 1); +FLUSH LOGS; +UPDATE t1 SET val = val + 1 WHERE charId = ''; +FLUSH LOGS; +DELETE FROM t1 WHERE charId = ''; +FLUSH LOGS; +Manually applying captured binlog +select * from t1; +charId enumId val version +drop table t1; +reset master; +show variables like '%log_update%'; +Variable_name Value +ndb_log_update_as_write ON +ndb_log_updated_only ON +sql_log_update ON +create table t1 (pk int not null primary key, name varchar(256)) engine = ndb; +FLUSH LOGS; +insert into t1 values (0, "zero"),(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five"),(6,"six"),(7,"seven"),(8,"eight"),(9,"nine"); +select * from t1 order by pk; +pk name +0 zero +1 one +2 two +3 three +4 four +5 five +6 six +7 seven +8 eight +9 nine +update t1 set name = "even" where pk in (0,2,4,6,8); +update t1 set name = "odd" where pk in (1,3,5,7,9); +delete from t1 where name = "odd"; +select * from t1 order by pk; +pk name +0 even +2 even +4 even +6 even +8 even +FLUSH LOGS; +truncate t1; +insert into t1 values (0, "zero"),(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five"),(6,"six"),(7,"seven"),(8,"eight"),(9,"nine"); +select * from t1 order by pk; +pk name +0 zero +1 one +2 two +3 three +4 four +5 five +6 six +7 seven +8 eight +9 nine +FLUSH LOGS; +Manually applying captured binlog +select * from t1 order by pk; +pk name +0 even +2 even +4 even +6 even +8 even +drop table t1; === modified file 'mysql-test/suite/ndb_binlog/t/ndb_binlog_variants.test' --- a/mysql-test/suite/ndb_binlog/t/ndb_binlog_variants.test 2011-05-13 07:40:50 +0000 +++ b/mysql-test/suite/ndb_binlog/t/ndb_binlog_variants.test 2012-11-01 14:55:35 +0000 @@ -214,3 +214,152 @@ let $MYSQLD_DATADIR= `select @@datadir;` select * from bah order by tst; drop table bah; + +# Bug #14615095 ERROR 839 'ILLEGAL NULL ATTRIBUTE' WHEN REPLAYING BINLOG +# When applying WRITE_ROW events to tables where the rows are missing +# any errors should be ignored + +connection mysqld1; +reset master; +show variables like '%log_update%'; + +CREATE TABLE `t1` ( + `charId` varchar(60) NOT NULL, + `enumId` enum('A','B','C') NOT NULL, + `val` bigint(20) NOT NULL, + `version` int(11) NOT NULL, + PRIMARY KEY (`charId`,`enumId`) + ) ENGINE=ndbcluster DEFAULT CHARSET=latin1; + +INSERT INTO t1 VALUES ('', 'A', 0, 1); + +--disable_query_log +# Add an event-stream marker +create table stream_marker(a int) engine=ndb; +drop table stream_marker; +--let $wait_binlog_event=stream_marker +--enable_query_log + +# Wait until the INSERT statement is confirmed to have made it into the current binary log +--source include/wait_for_binlog_event.inc +FLUSH LOGS; + +UPDATE t1 SET val = val + 1 WHERE charId = ''; + +--disable_query_log +# Add an event-stream marker +create table stream_marker(a int) engine=ndb; +drop table stream_marker; +--let $wait_binlog_event=stream_marker +--enable_query_log + +# Wait until the UPDATE statement is confirmed to have made it into the current binary log +--sleep 5 +--let $binlog_file=mysqld-bin.000002 +--source include/wait_for_binlog_event.inc +FLUSH LOGS; + +DELETE FROM t1 WHERE charId = ''; + +--disable_query_log +# Add an event-stream marker +create table stream_marker(a int) engine=ndb; +drop table stream_marker; +--let $wait_binlog_event=stream_marker +--enable_query_log + +# Wait until the DELETE statement is confirmed to have made it into the current binary log +--sleep 5 +--let $binlog_file=mysqld-bin.000003 +--source include/wait_for_binlog_event.inc +FLUSH LOGS; + +# Now let's re-apply the binlog from the UPDATE +# Without fix, this fails with 'Illegal null attribute' +--echo Manually applying captured binlog +--disable_query_log +let $MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/mysqld-bin.000002 > $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql +--exec $MYSQL -uroot < $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql + +--enable_query_log +# Check that the table is still empty +select * from t1; + +drop table t1; + +# Bug #14678088 CAN'T FIND RECORD IN +# We need to be idempotent when applying binlog +# test insert of existing row, update and delete +# of non-existing row + +connection mysqld1; +reset master; +show variables like '%log_update%'; + +create table t1 (pk int not null primary key, name varchar(256)) engine = ndb; + +--disable_query_log +# Add an event-stream marker +create table stream_marker(a int) engine=ndb; +drop table stream_marker; +--let $wait_binlog_event=stream_marker +--enable_query_log + +# Wait until all statements are confirmed to have made it into the current binary log +--let $binlog_file=mysqld-bin.000001 +--source include/wait_for_binlog_event.inc +FLUSH LOGS; + +insert into t1 values (0, "zero"),(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five"),(6,"six"),(7,"seven"),(8,"eight"),(9,"nine"); +select * from t1 order by pk; + +update t1 set name = "even" where pk in (0,2,4,6,8); +update t1 set name = "odd" where pk in (1,3,5,7,9); + +delete from t1 where name = "odd"; + +select * from t1 order by pk; + +--disable_query_log +# Add an event-stream marker +create table stream_marker(a int) engine=ndb; +drop table stream_marker; +--let $wait_binlog_event=stream_marker +--enable_query_log + +# Wait until all statements are confirmed to have made it into the current binary log +--let $binlog_file=mysqld-bin.000002 +--source include/wait_for_binlog_event.inc +FLUSH LOGS; + +truncate t1; +insert into t1 values (0, "zero"),(1,"one"),(2,"two"),(3,"three"),(4,"four"),(5,"five"),(6,"six"),(7,"seven"),(8,"eight"),(9,"nine"); +select * from t1 order by pk; + +--disable_query_log +# Add an event-stream marker +create table stream_marker(a int) engine=ndb; +drop table stream_marker; +--let $wait_binlog_event=stream_marker +--enable_query_log + +# Wait until all statements are confirmed to have made it into the current binary log +--let $binlog_file=mysqld-bin.000003 +--source include/wait_for_binlog_event.inc +FLUSH LOGS; + +# Now let's re-apply the binlog INSERT,UPDATE,DELETE +# Without fix, this fails with 'Illegal null attribute' +--echo Manually applying captured binlog +--disable_query_log +let $MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/mysqld-bin.000002 > $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql +--exec $MYSQL -uroot < $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql + +--enable_query_log +select * from t1 order by pk; + +drop table t1; + + === modified file 'sql/ha_ndbcluster.cc' --- a/sql/ha_ndbcluster.cc 2012-06-14 11:48:36 +0000 +++ b/sql/ha_ndbcluster.cc 2012-11-01 14:52:55 +0000 @@ -4082,27 +4082,6 @@ ha_ndbcluster::eventSetAnyValue(THD *thd #endif } -bool ha_ndbcluster::isManualBinlogExec(THD *thd) -{ - /* Are we executing handler methods as part of - * a mysql client BINLOG statement? - */ -#ifndef EMBEDDED_LIBRARY - return thd ? - ( thd->rli_fake? - ndb_mi_get_in_relay_log_statement(thd->rli_fake) : false) - : false; -#else - /* For Embedded library, we can't determine if we're - * executing Binlog manually - * TODO : Find better way to determine whether to use - * SQL REPLACE or Write_row semantics - */ - return false; -#endif - -} - static inline bool thd_allow_batch(const THD* thd) { @@ -4703,15 +4682,7 @@ int ha_ndbcluster::ndb_write_row(uchar * * to avoid trampling unchanged columns when an update is * logged as a WRITE */ - bool useWriteSet= isManualBinlogExec(thd); - -#ifdef HAVE_NDB_BINLOG - /* Slave always uses writeset - * TODO : What about SBR replicating a - * REPLACE command? - */ - useWriteSet |= thd->slave_thread; -#endif + bool useWriteSet= applying_binlog(thd); uchar* mask; if (useWriteSet) @@ -5153,7 +5124,7 @@ int ha_ndbcluster::exec_bulk_update(uint DBUG_RETURN(ndb_err(trans)); } THD *thd= table->in_use; - if (!thd->slave_thread) + if (!applying_binlog(thd)) { DBUG_PRINT("info", ("ignore_count: %u", ignore_count)); assert(m_rows_changed >= ignore_count); @@ -5197,7 +5168,7 @@ int ha_ndbcluster::exec_bulk_update(uint no_uncommitted_rows_execute_failure(); DBUG_RETURN(ndb_err(trans)); } - if (!thd->slave_thread) + if (!applying_binlog(thd)) { assert(m_rows_changed >= ignore_count); assert(m_rows_updated >= ignore_count); @@ -5522,7 +5493,7 @@ int ha_ndbcluster::ndb_update_row(const m_rows_changed++; m_rows_updated++; - if (!thd->slave_thread) + if (!applying_binlog(thd)) { assert(m_rows_changed >= ignore_count); assert(m_rows_updated >= ignore_count); @@ -5583,7 +5554,7 @@ int ha_ndbcluster::end_bulk_delete() DBUG_RETURN(ndb_err(trans)); } THD *thd= table->in_use; - if (!thd->slave_thread) + if (!applying_binlog(thd)) { DBUG_PRINT("info", ("ignore_count: %u", ignore_count)); assert(m_rows_deleted >= ignore_count); @@ -5625,7 +5596,7 @@ int ha_ndbcluster::end_bulk_delete() DBUG_RETURN(ndb_err(trans)); } - if (!thd->slave_thread) + if (!applying_binlog(thd)) { assert(m_rows_deleted >= ignore_count); m_rows_deleted-= ignore_count; @@ -5835,7 +5806,7 @@ int ha_ndbcluster::ndb_delete_row(const } if (!primary_key_update) { - if (!thd->slave_thread) + if (!applying_binlog(thd)) { assert(m_rows_deleted >= ignore_count); m_rows_deleted-= ignore_count; @@ -6801,8 +6772,11 @@ int ha_ndbcluster::extra(enum ha_extra_f case HA_EXTRA_WRITE_CAN_REPLACE: DBUG_PRINT("info", ("HA_EXTRA_WRITE_CAN_REPLACE")); if (!m_has_unique_index || - current_thd->slave_thread || /* always set if slave, quick fix for bug 27378 */ - isManualBinlogExec(current_thd)) /* or if manual binlog application, for bug 46662 */ + /* + Always set if slave, quick fix for bug 27378 + or if manual binlog application, for bug 46662 + */ + applying_binlog(current_thd)) { DBUG_PRINT("info", ("Turning ON use of write instead of insert")); m_use_write= TRUE; @@ -7200,6 +7174,13 @@ static void transaction_checks(THD *thd, THDVAR(thd, optimized_node_selection)= THDVAR(NULL, optimized_node_selection) & 1; /* using global value */ } +#ifndef EMBEDDED_LIBRARY + bool applying_binlog= + thd->rli_fake? + ndb_mi_get_in_relay_log_statement(thd->rli_fake) : false; + if (applying_binlog) + thd_ndb->trans_options|= TNTO_APPLYING_BINLOG; +#endif } int ha_ndbcluster::start_statement(THD *thd, @@ -7660,7 +7641,6 @@ ha_ndbcluster::start_transaction_part_id DBUG_RETURN(NULL); } - /** Commit a transaction started in NDB. */ @@ -7753,7 +7733,10 @@ int ndbcluster_commit(handlerton *hton, } } else - res= execute_commit(thd, thd_ndb, trans, THDVAR(thd, force_send), FALSE); + { + bool applying_binlog= (thd_ndb->trans_options & TNTO_APPLYING_BINLOG); + res= execute_commit(thd, thd_ndb, trans, THDVAR(thd, force_send), applying_binlog); + } } if (res != 0) === modified file 'sql/ha_ndbcluster.h' --- a/sql/ha_ndbcluster.h 2012-06-14 11:48:36 +0000 +++ b/sql/ha_ndbcluster.h 2012-11-01 14:52:55 +0000 @@ -274,6 +274,7 @@ enum THD_NDB_TRANS_OPTIONS TNTO_INJECTED_APPLY_STATUS= 1 << 0 ,TNTO_NO_LOGGING= 1 << 1 ,TNTO_TRANSACTIONS_OFF= 1 << 2 + ,TNTO_APPLYING_BINLOG= 1 << 3 }; struct Ndb_local_table_statistics { @@ -721,8 +722,6 @@ private: ulonglong *nb_reserved_values); bool uses_blob_value(const MY_BITMAP *bitmap) const; - static inline bool isManualBinlogExec(THD *thd); - char *update_table_comment(const char * comment); int write_ndb_file(const char *name); @@ -882,6 +881,21 @@ private: int update_stats(THD *thd, bool do_read_stat, bool have_lock= FALSE, uint part_id= ~(uint)0); int add_handler_to_open_tables(THD*, Thd_ndb*, ha_ndbcluster* handler); + + /* + Check if we are applying a binlog, either as a slave or + by applying BINLOG statements (from mysqlbinlog command line tool) + */ + bool applying_binlog(THD* thd) + { + return +#ifdef HAVE_NDB_BINLOG + thd->slave_thread || +#endif + m_thd_ndb->trans_options & TNTO_APPLYING_BINLOG; + }; + + }; int ndbcluster_discover(THD* thd, const char* dbname, const char* name, No bundle (reason: useless for push emails).