List:Commits« Previous MessageNext Message »
From:Libing Song Date:December 16 2010 3:05am
Subject:Re: bzr commit into mysql-trunk-bugfixing branch (Li-Bing.Song:3426)
Bug#55798 Bug#56184
View as plain text  
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
==================================

Thread
bzr commit into mysql-trunk-bugfixing branch (Li-Bing.Song:3426) Bug#55798Bug#56184Li-Bing.Song13 Dec
  • Re: bzr commit into mysql-trunk-bugfixing branch (Li-Bing.Song:3426)Bug#55798 Bug#56184Daogang Qu13 Dec
    • Re: bzr commit into mysql-trunk-bugfixing branch (Li-Bing.Song:3426)Bug#55798 Bug#56184Libing Song16 Dec
  • Re: bzr commit into mysql-trunk-bugfixing branch (Li-Bing.Song:3426)Bug#55798 Bug#56184Alfranio Correia27 Dec
    • Re: bzr commit into mysql-trunk-bugfixing branch (Li-Bing.Song:3426)Bug#55798 Bug#56184Libing Song28 Dec
      • Re: bzr commit into mysql-trunk-bugfixing branch (Li-Bing.Song:3426)Bug#55798 Bug#56184Alfranio Correia28 Dec
        • Re: bzr commit into mysql-trunk-bugfixing branch (Li-Bing.Song:3426)Bug#55798 Bug#56184Libing Song28 Dec