Pantek Library
Hosting Provided By
CybrHost
High Speed Hosting

bk commit into 5.0 tree (aelkin:1.2439) BUG#27417

From: Andrei Elkin <aelkin(at)mysql.com>
Date: Tue Jun 26 2007 - 11:22:03 EDT


Below is the list of changes that have just been committed into a local 5.0 repository of elkin. When elkin does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository.
For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@1.2439, 2007-06-26 18:21:52+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +18 -0   Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack   

  Once had been set the flag might later got reset inside of a stored routine execution stack.   The reason was in that there was no check if a new statement started at time of resetting.   The artifact affects most of binlogable DML queries. Notice, that multi-update is wrapped up within   bug@27716 fix, multi-delete bug@29136.   

  Fixed with saving parent's statement flag of whether the statement modified non-transactional table,   and unioning (merging) the value with that was gained in mysql_execute_command.   

  Resettling thd->no_trans_update members into thd->transaction.`member`;   Asserting code;
  Effectively the following properties are held.   

  1. At the end of a substatement thd->transaction.stmt.modified_non_trans_table reflects the fact if such a table got modified by the substatement. That also respects THD::really_abort_on_warnin() requirements.
  2. Eventually thd->transaction.stmt.modified_non_trans_table will be computed as the union of the values of all invoked sub-statements. That fixes this bug#27417;

  Computing of thd->transaction.all.modified_non_trans_table is refined to base to the stmt's   value for all the case including insert .. select statement which before the patch had an   extra issue bug#28960.
  Minor issues are covered with mysql_load, mysql_delete, and binloggin of insert into temp_table select.   

  The supplied test verifies limitely, mostly asserts. The ultimate testing is defered   for bug_13270, bug_23333.

  mysql-test/r/mix_innodb_myisam_binlog.result@1.31, 2007-06-26 18:21:46+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +68 -0     results changed

Do you need help?X

  mysql-test/r/stored_routines_side_effect.result@1.1, 2007-06-26 18:21:49+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +46 -0     new result file

  mysql-test/r/stored_routines_side_effect.result@1.0, 2007-06-26 18:21:49+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +0 -0

  mysql-test/t/mix_innodb_myisam_binlog.test@1.26, 2007-06-26 18:21:47+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +63 -2     regression test for a related bug#28960.

  mysql-test/t/stored_routines_side_effect.test@1.1, 2007-06-26 18:21:49+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +56 -0     the test basicly is to check asserts deployed within the patch.

  mysql-test/t/stored_routines_side_effect.test@1.0, 2007-06-26 18:21:49+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +0 -0

  sql/ha_ndbcluster.cc@1.309, 2007-06-26 18:21:47+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +1 -1     thd->transaction.{all,stmt}.modified_non_trans_table     

    instead of     

    thd->no_trans_update.{all,stmt}

Do you need more help?X

  sql/handler.cc@1.233, 2007-06-26 18:21:47+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +1 -1     thd->transaction.{all,stmt}.modified_non_trans_table     

    instead of     

    thd->no_trans_update.{all,stmt}

  sql/handler.h@1.184, 2007-06-26 18:21:47+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +1 -0     new member is added.

  sql/log.cc@1.210, 2007-06-26 18:21:47+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +2 -2     thd->transaction.{all,stmt}.modified_non_trans_table     

    instead of     

    thd->no_trans_update.{all,stmt}

  sql/set_var.cc@1.184, 2007-06-26 18:21:47+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +2 -2     thd->transaction.{all,stmt}.modified_non_trans_table     

Can we help you?X

    instead of     

    thd->no_trans_update.{all,stmt}

  sql/sp_head.cc@1.243, 2007-06-26 18:21:48+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +14 -4     thd->transaction.{all,stmt}.modified_non_trans_table     

    instead of     

    thd->no_trans_update.{all,stmt}     

    and saving and merging stmt's flag at the end of a substatement.

  sql/sql_class.cc@1.270, 2007-06-26 18:21:48+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +1 -1     thd->transaction.{all,stmt}.modified_non_trans_table     

    instead of     

Can't find what you're looking for?X

    thd->no_trans_update.{all,stmt}

  sql/sql_class.h@1.329, 2007-06-26 18:21:48+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +1 -5     moving thd->no_trans_update members into thd->transaction.`member`;     thd->transaction.{all,stmt}.modified_non_trans_table     

    instead of     

    thd->no_trans_update.{all,stmt}

  sql/sql_delete.cc@1.198, 2007-06-26 18:21:48+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +25 -12     correcting basic delete incl truncate branch and multi-delete queries to set     stmt.modified_non_trans_table;
    optimization to set the flag at the end of per-row loop;     multi-delete still has an extra issue similar to bug#27716 of multi-update - to be address with     bug_29136 fix.

  sql/sql_insert.cc@1.231, 2007-06-26 18:21:48+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +22 -19     insert and insert..select (send_eof and send_error both) cases.     

    thd->transaction.{all,stmt}.modified_non_trans_table     

    instead of     

Don't know where to look next?X

    thd->no_trans_update.{all,stmt}

  sql/sql_load.cc@1.114, 2007-06-26 18:21:48+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +6 -10     eliminating a separate issue where the stmt flag was saved and re-stored after write_record     that actually could change it and the change would be lost but should remain permanent;     thd->transaction.{all,stmt}.modified_non_trans_table     

    instead of     

    thd->no_trans_update.{all,stmt}

  sql/sql_parse.cc@1.618, 2007-06-26 18:21:48+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +12 -10     initialization to transaction.stmt.modified_non_trans_table at the common part of     all types of statements processing - mysql_execute_command().

  sql/sql_table.cc@1.341, 2007-06-26 18:21:49+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +0 -1     moving the reset up to the mysql_execute_command() caller

  sql/sql_update.cc@1.216, 2007-06-26 18:21:49+03:00, aelkin@dsl-hkibras1-ff5dc300-70.dhcp.inet.fi +10 -12     correcting update query case (multi-update part of the issues covered by other bug#27716 fix)     

    thd->transaction.{all,stmt}.modified_non_trans_table     

Confused? Frustrated?X

    instead of     

    thd->no_trans_update.{all,stmt}

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	aelkin
# Host:	dsl-hkibras1-ff5dc300-70.dhcp.inet.fi
# Root:	/home/elkin/MySQL/TEAM/FIXES/5.0/bug27417-no_trans_update__stmt

--- 1.232/sql/handler.cc	2007-04-12 12:46:06 +03:00
+++ 1.233/sql/handler.cc	2007-06-26 18:21:47 +03:00

@@ -830,7 +830,7 @@ int ha_rollback_trans(THD *thd, bool all
the error log; but we don't want users to wonder why they have this message in the error log, so we don't send it.
   */
- if (is_real_trans && thd->no_trans_update.all && + if (is_real_trans && thd->transaction.all.modified_non_trans_table &&
       !thd->slave_thread)
     push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                  ER_WARNING_NOT_COMPLETE_ROLLBACK,

--- 1.183/sql/handler.h	2007-03-30 11:00:20 +03:00
+++ 1.184/sql/handler.h	2007-06-26 18:21:47 +03:00

@@ -418,6 +418,7 @@ typedef struct st_thd_trans
bool no_2pc;

   /* storage engines that registered themselves for this transaction */    handlerton *ht[MAX_HA];
+ bool modified_non_trans_table;
 } THD_TRANS;    enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
  • 1.209/sql/log.cc 2007-04-12 12:46:06 +03:00 +++ 1.210/sql/log.cc 2007-06-26 18:21:47 +03:00
    @@ -162,7 +162,7 @@ static int binlog_rollback(THD *thd, boo
    table. Such cases should be rare (updating a non-transactional table inside a transaction...) */ - if (unlikely(thd->no_trans_update.all)) + if (unlikely(thd->transaction.all.modified_non_trans_table)) { Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
    @@ -217,7 +217,7 @@ static int binlog_savepoint_rollback(THD
    non-transactional table. Otherwise, truncate the binlog cache starting from the SAVEPOINT command. */ - if (unlikely(thd->no_trans_update.all)) + if (unlikely(thd->transaction.all.modified_non_trans_table)) { Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE); DBUG_RETURN(mysql_bin_log.write(&qinfo));
  • 1.269/sql/sql_class.cc 2007-04-20 11:35:22 +03:00 +++ 1.270/sql/sql_class.cc 2007-06-26 18:21:48 +03:00
    @@ -333,7 +333,7 @@ void THD::init(void)
    if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES; options= thd_startup_options; - no_trans_update.stmt= no_trans_update.all= FALSE; + transaction.all.modified_non_trans_table= transaction.stmt.modified_non_trans_table= FALSE; open_options=ha_open_options; update_lock_default= (variables.low_priority_updates ? TL_WRITE_LOW_PRIORITY :
  • 1.328/sql/sql_class.h 2007-04-03 14:55:14 +03:00 +++ 1.329/sql/sql_class.h 2007-06-26 18:21:48 +03:00
    @@ -1440,10 +1440,6 @@ public:
    bool charset_is_system_charset, charset_is_collation_connection; bool charset_is_character_set_filesystem; bool enable_slow_log; /* enable slow log for current statement */ - struct { - bool all:1; - bool stmt:1; - } no_trans_update; bool abort_on_warning; bool got_warning; /* Set on call to push_warning() */ bool no_warnings_for_error; /* no warnings on call to my_error() */
    @@ -1668,7 +1664,7 @@ public:
    inline bool really_abort_on_warning() { return (abort_on_warning && - (!no_trans_update.stmt || + (!transaction.stmt.modified_non_trans_table || (variables.sql_mode & MODE_STRICT_ALL_TABLES))); } void set_status_var_init();
  • 1.197/sql/sql_delete.cc 2007-04-17 16:51:56 +03:00 +++ 1.198/sql/sql_delete.cc 2007-06-26 18:21:48 +03:00
    @@ -91,7 +91,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *
    }

   select_lex->no_error= thd->lex->ignore; -
+ transactional_table= table->file->has_transactions();

   /*

     Test if the user wants to delete all rows and deletion doesn't have
     any side-effects (because of triggers), so we can use optimized

@@ -109,8 +109,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *
if (!(error=table->file->delete_all_rows())) { error= -1; // ok + if (!transactional_table && deleted > 0) + thd->transaction.stmt.modified_non_trans_table= TRUE; goto cleanup; } + deleted= 0; if (error != HA_ERR_WRONG_COMMAND) { table->file->print_error(error,MYF(0));
@@ -280,6 +283,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *
else table->file->unlock_row(); // Row failed selection, release lock on it
   }
+  if (!transactional_table && deleted > 0)
+    thd->transaction.stmt.modified_non_trans_table= TRUE;
+
   if (thd->killed && !error)
     error= 1;					// Aborted

   thd->proc_info="end";
@@ -314,7 +320,6 @@ cleanup:

   }  

   delete select;
- transactional_table= table->file->has_transactions();

   /* See similar binlogging code in sql_update.cc, for comments */    if ((error < 0) || (deleted && !transactional_table))    {
@@ -327,9 +332,10 @@ cleanup:

       if (mysql_bin_log.write(&qinfo) && transactional_table)
 	error=1;
     }
-    if (!transactional_table)
-      thd->no_trans_update.all= TRUE;
+    if (thd->transaction.stmt.modified_non_trans_table)
+      thd->transaction.all.modified_non_trans_table= TRUE;
Call Pantek today for Open Source Technical Support at 1-877-546-8934 - 24/7/365X

   }
+ DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table);

Do you need help?X

   free_underlaid_joins(thd, select_lex);    if (transactional_table)
   {
@@ -644,20 +650,22 @@ bool multi_delete::send_data(List<Item>

       if (table->triggers &&
           table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                             TRG_ACTION_BEFORE, FALSE))
-	DBUG_RETURN(1);
+        DBUG_RETURN(1);
       table->status|= STATUS_DELETED;
       if (!(error=table->file->delete_row(table->record[0])))
       {
-	deleted++;
+        deleted++;
+        if (!table->file->has_transactions())
+          thd->transaction.stmt.modified_non_trans_table= TRUE;
         if (table->triggers &&
             table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                               TRG_ACTION_AFTER, FALSE))
-	  DBUG_RETURN(1);
+          DBUG_RETURN(1);
       }
       else
       {
-	table->file->print_error(error,MYF(0));
-	DBUG_RETURN(1);
+        table->file->print_error(error,MYF(0));
+        DBUG_RETURN(1);
       }
     }
     else

@@ -707,6 +715,7 @@ void multi_delete::send_error(uint errco
error= 1; send_eof();

   }
+ DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);

   DBUG_VOID_RETURN;
 }  

@@ -734,6 +743,7 @@ int multi_delete::do_deletes()

   for (; table_being_deleted;

        table_being_deleted= table_being_deleted->next_local, counter++)    {
+ ha_rows last_deleted= deleted;

     TABLE *table = table_being_deleted->table;
     if (tempfiles[counter]->get(table))
     {

@@ -771,6 +781,8 @@ int multi_delete::do_deletes()
break; } } + if (last_deleted != deleted && !table->file->has_transactions()) + thd->transaction.stmt.modified_non_trans_table= TRUE; end_read_record(&info); if (thd->killed && !local_error) local_error= 1;

@@ -809,7 +821,6 @@ bool multi_delete::send_eof()

   {
     query_cache_invalidate3(thd, delete_tables, 1);    }
-

   if ((local_error == 0) || (deleted && normal_tables))    {
     if (mysql_bin_log.is_open())
@@ -821,9 +832,11 @@ bool multi_delete::send_eof()

       if (mysql_bin_log.write(&qinfo) && !normal_tables)
 	local_error=1;  // Log write failed: roll back the SQL statement
     }
-    if (!transactional_tables)
-      thd->no_trans_update.all= TRUE;
+    if (thd->transaction.stmt.modified_non_trans_table)
+      thd->transaction.all.modified_non_trans_table= TRUE;

   }
+ DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table); +

Do you need more help?X

   /* Commit or rollback the current SQL statement */    if (transactional_tables)
     if (ha_autocommit_or_rollback(thd,local_error > 0))

  • 1.230/sql/sql_insert.cc 2007-04-12 12:46:07 +03:00 +++ 1.231/sql/sql_insert.cc 2007-06-26 18:21:48 +03:00
    @@ -629,7 +629,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
    if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode) table->file->start_bulk_insert(values_list.elements);
    • thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)));
      @@ -775,10 +774,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
      if (mysql_bin_log.write(&qinfo) && transactional_table) error=1; }
    • if (!transactional_table)
    • thd->no_trans_update.all= TRUE; + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE; } } + DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); if (transactional_table) error=ha_autocommit_or_rollback(thd,error);

@@ -1175,7 +1175,7 @@ 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.
Can we help you?X
  • Sets thd->no_trans_update.stmt to TRUE if table which is updated didn't have + Sets thd->transaction.stmt.modified_non_trans_table to TRUE if table which is updated didn't have transactions.

   RETURN VALUE
@@ -1341,7 +1341,7 @@ int write_record(THD *thd, TABLE *table,

             goto err;
           info->deleted++;
           if (!table->file->has_transactions())
-            thd->no_trans_update.stmt= TRUE;
+            thd->transaction.stmt.modified_non_trans_table= TRUE;
           if (table->triggers &&
               table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
                                                 TRG_ACTION_AFTER, TRUE))

@@ -1373,7 +1373,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->no_trans_update.stmt= TRUE;
+ thd->transaction.stmt.modified_non_trans_table= TRUE;

   DBUG_RETURN(trg_error);  

 err:
@@ -2564,7 +2564,6 @@ select_insert::prepare(List<Item> &value

       table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
     table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
   }
- thd->no_trans_update.stmt= FALSE;

   thd->abort_on_warning= (!info.ignore &&

                           (thd->variables.sql_mode &
                            (MODE_STRICT_TRANS_TABLES |

@@ -2691,6 +2690,7 @@ void select_insert::store_values(List<It
 

 void select_insert::send_error(uint errcode,const char *err)  {
+ bool changed, transactional_table;

Can't find what you're looking for?X

   DBUG_ENTER("select_insert::send_error");  

   my_message(errcode, err, MYF(0));
@@ -2703,6 +2703,7 @@ void select_insert::send_error(uint errc

     */
     DBUG_VOID_RETURN;

   }
+ transactional_table= table->file->has_transactions();

   if (!thd->prelocked_mode)
     table->file->end_bulk_insert();
   /*
@@ -2711,21 +2712,22 @@ void select_insert::send_error(uint errc

     error while inserting into a MyISAM table) we must write to the binlog (and
     the error code will make the slave stop).
   */
- if ((info.copied || info.deleted || info.updated) && - !table->file->has_transactions()) + if ((changed= info.copied || info.deleted || info.updated) && + !transactional_table)

   {

     if (last_insert_id)
       thd->insert_id(last_insert_id);		// For binary log
     if (mysql_bin_log.is_open())
     {
       Query_log_event qinfo(thd, thd->query, thd->query_length,
-                            table->file->has_transactions(), FALSE);
+                            transactional_table, FALSE);
       mysql_bin_log.write(&qinfo);
     }
-    if (!table->s->tmp_table)
-      thd->no_trans_update.all= TRUE;
+    if (thd->transaction.stmt.modified_non_trans_table)
+      thd->transaction.all.modified_non_trans_table= TRUE;

   }
- if (info.copied || info.deleted || info.updated) + DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); + if (changed)

   {
     query_cache_invalidate3(thd, table, 1);    }
@@ -2736,7 +2738,8 @@ void select_insert::send_error(uint errc
 

 bool select_insert::send_eof()
 {
- int error,error2;
+ int error, error2;
+ bool changed, transactional_table= table->file->has_transactions();

   DBUG_ENTER("select_insert::send_eof");  

Don't know where to look next?X

   error= (!thd->prelocked_mode) ? table->file->end_bulk_insert():0;
@@ -2748,12 +2751,13 @@ bool select_insert::send_eof()

     and ha_autocommit_or_rollback
   */  

  • if (info.copied || info.deleted || info.updated) + if (changed= (info.copied || info.deleted || info.updated)) { query_cache_invalidate3(thd, table, 1);
  • if (!(table->file->has_transactions() || table->s->tmp_table))
  • thd->no_trans_update.all= TRUE; + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE; } + DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table);

   if (last_insert_id)
     thd->insert_id(info.copied ? last_insert_id : 0); // For binary log
@@ -2763,7 +2767,7 @@ bool select_insert::send_eof()

     if (!error)
       thd->clear_error();
     Query_log_event qinfo(thd, thd->query, thd->query_length,
-			  table->file->has_transactions(), FALSE);
+			  transactional_table, FALSE);
     mysql_bin_log.write(&qinfo);

   }
   if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
@@ -2978,7 +2982,6 @@ select_create::prepare(List<Item> &value

   }
   if (!thd->prelocked_mode)
     table->file->start_bulk_insert((ha_rows) 0); - thd->no_trans_update.stmt= FALSE;

   thd->abort_on_warning= (!info.ignore &&

                           (thd->variables.sql_mode &
                            (MODE_STRICT_TRANS_TABLES |

--- 1.113/sql/sql_load.cc	2007-05-08 03:43:16 +03:00
+++ 1.114/sql/sql_load.cc	2007-06-26 18:21:48 +03:00
Confused? Frustrated?X

@@ -377,7 +377,6 @@ bool mysql_load(THD *thd,sql_exchange *e
table->file->start_bulk_insert((ha_rows) 0); table->copy_blobs=1; - thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= (!ignore && (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES |
@@ -411,7 +410,6 @@ bool mysql_load(THD *thd,sql_exchange *e
ha_autocommit_...

   */
   query_cache_invalidate3(thd, table_list, 0); -

   if (error)
   {
     if (read_file_from_client)
@@ -466,8 +464,8 @@ bool mysql_load(THD *thd,sql_exchange *e

   sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,

           (ulong) (info.records - info.copied), (ulong) thd->cuted_fields);  

  • if (!transactional_table)
  • thd->no_trans_update.all= TRUE; + 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()) {
    @@ -488,6 +486,8 @@ bool mysql_load(THD *thd,sql_exchange *e
    /* ok to client sent only after binlog write and engine commit */ send_ok(thd, info.copied + info.deleted, 0L, name); err: + DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) || + thd->transaction.stmt.modified_non_trans_table); if (thd->lock) { mysql_unlock_tables(thd, thd->lock);
    @@ -532,7 +532,7 @@ read_fixed_length(THD *thd, COPY_INFO &i
    Item_field *sql_field; TABLE *table= table_list->table; ulonglong id;
  • bool no_trans_update_stmt, err; + bool err; DBUG_ENTER("read_fixed_length");
Call Pantek today for Open Source Technical Support at 1-877-546-8934 - 24/7/365X

   id= 0;
@@ -560,7 +560,6 @@ read_fixed_length(THD *thd, COPY_INFO &i
 #ifdef HAVE_purify

     read_info.row_end[0]=0;
 #endif
- no_trans_update_stmt= !table->file->has_transactions();  

     restore_record(table, s->default_values);
     /*

@@ -628,7 +627,6 @@ read_fixed_length(THD *thd, COPY_INFO &i
table->auto_increment_field_not_null= FALSE; if (err) DBUG_RETURN(1);

- thd->no_trans_update.stmt= no_trans_update_stmt;     
     /*
       If auto_increment values are used, save the first one for

@@ -671,12 +669,11 @@ read_sep_field(THD *thd, COPY_INFO &info

   TABLE *table= table_list->table;
   uint enclosed_length;
   ulonglong id;
- bool no_trans_update_stmt, err;
+ bool err;

   DBUG_ENTER("read_sep_field");  

   enclosed_length=enclosed.length();
   id= 0;
- no_trans_update_stmt= !table->file->has_transactions();  

   for (;;it.rewind())
   {
@@ -817,7 +814,6 @@ read_sep_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->no_trans_update.stmt= no_trans_update_stmt;
     if (read_info.next_line())			// Skip to next line
       break;
     if (read_info.line_cuted)

--- 1.617/sql/sql_parse.cc	2007-04-03 14:11:32 +03:00
+++ 1.618/sql/sql_parse.cc	2007-06-26 18:21:48 +03:00

@@ -148,7 +148,7 @@ static bool end_active_trans(THD *thd)
if (ha_commit(thd)) error=1; thd->options&= ~(ulong) OPTION_BEGIN;
- thd->no_trans_update.all= FALSE;
+ thd->transaction.all.modified_non_trans_table= FALSE;

   }
   DBUG_RETURN(error);
 }
@@ -172,7 +172,7 @@ static bool begin_trans(THD *thd)

   else
   {
     LEX *lex= thd->lex;

-    thd->no_trans_update.all= FALSE;
+    thd->transaction.all.modified_non_trans_table= FALSE;
     thd->options|= (ulong) OPTION_BEGIN;
     thd->server_status|= SERVER_STATUS_IN_TRANS;
     if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)

@@ -1466,7 +1466,7 @@ int end_trans(THD *thd, enum enum_mysql_
thd->server_status&= ~SERVER_STATUS_IN_TRANS; res= ha_commit(thd); thd->options&= ~(ulong) OPTION_BEGIN;
- thd->no_trans_update.all= FALSE;
+ thd->transaction.all.modified_non_trans_table= FALSE;
Do you need help?X

     break;
   case COMMIT_RELEASE:
     do_release= 1; /* fall through */
@@ -1484,7 +1484,7 @@ int end_trans(THD *thd, enum enum_mysql_

     if (ha_rollback(thd))
       res= -1;
     thd->options&= ~(ulong) OPTION_BEGIN;
- thd->no_trans_update.all= FALSE;
+ thd->transaction.all.modified_non_trans_table= FALSE;
     if (!res && (completion == ROLLBACK_AND_CHAIN))
       res= begin_trans(thd);
     break;

@@ -2587,6 +2587,8 @@ mysql_execute_command(THD *thd)
statistic_increment(thd->status_var.com_stat[lex->sql_command], &LOCK_status);

+ thd->transaction.stmt.modified_non_trans_table= FALSE; +

   switch (lex->sql_command) {
   case SQLCOM_SELECT:
   {
@@ -2924,7 +2926,7 @@ mysql_execute_command(THD *thd)

     else 
     {
       /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
Do you need more help?X
- thd->no_trans_update.all= TRUE; + thd->transaction.all.modified_non_trans_table= TRUE; } DBUG_ASSERT(first_table == all_tables && first_table != 0); bool link_to_local;
@@ -3701,7 +3703,7 @@ end_with_restore_list:
lex->drop_if_exists= 1; /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ - thd->no_trans_update.all= TRUE; + thd->transaction.all.modified_non_trans_table= TRUE; } /* DDL and binlog write order protected by LOCK_open */ res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
@@ -4292,7 +4294,7 @@ end_with_restore_list:
res= TRUE; // cannot happen else { - if (thd->no_trans_update.all && + if (thd->transaction.all.modified_non_trans_table && !thd->slave_thread) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK,
@@ -4935,7 +4937,7 @@ create_sp_error:
thd->transaction.xid_state.xa_state=XA_ACTIVE; thd->transaction.xid_state.xid.set(thd->lex->xid); xid_cache_insert(&thd->transaction.xid_state); - thd->no_trans_update.all= FALSE; + thd->transaction.all.modified_non_trans_table= FALSE; thd->options|= (ulong) OPTION_BEGIN; thd->server_status|= SERVER_STATUS_IN_TRANS; send_ok(thd);
@@ -5030,7 +5032,7 @@ create_sp_error:
break; } thd->options&= ~(ulong) OPTION_BEGIN; - thd->no_trans_update.all= FALSE; + thd->transaction.all.modified_non_trans_table= FALSE; thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR;
@@ -5061,7 +5063,7 @@ create_sp_error:
else send_ok(thd); thd->options&= ~(ulong) OPTION_BEGIN; - thd->no_trans_update.all= FALSE; + thd->transaction.all.modified_non_trans_table= FALSE; thd->server_status&= ~SERVER_STATUS_IN_TRANS;
Can we help you?X
xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state=XA_NOTR; --- 1.340/sql/sql_table.cc 2007-04-17 16:51:57 +03:00 +++ 1.341/sql/sql_table.cc 2007-06-26 18:21:49 +03:00

@@ -4004,7 +4004,6 @@ copy_data_between_tables(TABLE *from,TAB

   alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);  

   /* We can abort alter table for any table type */ - thd->no_trans_update.stmt= FALSE;

   thd->abort_on_warning= !ignore && test(thd->variables.sql_mode &

                                          (MODE_STRICT_TRANS_TABLES |
                                           MODE_STRICT_ALL_TABLES));

--- 1.215/sql/sql_update.cc	2007-04-12 12:46:07 +03:00
+++ 1.216/sql/sql_update.cc	2007-06-26 18:21:49 +03:00

@@ -429,7 +429,6 @@ int mysql_update(THD *thd,

   query_id=thd->query_id;  

   transactional_table= table->file->has_transactions();
-  thd->no_trans_update.stmt= FALSE;
   thd->abort_on_warning= test(!ignore &&
                               (thd->variables.sql_mode &
                                (MODE_STRICT_TRANS_TABLES |

@@ -486,7 +485,6 @@ int mysql_update(THD *thd,
(byte*) table->record[0]))) { updated++; - thd->no_trans_update.stmt= !transactional_table; if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
@@ -520,6 +518,10 @@ int mysql_update(THD *thd,
table->file->unlock_row(); thd->row_count++;

   }
+
+  if (!transactional_table && updated > 0)
+    thd->transaction.stmt.modified_non_trans_table= TRUE;
+
   if (thd->killed && !error)
     error= 1;					// Aborted

   end_read_record(&info);
@@ -557,9 +559,10 @@ int mysql_update(THD *thd,
       if (mysql_bin_log.write(&qinfo) && transactional_table)
 	error=1;				// Rollback update
     }
-    if (!transactional_table)
-      thd->no_trans_update.all= TRUE;
+    if (thd->transaction.stmt.modified_non_trans_table)
+      thd->transaction.all.modified_non_trans_table= TRUE;

   }
+ DBUG_ASSERT(transactional_table || !updated || thd->transaction.stmt.modified_non_trans_table);

Can't find what you're looking for?X

   free_underlaid_joins(thd, select_lex);    if (transactional_table)
   {
@@ -922,7 +925,6 @@ bool mysql_multi_update(THD *thd,

 				 handle_duplicates, ignore)))
     DBUG_RETURN(TRUE);
 
  • thd->no_trans_update.stmt= FALSE; thd->abort_on_warning= test(thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES));
    @@ -1249,8 +1251,6 @@ multi_update::~multi_update()
    if (copy_field) delete [] copy_field; thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting
  • if (!trans_safe)
  • thd->no_trans_update.all= TRUE; }

@@ -1337,7 +1337,7 @@ bool multi_update::send_data(List<Item>

         else
         {
           if (!table->file->has_transactions())
-            thd->no_trans_update.stmt= TRUE;
+            thd->transaction.stmt.modified_non_trans_table= TRUE;
Don't know where to look next?X
if (table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE))

@@ -1384,7 +1384,6 @@ void multi_update::send_error(uint errco
 

   /* Something already updated so we have to invalidate cache */    query_cache_invalidate3(thd, update_tables, 1); -

   /*

     If all tables that has been updated are trans safe then just do rollback.
     If not attempt to do remaining updates.

@@ -1551,7 +1550,6 @@ bool multi_update::send_eof()

   {
     query_cache_invalidate3(thd, update_tables, 1);    }
-

   /*

     Write the SQL statement to the binlog if we updated
     rows and we succeeded or if we updated some non

@@ -1569,8 +1567,8 @@ bool multi_update::send_eof()
if (mysql_bin_log.write(&qinfo) && trans_safe) local_error= 1; // Rollback update } - if (!transactional_tables) - thd->no_trans_update.all= TRUE; + if (thd->transaction.stmt.modified_non_trans_table) + thd->transaction.all.modified_non_trans_table= TRUE;

   }  

   if (transactional_tables)
--- New file ---
+++ mysql-test/r/stored_routines_side_effect.result 07/06/26 18:21:49 drop function if exists bug27417;
drop table if exists t1,t2;
CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a)); create function bug27417(n int)
RETURNS int(11)
DETERMINISTIC
begin
insert into t1 values (null);
return n;
end|
reset master;
insert into t2 values (bug27417(1));
insert into t2 select bug27417(2);
reset master;
insert into t2 values (bug27417(2));
ERROR 23000: Duplicate entry '2' for key 1 show master status;

File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	98		

/* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */; count(*)
3
reset master;
select count(*) from t2;
count(*)
2
delete from t2 where a=bug27417(3);
select count(*) from t2 /* nothing got deleted */; count(*)
2
show master status;
File	Position	Binlog_Do_DB	Binlog_Ignore_DB
master-bin.000001	195		

/* the query must be in regardless of #23333 */; select count(*) from t1 /* must be 5 */; count(*)
5
delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; affected rows: 0
select count(*) from t1 /* must be 7 */; count(*)
7
drop table t1,t2;
end of tests
  • New file --- +++ mysql-test/t/stored_routines_side_effect.test 07/06/26 18:21:49 # # Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack # # Testing the assertion: if there is a side effect of modifying non-transactional # table thd->no_trans_update.stmt must be TRUE; # the assert is active with debug build #
Confused? Frustrated?X

--disable_warnings
drop function if exists bug27417;
drop table if exists t1,t2;
--enable_warnings
# side effect table
CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM; # target tables
CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a));

delimiter |;
create function bug27417(n int)
RETURNS int(11)
DETERMINISTIC
begin
  insert into t1 values (null);
  return n;
end|
delimiter ;|

reset master;

# execute

insert into t2 values (bug27417(1));
insert into t2 select bug27417(2);
reset master;

--error ER_DUP_ENTRY
insert into t2 values (bug27417(2));
show master status; /* only (!) with fixes for #23333 will show there is the query */; select count(*) from t1 /* must be 3 */;

reset master;
select count(*) from t2;
delete from t2 where a=bug27417(3);
select count(*) from t2 /* nothing got deleted */; show master status; /* the query must be in regardless of #23333 */; select count(*) from t1 /* must be 5 */;

--enable_info
delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */; --disable_info
select count(*) from t1 /* must be 7 */;

Call Pantek today for Open Source Technical Support at 1-877-546-8934 - 24/7/365X

drop table t1,t2;

--echo end of tests

  • 1.30/mysql-test/r/mix_innodb_myisam_binlog.result 2006-11-28 14:26:08 +02:00 +++ 1.31/mysql-test/r/mix_innodb_myisam_binlog.result 2007-06-26 18:21:46 +03:00
    @@ -280,3 +280,71 @@ select
    @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" @a not like "%#%error_code=%error_code=%" 1 1 drop table t1, t2; +create temporary table tt (a int unique); +create table ti (a int) engine=innodb; +reset master; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 98 +begin; +insert into ti values (1); +insert into ti values (2) ; +insert into tt select * from ti; +rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +select count(*) from tt /* 2 */; +count(*) +2 +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 507 +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # use `test`; BEGIN +master-bin.000001 # Query 1 # use `test`; insert into ti values (1) +master-bin.000001 # Query 1 # use `test`; insert into ti values (2) +master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti +master-bin.000001 # Query 1 # use `test`; ROLLBACK +select count(*) from ti /* zero */; +count(*) +0 +insert into ti select * from tt; +select * from ti /* that is what slave would miss - a bug */; +a +1 +2 +delete from ti; +delete from tt where a=1; +reset master; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 98 +begin; +insert into ti values (1); +insert into ti values (2) /* to make the dup error in the following */; +insert into tt select * from ti /* one affected and error */; +ERROR 23000: Duplicate entry '2' for key 1 +rollback; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 581 +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # use `test`; BEGIN +master-bin.000001 # Query 1 # use `test`; insert into ti values (1) +master-bin.000001 # Query 1 # use `test`; insert into ti values (2) /* to make the dup error in the following */ +master-bin.000001 # Query 1 # use `test`; insert into tt select * from ti /* one affected and error */ +master-bin.000001 # Query 1 # use `test`; ROLLBACK +select count(*) from ti /* zero */; +count(*) +0 +insert into ti select * from tt; +select * from tt /* that is what slave would miss - the bug */; +a +1 +2 +drop table ti; +end of tests
  • 1.25/mysql-test/t/mix_innodb_myisam_binlog.test 2007-01-18 19:05:03 +02:00 +++ 1.26/mysql-test/t/mix_innodb_myisam_binlog.test 2007-06-26 18:21:47 +03:00
    @@ -259,8 +259,6 @@ show binlog events from 98;
    do release_lock("lock1"); drop table t0,t2;

-# End of 4.1 tests
-

 # Test for BUG#16559 (ROLLBACK should always have a zero error code in
 # binlog). Has to be here and not earlier, as the SELECTs influence
 # XIDs differently between normal and ps-protocol (and SHOW BINLOG

@@ -293,3 +291,66 @@ eval select

 @a like "%#%error_code=0%ROLLBACK/*!*/;%ROLLBACK /* added by mysqlbinlog */;%",  @a not like "%#%error_code=%error_code=%";  drop table t1, t2;
+
+#
+# bug#27417,bug#28960
+#
+# testing appearence of insert into temp_table
+#
+
+## send_eof() branch
+
+# prepare
+
+create temporary table tt (a int unique);
+create table ti (a int) engine=innodb;
+reset master;
+show master status;
+
+# action
+
+begin; 
+insert into ti values (1); 
+insert into ti values (2) ; 
+insert into tt select * from ti;
+rollback;
+
+# check
+
+select count(*) from tt /* 2 */;
+show master status;
+--replace_column 2 # 5 #
+show binlog events from 98;
+select count(*) from ti /* zero */;
+insert into ti select * from tt;
+select * from ti /* that is what slave would miss - a bug */;
+
+
+## send_error() branch
+delete from ti;
+delete from tt where a=1;
+reset master;
+show master status;
Do you need help?X
+ +# action + +begin; +insert into ti values (1); +insert into ti values (2) /* to make the dup error in the following */; +--error ER_DUP_ENTRY +insert into tt select * from ti /* one affected and error */; +rollback; + +# check + +show master status; +--replace_column 2 # 5 # +show binlog events from 98; +select count(*) from ti /* zero */; +insert into ti select * from tt; +select * from tt /* that is what slave would miss - the bug */; + +drop table ti; + +--echo end of tests + --- 1.308/sql/ha_ndbcluster.cc 2007-04-17 16:51:56 +03:00 +++ 1.309/sql/ha_ndbcluster.cc 2007-06-26 18:21:47 +03:00
@@ -3697,7 +3697,7 @@ int ha_ndbcluster::external_lock(THD *th
{ m_transaction_on= FALSE; /* Would be simpler if has_transactions() didn't always say "yes" */ - thd->no_trans_update.all= thd->no_trans_update.stmt= TRUE; + thd->transaction.all.modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table= TRUE; } else if (!thd->transaction.on) m_transaction_on= FALSE; --- 1.183/sql/set_var.cc 2007-04-20 11:35:22 +03:00 +++ 1.184/sql/set_var.cc 2007-06-26 18:21:47 +03:00
@@ -2882,14 +2882,14 @@ static bool set_option_autocommit(THD *t
{ /* We changed to auto_commit mode */ thd->options&= ~(ulong) OPTION_BEGIN; - thd->no_trans_update.all= FALSE; + thd->transaction.all.modified_non_trans_table= FALSE; thd->server_status|= SERVER_STATUS_AUTOCOMMIT; if (ha_commit(thd)) return 1; } else { - thd->no_trans_update.all= FALSE; + thd->transaction.all.modified_non_trans_table= FALSE; thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT; }

   }
  • 1.242/sql/sp_head.cc 2007-04-12 12:46:07 +03:00 +++ 1.243/sql/sp_head.cc 2007-06-26 18:21:48 +03:00
    @@ -337,13 +337,13 @@ sp_eval_expr(THD *thd, Field *result_fie

   enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;

   bool save_abort_on_warning= thd->abort_on_warning;
-  bool save_no_trans_update_stmt= thd->no_trans_update.stmt;
+  bool save_stmt_modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table;
 

   thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;    thd->abort_on_warning=

     thd->variables.sql_mode &
Do you need more help?X
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES);
- thd->no_trans_update.stmt= FALSE;
+ thd->transaction.stmt.modified_non_trans_table= FALSE;  

   /* Save the value in the field. Convert the value if needed. */  

@@ -351,7 +351,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->no_trans_update.stmt= save_no_trans_update_stmt;
+  thd->transaction.stmt.modified_non_trans_table= save_stmt_modified_non_trans_table;
 

   if (thd->net.report_error)
   {
@@ -2365,6 +2365,12 @@ sp_lex_keeper::reset_lex_and_exec_core(T

                                        bool open_tables, sp_instr* instr)
 {
   int res= 0;
+  /* 
+     the flag is saved at the entry to the following substatement.
+     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;
 
Can we help you?X

   DBUG_ASSERT(!thd->derived_tables);
   DBUG_ASSERT(thd->change_list.is_empty());
@@ -2432,7 +2438,11 @@ sp_lex_keeper::reset_lex_and_exec_core(T

   /* Update the state of the active arena. */    thd->stmt_arena->state= Query_arena::EXECUTED;  

-

+  /*
+    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;
   /*
     Unlike for PS we should not call Item's destructors for newly created
     items after execution of each instruction in stored routine. This is
-- 
MySQL Code Commits Mailing List
For list archives: 
http://lists.mysql.com/commits
To unsubscribe:    
http://lists.mysql.com/commits?unsub=lists@pantek.com
Received on Tue Jun 26 11:22:20 2007

This archive was generated by hypermail 2.1.8 : Tue Jun 26 2007 - 11:30:03 EDT


Contact Us  Legal Notices  Order Services Online 
Pantek Home  Privacy Policy  IT news  Site Map  Pantek Library