Hi Alfranio,
Great work!
I think the patch is almost OK, I have one proposal about M statement,
currently we consider all statement that referenced both N-table and
T-table as unsafe, I think there need a refinement, we should only
consider tables that are modified within the transaction before this
statement or will be modified by this statement, and ignore tables that
are not modified within the transaction before and are not for update.
Let's assume 't' as a trans table, and 'n' as a non-trans table, so the
following INSERT .. SELECT statements will be considered an N or T
statement, not an M-statement, and so should not generate unsafe errors
nor switch to row format in mixed mode:
BEGIN;
INSERT INTO n SELECT * FROM t; /* This is an N statement, safe */
COMMIT;
BEGIN;
INSERT INTO t SELECT * FROM n; /* This is an T statemet, safe */
COMMIT;
But this INSERT .. SELECT is considered as an M-statement:
BEGIN;
INSERT INTO t VALUES (1);
INSERT INTO n SELECT * FROM t; /* This is an M statement, unsafe */
COMMIT;
BEGIN;
INSERT INTO n VALUES (1);
INSERT INTO t SELECT * FROM n; /* Because the above statement will be logged separately,
so this is a *T* statement, safe */
COMMIT;
In nuts shell, if a table is not for update, and it has not been
modified within the transaction before this statement, then this table
will be ignored when deciding if the statement is N,T or M.
Please see also comments below!
Alfranio Correia wrote:
> #At
> file:///home/acorreia/workspace.sun/repository.mysql/bzrwork/bug-40278/mysql-5.1-bugteam/
> based on revid:staale.smedseng@stripped
>
> 2911 Alfranio Correia 2009-06-06
> WL#2687
>
> removed:
> mysql-test/suite/rpl/r/rpl_row_basic_11bugs-master.opt
> mysql-test/suite/rpl/r/rpl_row_basic_11bugs-slave.opt
> added:
> mysql-test/suite/rpl/include/rpl_mixed_engines.inc
> mysql-test/suite/rpl/r/rpl_mixing_mixed_engines.result
> mysql-test/suite/rpl/r/rpl_mixing_row_engines.result
> mysql-test/suite/rpl/r/rpl_mixing_stmt_engines.result
> mysql-test/suite/rpl/t/rpl_mixing_mixed_engines.test
> mysql-test/suite/rpl/t/rpl_mixing_row_engines.test
> mysql-test/suite/rpl/t/rpl_mixing_stmt_engines.test
I think the convention is to put the mode name (row,stm,mixed) right
after the 'rpl_' prefix in the test names, so I'd suggest to name these
as:
rpl_row_mixing_engines.test
rpl_stm_mixing_engines.test
rpl_mixed_mixing_engines.test
> modified:
> mysql-test/extra/rpl_tests/rpl_flsh_tbls.test
> mysql-test/extra/rpl_tests/rpl_insert_delayed.test
> mysql-test/extra/rpl_tests/rpl_insert_ignore.test
> mysql-test/extra/rpl_tests/rpl_log.test
> mysql-test/r/commit_1innodb.result
> mysql-test/suite/binlog/r/binlog_database.result
> mysql-test/suite/binlog/r/binlog_multi_engine.result
> mysql-test/suite/binlog/r/binlog_row_binlog.result
> mysql-test/suite/binlog/r/binlog_row_ctype_ucs.result
> mysql-test/suite/binlog/r/binlog_row_insert_select.result
> mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
> mysql-test/suite/binlog/r/binlog_stm_binlog.result
> mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
> mysql-test/suite/binlog/r/binlog_stm_row.result
> mysql-test/suite/binlog/t/binlog_incident.test
> mysql-test/suite/ndb/r/ndb_binlog_format.result
> mysql-test/suite/rpl/r/rpl_blackhole.result
> mysql-test/suite/rpl/r/rpl_extraCol_myisam.result
> mysql-test/suite/rpl/r/rpl_innodb.result
> mysql-test/suite/rpl/r/rpl_loaddata_fatal.result
> mysql-test/suite/rpl/r/rpl_log_pos.result
> mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result
> mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result
> mysql-test/suite/rpl/r/rpl_row_conflicts.result
> mysql-test/suite/rpl/r/rpl_row_create_table.result
> mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result
> mysql-test/suite/rpl/r/rpl_row_insert_delayed.result
> mysql-test/suite/rpl/r/rpl_row_log.result
> mysql-test/suite/rpl/r/rpl_row_log_innodb.result
> mysql-test/suite/rpl/r/rpl_sp.result
> mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result
> mysql-test/suite/rpl/r/rpl_stm_insert_delayed.result
> mysql-test/suite/rpl/r/rpl_stm_log.result
> mysql-test/suite/rpl/t/rpl_blackhole.test
> mysql-test/suite/rpl/t/rpl_empty_master_crash.test
> mysql-test/suite/rpl/t/rpl_innodb.test
> mysql-test/suite/rpl/t/rpl_invoked_features.test
> mysql-test/suite/rpl/t/rpl_loaddata_fatal.test
> mysql-test/suite/rpl/t/rpl_log_pos.test
> mysql-test/suite/rpl/t/rpl_read_only.test
> mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
> mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test
> mysql-test/suite/rpl/t/rpl_row_until.test
> mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test
> mysql-test/suite/rpl/t/rpl_trigger.test
> mysql-test/suite/rpl_ndb/r/rpl_ndb_mixed_engines_transactions.result
> sql/ha_ndbcluster_binlog.cc
> sql/handler.cc
> sql/handler.h
> sql/log.cc
> sql/log.h
> sql/log_event.cc
> sql/log_event.h
> sql/log_event_old.cc
> sql/rpl_injector.cc
> sql/set_var.cc
> sql/sp.cc
> sql/sp_head.cc
> sql/sql_acl.cc
> sql/sql_base.cc
> sql/sql_class.cc
> sql/sql_class.h
> sql/sql_delete.cc
> sql/sql_insert.cc
> sql/sql_load.cc
> sql/sql_parse.cc
> sql/sql_table.cc
> sql/sql_update.cc
> sql/sql_view.cc
> === modified file 'mysql-test/extra/rpl_tests/rpl_flsh_tbls.test'
> --- a/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test 2008-12-12 11:34:18 +0000
> +++ b/mysql-test/extra/rpl_tests/rpl_flsh_tbls.test 2009-06-06 17:51:51 +0000
> @@ -20,19 +20,13 @@ rename table t1 to t5, t2 to t1;
> # first don't write it to the binlog, to test the NO_WRITE_TO_BINLOG keyword.
> flush no_write_to_binlog tables;
> # Check that it's not in the binlog.
> ---replace_result $SERVER_VERSION SERVER_VERSION
> ---replace_column 2 # 5 #
> ---replace_regex /table_id: [0-9]+/table_id: #/
> -eval SHOW BINLOG EVENTS FROM $rename_event_pos ;
> +source include/show_binlog_events2.inc;
I'd suggest to use:
let $pos= query_get_value("SHOW MASTER STATUS", Position, 1);
to get the desired position.
[snip]
> @@ -430,7 +404,7 @@ select
> @a not like "%#%error_code=%error_code=%";
> @a like "%#%error_code=0%ROLLBACK\n/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" OR
> @a like "%#%error_code=0%ROLLBACK\r\n/*!*/;%ROLLBACK /* added by mysqlbinlog
> */;%" @a not like "%#%error_code=%error_code=%"
> -1 1
> +0 1
This looks like a test problem, below is some codes in the test case
before the above output:
if (`select @@binlog_format = 'ROW'`)
{
--exec $MYSQL_BINLOG --start-position=524 $MYSQLD_DATADIR/master-bin.000001 >
$MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output
}
if (`select @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
{
--exec $MYSQL_BINLOG --start-position=555 $MYSQLD_DATADIR/master-bin.000001 >
$MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output
}
this part of the test used absolute binlog positions, and that can be
problematic, probably the binlog positions should be changed
accordingly, please double check that the test case still works as
expected.
[snip]
> === added file 'mysql-test/suite/rpl/include/rpl_mixed_engines.inc'
> --- a/mysql-test/suite/rpl/include/rpl_mixed_engines.inc 1970-01-01 00:00:00 +0000
> +++ b/mysql-test/suite/rpl/include/rpl_mixed_engines.inc 2009-06-06 17:51:51 +0000
> @@ -0,0 +1,905 @@
> +###################################################################################
> +# This test checks if transactions that mixes transactional and non-transactional
> +# tables are correctly handled. Thus to check the behavior provided by the current
> +# code we devide the test as follows:
> +#
> +# 1 - CREATING TABLES through SELECT * FROM
> +# 2 - MIXING TRANSACTIONAL and NON-TRANSACTIONAL TABLES
> +# 3 - CONCURRENCY:
> +# 2.1 - NON-TRANSACT TABLES - SET AUTOCOMMIT = 0 | COMMIT
> +# 2.2 - NON-TRANSACT TABLES - SET AUTOCOMMIT = 1 | START - COMMIT
> +# 4 - SAVE POINTS
> +###################################################################################
> +
> +--echo
> ###################################################################################
> +--echo # CONFIGURATION
> +--echo
> ###################################################################################
> +connection master;
> +
> +CREATE TABLE t1 (a text, b int PRIMARY KEY, c text) ENGINE = MyISAM;
> +CREATE TABLE t2 (a text, b int PRIMARY KEY, c text) ENGINE = Innodb;
> +CREATE TABLE t3 (a text, b int PRIMARY KEY, c text) ENGINE = Innodb;
> +CREATE TABLE t4 (a text, b int PRIMARY KEY, c text) ENGINE = Innodb;
> +CREATE TABLE t5 (a text, b int PRIMARY KEY, c text) ENGINE = MyISAM;
> +CREATE TABLE t6 (a text, b int PRIMARY KEY, c text) ENGINE = Innodb;
> +CREATE TABLE t7 (a text, b int PRIMARY KEY, c text) ENGINE = Innodb;
> +CREATE TABLE t8 (a text, b int PRIMARY KEY, c text) ENGINE = MyISAM;
> +CREATE TABLE t9 (a text, b int PRIMARY KEY, c text) ENGINE = MyISAM;
I'd suggest to name all trans-tables t1,t2... and non-trans tables n1,
n2..., so that's easier to understand the test.
> +
> +INSERT INTO t1 VALUES("text 1", 1, "text 1"), ("text 2", 2, "text 2"), ("text 3", 3,
> "text 3");
> +INSERT INTO t2 VALUES("text 1", 1, "text 1"), ("text 2", 2, "text 2"), ("text 3", 3,
> "text 3");
> +INSERT INTO t3 VALUES("text 1", 1, "text 1"), ("text 2", 2, "text 2"), ("text 3", 3,
> "text 3");
> +INSERT INTO t4 VALUES("text 1", 1, "text 1"), ("text 2", 2, "text 2"), ("text 3", 3,
> "text 3");
> +INSERT INTO t5 VALUES("text 1", 1, "text 1"), ("text 2", 2, "text 2"), ("text 3", 3,
> "text 3");
> +
> +DELIMITER |;
> +
> +CREATE FUNCTION f1 () RETURNS VARCHAR(64)
> +BEGIN
> + RETURN "Testing...";
> +END|
> +
> +CREATE FUNCTION f2 () RETURNS VARCHAR(64)
> +BEGIN
> + RETURN f1();
> +END|
> +
> +CREATE PROCEDURE pc6 (IN x INT, IN y VARCHAR(64))
> +BEGIN
> + INSERT INTO t6 VALUES (y,x,x);
> +END|
> +
> +CREATE TRIGGER tr6_i BEFORE INSERT ON t6 FOR EACH ROW
> +BEGIN
> + INSERT INTO t7 VALUES (NEW.a, NEW.b, NEW.c);
> + INSERT INTO t8 VALUES (NEW.a, NEW.b, NEW.c);
> + INSERT INTO t9 VALUES (NEW.a, NEW.b, NEW.c);
> +END|
> +
> +DELIMITER ;|
> +
> +INSERT INTO t6 VALUES("text 100", 100, "text 100"), ("text 200", 200, "text 200"),
> ("text 300", 300, "text 300");
> +INSERT INTO t7 VALUES("text 1", 1, "text 1"), ("text 2", 2, "text 2"), ("text 3", 3,
> "text 3");
> +INSERT INTO t8 VALUES("text 1", 1, "text 1"), ("text 2", 2, "text 2"), ("text 3", 3,
> "text 3");
> +INSERT INTO t9 VALUES("text 1", 1, "text 1"), ("text 2", 2, "text 2"), ("text 3", 3,
> "text 3");
> +
> +--echo
> ###################################################################################
> +--echo # 1 - CREATING TABLES
> +--echo
> ###################################################################################
> +connection master;
> +
> +CREATE TABLE t10 SELECT * FROM t2;
> +DROP TABLE t10;
> +CREATE TABLE t11 SELECT * FROM t2;
> +DROP TABLE t11;
> +
> +
> +--echo
> ###################################################################################
> +--echo # 2 - MIXING TRANSACTIONAL and NON-TRANSACTIONAL TABLES
> +--echo
> ###################################################################################
> +connection master;
> +
> +# Caching (C): (stmt-cache (s), trx-cache (t), ignored (i))
> +# Flushing (F): (upon committing/rollingback a statement (d), upon
> +# committing/rolling back a transaction (c/r), ignored (i))
> +
> +#
> +# STMT ROW MIXED
> +#
> +
> +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
> +--echo # C - T C - T C - T
> +--echo #1.a) B T T C F - C F - C F - C
> +--echo #
> +BEGIN;
> +INSERT INTO t2 VALUES ("new text 5", 5, "new text 5");
Please also add show_binlog_events or other methods after statements
within transaction to check that statement cache are correctly flushed..
[snip]
> === modified file 'mysql-test/suite/rpl/r/rpl_extraCol_myisam.result'
> --- a/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result 2008-11-04 07:43:21 +0000
> +++ b/mysql-test/suite/rpl/r/rpl_extraCol_myisam.result 2009-06-06 17:51:51 +0000
> @@ -434,7 +434,7 @@ Replicate_Ignore_Table #
> Replicate_Wild_Do_Table
> Replicate_Wild_Ignore_Table
> Last_Errno 1364
> -Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't
> have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's
> master log master-bin.000001, end_log_pos 330
> +Last_Error Could not execute Write_rows event on table test.t9; Field 'e' doesn't
> have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the event's
> master log master-bin.000001, end_log_pos 262
Please mask out the log position.
> Skip_Counter 0
> Exec_Master_Log_Pos #
> Relay_Log_Space #
> @@ -452,7 +452,7 @@ Master_SSL_Verify_Server_Cert No
> Last_IO_Errno #
> Last_IO_Error #
> Last_SQL_Errno 1364
> -Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e'
> doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the
> event's master log master-bin.000001, end_log_pos 330
> +Last_SQL_Error Could not execute Write_rows event on table test.t9; Field 'e'
> doesn't have a default value, Error_code: 1364; handler error HA_ERR_ROWS_EVENT_APPLY; the
> event's master log master-bin.000001, end_log_pos 262
> SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2;
> START SLAVE;
> *** Create t10 on slave ***
[snip]
> === modified file 'mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result'
> --- a/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result 2008-07-16 09:17:10 +0000
> +++ b/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result 2009-06-06 17:51:51 +0000
> @@ -19,10 +19,8 @@ Log_name Pos Event_type Server_id End_lo
> master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
> master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1 (a INT, b LONG)
> master-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
> -master-bin.000001 # Query 1 # use `test`; BEGIN
> master-bin.000001 # Table_map 1 # table_id: # (test.t1)
> master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
> -master-bin.000001 # Query 1 # use `test`; COMMIT
> **** On Slave ****
> SHOW SLAVE STATUS;
> Slave_IO_State #
> @@ -31,7 +29,7 @@ Master_User root
> Master_Port MASTER_PORT
> Connect_Retry 1
> Master_Log_File master-bin.000001
> -Read_Master_Log_Pos 594
> +Read_Master_Log_Pos 457
Mask out the position
> Relay_Log_File #
> Relay_Log_Pos #
> Relay_Master_Log_File master-bin.000001
> @@ -46,7 +44,7 @@ Replicate_Wild_Ignore_Table
> Last_Errno 0
> Last_Error
> Skip_Counter 0
> -Exec_Master_Log_Pos 594
> +Exec_Master_Log_Pos 457
> Relay_Log_Space #
> Until_Condition None
> Until_Log_File
> @@ -68,9 +66,7 @@ Log_name Pos Event_type Server_id End_lo
> slave-bin.000001 # Format_desc 2 # Server ver: VERSION, Binlog ver: 4
> slave-bin.000001 # Query 1 # use `test`; CREATE TABLE t1 (a INT, b LONG)
> slave-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
> -slave-bin.000001 # Query 1 # use `test`; BEGIN
> slave-bin.000001 # Table_map 1 # table_id: # (test.t1)
> slave-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
> -slave-bin.000001 # Query 1 # use `test`; COMMIT
> DROP TABLE IF EXISTS t1;
> SET @@global.binlog_format= @old_binlog_format;
[snip]
> === modified file 'mysql-test/suite/rpl/r/rpl_row_conflicts.result'
> --- a/mysql-test/suite/rpl/r/rpl_row_conflicts.result 2009-01-09 14:12:31 +0000
> +++ b/mysql-test/suite/rpl/r/rpl_row_conflicts.result 2009-06-06 17:51:51 +0000
> @@ -24,7 +24,7 @@ a
> 1
> [on slave]
> ---- Wait until slave stops with an error ----
> -Last_SQL_Error = Could not execute Write_rows event on table test.t1; Duplicate
> entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the
> event's master log master-bin.000001, end_log_pos 346 (expected "duplicate key" error)
> +Last_SQL_Error = Could not execute Write_rows event on table test.t1; Duplicate
> entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the
> event's master log master-bin.000001, end_log_pos 278 (expected "duplicate key" error)
Mask out the position
> SELECT * FROM t1;
> a
> 1
> @@ -50,7 +50,7 @@ SELECT * FROM t1;
> a
> [on slave]
> ---- Wait until slave stops with an error ----
> -Last_SQL_Error = Could not execute Delete_rows event on table test.t1; Can't find
> record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master
> log master-bin.000001, end_log_pos 982 (expected "can't find record" error)
> +Last_SQL_Error = Could not execute Delete_rows event on table test.t1; Can't find
> record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master
> log master-bin.000001, end_log_pos 503 (expected "can't find record" error)
> SELECT * FROM t1;
> a
> ---- Resolve the conflict on the slave and restart SQL thread ----
[snip]
> === modified file 'mysql-test/suite/rpl/t/rpl_blackhole.test'
> --- a/mysql-test/suite/rpl/t/rpl_blackhole.test 2009-01-30 13:44:49 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_blackhole.test 2009-06-06 17:51:51 +0000
> @@ -45,9 +45,20 @@ source extra/rpl_tests/rpl_blackhole.tes
> let $statement = INSERT INTO t1 SELECT * FROM t2;
> source extra/rpl_tests/rpl_blackhole.test;
>
> +#
> +# The MASTER has MyISAM as the engine for both tables. The SLAVE has Blackhole
> +# on t1 (transactional engine) and MyISAM on t2 (non-transactional engine).
> +#
> +# In MIXED MODE, the command below is logged as statement on the MASTER. On the
> +# other hand, on the SLAVE, it is tagged as unsafe and then executed in ROW
> +# MODE. In a nutshell, statements that mixes transactional and non-transactional
> +# engines are tagged as unsafe. This behavior generates a problem as no rows are
> +# returned and makes the # SLAVE diverge from the MASTER.
> +#
> # Test INSERT-SELECT from Blackhole, no primary key
> -let $statement = INSERT INTO t2 SELECT * FROM t1;
> -source extra/rpl_tests/rpl_blackhole.test;
> +#let $statement = INSERT INTO t2 SELECT * FROM t1;
> +#source extra/rpl_tests/rpl_blackhole.test;
> +#
>
If following the proposal at the beginning, then the above statement
will not be considered unsafe, the the test will pass in mixed mode too.
> connection master;
> ALTER TABLE t1 ADD PRIMARY KEY pk_t1 (a,b);
>
> === modified file 'mysql-test/suite/rpl/t/rpl_empty_master_crash.test'
> --- a/mysql-test/suite/rpl/t/rpl_empty_master_crash.test 2007-06-27 12:29:10 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_empty_master_crash.test 2009-06-06 17:51:51 +0000
> @@ -1,6 +1,6 @@
> source include/master-slave.inc;
>
> -source include/show_slave_status.inc;
> +source include/show_slave_status2.inc;
>
> #
> # Load table should not succeed on the master as this is not a slave
>
> === modified file 'mysql-test/suite/rpl/t/rpl_innodb.test'
> --- a/mysql-test/suite/rpl/t/rpl_innodb.test 2008-10-29 13:25:03 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_innodb.test 2009-06-06 17:51:51 +0000
> @@ -111,7 +111,6 @@ connection slave;
> SHOW CREATE TABLE mysqltest1.tmp;
> --error ER_NO_SUCH_TABLE
> SHOW CREATE TABLE mysqltest1.tmp2;
> -# t1 has two rows here: the transaction not rolled back since t1 uses MyISAM
Please check this part of the test, I think it need to be rewritten (or
removed).
> SELECT COUNT(*) FROM mysqltest1.t1;
> FLUSH LOGS;
>
[snip]
> === modified file 'mysql-test/suite/rpl/t/rpl_row_until.test'
> --- a/mysql-test/suite/rpl/t/rpl_row_until.test 2009-02-19 20:29:12 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_row_until.test 2009-06-06 17:51:51 +0000
> @@ -14,18 +14,21 @@ INSERT INTO t1 VALUES (1),(2),(3),(4);
> DROP TABLE t1;
> # Save master log postion for query DROP TABLE t1
> save_master_pos;
> -let $master_pos_drop_t1= query_get_value(SHOW BINLOG EVENTS, Pos, 7);
> +let $master_pos_drop_t1= query_get_value(SHOW BINLOG EVENTS, Pos, 5);
> +#show binlog events;
>
I'd suggest to use:
let $master_pos_drop_t1= query_get_value(SHOW MASTER STATUS, Position, 1);
right before the DROP statement.
> CREATE TABLE t2(n INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
> # Save master log postion for query CREATE TABLE t2
> save_master_pos;
> -let $master_pos_create_t2= query_get_value(SHOW BINLOG EVENTS, Pos, 8);
> +let $master_pos_create_t2= query_get_value(SHOW BINLOG EVENTS, Pos, 6);
> +#show binlog events;
>
> INSERT INTO t2 VALUES (1),(2);
> save_master_pos;
> # Save master log postion for query INSERT INTO t2 VALUES (1),(2);
> -let $master_pos_insert1_t2= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 12);
> +let $master_pos_insert1_t2= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 8);
> sync_slave_with_master;
> +#show binlog events;
>
> # Save relay log postion for query INSERT INTO t2 VALUES (1),(2);
> let $relay_pos_insert1_t2= query_get_value(show slave status, Relay_Log_Pos, 1);
> @@ -34,8 +37,9 @@ connection master;
> INSERT INTO t2 VALUES (3),(4);
> DROP TABLE t2;
> # Save master log postion for query INSERT INTO t2 VALUES (1),(2);
> -let $master_pos_drop_t2= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 17);
> +let $master_pos_drop_t2= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 11);
> sync_slave_with_master;
> +#show binlog events;
>
> --source include/stop_slave.inc
> # Reset slave.
> @@ -45,6 +49,7 @@ eval CHANGE MASTER TO MASTER_USER='root'
> --enable_query_log
>
> # Try to replicate all queries until drop of t1
> +
> connection slave;
> echo START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001',
> MASTER_LOG_POS=master_pos_drop_t1;
> --disable_query_log
[snip]
> === modified file 'sql/ha_ndbcluster_binlog.cc'
> --- a/sql/ha_ndbcluster_binlog.cc 2008-04-09 16:42:05 +0000
> +++ b/sql/ha_ndbcluster_binlog.cc 2009-06-06 17:51:51 +0000
> @@ -257,6 +257,7 @@ static void run_query(THD *thd, char *bu
> thd->query= buf;
> thd->variables.pseudo_thread_id= thread_id;
> thd->transaction.stmt.modified_non_trans_table= FALSE;
> + thd->transaction.stmt.modified_trans_table= FALSE;
> if (disable_binlog)
> thd->options&= ~OPTION_BIN_LOG;
>
> @@ -1857,7 +1858,8 @@ static void ndb_binlog_query(THD *thd, C
> thd->db= schema->db;
> thd->binlog_query(THD::STMT_QUERY_TYPE, schema->query,
> schema->query_length, FALSE,
> - schema->name[0] == 0 || thd->db[0] == 0);
> + schema->name[0] == 0 || thd->db[0] == 0,
> + FALSE, THD::KILLED_NO_VALUE);
Can we add a new argument 'direct' to ndb_binlog_query and pass it down
to THD::binlog_query? So that we can get ride of the DDL hack below.
> thd->server_id= thd_server_id_save;
> thd->db= thd_db_save;
> }
[snip]
> /*
> In most cases this is only called if 'is_open()' is true; in fact this is
> @@ -3936,7 +4008,6 @@ bool MYSQL_BIN_LOG::write(Log_event *eve
> */
> if (likely(is_open()))
> {
> - IO_CACHE *file= &log_file;
> #ifdef HAVE_REPLICATION
> /*
> In the future we need to add to the following if tests like
> @@ -3946,48 +4017,50 @@ bool MYSQL_BIN_LOG::write(Log_event *eve
> const char *local_db= event_info->get_db();
> if ((thd && !(thd->options & OPTION_BIN_LOG)) ||
> (!binlog_filter->db_ok(local_db)))
> - {
> - VOID(pthread_mutex_unlock(&LOCK_log));
> DBUG_RETURN(0);
> - }
> #endif /* HAVE_REPLICATION */
> + IO_CACHE *file= NULL;
>
> -#if defined(USING_TRANSACTIONS)
> /*
> - Should we write to the binlog cache or to the binlog on disk?
> - Write to the binlog cache if:
> - - it is already not empty (meaning we're in a transaction; note that the
> - present event could be about a non-transactional table, but still we need
> - to write to the binlog cache in that case to handle updates to mixed
> - trans/non-trans table types the best possible in binlogging)
> - - or if the event asks for it (cache_stmt == TRUE).
> + This is an ugly hacking that must be removed as soon as we fix a bug in
> + NDB. In a nutshell, this means that we should use the binary log directly
> + if we are processing a DDL.
> */
> - if (opt_using_transactions && thd)
> +
> + bool ddl=
> + (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
> + !thd->transaction.stmt.modified_non_trans_table &&
> + !thd->transaction.stmt.modified_trans_table &&
> + !thd->transaction.all.modified_non_trans_table &&
> + !thd->transaction.all.modified_trans_table &&
> + !event_info->is_trans_event());
> +
Hmmm, this looks really really really ugly, why cannot we add change the
interface of ndb_binlog_query to add a new argument 'direct', and pass
it down to this function?
> + direct= direct || ddl;
> +
> + if (direct)
> + {
> + file= &log_file;
> + pthread_mutex_lock(&LOCK_log);
> + }
> + else
> {
> - if (thd->binlog_setup_trx_data())
> + thd->binlog_setup_trx_data();
> goto err;
Must be a mistake, should not remove the 'if'.
[snip]