Hi Daogang,
Thanks for your review.
The post patch was committed, please review it.
Please find my comments below.
On Mon, 2010-12-13 at 15:20 +0800, Daogang Qu wrote:
> Hi Libing,
> Great work. See comments in-line.
>
> STATUS
> -------------------
> Not approved.
>
> RC1:
> Please s / unsafe_rollback_flags= MODIFIED_NON_TRANS_TABLE /
>
> unsafe_rollback_flags|= MODIFIED_NON_TRANS_TABLE/
> for extendibility.
OK.
I'd thought it before the patch. Both codes will have the same effect,
as these flags never appear in a statement together.
>
> RC2:
> Please s / in cannot_safely_rollback / of unsafe_rollback_flags
>
OK.
> RC3:
> Please handle these affected test cases:
> rpl.rpl_sp 'mix' [ fail ]
> rpl.rpl_mixed_drop_create_temp_table 'mix' [ fail ]
> rpl.rpl_mixed_mixing_engines 'mix' [ fail ]
> rpl.rpl_non_direct_mixed_mixing_engines 'mix' [ fail ]
> rpl.rpl_stm_innodb 'mix' [ fail ]
> rpl.rpl_non_direct_row_mixing_engines 'row' [ fail ]
> rpl.rpl_row_mixing_engines 'row' [ fail ]
> rpl.rpl_non_direct_stm_mixing_engines 'stmt' [ fail ]
>
> ROLLBACKs are binlogged for pure transaction.
> Please check updated code and fix it. Thanks!
OK.
Used --replace_column to mask the error number.
>
> RC4:
> Please s / It will lock table t2 on row /
> It will lock table t1 on row/
>
> Please s / An auxaliary file for test temporary error/
> An auxaliary file for causing temporary error/
>
OK.
> Best Regards,
>
> Daogang
>
>
> 2010-12-13 11:44, Li-Bing.Song@stripped wrote:
> > #At file:///home/anders/Work/bzrwork/wt3/mysql-trunk-bugfixing/ based on
> revid:ramil@stripped
> >
> > 3426 Li-Bing.Song@stripped 2010-12-13
> > Bug#56184 Rolled back transaction without non-trasactional table updated
> was binlogged
> > Bug#55798 Slave SQL retry on transaction inserts extra data into
> non-transaction table
> >
> > Bug#56184
> > The transaction modified non-transactional table will be binlogged with
> ROLLBACK if it
> > rolls back on master. It includes the case that all statements which
> modified
> > non-transactional table are binlogged outside(before) the transaction.
> > Example:
> > BEGIN
> > INSERT INTO trans-table;
> > INSERT INOT non-trans-table;
> > ROLLBACK
> > it will be binlogged as:
> > BEGIN
> > INSERT INTO non-trans-table;
> > COMMIT
> > BEGIN
> > INSERT INTO trans-table;
> > ROLLBACK;
> > All statements in the second binlogged transaction modify only
> transactional tables and
> > are rolled back safely on master. So the second transaction should not be
> binlogged.
> >
> > After 5.5, there are two caches for binary logs, a transactional cache
> > and a statement cache. When executing a transaction, statements that
> > modified only transactional tables are always put in transactional
> > cache. Statements that modified non-transactional tables can be put in
> > either transactional or non-transactional cache depending on different
> > situations. In this patch, a flag is added to mark if there is any
> > statement that modified non-transactional table in transactional cache.
> > When rolling back a transaction on master, transactional cache should
> > not be flushed to binary log, if there is no statement in it that
> > modified a non-transactional table. Otherwise, it should be flushed into
> > binary log followed by 'ROLLBACK' statement.
> >
> > BUG#55798
> > When a temporary error(eg. Lock timeout) happens, Slave SQL thread will
> rollback the
> > transaction and retry it again. But it is possible that the transaction
> cannot be
> > rolled back safely. For example a non-transactional table has been
> modified by the
> > transaction. It will make master and slave diversely.
> >
> > After this patch, SQL thread will not retry to execute a transaction which
> can not be rolled
> > back safely if temporary error is encountered.
> > @ mysql-test/suite/rpl/t/rpl_begin_commit_rollback.test
> > Add test to verify this patch.
> >
> >
> [ snip ]
> > === modified file 'sql/handler.h'
> > --- a/sql/handler.h 2010-11-18 16:34:56 +0000
> > +++ b/sql/handler.h 2010-12-13 03:44:47 +0000
> > @@ -830,36 +830,93 @@ struct THD_TRANS
> > /* storage engines that registered in this transaction */
> > Ha_trx_info *ha_list;
> > /*
> > - The purpose of this flag is to keep track of non-transactional
> > - tables that were modified in scope of:
> > - - transaction, when the variable is a member of
> > - THD::transaction.all
> > + The purpose of this flag is to keep track of statements which cannot be
> > + rolled back safely(completely). For example, statements modified
> > + non-transactional tables, 'DROP TEMPORARY TABLE' and
> > + 'CREATE TEMPORARY TABLE' statements. The tracked statements are
> > + modified in scope of:
> > + - transaction, when the variable is a member of THD::transaction.all
> > - top-level statement or sub-statement, when the variable is a
> > member of THD::transaction.stmt
> > This member has the following life cycle:
> > - * stmt.modified_non_trans_table is used to keep track of
> > - modified non-transactional tables of top-level statements. At
> > - the end of the previous statement and at the beginning of the session,
> > - it is reset to FALSE. If such functions
> > - as mysql_insert, mysql_update, mysql_delete etc modify a
> > - non-transactional table, they set this flag to TRUE. At the
> > - end of the statement, the value of stmt.modified_non_trans_table
> > - is merged with all.modified_non_trans_table and gets reset.
> > - * all.modified_non_trans_table is reset at the end of transaction
> > -
> > - * Since we do not have a dedicated context for execution of a
> > - sub-statement, to keep track of non-transactional changes in a
> > - sub-statement, we re-use stmt.modified_non_trans_table.
> > - At entrance into a sub-statement, a copy of the value of
> > - stmt.modified_non_trans_table (containing the changes of the
> > - outer statement) is saved on stack. Then
> > - stmt.modified_non_trans_table is reset to FALSE and the
> > - substatement is executed. Then the new value is merged with the
> > - saved value.
> > + * stmt.unsafe_rollback_flags is used to keep track of top-level statements
> > + which cannot be rolled back safely. At the end of the previous statement
> > + and at the beginning of the session, it is reset to 0. If such functions
> > + as mysql_insert, mysql_update, mysql_delete etc modify a non-transactional
> > + table, flag MODIFIED_NON_TRANS_TABLE is set. After 'CREATE TEMPORARY
> TABLE'
> > + creates a table successfully, flag CREATED_TEMP_TABLE is set. After
> > + 'DROP TEMPORARY TABLE' drops a temporary table, flag DROPPED_TEMP_TABLE is
> > + set. At the end of the statement, the value of stmt.unsafe_rollback_flags
> > + is merged with all.unsafe_rollback_flags and gets reset.
> > + * all.cannot_safely_rollback is reset at the end of transaction
> > +
> > + * Since we do not have a dedicated context for execution of a
> sub-statement,
> > + to keep track of non-transactional changes in a sub-statement, we re-use
> > + stmt.unsafe_rollback_flags. At entrance into a sub-statement, a copy of
> the
> > + value of stmt.unsafe_rollback_flags (containing the changes of the outer
> > + statement) is saved on stack. Then stmt.unsafe_rollback_flags is reset
> > + to FALSE and the substatement is executed. Then the new value is merged
> with
> > + the saved value.
> > + */
> > +private:
> > + unsigned int unsafe_rollback_flags;
> > + /*
> > + Define the type of statemens which cannot be rolled back safely.
> > + Each type occupies one bit in cannot_safely_rollback.
> >
> Please s / in cannot_safely_rollback / of unsafe_rollback_flags/
> > */
> > - bool modified_non_trans_table;
> > + enum
> > + {
> > + MODIFIED_NON_TRANS_TABLE= 0x01,
> > + CREATED_TEMP_TABLE= 0x02,
> > + DROPPED_TEMP_TABLE= 0x04
> > + };
> > +public:
> > + bool cannot_safely_rollback() const
> > + {
> > + return unsafe_rollback_flags > 0;
> > + }
> > + unsigned int get_unsafe_rollback_flags() const
> > + {
> > + return unsafe_rollback_flags;
> > + }
> > + void set_unsafe_rollback_flags(unsigned int flags)
> > + {
> > + unsafe_rollback_flags= flags;
> > + }
> > + void add_unsafe_rollback_flags(unsigned int flags)
> > + {
> > + unsafe_rollback_flags|= flags;
> > + }
> > + void reset_unsafe_rollback_flags()
> > + {
> > + unsafe_rollback_flags= 0;
> > + }
> > + void modified_non_trans_table()
> > + {
> > + unsafe_rollback_flags= MODIFIED_NON_TRANS_TABLE;
> >
> Please s / unsafe_rollback_flags= MODIFIED_NON_TRANS_TABLE /
>
> unsafe_rollback_flags|= MODIFIED_NON_TRANS_TABLE/
> for extendibility.
>
> > + }
> > + bool has_modified_non_trans_table() const
> > + {
> > + return unsafe_rollback_flags & MODIFIED_NON_TRANS_TABLE;
> > + }
> > + void created_temp_table()
> > + {
> > + unsafe_rollback_flags= CREATED_TEMP_TABLE;
> >
> Please s / unsafe_rollback_flags= CREATED_TEMP_TABLE /
>
> unsafe_rollback_flags|= CREATED_TEMP_TABLE/
> for extendibility.
>
> > + }
> > + bool has_created_temp_table() const
> > + {
> > + return unsafe_rollback_flags & CREATED_TEMP_TABLE;
> > + }
> > + void dropped_temp_table()
> > + {
> > + unsafe_rollback_flags= DROPPED_TEMP_TABLE;
> >
> Please s / unsafe_rollback_flags= DROPPED_TEMP_TABLE /
>
> unsafe_rollback_flags|= DROPPED_TEMP_TABLE/
> for extendibility.
>
> > + }
> > + bool has_dropped_temp_table() const
> > + {
> > + return unsafe_rollback_flags & DROPPED_TEMP_TABLE;
> > + }
> >
> > - void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; }
> > + void reset() { no_2pc= FALSE; reset_unsafe_rollback_flags(); }
> > bool is_empty() const { return ha_list == NULL; }
> > };
> >
> >
> > === modified file 'sql/log_event.cc'
> > --- a/sql/log_event.cc 2010-12-05 22:51:49 +0000
> > +++ b/sql/log_event.cc 2010-12-13 03:44:47 +0000
> > @@ -3752,7 +3752,7 @@ Default database: '%s'. Query: '%s'",
> > if (strcmp("COMMIT", query) != 0 &&
> > strcmp("BEGIN", query) != 0)
> > {
> > - if (thd->transaction.all.modified_non_trans_table)
> > + if (thd->transaction.all.cannot_safely_rollback())
> > const_cast<Relay_log_info*>(rli)->abort_slave=
> 1;
> > };);
> > }
> > @@ -7894,7 +7894,7 @@ int Rows_log_event::do_apply_event(Relay
> > has not yet modified anything. Note, all.modified is reset
> > by mysql_reset_thd_for_next_command.
> > */
> > - thd->transaction.stmt.modified_non_trans_table= FALSE;
> > + thd->transaction.stmt.reset_unsafe_rollback_flags();
> > /*
> > This is a row injection, so we flag the "statement" as
> > such. Note that this code is called both when the slave does row
> > @@ -8129,8 +8129,10 @@ int Rows_log_event::do_apply_event(Relay
> > m_curr_row= m_curr_row_end;
> >
> > if (error == 0 && !transactional_table)
> > - thd->transaction.all.modified_non_trans_table=
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + {
> > + thd->transaction.all.modified_non_trans_table();
> > + thd->transaction.stmt.modified_non_trans_table();
> > + }
> >
> > if (m_curr_row == m_rows_end)
> > break;
> > @@ -8143,7 +8145,7 @@ int Rows_log_event::do_apply_event(Relay
> > to shutdown trying to finish incomplete events group.
> > */
> > DBUG_EXECUTE_IF("stop_slave_middle_group",
> > - if (thd->transaction.all.modified_non_trans_table)
> > + if (thd->transaction.all.cannot_safely_rollback())
> > const_cast<Relay_log_info*>(rli)->abort_slave=
> 1;);
> > }
> >
> >
> > === modified file 'sql/rpl_slave.cc'
> > --- a/sql/rpl_slave.cc 2010-12-06 13:12:51 +0000
> > +++ b/sql/rpl_slave.cc 2010-12-13 03:44:47 +0000
> > @@ -1016,17 +1016,7 @@ static bool sql_slave_killed(THD* thd, R
> > DBUG_ASSERT(rli->slave_running == 1);// tracking buffer overrun
> > if (abort_loop || thd->killed || rli->abort_slave)
> > {
> > - /*
> > - The transaction should always be binlogged if OPTION_KEEP_LOG is set
> > - (it implies that something can not be rolled back). And such case
> > - should be regarded similarly as modifing a non-transactional table
> > - because retrying of the transaction will lead to an error or
> inconsistency
> > - as well.
> > - Example: OPTION_KEEP_LOG is set if a temporary table is created or
> dropped.
> > - */
> > - if ((thd->transaction.all.modified_non_trans_table ||
> > - (thd->variables.option_bits & OPTION_KEEP_LOG))
> > - && rli->is_in_group())
> > + if (thd->transaction.all.cannot_safely_rollback() &&
> rli->is_in_group())
> > {
> > char msg_stopped[]=
> > "... The slave SQL is stopped, leaving the current group "
> > @@ -2933,7 +2923,7 @@ static int exec_relay_log_event(THD* thd
> > ((ev->get_type_code() == QUERY_EVENT) &&
> > strcmp("COMMIT", ((Query_log_event *) ev)->query)
> == 0))
> > {
> > -
> DBUG_ASSERT(thd->transaction.all.modified_non_trans_table);
> > +
> DBUG_ASSERT(thd->transaction.all.cannot_safely_rollback());
> > rli->abort_slave= 1;
> > mysql_mutex_unlock(&rli->data_lock);
> > delete ev;
> > @@ -2972,7 +2962,8 @@ static int exec_relay_log_event(THD* thd
> > if (slave_trans_retries)
> > {
> > int UNINIT_VAR(temp_err);
> > - if (exec_res && (temp_err= has_temporary_error(thd)))
> > + if (exec_res && (temp_err= has_temporary_error(thd)) &&
> > + !thd->transaction.all.cannot_safely_rollback())
> > {
> > const char *errmsg;
> > /*
> >
> > === modified file 'sql/share/errmsg-utf8.txt'
> > --- a/sql/share/errmsg-utf8.txt 2010-12-05 22:51:49 +0000
> > +++ b/sql/share/errmsg-utf8.txt 2010-12-13 03:44:47 +0000
> > @@ -6439,6 +6439,7 @@ ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MA
> > ER_PARTITION_EXCHANGE_FOREIGN_KEY
> > eng "Table to exchange with partition has foreign key references: '%-.64s'"
> > swe "Tabellen att byta ut mot partition har foreign key referenser:
> '%-.64s'"
> > +
> > ER_NO_SUCH_KEY_VALUE
> > eng "Key value '%-.192s' was not found in table '%-.192s.%-.192s'"
> > ER_RPL_INFO_DATA_TOO_LONG
> > @@ -6454,3 +6455,9 @@ ER_STMT_CACHE_FULL
> > eng "Multi-row statements required more than
> 'max_binlog_stmt_cache_size' bytes of storage; increase this mysqld variable and try
> again"
> > ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_MAX
> > eng "Option binlog_stmt_cache_size (%lu) is greater than
> max_binlog_stmt_cache_size (%lu); setting binlog_stmt_cache_size equal to
> max_binlog_stmt_cache_size."
> > +
> > +ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE
> > + eng "The creation of some temporary tables could not be rolled back."
> > +
> > +ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE
> > + eng "Some temporary tables were dropped, but these operations could not be
> rolled back."
> >
> > === modified file 'sql/sp_head.cc'
> > --- a/sql/sp_head.cc 2010-12-06 13:12:51 +0000
> > +++ b/sql/sp_head.cc 2010-12-13 03:44:47 +0000
> > @@ -376,8 +376,8 @@ sp_eval_expr(THD *thd, Field *result_fie
> > Item *expr_item;
> > enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
> > bool save_abort_on_warning= thd->abort_on_warning;
> > - bool save_stmt_modified_non_trans_table=
> > - thd->transaction.stmt.modified_non_trans_table;
> > + unsigned int stmt_unsafe_rollback_flags=
> > + thd->transaction.stmt.get_unsafe_rollback_flags();
> >
> > DBUG_ENTER("sp_eval_expr");
> >
> > @@ -398,7 +398,7 @@ sp_eval_expr(THD *thd, Field *result_fie
> > thd->abort_on_warning=
> > thd->variables.sql_mode &
> > (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES);
> > - thd->transaction.stmt.modified_non_trans_table= FALSE;
> > + thd->transaction.stmt.reset_unsafe_rollback_flags();
> >
> > /* Save the value in the field. Convert the value if needed. */
> >
> > @@ -406,7 +406,7 @@ sp_eval_expr(THD *thd, Field *result_fie
> >
> > thd->count_cuted_fields= save_count_cuted_fields;
> > thd->abort_on_warning= save_abort_on_warning;
> > - thd->transaction.stmt.modified_non_trans_table=
> save_stmt_modified_non_trans_table;
> > +
> thd->transaction.stmt.set_unsafe_rollback_flags(stmt_unsafe_rollback_flags);
> >
> > if (!thd->is_error())
> > DBUG_RETURN(FALSE);
> > @@ -2914,11 +2914,13 @@ sp_lex_keeper::reset_lex_and_exec_core(T
> > It's reset further in the common code part.
> > It's merged with the saved parent's value at the exit of this func.
> > */
> > - bool parent_modified_non_trans_table=
> thd->transaction.stmt.modified_non_trans_table;
> > - if (check_stack_overrun(thd, STACK_MIN_SIZE,
> (uchar*)&parent_modified_non_trans_table))
> > + unsigned int parent_unsafe_rollback_flags=
> > + thd->transaction.stmt.get_unsafe_rollback_flags();
> > + if (check_stack_overrun(thd, STACK_MIN_SIZE,
> > + (uchar*)&parent_unsafe_rollback_flags))
> > DBUG_RETURN(TRUE);
> >
> > - thd->transaction.stmt.modified_non_trans_table= FALSE;
> > + thd->transaction.stmt.reset_unsafe_rollback_flags();
> > DBUG_ASSERT(!thd->derived_tables);
> > DBUG_ASSERT(thd->change_list.is_empty());
> > /*
> > @@ -3015,7 +3017,7 @@ sp_lex_keeper::reset_lex_and_exec_core(T
> > Merge here with the saved parent's values
> > what is needed from the substatement gained
> > */
> > - thd->transaction.stmt.modified_non_trans_table |=
> parent_modified_non_trans_table;
> > +
> thd->transaction.stmt.add_unsafe_rollback_flags(parent_unsafe_rollback_flags);
> > /*
> > Unlike for PS we should not call Item's destructors for newly created
> > items after execution of each instruction in stored routine. This is
> >
> > === modified file 'sql/sql_class.cc'
> > --- a/sql/sql_class.cc 2010-11-18 16:34:56 +0000
> > +++ b/sql/sql_class.cc 2010-12-13 03:44:47 +0000
> > @@ -938,8 +938,8 @@ void THD::init(void)
> > if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
> > server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
> >
> > - transaction.all.modified_non_trans_table=
> > - transaction.stmt.modified_non_trans_table= FALSE;
> > + transaction.all.reset_unsafe_rollback_flags();
> > + transaction.stmt.reset_unsafe_rollback_flags();
> > open_options=ha_open_options;
> > update_lock_default= (variables.low_priority_updates ?
> > TL_WRITE_LOW_PRIORITY :
> > @@ -3221,7 +3221,7 @@ extern "C" int thd_slave_thread(const MY
> >
> > extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
> > {
> > - return(thd->transaction.all.modified_non_trans_table);
> > + return thd->transaction.all.has_modified_non_trans_table();
> > }
> >
> > extern "C" int thd_binlog_format(const MYSQL_THD thd)
> >
> > === modified file 'sql/sql_class.h'
> > --- a/sql/sql_class.h 2010-11-29 16:27:58 +0000
> > +++ b/sql/sql_class.h 2010-12-13 03:44:47 +0000
> > @@ -1741,6 +1741,23 @@ public:
> > xid_state.xid.null();
> > init_sql_alloc(&mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
> > }
> > + void push_unsafe_rollback_warnings(THD *thd)
> > + {
> > + if (all.has_modified_non_trans_table())
> > + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> > + ER_WARNING_NOT_COMPLETE_ROLLBACK,
> > + ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
> > +
> > + if (all.has_created_temp_table())
> > + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> > + ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE,
> > +
> ER(ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_CREATED_TEMP_TABLE));
> > +
> > + if (all.has_dropped_temp_table())
> > + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> > + ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE,
> > +
> ER(ER_WARNING_NOT_COMPLETE_ROLLBACK_WITH_DROPPED_TEMP_TABLE));
> > + }
> > } transaction;
> > Global_read_lock global_read_lock;
> > Field *dup_field;
> > @@ -2544,7 +2561,7 @@ public:
> > inline bool really_abort_on_warning()
> > {
> > return (abort_on_warning &&
> > - (!transaction.stmt.modified_non_trans_table ||
> > + (!transaction.stmt.cannot_safely_rollback() ||
> > (variables.sql_mode & MODE_STRICT_ALL_TABLES)));
> > }
> > void set_status_var_init();
> >
> > === modified file 'sql/sql_delete.cc'
> > --- a/sql/sql_delete.cc 2010-10-21 11:34:17 +0000
> > +++ b/sql/sql_delete.cc 2010-12-13 03:44:47 +0000
> > @@ -372,11 +372,10 @@ cleanup:
> > transactional_table= table->file->has_transactions();
> >
> > if (!transactional_table && deleted > 0)
> > - thd->transaction.stmt.modified_non_trans_table=
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> >
> > /* See similar binlogging code in sql_update.cc, for comments */
> > - if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
> > + if ((error < 0) || thd->transaction.stmt.cannot_safely_rollback())
> > {
> > if (mysql_bin_log.is_open())
> > {
> > @@ -403,7 +402,7 @@ cleanup:
> > }
> > }
> > }
> > - DBUG_ASSERT(transactional_table || !deleted ||
> thd->transaction.stmt.modified_non_trans_table);
> > + DBUG_ASSERT(transactional_table || !deleted ||
> thd->transaction.stmt.cannot_safely_rollback());
> > free_underlaid_joins(thd, select_lex);
> > if (error < 0 ||
> > (thd->lex->ignore && !thd->is_error() &&
> !thd->is_fatal_error))
> > @@ -727,7 +726,7 @@ bool multi_delete::send_data(List<Item>
> > {
> > deleted++;
> > if (!table->file->has_transactions())
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> > if (table->triggers &&
> > table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
> > TRG_ACTION_AFTER, FALSE))
> > @@ -774,16 +773,13 @@ void multi_delete::abort_result_set()
> >
> > /* the error was handled or nothing deleted and no side effects return */
> > if (error_handled ||
> > - (!thd->transaction.stmt.modified_non_trans_table &&
> !deleted))
> > + (!thd->transaction.stmt.cannot_safely_rollback() &&
> !deleted))
> > DBUG_VOID_RETURN;
> >
> > /* Something already deleted so we have to invalidate cache */
> > if (deleted)
> > query_cache_invalidate3(thd, delete_tables, 1);
> >
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > -
> > /*
> > If rows from the first table only has been deleted and it is
> > transactional, just do rollback.
> > @@ -804,7 +800,7 @@ void multi_delete::abort_result_set()
> > DBUG_VOID_RETURN;
> > }
> >
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > + if (thd->transaction.stmt.cannot_safely_rollback())
> > {
> > /*
> > there is only side effects; to binlog with the error
> > @@ -941,7 +937,7 @@ int multi_delete::do_table_deletes(TABLE
> > }
> > }
> > if (last_deleted != deleted &&
> !table->file->has_transactions())
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> >
> > end_read_record(&info);
> >
> > @@ -969,9 +965,6 @@ bool multi_delete::send_eof()
> > /* reset used flags */
> > thd_proc_info(thd, "end");
> >
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > -
> > /*
> > We must invalidate the query cache before binlog writing and
> > ha_autocommit_...
> > @@ -980,7 +973,7 @@ bool multi_delete::send_eof()
> > {
> > query_cache_invalidate3(thd, delete_tables, 1);
> > }
> > - if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
> > + if ((local_error == 0) || thd->transaction.stmt.cannot_safely_rollback())
> > {
> > if (mysql_bin_log.is_open())
> > {
> >
> > === modified file 'sql/sql_insert.cc'
> > --- a/sql/sql_insert.cc 2010-11-29 16:27:58 +0000
> > +++ b/sql/sql_insert.cc 2010-12-13 03:44:47 +0000
> > @@ -976,11 +976,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
> > query_cache_invalidate3(thd, table_list, 1);
> > }
> >
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > -
> > if ((changed && error <= 0) ||
> > - thd->transaction.stmt.modified_non_trans_table ||
> > + thd->transaction.stmt.cannot_safely_rollback() ||
> > was_insert_delayed)
> > {
> > if (mysql_bin_log.is_open())
> > @@ -1041,7 +1038,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
> > }
> > }
> > DBUG_ASSERT(transactional_table || !changed ||
> > - thd->transaction.stmt.modified_non_trans_table);
> > + thd->transaction.stmt.cannot_safely_rollback());
> > }
> > thd_proc_info(thd, "end");
> > /*
> > @@ -1481,8 +1478,8 @@ static int last_uniq_key(TABLE *table,ui
> > then both on update triggers will work instead. Similarly both on
> > delete triggers will be invoked if we will delete conflicting records.
> >
> > - Sets thd->transaction.stmt.modified_non_trans_table to TRUE if table
> which is updated didn't have
> > - transactions.
> > + Call thd->transaction.stmt.modified_non_trans_table() if table is a
> > + a non-transactional table.
> >
> > RETURN VALUE
> > 0 - success
> > @@ -1699,7 +1696,7 @@ int write_record(THD *thd, TABLE *table,
> > goto err;
> > info->deleted++;
> > if (!table->file->has_transactions())
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> > if (table->triggers &&
> > table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
> > TRG_ACTION_AFTER, TRUE))
> > @@ -1751,7 +1748,7 @@ ok_or_after_trg_err:
> > if (key)
> > my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH);
> > if (!table->file->has_transactions())
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> > DBUG_RETURN(trg_error);
> >
> > err:
> > @@ -3527,11 +3524,8 @@ bool select_insert::send_eof()
> > query_cache_invalidate3(thd, table, 1);
> > }
> >
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > -
> > DBUG_ASSERT(trans_table || !changed ||
> > - thd->transaction.stmt.modified_non_trans_table);
> > + thd->transaction.stmt.cannot_safely_rollback());
> >
> > /*
> > Write to binlog before commiting transaction. No statement will
> > @@ -3540,7 +3534,7 @@ bool select_insert::send_eof()
> > ha_autocommit_or_rollback() is issued below.
> > */
> > if (mysql_bin_log.is_open() &&
> > - (!error || thd->transaction.stmt.modified_non_trans_table))
> > + (!error || thd->transaction.stmt.cannot_safely_rollback()))
> > {
> > int errcode= 0;
> > if (!error)
> > @@ -3618,10 +3612,10 @@ void select_insert::abort_result_set() {
> > */
> > changed= (info.copied || info.deleted || info.updated);
> > transactional_table= table->file->has_transactions();
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > + if (thd->transaction.stmt.cannot_safely_rollback())
> > {
> > if (!can_rollback_data())
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > + thd->transaction.all.modified_non_trans_table();
> >
> > if (mysql_bin_log.is_open())
> > {
> > @@ -3635,7 +3629,7 @@ void select_insert::abort_result_set() {
> > query_cache_invalidate3(thd, table, 1);
> > }
> > DBUG_ASSERT(transactional_table || !changed ||
> > - thd->transaction.stmt.modified_non_trans_table);
> > + thd->transaction.stmt.cannot_safely_rollback());
> > table->file->ha_release_auto_increment();
> > }
> >
> > @@ -4055,6 +4049,9 @@ void select_create::send_error(uint errc
> >
> > bool select_create::send_eof()
> > {
> > + if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
> > + thd->transaction.stmt.created_temp_table();
> > +
> > bool tmp=select_insert::send_eof();
> > if (tmp)
> > abort_result_set();
> > @@ -4105,7 +4102,7 @@ void select_create::abort_result_set()
> > */
> > tmp_disable_binlog(thd);
> > select_insert::abort_result_set();
> > - thd->transaction.stmt.modified_non_trans_table= FALSE;
> > + thd->transaction.stmt.reset_unsafe_rollback_flags();
> > reenable_binlog(thd);
> > /* possible error of writing binary log is ignored deliberately */
> > (void) thd->binlog_flush_pending_rows_event(TRUE, TRUE);
> >
> > === modified file 'sql/sql_lex.h'
> > --- a/sql/sql_lex.h 2010-12-02 15:05:07 +0000
> > +++ b/sql/sql_lex.h 2010-12-13 03:44:47 +0000
> > @@ -1425,24 +1425,6 @@ public:
> > DBUG_RETURN((stmt_accessed_table_flag & (1U << accessed_table))
> != 0);
> > }
> >
> > - /**
> > - Checks if a temporary non-transactional table is about to be accessed
> > - while executing a statement.
> > -
> > - @return
> > - @retval TRUE if a temporary non-transactional table is about to be
> > - accessed
> > - @retval FALSE otherwise
> > - */
> > - inline bool stmt_accessed_non_trans_temp_table()
> > - {
> > - DBUG_ENTER("THD::stmt_accessed_non_trans_temp_table");
> > -
> > - DBUG_RETURN((stmt_accessed_table_flag &
> > - ((1U << STMT_READS_TEMP_NON_TRANS_TABLE) |
> > - (1U << STMT_WRITES_TEMP_NON_TRANS_TABLE))) != 0);
> > - }
> > -
> > /*
> > Checks if a mixed statement is unsafe.
> >
> >
> > === modified file 'sql/sql_load.cc'
> > --- a/sql/sql_load.cc 2010-10-21 12:18:25 +0000
> > +++ b/sql/sql_load.cc 2010-12-13 03:44:47 +0000
> > @@ -568,7 +568,7 @@ int mysql_load(THD *thd,sql_exchange *ex
> >
> > /* since there is already an error, the possible error of
> > writing binary log will be ignored */
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > + if (thd->transaction.stmt.cannot_safely_rollback())
> > (void) write_execute_load_query_log_event(thd, ex,
> > table_list->db,
> >
> table_list->table_name,
> > @@ -592,8 +592,6 @@ int mysql_load(THD *thd,sql_exchange *ex
> > (ulong) (info.records - info.copied),
> > (ulong) thd->warning_info->statement_warn_count());
> >
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > #ifndef EMBEDDED_LIBRARY
> > if (mysql_bin_log.is_open())
> > {
> > @@ -635,7 +633,7 @@ int mysql_load(THD *thd,sql_exchange *ex
> > my_ok(thd, info.copied + info.deleted, 0L, name);
> > err:
> > DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) ||
> > - thd->transaction.stmt.modified_non_trans_table);
> > + thd->transaction.stmt.cannot_safely_rollback());
> > table->file->ha_release_auto_increment();
> > table->auto_increment_field_not_null= FALSE;
> > thd->abort_on_warning= 0;
> > @@ -1256,7 +1254,8 @@ read_xml_field(THD *thd, COPY_INFO &info
> > We don't need to reset auto-increment field since we are restoring
> > its default value at the beginning of each loop iteration.
> > */
> > - thd->transaction.stmt.modified_non_trans_table= no_trans_update_stmt;
> > + if (no_trans_update_stmt)
> > + thd->transaction.stmt.modified_non_trans_table();
> > thd->warning_info->inc_current_row_for_warning();
> > continue_loop:;
> > }
> >
> > === modified file 'sql/sql_parse.cc'
> > --- a/sql/sql_parse.cc 2010-11-29 11:28:55 +0000
> > +++ b/sql/sql_parse.cc 2010-12-13 03:44:47 +0000
> > @@ -1993,7 +1993,7 @@ mysql_execute_command(THD *thd)
> >
> > status_var_increment(thd->status_var.com_stat[lex->sql_command]);
> >
> > - DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
> > + DBUG_ASSERT(thd->transaction.stmt.cannot_safely_rollback() == FALSE);
> >
> > /*
> > End a active transaction so that this command will have it's
> > @@ -2446,10 +2446,6 @@ case SQLCOM_PREPARE:
> > */
> > lex->unlink_first_table(&link_to_local);
> >
> > - /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
> > - if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
> > - thd->variables.option_bits|= OPTION_KEEP_LOG;
> > -
> > /*
> > select_create is currently not re-execution friendly and
> > needs to be created for every execution of a PS/SP.
> > @@ -2475,9 +2471,6 @@ case SQLCOM_PREPARE:
> > }
> > else
> > {
> > - /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
> > - if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
> > - thd->variables.option_bits|= OPTION_KEEP_LOG;
> > /* regular create */
> > if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
> > {
> > @@ -2998,11 +2991,6 @@ end_with_restore_list:
> > if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX,
> FALSE))
> > goto error; /* purecov: inspected */
> > }
> > - else
> > - {
> > - /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
> > - thd->variables.option_bits|= OPTION_KEEP_LOG;
> > - }
> > /* DDL and binlog write order are protected by metadata locks. */
> > res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
> > lex->drop_temporary);
> > @@ -4368,9 +4356,17 @@ finish:
> > DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() ||
> > thd->in_multi_stmt_transaction_mode());
> >
> > -
> > if (! thd->in_sub_stmt)
> > {
> > +
> > + /*
> > + Merge stmt.unsafe_rollback_flags to all.unsafe_rollback_flags. If
> > + the statement cannot be rolled back safely, the transaction including
> > + this transaction definitely cannot rolled back safely.
> > + */
> > + THD::st_transactions &trans= thd->transaction;
> > +
> trans.all.add_unsafe_rollback_flags(trans.stmt.get_unsafe_rollback_flags());
> > +
> > /* report error issued during command execution */
> > if (thd->killed_errno())
> > {
> > @@ -5247,15 +5243,9 @@ void THD::reset_for_next_command()
> > beginning of each SQL statement.
> > */
> > thd->server_status&= ~SERVER_STATUS_CLEAR_SET;
> > - /*
> > - If in autocommit mode and not in a transaction, reset
> > - OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings
> > - in ha_rollback_trans() about some tables couldn't be rolled back.
> > - */
> > if (!thd->in_multi_stmt_transaction_mode())
> > {
> > - thd->variables.option_bits&= ~OPTION_KEEP_LOG;
> > - thd->transaction.all.modified_non_trans_table= FALSE;
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> > }
> > DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
> > thd->thread_specific_used= FALSE;
> >
> > === modified file 'sql/sql_priv.h'
> > --- a/sql/sql_priv.h 2010-12-06 13:12:51 +0000
> > +++ b/sql/sql_priv.h 2010-12-13 03:44:47 +0000
> > @@ -101,7 +101,6 @@
> > #define OPTION_BEGIN (1ULL << 20) // THD, intern
> > #define OPTION_TABLE_LOCK (1ULL << 21) // THD, intern
> > #define OPTION_QUICK (1ULL << 22) // SELECT (for DELETE)
> > -#define OPTION_KEEP_LOG (1ULL << 23) // THD, user
> >
> > /* The following is used to detect a conflict with DISTINCT */
> > #define SELECT_ALL (1ULL << 24) // SELECT, user, parser
> >
> > === modified file 'sql/sql_table.cc'
> > --- a/sql/sql_table.cc 2010-11-29 16:27:58 +0000
> > +++ b/sql/sql_table.cc 2010-12-13 03:44:47 +0000
> > @@ -2240,6 +2240,14 @@ int mysql_rm_table_no_locks(THD *thd, TA
> > goto err;
> > }
> >
> > + /*
> > + DROP TEMPORARY TABLE doesn't terminate a transaction. Calling
> > + stmt.dropped_temp_table() guarantees the transaction can be binlogged
> > + correctly.
> > + */
> > + if (!error && drop_temporary)
> > + thd->transaction.stmt.dropped_temp_table();
> > +
> > if ((drop_temporary && if_exists) || !error)
> > {
> > /*
> > @@ -4541,6 +4549,13 @@ bool mysql_create_table(THD *thd, TABLE_
> > result= mysql_create_table_no_lock(thd, create_table->db,
> > create_table->table_name, create_info,
> > alter_info, FALSE, 0, &is_trans);
> > + /*
> > + CREATE TEMPORARY TABLE doesn't terminate a transaction. Calling
> > + stmt.created_temp_table() guarantees the transaction can be binlogged
> > + correctly.
> > + */
> > + if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
> > + thd->transaction.stmt.created_temp_table();
> >
> > /*
> > Don't write statement if:
> > @@ -4773,6 +4788,14 @@ bool mysql_create_like_table(THD* thd, T
> > table->table_name,
> > MDL_EXCLUSIVE));
> > /*
> > + CREATE TEMPORARY TABLE doesn't terminate a transaction. Calling
> > + stmt.created_temp_table() guarantees the transaction can be binlogged
> > + correctly.
> > + */
> > + if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
> > + thd->transaction.stmt.created_temp_table();
> > +
> > + /*
> > We have to write the query before we unlock the tables.
> > */
> > if (thd->is_current_stmt_binlog_format_row())
> >
> > === modified file 'sql/sql_truncate.cc'
> > --- a/sql/sql_truncate.cc 2010-10-21 11:34:17 +0000
> > +++ b/sql/sql_truncate.cc 2010-12-13 03:44:47 +0000
> > @@ -415,7 +415,7 @@ bool Sql_cmd_truncate_table::truncate_ta
> > if ((error= recreate_temporary_table(thd, table)))
> > binlog_stmt= FALSE; /* No need to binlog failed truncate-by-recreate.
> */
> >
> > - DBUG_ASSERT(! thd->transaction.stmt.modified_non_trans_table);
> > + DBUG_ASSERT(! thd->transaction.stmt.cannot_safely_rollback());
> > }
> > else
> > {
> >
> > === modified file 'sql/sql_update.cc'
> > --- a/sql/sql_update.cc 2010-11-18 16:34:56 +0000
> > +++ b/sql/sql_update.cc 2010-12-13 03:44:47 +0000
> > @@ -834,7 +834,7 @@ int mysql_update(THD *thd,
> > table->file->try_semi_consistent_read(0);
> >
> > if (!transactional_table && updated > 0)
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> >
> > end_read_record(&info);
> > delete select;
> > @@ -850,9 +850,6 @@ int mysql_update(THD *thd,
> > query_cache_invalidate3(thd, table_list, 1);
> > }
> >
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > -
> > /*
> > error < 0 means really no error at all: we processed all rows until the
> > last one without error. error > 0 means an error (e.g. unique key
> > @@ -862,7 +859,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) || thd->transaction.stmt.modified_non_trans_table)
> > + if ((error < 0) || thd->transaction.stmt.cannot_safely_rollback())
> > {
> > if (mysql_bin_log.is_open())
> > {
> > @@ -880,7 +877,8 @@ int mysql_update(THD *thd,
> > }
> > }
> > }
> > - DBUG_ASSERT(transactional_table || !updated ||
> thd->transaction.stmt.modified_non_trans_table);
> > + DBUG_ASSERT(transactional_table || !updated ||
> > + thd->transaction.stmt.cannot_safely_rollback());
> > free_underlaid_joins(thd, select_lex);
> >
> > /* If LAST_INSERT_ID(X) was used, report X */
> > @@ -1670,8 +1668,8 @@ multi_update::~multi_update()
> > if (copy_field)
> > delete [] copy_field;
> > thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting
> > - DBUG_ASSERT(trans_safe || !updated ||
> > - thd->transaction.all.modified_non_trans_table);
> > + DBUG_ASSERT(trans_safe || !updated ||
> > + thd->transaction.stmt.cannot_safely_rollback());
> > }
> >
> >
> > @@ -1772,7 +1770,7 @@ bool multi_update::send_data(List<Item>
> > else
> > {
> > trans_safe= FALSE;
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> > }
> > }
> > }
> > @@ -1843,7 +1841,7 @@ void multi_update::abort_result_set()
> > {
> > /* the error was handled or nothing deleted and no side effects return */
> > if (error_handled ||
> > - (!thd->transaction.stmt.modified_non_trans_table &&
> !updated))
> > + (!thd->transaction.stmt.cannot_safely_rollback() &&
> !updated))
> > return;
> >
> > /* Something already updated so we have to invalidate cache */
> > @@ -1856,7 +1854,7 @@ void multi_update::abort_result_set()
> >
> > if (! trans_safe)
> > {
> > - DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table);
> > + DBUG_ASSERT(thd->transaction.stmt.cannot_safely_rollback());
> > if (do_update && table_count > 1)
> > {
> > /* Add warning here */
> > @@ -1867,7 +1865,7 @@ void multi_update::abort_result_set()
> > (void) do_updates();
> > }
> > }
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > + if (thd->transaction.stmt.cannot_safely_rollback())
> > {
> > /*
> > The query has to binlog because there's a modified non-transactional
> table
> > @@ -1886,9 +1884,9 @@ void multi_update::abort_result_set()
> > thd->query(), thd->query_length(),
> > transactional_tables, FALSE, FALSE, errcode);
> > }
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > + thd->transaction.all.modified_non_trans_table();
> > }
> > - DBUG_ASSERT(trans_safe || !updated ||
> thd->transaction.stmt.modified_non_trans_table);
> > + DBUG_ASSERT(trans_safe || !updated ||
> thd->transaction.stmt.cannot_safely_rollback());
> > }
> >
> >
> > @@ -2020,7 +2018,7 @@ int multi_update::do_updates()
> > else
> > {
> > trans_safe= FALSE; // Can't do safe rollback
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> > }
> > }
> > (void) table->file->ha_rnd_end();
> > @@ -2052,7 +2050,7 @@ err2:
> > else
> > {
> > trans_safe= FALSE;
> > - thd->transaction.stmt.modified_non_trans_table= TRUE;
> > + thd->transaction.stmt.modified_non_trans_table();
> > }
> > }
> > DBUG_RETURN(1);
> > @@ -2099,10 +2097,7 @@ bool multi_update::send_eof()
> > either from the query's list or via a stored routine: bug#13270,23333
> > */
> >
> > - if (thd->transaction.stmt.modified_non_trans_table)
> > - thd->transaction.all.modified_non_trans_table= TRUE;
> > -
> > - if (local_error == 0 || thd->transaction.stmt.modified_non_trans_table)
> > + if (local_error == 0 || thd->transaction.stmt.cannot_safely_rollback())
> > {
> > if (mysql_bin_log.is_open())
> > {
> > @@ -2120,7 +2115,7 @@ bool multi_update::send_eof()
> > }
> > }
> > DBUG_ASSERT(trans_safe || !updated ||
> > - thd->transaction.stmt.modified_non_trans_table);
> > + thd->transaction.stmt.cannot_safely_rollback());
> >
> > if (local_error != 0)
> > error_handled= TRUE; // to force early leave from ::send_error()
> >
> > === modified file 'sql/sys_vars.cc'
> > --- a/sql/sys_vars.cc 2010-12-07 18:11:49 +0000
> > +++ b/sql/sys_vars.cc 2010-12-13 03:44:47 +0000
> > @@ -2347,8 +2347,8 @@ static bool fix_autocommit(sys_var *self
> > transaction implicitly at the end (@sa stmt_causes_implicitcommit()).
> > */
> > thd->variables.option_bits&=
> > - ~(OPTION_BEGIN | OPTION_KEEP_LOG | OPTION_NOT_AUTOCOMMIT);
> > - thd->transaction.all.modified_non_trans_table= false;
> > + ~(OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT);
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> > thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
> > return false;
> > }
> > @@ -2357,7 +2357,7 @@ static bool fix_autocommit(sys_var *self
> > !(thd->variables.option_bits & OPTION_NOT_AUTOCOMMIT))
> > { // disabling autocommit
> >
> > - thd->transaction.all.modified_non_trans_table= false;
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> > thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT;
> > thd->variables.option_bits|= OPTION_NOT_AUTOCOMMIT;
> > return false;
> >
> > === modified file 'sql/transaction.cc'
> > --- a/sql/transaction.cc 2010-11-18 16:34:56 +0000
> > +++ b/sql/transaction.cc 2010-12-13 03:44:47 +0000
> > @@ -111,8 +111,8 @@ bool trans_begin(THD *thd, uint flags)
> > res= test(ha_commit_trans(thd, TRUE));
> > }
> >
> > - thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
> > - thd->transaction.all.modified_non_trans_table= FALSE;
> > + thd->variables.option_bits&= ~OPTION_BEGIN;
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> >
> > if (res)
> > DBUG_RETURN(TRUE);
> > @@ -160,8 +160,8 @@ bool trans_commit(THD *thd)
> > RUN_HOOK(transaction, after_rollback, (thd, FALSE));
> > else
> > RUN_HOOK(transaction, after_commit, (thd, FALSE));
> > - thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
> > - thd->transaction.all.modified_non_trans_table= FALSE;
> > + thd->variables.option_bits&= ~OPTION_BEGIN;
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> > thd->lex->start_transaction_opt= 0;
> >
> > DBUG_RETURN(test(res));
> > @@ -197,8 +197,8 @@ bool trans_commit_implicit(THD *thd)
> > res= test(ha_commit_trans(thd, TRUE));
> > }
> >
> > - thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
> > - thd->transaction.all.modified_non_trans_table= FALSE;
> > + thd->variables.option_bits&= ~OPTION_BEGIN;
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> >
> > /*
> > Upon implicit commit, reset the current transaction
> > @@ -232,8 +232,8 @@ bool trans_rollback(THD *thd)
> > thd->server_status&= ~SERVER_STATUS_IN_TRANS;
> > res= ha_rollback_trans(thd, TRUE);
> > RUN_HOOK(transaction, after_rollback, (thd, FALSE));
> > - thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
> > - thd->transaction.all.modified_non_trans_table= FALSE;
> > + thd->variables.option_bits&= ~OPTION_BEGIN;
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> > thd->lex->start_transaction_opt= 0;
> >
> > DBUG_RETURN(test(res));
> > @@ -437,12 +437,8 @@ bool trans_rollback_to_savepoint(THD *th
> >
> > if (ha_rollback_to_savepoint(thd, sv))
> > res= TRUE;
> > - else if (((thd->variables.option_bits & OPTION_KEEP_LOG) ||
> > - thd->transaction.all.modified_non_trans_table) &&
> > - !thd->slave_thread)
> > - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> > - ER_WARNING_NOT_COMPLETE_ROLLBACK,
> > - ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
> > + else if (thd->transaction.all.cannot_safely_rollback() &&
> !thd->slave_thread)
> > + thd->transaction.push_unsafe_rollback_warnings(thd);
> >
> > thd->transaction.savepoints= sv;
> >
> > @@ -679,8 +675,8 @@ bool trans_xa_commit(THD *thd)
> > DBUG_RETURN(TRUE);
> > }
> >
> > - thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
> > - thd->transaction.all.modified_non_trans_table= FALSE;
> > + thd->variables.option_bits&= ~OPTION_BEGIN;
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> > thd->server_status&= ~SERVER_STATUS_IN_TRANS;
> > xid_cache_delete(&thd->transaction.xid_state);
> > thd->transaction.xid_state.xa_state= XA_NOTR;
> > @@ -734,8 +730,8 @@ bool trans_xa_rollback(THD *thd)
> > if ((res= test(ha_rollback_trans(thd, TRUE))))
> > my_error(ER_XAER_RMERR, MYF(0));
> >
> > - thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
> > - thd->transaction.all.modified_non_trans_table= FALSE;
> > + thd->variables.option_bits&= ~OPTION_BEGIN;
> > + thd->transaction.all.reset_unsafe_rollback_flags();
> > thd->server_status&= ~SERVER_STATUS_IN_TRANS;
> > xid_cache_delete(&thd->transaction.xid_state);
> > thd->transaction.xid_state.xa_state= XA_NOTR;
> >
> >
> >
> >
> >
> >
>
--
Your Sincerely,
Libing Song
==================================
MySQL Replication Team
Software Engineer
Email : Li-Bing.Song@stripped
Skype : libing.song
MSN : slb_database@stripped
Phone : +86 010-6505-4020 ext. 319
Mobile: +86 138-1144-2038
==================================