List:Commits« Previous MessageNext Message »
From:konstantin Date:November 14 2007 2:46pm
Subject:bk commit into 5.1 tree (kostja:1.2607) BUG#12713
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of kostja. When kostja 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@stripped, 2007-11-14 17:46:40+03:00, kostja@bodhi.(none) +9 -0
  Bug#12713. This patch fixes the bug. No test cases, changeset comments, 
  or review comments.
  An intermediate commit for the passing test suite.

  sql/handler.cc@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +100 -56
    An intermediate commit for the passing test suite.

  sql/handler.h@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +56 -6
    An intermediate commit for the passing test suite.

  sql/log_event.cc@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +1 -1
    An intermediate commit for the passing test suite.

  sql/sql_base.cc@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +8 -10
    An intermediate commit for the passing test suite.

  sql/sql_class.h@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +31 -3
    An intermediate commit for the passing test suite.

  sql/sql_cursor.cc@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +3 -2
    An intermediate commit for the passing test suite.

  sql/sql_insert.cc@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +21 -13
    An intermediate commit for the passing test suite.

  sql/sql_parse.cc@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +21 -21
    An intermediate commit for the passing test suite.

  sql/sql_update.cc@stripped, 2007-11-14 17:46:37+03:00, kostja@bodhi.(none) +3 -4
    An intermediate commit for the passing test suite.

diff -Nrup a/sql/handler.cc b/sql/handler.cc
--- a/sql/handler.cc	2007-10-30 22:35:11 +03:00
+++ b/sql/handler.cc	2007-11-14 17:46:37 +03:00
@@ -596,7 +596,7 @@ void ha_close_connection(THD* thd)
 void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
 {
   THD_TRANS *trans;
-  handlerton **ht;
+  Ha_trx_info *ha_info;
   DBUG_ENTER("trans_register_ha");
   DBUG_PRINT("enter",("%s", all ? "all" : "stmt"));
 
@@ -608,12 +608,13 @@ void trans_register_ha(THD *thd, bool al
   else
     trans= &thd->transaction.stmt;
 
-  for (ht=trans->ht; *ht; ht++)
-    if (*ht == ht_arg)
-      DBUG_VOID_RETURN;  /* already registered, return */
+  ha_info= thd->ha_data[ht_arg->slot].ha_info + static_cast<unsigned>(all);
+
+  if (ha_info->ht)
+    DBUG_VOID_RETURN; /* already registered, return */
+
+  ha_info->register_ha(trans, ht_arg);
 
-  trans->ht[trans->nht++]=ht_arg;
-  DBUG_ASSERT(*ht == ht_arg);
   trans->no_2pc|=(ht_arg->prepare==0);
   if (thd->transaction.xid_state.xid.is_null())
     thd->transaction.xid_state.xid.set(thd->query_id);
@@ -629,18 +630,19 @@ int ha_prepare(THD *thd)
 {
   int error=0, all=1;
   THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
-  handlerton **ht=trans->ht;
+  Ha_trx_info *ha_info= trans->ha_list;
   DBUG_ENTER("ha_prepare");
 #ifdef USING_TRANSACTIONS
-  if (trans->nht)
+  if (ha_info)
   {
-    for (; *ht; ht++)
+    for (; ha_info; ha_info= ha_info->next)
     {
       int err;
+      handlerton *ht= ha_info->ht;
       status_var_increment(thd->status_var.ha_prepare_count);
-      if ((*ht)->prepare)
+      if (ht->prepare)
       {
-        if ((err= (*(*ht)->prepare)(*ht, thd, all)))
+        if ((err= ht->prepare(ht, thd, all)))
         {
           my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
           ha_rollback_trans(thd, all);
@@ -652,7 +654,7 @@ int ha_prepare(THD *thd)
       {
         push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                             ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
-                            ha_resolve_storage_engine_name(*ht));
+                            ha_resolve_storage_engine_name(ht));
       }
     }
   }
@@ -669,9 +671,13 @@ int ha_prepare(THD *thd)
 int ha_commit_trans(THD *thd, bool all)
 {
   int error= 0, cookie= 0;
+  /*
+    'all' means that this is either an explicit commit issued by
+    user, or an implicit commit issued by a DDL.
+  */
   THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
-  bool is_real_trans= all || thd->transaction.all.nht == 0;
-  handlerton **ht= trans->ht;
+  bool is_real_trans= all || thd->transaction.all.ha_list == 0;
+  Ha_trx_info *ha_info= trans->ha_list;
   my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
   DBUG_ENTER("ha_commit_trans");
 
@@ -696,7 +702,7 @@ int ha_commit_trans(THD *thd, bool all)
     DBUG_RETURN(2);
   }
 #ifdef USING_TRANSACTIONS
-  if (trans->nht)
+  if (ha_info)
   {
     if (is_real_trans && wait_if_global_read_lock(thd, 0, 0))
     {
@@ -722,12 +728,26 @@ int ha_commit_trans(THD *thd, bool all)
     if (is_real_trans)                          /* not a statement commit */
       thd->stmt_map.close_transient_cursors();
 
-    if (!trans->no_2pc && trans->nht > 1)
+    if (!trans->no_2pc && ha_info->next)
     {
-      for (; *ht && !error; ht++)
+      for (; ha_info && !error; ha_info= ha_info->next)
       {
         int err;
-        if ((err= (*(*ht)->prepare)(*ht, thd, all)))
+        handlerton *ht= ha_info->ht;
+        /**
+          Perform a two-phase commit only if:
+          - we're doing a DDL or
+          - we're issuing a DML that has actually updated rows.
+          In other cases, like read-only SELECT statements,
+          we would like to save on two-phase commits and therefore
+          avoid a potential disk sync of the binary log entailed by it.
+        */
+        if (!all &&
+            (sql_command_flags[thd->lex->sql_command] & CF_DML) &&
+            ha_info->is_trx_read_only())
+          continue;
+
+        if ((err= ht->prepare(ht, thd, all)))
         {
           my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
           error= 1;
@@ -765,24 +785,26 @@ int ha_commit_one_phase(THD *thd, bool a
 {
   int error=0;
   THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
-  bool is_real_trans=all || thd->transaction.all.nht == 0;
-  handlerton **ht=trans->ht;
+  bool is_real_trans=all || thd->transaction.all.ha_list == 0;
+  Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
   DBUG_ENTER("ha_commit_one_phase");
 #ifdef USING_TRANSACTIONS
-  if (trans->nht)
+  if (ha_info)
   {
-    for (ht=trans->ht; *ht; ht++)
+    for (; ha_info; ha_info= ha_info_next)
     {
       int err;
-      if ((err= (*(*ht)->commit)(*ht, thd, all)))
+      handlerton *ht= ha_info->ht;
+      if ((err= ht->commit(ht, thd, all)))
       {
         my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
         error=1;
       }
       status_var_increment(thd->status_var.ha_commit_count);
-      *ht= 0;
+      ha_info_next= ha_info->next;
+      ha_info->reset(); /* keep it conveniently zero-filled */
     }
-    trans->nht=0;
+    trans->ha_list= 0;
     trans->no_2pc=0;
     if (is_real_trans)
       thd->transaction.xid_state.xid.null();
@@ -805,7 +827,8 @@ int ha_rollback_trans(THD *thd, bool all
 {
   int error=0;
   THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
-  bool is_real_trans=all || thd->transaction.all.nht == 0;
+  Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
+  bool is_real_trans=all || thd->transaction.all.ha_list == 0;
   DBUG_ENTER("ha_rollback_trans");
   if (thd->in_sub_stmt)
   {
@@ -821,24 +844,26 @@ int ha_rollback_trans(THD *thd, bool all
     DBUG_RETURN(1);
   }
 #ifdef USING_TRANSACTIONS
-  if (trans->nht)
+  if (ha_info)
   {
     /* Close all cursors that can not survive ROLLBACK */
     if (is_real_trans)                          /* not a statement commit */
       thd->stmt_map.close_transient_cursors();
 
-    for (handlerton **ht=trans->ht; *ht; ht++)
+    for (; ha_info; ha_info= ha_info_next)
     {
       int err;
-      if ((err= (*(*ht)->rollback)(*ht, thd, all)))
+      handlerton *ht= ha_info->ht;
+      if ((err= ht->rollback(ht, thd, all)))
       { // cannot happen
         my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
         error=1;
       }
       status_var_increment(thd->status_var.ha_rollback_count);
-      *ht= 0;
+      ha_info_next= ha_info->next;
+      ha_info->reset(); /* keep it conveniently zero-filled */
     }
-    trans->nht=0;
+    trans->ha_list= 0;
     trans->no_2pc=0;
     if (is_real_trans)
       thd->transaction.xid_state.xid.null();
@@ -881,7 +906,7 @@ int ha_autocommit_or_rollback(THD *thd, 
 {
   DBUG_ENTER("ha_autocommit_or_rollback");
 #ifdef USING_TRANSACTIONS
-  if (thd->transaction.stmt.nht)
+  if (thd->transaction.stmt.ha_list)
   {
     if (!error)
     {
@@ -1236,43 +1261,49 @@ int ha_rollback_to_savepoint(THD *thd, S
   int error=0;
   THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
                                         &thd->transaction.all);
-  handlerton **ht=trans->ht, **end_ht;
+  Ha_trx_info *ha_info, *ha_info_next;
+
   DBUG_ENTER("ha_rollback_to_savepoint");
 
-  trans->nht=sv->nht;
   trans->no_2pc=0;
-  end_ht=ht+sv->nht;
   /*
     rolling back to savepoint in all storage engines that were part of the
     transaction when the savepoint was set
   */
-  for (; ht < end_ht; ht++)
+  for (ha_info= sv->ha_list; ha_info; ha_info= ha_info->next)
   {
     int err;
-    DBUG_ASSERT((*ht)->savepoint_set != 0);
-    if ((err= (*(*ht)->savepoint_rollback)(*ht, thd, (uchar *)(sv+1)+(*ht)->savepoint_offset)))
+    handlerton *ht= ha_info->ht;
+    DBUG_ASSERT(ht);
+    DBUG_ASSERT(ht->savepoint_set != 0);
+    if ((err= ht->savepoint_rollback(ht, thd,
+                                     (uchar *)(sv+1)+ht->savepoint_offset)))
     { // cannot happen
       my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
       error=1;
     }
     status_var_increment(thd->status_var.ha_savepoint_rollback_count);
-    trans->no_2pc|=(*ht)->prepare == 0;
+    trans->no_2pc|= ht->prepare == 0;
   }
   /*
     rolling back the transaction in all storage engines that were not part of
     the transaction when the savepoint was set
   */
-  for (; *ht ; ht++)
+  for (ha_info= trans->ha_list; ha_info != sv->ha_list;
+       ha_info= ha_info_next)
   {
     int err;
-    if ((err= (*(*ht)->rollback)(*ht, thd, !thd->in_sub_stmt)))
+    handlerton *ht= ha_info->ht;
+    if ((err= ht->rollback(ht, thd, !thd->in_sub_stmt)))
     { // cannot happen
       my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
       error=1;
     }
     status_var_increment(thd->status_var.ha_rollback_count);
-    *ht=0; // keep it conveniently zero-filled
+    ha_info_next= ha_info->next;
+    ha_info->reset(); /* keep it conveniently zero-filled */
   }
+  trans->ha_list= sv->ha_list;
   DBUG_RETURN(error);
 }
 
@@ -1286,26 +1317,32 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv
   int error=0;
   THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
                                         &thd->transaction.all);
-  handlerton **ht=trans->ht;
+  Ha_trx_info *ha_info= trans->ha_list;
   DBUG_ENTER("ha_savepoint");
 #ifdef USING_TRANSACTIONS
-  for (; *ht; ht++)
+  for (; ha_info; ha_info= ha_info->next) 
   {
     int err;
-    if (! (*ht)->savepoint_set)
+    handlerton *ht= ha_info->ht;
+    DBUG_ASSERT(ht);
+    if (! ht->savepoint_set)
     {
       my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT");
       error=1;
       break;
     }
-    if ((err= (*(*ht)->savepoint_set)(*ht, thd, (uchar *)(sv+1)+(*ht)->savepoint_offset)))
+    if ((err= ht->savepoint_set(ht, thd, (uchar *)(sv+1)+ht->savepoint_offset)))
     { // cannot happen
       my_error(ER_GET_ERRNO, MYF(0), err);
       error=1;
     }
     status_var_increment(thd->status_var.ha_savepoint_count);
   }
-  sv->nht=trans->nht;
+  /*
+    Remember the list of registered storage engines. All new
+    engines are prepended to the beginning of the list.
+  */
+  sv->ha_list= trans->ha_list;
 #endif /* USING_TRANSACTIONS */
   DBUG_RETURN(error);
 }
@@ -1313,20 +1350,19 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv
 int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
 {
   int error=0;
-  THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
-                                        &thd->transaction.all);
-  handlerton **ht=trans->ht, **end_ht;
+  Ha_trx_info *ha_info= sv->ha_list;
   DBUG_ENTER("ha_release_savepoint");
 
-  end_ht=ht+sv->nht;
-  for (; ht < end_ht; ht++)
+  for (; ha_info; ha_info= ha_info->next)
   {
     int err;
-    if (!(*ht)->savepoint_release)
+    handlerton *ht= ha_info->ht;
+    /* Savepoint life time is enclosed into transaction life time. */
+    DBUG_ASSERT(ht);
+    if (!ht->savepoint_release)
       continue;
-    if ((err= (*(*ht)->savepoint_release)(*ht, thd, 
-                                          (uchar *)(sv+1)+
-                                          (*ht)->savepoint_offset)))
+    if ((err= ht->savepoint_release(ht, thd,
+                                    (uchar *)(sv+1) + ht->savepoint_offset)))
     { // cannot happen
       my_error(ER_GET_ERRNO, MYF(0), err);
       error=1;
@@ -3677,6 +3713,8 @@ int handler::ha_reset()
 int handler::ha_write_row(uchar *buf)
 {
   int error;
+  if (has_transactions())
+    ha_thd()->ha_data[ht->slot].ha_info[0].set_trx_read_write();
   if (unlikely(error= write_row(buf)))
     return error;
   if (unlikely(error= binlog_log_row<Write_rows_log_event>(table, 0, buf)))
@@ -3695,6 +3733,8 @@ int handler::ha_update_row(const uchar *
    */
   DBUG_ASSERT(new_data == table->record[0]);
 
+  if (has_transactions())
+    ha_thd()->ha_data[ht->slot].ha_info[0].set_trx_read_write();
   if (unlikely(error= update_row(old_data, new_data)))
     return error;
   if (unlikely(error= binlog_log_row<Update_rows_log_event>(table, old_data, new_data)))
@@ -3705,6 +3745,10 @@ int handler::ha_update_row(const uchar *
 int handler::ha_delete_row(const uchar *buf)
 {
   int error;
+
+  if (has_transactions())
+    ha_thd()->ha_data[ht->slot].ha_info[0].set_trx_read_write();
+
   if (unlikely(error= delete_row(buf)))
     return error;
   if (unlikely(error= binlog_log_row<Delete_rows_log_event>(table, buf, 0)))
diff -Nrup a/sql/handler.h b/sql/handler.h
--- a/sql/handler.h	2007-09-07 17:41:46 +04:00
+++ b/sql/handler.h	2007-11-14 17:46:37 +03:00
@@ -721,14 +721,14 @@ struct handlerton
 #define HTON_SUPPORT_LOG_TABLES      (1 << 7) //Engine supports log tables
 #define HTON_NO_PARTITION            (1 << 8) //You can not partition these tables
 
-typedef struct st_thd_trans
+class Ha_trx_info;
+
+struct THD_TRANS
 {
-  /* number of entries in the ht[] */
-  uint        nht;
   /* true is not all entries in the ht[] support 2pc */
   bool        no_2pc;
-  /* storage engines that registered themselves for this transaction */
-  handlerton *ht[MAX_HA];
+  /* 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:
@@ -758,7 +758,57 @@ typedef struct st_thd_trans
     saved value.
   */
   bool modified_non_trans_table;
-} THD_TRANS;
+
+  void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; }
+};
+
+
+/**
+  Either statement- or transaction- local thread-specific
+  storage engine data.
+
+  If a storage engine participates in a statement/transaction,
+  an instance of this class is present in
+  thd->transaction.{stmt|all}.ha_list. The addition to ha_list
+  is done by trans_register_ha.
+
+  When it's time to commit or rollback, each element of ha_list
+  is used to access storage engine prepare/commit/rollback
+  methods, and also to evaluate whether a full two phase commit
+  is necessary.
+*/
+
+struct Ha_trx_info
+{
+  /**
+    Register this storage engine in the given transaction context.
+  */
+  void register_ha(THD_TRANS *trans, handlerton *ht_arg)
+  { next= trans->ha_list; trans->ha_list= this; ht= ht_arg; flags= 0; }
+
+  /** Clear, prepare for reuse. */
+  void reset() { next= NULL; ht= NULL; flags= 0; }
+
+  Ha_trx_info() { reset(); }
+
+  void set_trx_read_write() { flags|= (int) TRX_READ_WRITE; }
+  bool is_trx_read_only() const { return !(flags & (int) TRX_READ_WRITE); }
+public:
+  /** public only to simplify access. Please use methods to assign. */
+  /** Auxiliary, used for ha_list management */
+  Ha_trx_info *next;
+  /**
+    Although a given Ha_trx_info instance is currently always used
+    for the same storage engine, 'ht' is not-NULL only when the
+    corresponding storage is a part of a transaction.
+  */
+  handlerton *ht;
+private:
+  enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1 };
+  uchar      flags;
+};
+
+
 
 enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
 			 ISO_REPEATABLE_READ, ISO_SERIALIZABLE};
diff -Nrup a/sql/log_event.cc b/sql/log_event.cc
--- a/sql/log_event.cc	2007-11-04 13:35:15 +03:00
+++ b/sql/log_event.cc	2007-11-14 17:46:37 +03:00
@@ -2642,7 +2642,7 @@ int Format_description_log_event::do_app
     original place when it comes to us; we'll know this by checking
     log_pos ("artificial" events have log_pos == 0).
   */
-  if (!artificial_event && created && thd->transaction.all.nht)
+  if (!artificial_event && created && thd->transaction.all.ha_list)
   {
     /* This is not an error (XA is safe), just an information */
     rli->report(INFORMATION_LEVEL, 0,
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc	2007-11-04 13:35:17 +03:00
+++ b/sql/sql_base.cc	2007-11-14 17:46:37 +03:00
@@ -1270,16 +1270,14 @@ void close_thread_tables(THD *thd)
     mysql_unlock_tables(thd, thd->lock);
     thd->lock=0;
   }
-  /*
-    assume handlers auto-commit (if some doesn't - transaction handling
-    in MySQL should be redesigned to support it; it's a big change,
-    and it's not worth it - better to commit explicitly only writing
-    transactions, read-only ones should better take care of themselves.
-    saves some work in 2pc too)
-    see also sql_parse.cc - dispatch_command()
-  */
-  if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
-    bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
+
+  /* If commit fails, we should be able to reset the OK status. */
+  thd->main_da.can_overwrite_status= TRUE;
+  ha_autocommit_or_rollback(thd, thd->is_error());
+  thd->main_da.can_overwrite_status= FALSE;
+
+  thd->transaction.stmt.reset();
+
   if (!thd->active_transaction())
     thd->transaction.xid_state.xid.null();
 
diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
--- a/sql/sql_class.h	2007-11-04 13:35:17 +03:00
+++ b/sql/sql_class.h	2007-11-14 17:46:37 +03:00
@@ -685,7 +685,8 @@ private:
 struct st_savepoint {
   struct st_savepoint *prev;
   char                *name;
-  uint                 length, nht;
+  uint                 length;
+  Ha_trx_info         *ha_list;
 };
 
 enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
@@ -1090,6 +1091,32 @@ private:
 };
 
 
+/*
+  Storage engine specific thread local data.
+*/
+
+struct Ha_data
+{
+  /**
+    Storage engine specific thread local data.
+    Lifetime: one user connection.
+  */
+  void *ha_ptr;
+  /**
+    0: Life time: one statement within a transaction. If @@autocommit is
+    on, also represents the entire transaction.
+    @sa trans_register_ha()
+
+    1: Life time: one transaction within a connection.
+    If the storage engine does not participate in a transaction,
+    this should not be used.
+    @sa trans_register_ha()
+  */
+  Ha_trx_info ha_info[2];
+
+  Ha_data() :ha_ptr(NULL) {}
+};
+
 /**
   @class THD
   For each client connection we create a separate thread with THD serving as
@@ -1223,7 +1250,7 @@ public:
   uint in_sub_stmt;
 
   /* container for handler's private per-connection data */
-  void *ha_data[MAX_HA];
+  Ha_data ha_data[MAX_HA];
 
 #ifndef MYSQL_CLIENT
   int binlog_setup_trx_data();
@@ -2658,7 +2685,7 @@ public:
   bool send_data(List<Item> &items);
   bool initialize_tables (JOIN *join);
   void send_error(uint errcode,const char *err);
-  int  do_updates (bool from_send_error);
+  int  do_updates();
   bool send_eof();
 };
 
@@ -2701,6 +2728,7 @@ public:
 #define CF_STATUS_COMMAND	4
 #define CF_SHOW_TABLE_COMMAND	8
 #define CF_WRITE_LOGS_COMMAND  16
+#define CF_DML                 32
 
 /* Functions in sql_class.cc */
 
diff -Nrup a/sql/sql_cursor.cc b/sql/sql_cursor.cc
--- a/sql/sql_cursor.cc	2006-12-31 03:06:36 +03:00
+++ b/sql/sql_cursor.cc	2007-11-14 17:46:37 +03:00
@@ -315,9 +315,10 @@ Sensitive_cursor::post_open(THD *thd)
 
   close_at_commit= FALSE; /* reset in case we're reusing the cursor */
   info= &ht_info[0];
-  for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
+  for (Ha_trx_info *ha_trx_info= thd->transaction.stmt.ha_list;
+       ha_trx_info; ha_trx_info= ha_trx_info->next)
   {
-    handlerton *ht= *pht;
+    handlerton *ht= ha_trx_info->ht;
     close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
     if (ht->create_cursor_read_view)
     {
diff -Nrup a/sql/sql_insert.cc b/sql/sql_insert.cc
--- a/sql/sql_insert.cc	2007-11-04 13:35:18 +03:00
+++ b/sql/sql_insert.cc	2007-11-14 17:46:37 +03:00
@@ -893,9 +893,19 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
     }
     DBUG_ASSERT(transactional_table || !changed || 
                 thd->transaction.stmt.modified_non_trans_table);
-    if (transactional_table)
-      error=ha_autocommit_or_rollback(thd,error);
-    
+    /*
+      Let's commit or rollback the statement. If @@autocommit is
+      ON, this entails a full two-phase commit.
+
+      ha_autocommit_or_rollback() has an optimization to bypass
+      the two-phase commit when no transactional data is changed,
+      and thus this call is not necessarily resource-intensive.
+
+      Note, that ha_autocommit_or_rollback() preserves the value
+      of error if it's non-zero.
+    */
+    error= ha_autocommit_or_rollback(thd, error);
+
     if (thd->lock)
     {
       mysql_unlock_tables(thd, thd->lock);
@@ -3217,7 +3227,7 @@ void select_insert::abort() {
     table->file->ha_release_auto_increment();
   }
 
-  ha_rollback_stmt(thd);
+  (void) ha_autocommit_or_rollback(thd, 1);
   DBUG_VOID_RETURN;
 }
 
@@ -3679,16 +3689,13 @@ void select_create::abort()
   DBUG_ENTER("select_create::abort");
 
   /*
-   Disable binlog, because we "roll back" partial inserts in ::abort
-   by removing the table, even for non-transactional tables.
+    Disable binlog, because we "roll back" partial inserts in ::abort
+    by removing the table, even for non-transactional tables.
   */
   tmp_disable_binlog(thd);
-  select_insert::abort();
-  reenable_binlog(thd);
-
   /*
-    We roll back the statement, including truncating the transaction
-    cache of the binary log, if the statement failed.
+    In select_insert::abort() we roll back the statement, including
+    truncating the transaction cache of the binary log.
 
     We roll back the statement prior to deleting the table and prior
     to releasing the lock on the table, since there might be potential
@@ -3699,8 +3706,9 @@ void select_create::abort()
     of the table succeeded or not, since we need to reset the binary
     log state.
   */
-  if (thd->current_stmt_binlog_row_based)
-    ha_rollback_stmt(thd);
+  select_insert::abort();
+  reenable_binlog(thd);
+
 
   if (m_plock)
   {
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc	2007-11-04 13:35:18 +03:00
+++ b/sql/sql_parse.cc	2007-11-14 17:46:37 +03:00
@@ -204,7 +204,7 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_ALTER_TABLE]=    CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
   sql_command_flags[SQLCOM_TRUNCATE]=       CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
   sql_command_flags[SQLCOM_DROP_TABLE]=     CF_CHANGES_DATA;
-  sql_command_flags[SQLCOM_LOAD]=           CF_CHANGES_DATA;
+  sql_command_flags[SQLCOM_LOAD]=           CF_CHANGES_DATA | CF_DML;
   sql_command_flags[SQLCOM_CREATE_DB]=      CF_CHANGES_DATA;
   sql_command_flags[SQLCOM_DROP_DB]=        CF_CHANGES_DATA;
   sql_command_flags[SQLCOM_RENAME_TABLE]=   CF_CHANGES_DATA;
@@ -217,14 +217,15 @@ void init_update_queries(void)
   sql_command_flags[SQLCOM_ALTER_EVENT]=    CF_CHANGES_DATA;
   sql_command_flags[SQLCOM_DROP_EVENT]=     CF_CHANGES_DATA;
 
-  sql_command_flags[SQLCOM_UPDATE]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
-  sql_command_flags[SQLCOM_UPDATE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
-  sql_command_flags[SQLCOM_INSERT]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
-  sql_command_flags[SQLCOM_INSERT_SELECT]=  CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
-  sql_command_flags[SQLCOM_DELETE]=         CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
-  sql_command_flags[SQLCOM_DELETE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
-  sql_command_flags[SQLCOM_REPLACE]=        CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
-  sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
+  sql_command_flags[SQLCOM_SELECT]=	    CF_DML;
+  sql_command_flags[SQLCOM_UPDATE]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT | CF_DML;
+  sql_command_flags[SQLCOM_UPDATE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT | CF_DML;
+  sql_command_flags[SQLCOM_INSERT]=	    CF_CHANGES_DATA | CF_HAS_ROW_COUNT | CF_DML;
+  sql_command_flags[SQLCOM_INSERT_SELECT]=  CF_CHANGES_DATA | CF_HAS_ROW_COUNT | CF_DML;
+  sql_command_flags[SQLCOM_DELETE]=         CF_CHANGES_DATA | CF_HAS_ROW_COUNT | CF_DML;
+  sql_command_flags[SQLCOM_DELETE_MULTI]=   CF_CHANGES_DATA | CF_HAS_ROW_COUNT | CF_DML;
+  sql_command_flags[SQLCOM_REPLACE]=        CF_CHANGES_DATA | CF_HAS_ROW_COUNT | CF_DML;
+  sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | CF_DML;
 
   sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND;
   sql_command_flags[SQLCOM_SHOW_STATUS]=      CF_STATUS_COMMAND;
@@ -1324,19 +1325,13 @@ bool dispatch_command(enum enum_server_c
     break;
   }
 
-  thd->proc_info= "closing tables";
-  /* Free tables */
-  close_thread_tables(thd);
+  /* If commit fails, we should be able to reset the OK status. */
+  thd->main_da.can_overwrite_status= TRUE;
+  ha_autocommit_or_rollback(thd, thd->is_error());
+  thd->main_da.can_overwrite_status= FALSE;
+
+  thd->transaction.stmt.reset();
 
-  /*
-    assume handlers auto-commit (if some doesn't - transaction handling
-    in MySQL should be redesigned to support it; it's a big change,
-    and it's not worth it - better to commit explicitly only writing
-    transactions, read-only ones should better take care of themselves.
-    saves some work in 2pc too)
-    see also sql_base.cc - close_thread_tables()
-  */
-  bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
   if (!thd->active_transaction())
     thd->transaction.xid_state.xid.null();
 
@@ -1346,6 +1341,11 @@ bool dispatch_command(enum enum_server_c
 
   net_end_statement(thd);
   query_cache_end_of_result(thd);
+
+  thd->proc_info= "closing tables";
+  /* Free tables */
+  close_thread_tables(thd);
+
 
   log_slow_statement(thd);
 
diff -Nrup a/sql/sql_update.cc b/sql/sql_update.cc
--- a/sql/sql_update.cc	2007-10-30 20:08:13 +03:00
+++ b/sql/sql_update.cc	2007-11-14 17:46:37 +03:00
@@ -1739,7 +1739,7 @@ void multi_update::send_error(uint errco
          todo/fixme: do_update() is never called with the arg 1.
          should it change the signature to become argless?
       */
-      VOID(do_updates(0));
+      VOID(do_updates());
     }
   }
   if (thd->transaction.stmt.modified_non_trans_table)
@@ -1766,7 +1766,7 @@ void multi_update::send_error(uint errco
 }
 
 
-int multi_update::do_updates(bool from_send_error)
+int multi_update::do_updates()
 {
   TABLE_LIST *cur_table;
   int local_error= 0;
@@ -1913,7 +1913,6 @@ int multi_update::do_updates(bool from_s
   DBUG_RETURN(0);
 
 err:
-  if (!from_send_error)
   {
     thd->fatal_error();
     prepare_record_for_error_message(local_error, table);
@@ -1951,7 +1950,7 @@ bool multi_update::send_eof()
   thd->proc_info="updating reference tables";
 
   /* Does updates for the last n - 1 tables, returns 0 if ok */
-  int local_error = (table_count) ? do_updates(0) : 0;
+  int local_error = (table_count) ? do_updates() : 0;
   thd->proc_info= "end";
 
   /* We must invalidate the query cache before binlog writing and
Thread
bk commit into 5.1 tree (kostja:1.2607) BUG#12713konstantin14 Nov
  • Re: bk commit into 5.1 tree (kostja:1.2607) BUG#12713Sergei Golubchik20 Nov
    • Re: bk commit into 5.1 tree (kostja:1.2607) BUG#12713Konstantin Osipov23 Nov