From: Jon Olav Hauglid Date: March 22 2011 1:56pm Subject: bzr commit into mysql-trunk branch (jon.hauglid:3310) Bug#11766752 List-Archive: http://lists.mysql.com/commits/133529 X-Bug: 11766752 Message-Id: <201103221357.p2MDv54l004318@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7702751650744928759==" --===============7702751650744928759== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/x/mysql-trunk-bug11766752/ based on revid:magne.mahre@stripped 3310 Jon Olav Hauglid 2011-03-22 Bug #11766752 (former 59936) Multiple XA assertions - transactional statement fuzzer The problem was that the server for several statements did not check the state of the current XA transaction (if any) before trying to execute the statement. Specifically, you are not supposed to do anything other than XA PREPARE / XA COMMIT ONE PHASE when in IDLE state, or anything other than XA COMMIT / XA ROLLBACK in PREPARED state. The assertions triggered by the testcase posted in the bug report, was triggered by trying to access a table or rollback to a savepoint when the current XA transaction was in PREPARED state. This patch fixes the problem by reporting ER_XAER_RMFAIL error if 1) A statement is issued which would have caused data updates or generated row events when XA state is IDLE or PREPARED. 2) SAVEPOINT or ROLLBACK TO SAVEPOINT is executed with an active XA transaction. (Similar to what is already done for COMMIT/ROLLBACK) Test case added to xa.test. Also verified with the C testcase posted on the bug report. modified: mysql-test/r/xa.result mysql-test/t/xa.test sql/binlog.cc sql/log_event.cc sql/log_event.h sql/sql_class.cc sql/sql_parse.cc sql/sql_parse.h sql/transaction.cc sql/transaction.h === modified file 'mysql-test/r/xa.result' --- a/mysql-test/r/xa.result 2011-02-14 13:16:31 +0000 +++ b/mysql-test/r/xa.result 2011-03-22 13:56:52 +0000 @@ -166,3 +166,31 @@ ERROR XA102: XA_RBDEADLOCK: Transaction XA END 'b'; XA ROLLBACK 'b'; DROP TABLE t1; +# +# Bug#11766752 59936: multiple xa assertions - transactional +# statement fuzzer +# +CREATE TABLE t1 (a INT) engine=InnoDB; +XA START 'a'; +INSERT INTO t1 VALUES (1); +SAVEPOINT savep; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state +XA END 'a'; +SELECT * FROM t1; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state +INSERT INTO t1 VALUES (2); +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state +SAVEPOINT savep; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state +XA PREPARE 'a'; +SELECT * FROM t1; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state +INSERT INTO t1 VALUES (2); +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state +SAVEPOINT savep; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state +XA COMMIT 'a'; +SELECT * FROM t1; +a +1 +DROP TABLE t1; === modified file 'mysql-test/t/xa.test' --- a/mysql-test/t/xa.test 2011-02-14 13:16:31 +0000 +++ b/mysql-test/t/xa.test 2011-03-22 13:56:52 +0000 @@ -287,6 +287,39 @@ DROP TABLE t1; disconnect con1; +--echo # +--echo # Bug#11766752 59936: multiple xa assertions - transactional +--echo # statement fuzzer +--echo # + +CREATE TABLE t1 (a INT) engine=InnoDB; +XA START 'a'; +INSERT INTO t1 VALUES (1); + +--error ER_XAER_RMFAIL +SAVEPOINT savep; + +XA END 'a'; +--error ER_XAER_RMFAIL +SELECT * FROM t1; +--error ER_XAER_RMFAIL +INSERT INTO t1 VALUES (2); +--error ER_XAER_RMFAIL +SAVEPOINT savep; + +XA PREPARE 'a'; +--error ER_XAER_RMFAIL +SELECT * FROM t1; # used to cause InnoDB assert +--error ER_XAER_RMFAIL +INSERT INTO t1 VALUES (2); # used to cause InnoDB assert +--error ER_XAER_RMFAIL +SAVEPOINT savep; + +XA COMMIT 'a'; +SELECT * FROM t1; +DROP TABLE t1; + + # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc === modified file 'sql/binlog.cc' --- a/sql/binlog.cc 2011-03-14 17:55:26 +0000 +++ b/sql/binlog.cc 2011-03-22 13:56:52 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2009, 2011 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #include "log.h" #include "binlog.h" #include "log_event.h" +#include "sql_parse.h" #include "rpl_filter.h" #include "rpl_rli.h" #include "sql_plugin.h" @@ -5184,7 +5185,7 @@ int THD::decide_logging_format(TABLE_LIS my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0)); } else if (variables.binlog_format == BINLOG_FORMAT_ROW && - sqlcom_can_generate_row_events(this)) + can_generate_row_events(lex->sql_command)) { /* 2. Error: Cannot modify table that uses a storage engine @@ -5223,7 +5224,7 @@ int THD::decide_logging_format(TABLE_LIS my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0)); } else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 && - sqlcom_can_generate_row_events(this)) + can_generate_row_events(lex->sql_command)) { /* 5. Error: Cannot modify table that uses a storage engine === modified file 'sql/log_event.cc' --- a/sql/log_event.cc 2011-03-14 17:09:16 +0000 +++ b/sql/log_event.cc 2011-03-22 13:56:52 +0000 @@ -2824,7 +2824,7 @@ Query_log_event::Query_log_event(THD* th use_cache= trx_cache= TRUE; break; default: - use_cache= sqlcom_can_generate_row_events(thd); + use_cache= can_generate_row_events(thd->lex->sql_command); break; } === modified file 'sql/log_event.h' --- a/sql/log_event.h 2011-03-14 17:55:26 +0000 +++ b/sql/log_event.h 2011-03-22 13:56:52 +0000 @@ -4213,7 +4213,6 @@ private: int append_query_string(const CHARSET_INFO *csinfo, String const *from, String *to); -bool sqlcom_can_generate_row_events(const THD *thd); void handle_rows_query_log_event(Log_event *ev, Relay_log_info *rli); bool event_checksum_test(uchar *buf, ulong event_len, uint8 alg); === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2011-03-09 20:54:55 +0000 +++ b/sql/sql_class.cc 2011-03-22 13:56:52 +0000 @@ -41,7 +41,6 @@ #include "rpl_record.h" #include "rpl_slave.h" #include -#include "log_event.h" #include "sql_audit.h" #include #include @@ -3327,7 +3326,7 @@ extern "C" bool thd_binlog_filter_ok(con extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd) { - return sqlcom_can_generate_row_events(thd); + return can_generate_row_events(thd->lex->sql_command); } #ifndef EMBEDDED_LIBRARY === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2011-03-11 09:35:38 +0000 +++ b/sql/sql_parse.cc 2011-03-22 13:56:52 +0000 @@ -447,10 +447,11 @@ void init_update_queries(void) sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS; } -bool sqlcom_can_generate_row_events(const THD *thd) + +bool can_generate_row_events(enum enum_sql_command command) { - return (sql_command_flags[thd->lex->sql_command] & - CF_CAN_GENERATE_ROW_EVENTS); + DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); + return (sql_command_flags[command] & CF_CAN_GENERATE_ROW_EVENTS) != 0; } bool is_update_query(enum enum_sql_command command) @@ -1855,6 +1856,10 @@ mysql_execute_command(THD *thd) context.resolve_in_table_list_only(select_lex-> table_list.first); + /* Check if the command can be executed in the current XA state (if any). */ + if (trans_xa_check_state(thd)) + DBUG_RETURN(true); + /* Reset warning count for each query that uses tables A better approach would be to reset this for any commands === modified file 'sql/sql_parse.h' --- a/sql/sql_parse.h 2011-03-09 20:54:55 +0000 +++ b/sql/sql_parse.h 2011-03-22 13:56:52 +0000 @@ -79,6 +79,7 @@ bool check_host_name(LEX_STRING *str); bool check_identifier_name(LEX_STRING *str, uint max_char_length, uint err_code, const char *param_for_err_msg); bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); +bool can_generate_row_events(enum enum_sql_command command); bool is_update_query(enum enum_sql_command command); bool is_log_table_write_query(enum enum_sql_command command); bool is_rpl_info_table_write_query(enum enum_sql_command command); === modified file 'sql/transaction.cc' --- a/sql/transaction.cc 2011-02-14 14:15:28 +0000 +++ b/sql/transaction.cc 2011-03-22 13:56:52 +0000 @@ -21,6 +21,7 @@ #include "sql_priv.h" #include "transaction.h" #include "rpl_handler.h" +#include "sql_parse.h" #include "debug_sync.h" // DEBUG_SYNC /* Conditions under which the transaction state must not change. */ @@ -362,6 +363,13 @@ bool trans_savepoint(THD *thd, LEX_STRIN !opt_using_transactions) DBUG_RETURN(FALSE); + enum xa_states xa_state= thd->transaction.xid_state.xa_state; + if (xa_state != XA_NOTR) + { + my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); + DBUG_RETURN(TRUE); + } + sv= find_savepoint(thd, name); if (*sv) /* old savepoint of the same name exists */ @@ -435,6 +443,13 @@ bool trans_rollback_to_savepoint(THD *th DBUG_RETURN(TRUE); } + enum xa_states xa_state= thd->transaction.xid_state.xa_state; + if (xa_state != XA_NOTR) + { + my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); + DBUG_RETURN(TRUE); + } + if (ha_rollback_to_savepoint(thd, sv)) res= TRUE; else if (((thd->variables.option_bits & OPTION_KEEP_LOG) || @@ -743,3 +758,26 @@ bool trans_xa_rollback(THD *thd) DBUG_RETURN(res); } + + +/** + Check if the current command can be safely executed in the current XA + state (if any). If not, report ER_XAER_RMFAIL. + + The check is performed for XA_IDLE and XA_PREPARED states. + A command is unsafe if it reads or writes data. Determined using the + CF_CHANGES_DATA and CF_CAN_GENERATE_ROW_EVENTS command flags. +*/ + +bool trans_xa_check_state(THD *thd) +{ + enum xa_states xa_state= thd->transaction.xid_state.xa_state; + if ((xa_state == XA_IDLE || xa_state == XA_PREPARED) && + (is_update_query(thd->lex->sql_command) || + can_generate_row_events(thd->lex->sql_command))) + { + my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); + return true; + } + return false; +} === modified file 'sql/transaction.h' --- a/sql/transaction.h 2010-07-02 02:58:51 +0000 +++ b/sql/transaction.h 2011-03-22 13:56:52 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2008 Sun/MySQL +/* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -43,4 +43,15 @@ bool trans_xa_prepare(THD *thd); bool trans_xa_commit(THD *thd); bool trans_xa_rollback(THD *thd); +/** + Check if the current command can be safely executed in the current XA + state (if any). If not, report ER_XAER_RMFAIL. + + @param thd Thread handler + + @retval false Command can safely be executed. + @retval true Command can not be executed, ER_XAER_RMFAIL reported. +*/ +bool trans_xa_check_state(THD *thd); + #endif /* TRANSACTION_H */ --===============7702751650744928759== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/jon.hauglid@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: jon.hauglid@stripped # target_branch: file:///export/home/x/mysql-trunk-bug11766752/ # testament_sha1: 2a1af6527ec9f5c5bf15e7f198f82559766d5426 # timestamp: 2011-03-22 14:56:58 +0100 # base_revision_id: magne.mahre@stripped\ # 1vcsv5j1ejhqruwv # # Begin bundle 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 M9Tp --===============7702751650744928759==--