=== modified file 'mysql-test/suite/ndb_binlog/r/ndb_binlog_variants.result' --- mysql-test/suite/ndb_binlog/r/ndb_binlog_variants.result 2009-09-29 14:25:03 +0000 +++ mysql-test/suite/ndb_binlog/r/ndb_binlog_variants.result 2009-10-06 11:47:20 +0000 @@ -3,6 +3,10 @@ insert into ba values (1, 1, 1), (2,2,2) update ba set lp=40 where ks=4; delete from ba where ks=2; flush logs; +flush logs; +flush logs; +flush logs; +delete from ba; show variables like '%log_update%'; Variable_name Value sql_log_update ON @@ -14,7 +18,12 @@ INSERT INTO test.ba SET @1=2 @2=2 INSERT INTO test.ba SET @1=3 @2=3 @3=3 INSERT INTO test.ba SET @1=4 @2=4 @3=4 INSERT INTO test.ba SET @1=4 @3=40 -flush logs; +select * from ba order by ks; +ks st lp +1 1 1 +3 3 3 +4 4 40 +delete from ba; show variables like '%log_update%'; Variable_name Value sql_log_update ON @@ -26,7 +35,12 @@ INSERT INTO test.ba SET @1=2 @2=2 INSERT INTO test.ba SET @1=3 @2=3 @3=3 INSERT INTO test.ba SET @1=4 @2=4 @3=4 INSERT INTO test.ba SET @1=4 @2=4 @3=40 -flush logs; +select * from ba order by ks; +ks st lp +1 1 1 +3 3 3 +4 4 40 +delete from ba; show variables like '%log_update%'; Variable_name Value sql_log_update ON @@ -38,7 +52,12 @@ INSERT INTO test.ba SET @1=2 @2=2 INSERT INTO test.ba SET @1=3 @2=3 @3=3 INSERT INTO test.ba SET @1=4 @2=4 @3=4 UPDATE test.ba WHERE @1=4 @3=4 SET @1=4 @3=40 -flush logs; +select * from ba order by ks; +ks st lp +1 1 1 +3 3 3 +4 4 40 +delete from ba; show variables like '%log_update%'; Variable_name Value sql_log_update ON @@ -50,4 +69,9 @@ INSERT INTO test.ba SET @1=2 @2=2 INSERT INTO test.ba SET @1=3 @2=3 @3=3 INSERT INTO test.ba SET @1=4 @2=4 @3=4 UPDATE test.ba WHERE @1=4 @2=4 @3=4 SET @1=4 @2=4 @3=40 +select * from ba order by ks; +ks st lp +1 1 1 +3 3 3 +4 4 40 drop table ba; === modified file 'mysql-test/suite/ndb_binlog/t/ndb_binlog_variants.test' --- mysql-test/suite/ndb_binlog/t/ndb_binlog_variants.test 2009-09-29 14:25:03 +0000 +++ mysql-test/suite/ndb_binlog/t/ndb_binlog_variants.test 2009-10-06 11:47:20 +0000 @@ -70,34 +70,85 @@ drop table stream_marker; --let $wait_binlog_event=stream_marker --enable_query_log -# Now let's have a look at what's in the Binlog on each server +# Now let's trim the Binlogs on each server +connection mysqld1; --source include/wait_for_binlog_event.inc flush logs; +connection mysqld2; +--source include/wait_for_binlog_event.inc +flush logs; +connection mysqld3; +--source include/wait_for_binlog_event.inc +flush logs; +connection mysqld4; +--source include/wait_for_binlog_event.inc +flush logs; + +# Empty the table +delete from ba; + +# Now let's examine the contents of the first binlog +# on each server +# We'll also apply the Binlog and check that the +# table contents are as expected in each case. +# As each server is recording in a new binlog, the +# new updates will go there. + +connection mysqld1; + show variables like '%log_update%'; --source suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts.inc +--disable_query_log +let $MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/mysqld-bin.000001 > $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql +--exec $MYSQL -uroot < $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql + +--enable_query_log +select * from ba order by ks; +delete from ba; + connection mysqld2; ---source include/wait_for_binlog_event.inc -flush logs; show variables like '%log_update%'; --source suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts.inc +--disable_query_log +let $MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/mysqld-bin.000001 > $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql +--exec $MYSQL -uroot < $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql + +--enable_query_log + +select * from ba order by ks; +delete from ba; + connection mysqld3; ---source include/wait_for_binlog_event.inc -flush logs; show variables like '%log_update%'; --source suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts.inc +--disable_query_log +let $MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/mysqld-bin.000001 > $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql +--exec $MYSQL -uroot < $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql + +--enable_query_log +select * from ba order by ks; +delete from ba; + connection mysqld4; ---source include/wait_for_binlog_event.inc -flush logs; show variables like '%log_update%'; --source suite/ndb_binlog/t/ndb_binlog_get_binlog_stmts.inc +--disable_query_log +let $MYSQLD_DATADIR= `select @@datadir;`; +--exec $MYSQL_BINLOG $MYSQLD_DATADIR/mysqld-bin.000001 > $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql +--exec $MYSQL -uroot < $MYSQLTEST_VARDIR/tmp/ndb_binlog_mysqlbinlog.sql -drop table ba; +--enable_query_log +select * from ba order by ks; +drop table ba; === modified file 'sql/ha_ndbcluster.cc' --- sql/ha_ndbcluster.cc 2009-09-24 14:32:40 +0000 +++ sql/ha_ndbcluster.cc 2009-10-06 13:45:35 +0000 @@ -2886,6 +2886,27 @@ ha_ndbcluster::eventSetAnyValue(THD *thd } } +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? + thd->rli_fake->get_flag(Relay_log_info::IN_STMT) : 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 + +} + int ha_ndbcluster::write_row(uchar *record) { DBUG_ENTER("ha_ndbcluster::write_row"); @@ -3042,27 +3063,28 @@ int ha_ndbcluster::ndb_write_row(uchar * if (m_use_write) { const uchar *mask; -#ifdef HAVE_NDB_BINLOG - /* - The use of table->write_set is tricky here. This is done as a temporary - workaround for BUG#22045. - - There is some confusion on the precise meaning of write_set in write_row, - with REPLACE INTO and replication SQL thread having different opinions. - There is work on the way to sort that out, but until then we need to - implement different semantics depending on whether we are in the slave - SQL thread or not. + /* Should we use the supplied table writeset or not? + * For a REPLACE command, we should ignore it, and write + * all columns to get correct REPLACE behaviour. + * For applying Binlog events, we need to use the writeset + * to avoid trampling unchanged columns when an update is + * logged as a WRITE + */ + bool useWriteSet= isManualBinlogExec(thd); - SQL thread -> use the write_set for writeTuple(). - otherwise (REPLACE INTO) -> do not use write_set. - */ - if (thd->slave_thread) +#ifdef HAVE_NDB_BINLOG + /* Slave always uses writeset + * TODO : What about SBR replicating a + * REPLACE command? + */ + useWriteSet |= thd->slave_thread; +#endif + if (useWriteSet) { user_cols_written_bitmap= table->write_set; mask= (uchar *)(user_cols_written_bitmap->bitmap); } else -#endif { user_cols_written_bitmap= NULL; mask= NULL; === modified file 'sql/ha_ndbcluster.h' --- sql/ha_ndbcluster.h 2009-09-24 14:22:10 +0000 +++ sql/ha_ndbcluster.h 2009-10-06 11:47:20 +0000 @@ -616,6 +616,8 @@ private: ulonglong *nb_reserved_values); bool uses_blob_value(const MY_BITMAP *bitmap); + static inline bool isManualBinlogExec(THD *thd); + char *update_table_comment(const char * comment); int write_ndb_file(const char *name);