List:Commits« Previous MessageNext Message »
From:marc.alff Date:September 8 2006 11:23pm
Subject:bk commit into 5.0 tree (malff:1.2258)
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of marcsql. When marcsql 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, 2006-09-08 16:23:22-07:00, malff@weblab.(none) +22 -0
  Temporary change set, disregard. Not for review.
  Collapsed

  BitKeeper/deleted/.del-autocommit_ndb.result@stripped, 2006-09-08 16:23:19-07:00, malff@weblab.(none) +0 -2
    Intermediate checkin, 1st code review comments.

  BitKeeper/deleted/.del-autocommit_ndb.result@stripped, 2006-09-08 16:21:38-07:00, malff@weblab.(none) +0 -0
    Rename: mysql-test/r/autocommit_ndb.result -> BitKeeper/deleted/.del-autocommit_ndb.result

  BitKeeper/deleted/.del-autocommit_ndb.test@stripped, 2006-09-08 16:21:38-07:00, malff@weblab.(none) +0 -0
    Rename: mysql-test/t/autocommit_ndb.test -> BitKeeper/deleted/.del-autocommit_ndb.test

  mysql-test/include/autocommit_common.inc@stripped, 2006-09-08 16:23:19-07:00, malff@weblab.(none) +93 -11
    Intermediate checkin, 1st code review comments.

  mysql-test/include/engine_mix_common.inc@stripped, 2006-09-08 16:23:19-07:00, malff@weblab.(none) +0 -10
    Intermediate checkin, 1st code review comments.

  mysql-test/r/autocommit_bdb.result@stripped, 2006-09-08 16:23:19-07:00, malff@weblab.(none) +52 -10
    Intermediate checkin, 1st code review comments.

  mysql-test/r/autocommit_innodb.result@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +52 -10
    Intermediate checkin, 1st code review comments.

  mysql-test/t/disabled.def@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +0 -1
    Removed autocommit_ndb, 21667 is not a bug

  sql/ha_berkeley.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +11 -23
    Rollback changes
    ---
    implicit commit

  sql/ha_ndbcluster.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +45 -46
    Rollback changes
    ---
    implicit commit

  sql/handler.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +60 -0
    implicit commit

  sql/handler.h@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +1 -0
    implicit commit

  sql/sp_rcontext.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +16 -0
    Intermediate checkin, 1st code review comments.

  sql/sp_rcontext.h@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +2 -1
    Intermediate checkin, 1st code review comments.

  sql/sql_class.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +93 -7
    Intermediate checkin, 1st code review comments.
    ---
    ha_autocommit_or_rollback for select statements

  sql/sql_class.h@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +9 -2
    Intermediate checkin, 1st code review comments.

  sql/sql_delete.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +11 -14
    Intermediate checkin, 1st code review comments.

  sql/sql_do.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +2 -2
    Intermediate checkin, 1st code review comments.

  sql/sql_insert.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +3 -2
    Intermediate checkin, 1st code review comments.

  sql/sql_load.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +2 -2
    Intermediate checkin, 1st code review comments.

  sql/sql_parse.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +32 -28
    Intermediate checkin, 1st code review comments.
    ---
    comments

  sql/sql_union.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +6 -0
    Intermediate checkin, 1st code review comments.

  sql/sql_update.cc@stripped, 2006-09-08 16:23:20-07:00, malff@weblab.(none) +15 -10
    Intermediate checkin, 1st code review comments.

# 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:	malff
# Host:	weblab.(none)
# Root:	/home/marcsql/TREE/mysql-5.0-12713

--- 1.162/sql/ha_berkeley.cc	2006-09-08 16:23:27 -07:00
+++ 1.163/sql/ha_berkeley.cc	2006-09-08 16:23:27 -07:00
@@ -254,21 +254,14 @@ bool berkeley_flush_logs()
 
 static int berkeley_commit(THD *thd, bool all)
 {
-  int error=0;
   DBUG_ENTER("berkeley_commit");
   DBUG_PRINT("trans",("ending transaction %s", all ? "all" : "stmt"));
   berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
-
-  if (trx)
-  {
-    DB_TXN **txn= all ? &trx->all : &trx->stmt;
-    if (*txn)
-    {
-      error=txn_commit(*txn,0);
-      *txn=0;
-    }
-  }
-
+  DBUG_ASSERT(trx);
+  DB_TXN **txn= all ? &trx->all : &trx->stmt;
+  DBUG_ASSERT(*txn);
+  int error=txn_commit(*txn,0);
+  *txn=0;
 #ifndef DBUG_OFF
   if (error)
     DBUG_PRINT("error",("error: %d",error));
@@ -278,20 +271,14 @@ static int berkeley_commit(THD *thd, boo
 
 static int berkeley_rollback(THD *thd, bool all)
 {
-  int error=0;
   DBUG_ENTER("berkeley_rollback");
   DBUG_PRINT("trans",("aborting transaction %s", all ? "all" : "stmt"));
   berkeley_trx_data *trx=(berkeley_trx_data *)thd->ha_data[berkeley_hton.slot];
-
-  if (trx)
-  {
-    DB_TXN **txn= all ? &trx->all : &trx->stmt;
-    if (*txn)
-    {
-      error=txn_abort(*txn);
-      *txn=0;
-    }
-  }
+  DBUG_ASSERT(trx);
+  DB_TXN **txn= all ? &trx->all : &trx->stmt;
+  DBUG_ASSERT(*txn);
+  int error=txn_abort(*txn);
+  *txn=0;
   DBUG_RETURN(error);
 }
 
@@ -1909,6 +1896,7 @@ int ha_berkeley::external_lock(THD *thd,
 	DBUG_PRINT("trans",("commiting non-updating transaction"));
         error= txn_commit(trx->stmt,0);
         trx->stmt= transaction= 0;
+        trans_unregister_ha(thd, FALSE, &berkeley_hton);
       }
     }
   }

--- 1.217/sql/handler.cc	2006-09-08 16:23:27 -07:00
+++ 1.218/sql/handler.cc	2006-09-08 16:23:27 -07:00
@@ -611,6 +611,66 @@ void trans_register_ha(THD *thd, bool al
   DBUG_VOID_RETURN;
 }
 
+
+void trans_unregister_ha(THD *thd, bool all, handlerton *ht_arg)
+{
+  THD_TRANS *trans;
+  handlerton **ht;
+  int ht_index= -1;
+  int i;
+  DBUG_ENTER("trans_unregister_ha");
+  DBUG_PRINT("enter",("%s", all ? "all" : "stmt"));
+
+  if (all)
+  {
+    trans= &thd->transaction.all;
+  }
+  else
+  {
+    trans= &thd->transaction.stmt;
+  }
+
+  /*
+     Searching for the handlerton in the transaction.
+   */
+  for (i= 0; i < trans->nht ; i++)
+  {
+    if (trans->ht[i] == ht_arg)
+    {
+      ht_index= i;
+      break;
+    }
+  }
+
+  if (ht_index >= 0)
+  {
+    if (trans->nht > 1)
+    {
+      /* Remove the handlerton found */
+      trans->ht[ht_index]= trans->ht[trans->nht -1];
+      trans->ht[trans->nht -1]= 0;
+      trans->nht--;
+
+      /* Re-evaluate the 2 phase commit property */
+      trans->no_2pc= 0;
+      for (ht=trans->ht; *ht; ht++)
+      {
+        trans->no_2pc|= ((*ht)->prepare==0);
+      }
+    }
+    else
+    {
+      /* The transaction is now empty */
+      trans->ht[0]= 0;
+      trans->nht= 0;
+      trans->no_2pc= 0;
+    }
+  }
+
+  DBUG_VOID_RETURN;
+}
+
+
 /*
   RETURN
       0  - ok

--- 1.177/sql/handler.h	2006-09-08 16:23:27 -07:00
+++ 1.178/sql/handler.h	2006-09-08 16:23:27 -07:00
@@ -961,6 +961,7 @@ int ha_release_savepoint(THD *thd, SAVEP
 
 /* these are called by storage engines */
 void trans_register_ha(THD *thd, bool all, handlerton *ht);
+void trans_unregister_ha(THD *thd, bool all, handlerton *ht);
 
 /*
   Storage engine has to assume the transaction will end up with 2pc if

--- 1.247/sql/sql_class.cc	2006-09-08 16:23:27 -07:00
+++ 1.248/sql/sql_class.cc	2006-09-08 16:23:27 -07:00
@@ -869,6 +869,32 @@ void select_result::cleanup()
   /* do nothing */
 }
 
+int select_result::complete_statement(int error)
+{
+  /*
+     Please note :
+     While is may seem that this code performs a commit or rollback
+     for every select statement, what really happens is the following:
+
+     - For selects with no side effects, only READ locks are used
+     during the select execution. As an optinization in JOIN::exec(),
+     handler::external_lock(F_UNLCK) is called early, which, upon
+     releasing the last lock for a given transactional engine,
+     will cause an implicit commit ("commiting non-updating transaction").
+     ha_autocommit_or_rollback() will be a no-op in this case.
+
+     - For selects with side effects, when involving stored functions
+     that may perform data modifications, at least a WRITE lock for
+     the table modified will be used. When releasing the READ locks as
+     part of the JOIN::exec() optimizations, the lock count in the engine
+     will never reach 0, the statement transaction is still pending,
+     and has to be properly commited or rollbacked to ensure data integrity.
+     ha_autocommit_or_rollback() will properly complete the stmt transaction.
+   */
+  error= ha_autocommit_or_rollback(thd, error);
+  return error;
+}
+
 static String default_line_term("\n",default_charset_info);
 static String default_escaped("\\",default_charset_info);
 static String default_field_term("\t",default_charset_info);
@@ -955,8 +981,17 @@ bool select_send::send_data(List<Item> &
   DBUG_RETURN(1);
 }
 
+void select_send::send_error(uint errcode,const char *err)
+{
+  my_message(errcode, err, MYF(0));
+
+  (void) complete_statement(errcode);
+}
+
 bool select_send::send_eof()
 {
+  int error= complete_statement(0);
+
   /* We may be passing the control from mysqld to the client: release the
      InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
      by thd */
@@ -968,14 +1003,14 @@ bool select_send::send_eof()
     mysql_unlock_tables(thd, thd->lock);
     thd->lock=0;
   }
-  if (!thd->net.report_error)
+  if (!thd->net.report_error && !error)
   {
     ::send_eof(thd);
     status= 0;
     return 0;
   }
-  else
-    return 1;
+
+  return 1;
 }
 
 
@@ -986,6 +1021,9 @@ bool select_send::send_eof()
 void select_to_file::send_error(uint errcode,const char *err)
 {
   my_message(errcode, err, MYF(0));
+
+  (void) complete_statement(errcode);
+
   if (file > 0)
   {
     (void) end_io_cache(&cache);
@@ -1001,8 +1039,17 @@ bool select_to_file::send_eof()
   int error= test(end_io_cache(&cache));
   if (my_close(file,MYF(MY_WME)))
     error= 1;
+
+  error= complete_statement(error);
+
   if (!error)
+  {
     ::send_ok(thd,row_count);
+  }
+  else
+  {
+    (void) my_delete(path,MYF(0));		// Delete file on error
+  }
   file= -1;
   return error;
 }
@@ -1338,6 +1385,18 @@ select_subselect::select_subselect(Item_
 }
 
 
+void select_subselect::send_error(uint errcode, const char *err)
+{
+  my_message(errcode, err, MYF(0));
+}
+
+
+bool select_subselect::send_eof()
+{
+  return FALSE;
+}
+
+
 bool select_singlerow_subselect::send_data(List<Item> &items)
 {
   DBUG_ENTER("select_singlerow_subselect::send_data");
@@ -1883,21 +1942,48 @@ bool select_dumpvar::send_data(List<Item
     {
       if ((xx=li++))
       {
-        xx->check(0);
-	xx->update();
+        if (xx->check(0))
+	  DBUG_RETURN(1);
+
+        if (thd->net.report_error)
+	  DBUG_RETURN(1);
+
+        if (xx->update())
+	  DBUG_RETURN(1);
+
+        if (thd->net.report_error)
+	  DBUG_RETURN(1);
       }
     }
   }
   DBUG_RETURN(0);
 }
 
+
+void select_dumpvar::send_error(uint errcode, const char *err)
+{
+  my_message(errcode, err, MYF(0));
+
+  (void) complete_statement(errcode);
+}
+
+
 bool select_dumpvar::send_eof()
 {
+  int error;
+
   if (! row_count)
     push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                  ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
-  ::send_ok(thd,row_count);
-  return 0;
+
+  error= complete_statement(0);
+
+  if (!error)
+  {
+    ::send_ok(thd,row_count);
+  }
+
+  return error;
 }
 
 /****************************************************************************

--- 1.293/sql/sql_class.h	2006-09-08 16:23:27 -07:00
+++ 1.294/sql/sql_class.h	2006-09-08 16:23:27 -07:00
@@ -1683,7 +1683,7 @@ public:
   virtual bool send_fields(List<Item> &list, uint flags)=0;
   virtual bool send_data(List<Item> &items)=0;
   virtual bool initialize_tables (JOIN *join=0) { return 0; }
-  virtual void send_error(uint errcode,const char *err);
+  virtual void send_error(uint errcode,const char *err)=0;
   virtual bool send_eof()=0;
   virtual bool simple_select() { return 0; }
   virtual void abort() {}
@@ -1698,6 +1698,9 @@ public:
 #else
   void begin_dataset() {}
 #endif
+
+protected:
+  int complete_statement(int error);
 };
 
 
@@ -1722,6 +1725,7 @@ public:
   select_send() :status(0) {}
   bool send_fields(List<Item> &list, uint flags);
   bool send_data(List<Item> &items);
+  void send_error(uint errcode,const char *err);
   bool send_eof();
   bool simple_select() { return 1; }
   void abort();
@@ -1888,6 +1892,7 @@ public:
   select_union() :table(0) {}
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
   bool send_data(List<Item> &items);
+  void send_error(uint errcode,const char *err);
   bool send_eof();
   bool flush();
 
@@ -1904,7 +1909,8 @@ protected:
 public:
   select_subselect(Item_subselect *item);
   bool send_data(List<Item> &items)=0;
-  bool send_eof() { return 0; };
+  void send_error(uint errcode,const char *err);
+  bool send_eof();
 };
 
 /* Single value subselect interface class */
@@ -2162,6 +2168,7 @@ public:
   ~select_dumpvar() {}
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
   bool send_data(List<Item> &items);
+  void send_error(uint errcode,const char *err);
   bool send_eof();
   void cleanup();
 };

--- 1.179/sql/sql_delete.cc	2006-09-08 16:23:27 -07:00
+++ 1.180/sql/sql_delete.cc	2006-09-08 16:23:27 -07:00
@@ -39,7 +39,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *
   ha_rows	deleted;
   uint usable_index= MAX_KEY;
   SELECT_LEX   *select_lex= &thd->lex->select_lex;
-  int           tx_error= 0;
   DBUG_ENTER("mysql_delete");
 
   if (open_and_lock_tables(thd, table_list))
@@ -310,8 +309,7 @@ cleanup:
 
   /* WARNING: error == 0 *is* an error */
   /* On success, error == -1 */
-  tx_error= (error >= 0) ? 1 : 0;
-  if (ha_autocommit_or_rollback(thd, tx_error))
+  if (ha_autocommit_or_rollback(thd, (error >= 0)))
   {
     error= 1;
   }
@@ -470,9 +468,10 @@ bool mysql_multi_delete_prepare(THD *thd
 
 
 multi_delete::multi_delete(TABLE_LIST *dt, uint num_of_tables_arg)
-  : delete_tables(dt), deleted(0), found(0),
+  : delete_tables(dt), table_being_deleted(0), deleted(0), found(0),
     num_of_tables(num_of_tables_arg), error(0),
-    do_delete(0), transactional_tables(0), normal_tables(0)
+    do_delete(0), transactional_tables(0), normal_tables(0),
+    delete_while_scanning(0)
 {
   tempfiles= (Unique **) sql_calloc(sizeof(Unique *) * num_of_tables);
 }
@@ -639,12 +638,11 @@ void multi_delete::send_error(uint errco
   /* First send error what ever it is ... */
   my_message(errcode, err, MYF(0));
 
-  /* If nothing deleted return */
-  if (!deleted)
-    DBUG_VOID_RETURN;
-
-  /* Something already deleted so we have to invalidate cache */
-  query_cache_invalidate3(thd, delete_tables, 1);
+  if (deleted)
+  {
+    /* Something already deleted so we have to invalidate cache */
+    query_cache_invalidate3(thd, delete_tables, 1);
+  }
 
   /*
     If rows from the first table only has been deleted and it is
@@ -783,9 +781,8 @@ bool multi_delete::send_eof()
       thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
   }
   /* Commit or rollback the current SQL statement */
-  if (transactional_tables)
-    if (ha_autocommit_or_rollback(thd,local_error > 0))
-      local_error=1;
+  if (ha_autocommit_or_rollback(thd, local_error > 0))
+    local_error=1;
 
   if (!local_error)
   {

--- 1.200/sql/sql_insert.cc	2006-09-08 16:23:27 -07:00
+++ 1.201/sql/sql_insert.cc	2006-09-08 16:23:27 -07:00
@@ -2532,8 +2532,9 @@ bool select_insert::send_eof()
 			  table->file->has_transactions(), FALSE);
     mysql_bin_log.write(&qinfo);
   }
-  if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
-    error=error2;
+
+  error= ha_autocommit_or_rollback(thd, error);
+
   if (error)
   {
     table->file->print_error(error,MYF(0));

--- 1.98/sql/sql_load.cc	2006-09-08 16:23:27 -07:00
+++ 1.99/sql/sql_load.cc	2006-09-08 16:23:27 -07:00
@@ -407,10 +407,10 @@ bool mysql_load(THD *thd,sql_exchange *e
   */
   query_cache_invalidate3(thd, table_list, 0);
 
-  error= ha_autocommit_or_rollback(thd, error);
-
   if (error)
   {
+    (void) ha_autocommit_or_rollback(thd, error);
+
     if (read_file_from_client)
       while (!read_info.next_line())
 	;

--- 1.566/sql/sql_parse.cc	2006-09-08 16:23:27 -07:00
+++ 1.567/sql/sql_parse.cc	2006-09-08 16:23:27 -07:00
@@ -2401,9 +2401,6 @@ static void reset_one_shot_variables(THD
     ===============================================================
 
     The following statements do manipulate transactions explicitly:
-    - SQLCOM_HA_OPEN
-    - SQLCOM_HA_CLOSE
-    - SQLCOM_HA_READ
     - SQLCOM_BEGIN
     - SQLCOM_COMMIT
     - SQLCOM_ROLLBACK
@@ -2416,12 +2413,19 @@ static void reset_one_shot_variables(THD
     - SQLCOM_XA_COMMIT
     - SQLCOM_XA_ROLLBACK
     - SQLCOM_XA_RECOVER
-    - SQLCOM_UNLOCK_TABLES
-    - SQLCOM_LOCK_TABLES
     For these statements, ha_autocommit_or_rollback should *not* be called.
     See http://dev.mysql.com/doc/refman/5.1/en/transactional-commands.html
 
     The following statements do manipulate transactions implicitly:
+    - Cursor
+      - SQLCOM_HA_OPEN
+      - SQLCOM_HA_CLOSE
+      - SQLCOM_HA_READ
+
+    - Table locks
+      - SQLCOM_UNLOCK_TABLES
+      - SQLCOM_LOCK_TABLES
+
     - Data Definition
       - SQLCOM_CREATE_TABLE
       - SQLCOM_CREATE_INDEX
@@ -2459,9 +2463,6 @@ static void reset_one_shot_variables(THD
     code is *not* transaction-aware (for example, rollback may not be clean
     and may leave .frm files around).
 
-    LATER: Once the implementation of the DDL statements is transaction-aware,
-    - explicit calls to end_active_trans() should be removed,
-    - a call to ha_autocommit_or_rollback() should be added.
     See http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html
 
     The following statements:
@@ -2506,7 +2507,6 @@ static void reset_one_shot_variables(THD
     - SQLCOM_SHOW_CREATE_FUNC
     - SQLCOM_SHOW_PROC_CODE
     - SQLCOM_SHOW_FUNC_CODE
-    - SQLCOM_SET_OPTION
     are known to have no possible side effect on the transactional data.
     No ha_autocommit_or_rollback() is needed, nor in some cases is desirable
     (for very low level server state inspection like SQLCOM_SHOW_MUTEX_STATUS).
@@ -2540,6 +2540,7 @@ static void reset_one_shot_variables(THD
     - SQLCOM_DELETE_MULTI
     - SQLCOM_LOAD
     - SQLCOM_CALL
+    - SQLCOM_SET_OPTION
 
     The following commands:
     - SQLCOM_REVOKE_ALL
@@ -2565,14 +2566,14 @@ static void reset_one_shot_variables(THD
     Note that the relative order of code that :
     - lock tables with storage engines
     - open / execute / closes cursors, read / write with storage engines
+    - generates a binlog event
     - calls ha_autocommit_or_rollback()
     - unlock tables with storage engines
     - respond with send_ok(thd) / send_eof(thd) to the client
-    has to be *strictly* respected, otherwise disastrous side effects
-    will occur.
-    As a result, the place where in practice ha_autocommit_or_rollback()
-    is called varies greatly between commands, to comply with the constrainst
-    of the original design.
+    has to be *strictly* respected.
+    As a result, the place in the code where in practice
+    ha_autocommit_or_rollback() is called varies greatly between commands,
+    to comply with the of the original code structure.
 
   RETURN
     FALSE       OK
@@ -2748,7 +2749,7 @@ mysql_execute_command(THD *thd)
           goto error;
 	query_cache_store_query(thd, all_tables);
 	res= handle_select(thd, lex, result, 0);
-        res= ha_autocommit_or_rollback(thd, res);
+        /* ha_autocommit_or_rollback() performed by select_send::send_eof() */
         if (result != lex->result)
           delete result;
       }
@@ -3463,17 +3464,17 @@ end_with_restore_list:
                                unit->select_limit_cnt,
                                lex->duplicates, lex->ignore));
     /*
-     mysql_update return 2 if we need to switch to multi-update.
-     Note that in this case, mysql_update() did no processing,
-     and that the current statement transaction is still opened.
-     It will be commited/rollbacked by the MULTI-UPDATE code below.
-     TODO: refactor this code.
+       mysql_update return 2 if we need to switch to multi-update.
+       Note that in this case, mysql_update() did no processing,
+       and that the current statement transaction is still opened.
+       It will be commited/rollbacked by the MULTI-UPDATE code below.
+       TODO: refactor this code.
      */
     if (result != 2)
     {
       break;
     }
-    /* FALL THOUGH */
+    /* fall through */
   case SQLCOM_UPDATE_MULTI:
   {
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -3528,7 +3529,7 @@ end_with_restore_list:
                             select_lex->where,
                             select_lex->options,
                             lex->duplicates, lex->ignore, unit, select_lex);
-    res= ha_autocommit_or_rollback(thd, res);
+    /* ha_autocommit_or_rollback() performed by multi_update::send_eof() */
     break;
   }
   case SQLCOM_REPLACE:
@@ -3594,7 +3595,7 @@ end_with_restore_list:
                                              lex->duplicates, lex->ignore)))
       {
 	res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
-        res= ha_autocommit_or_rollback(thd, res);
+        /* ha_autocommit_or_rollback() performed by select_insert::send_eof() */
         /*
           Invalidate the table in the query cache if something changed
           after unlocking when changes become visible.
@@ -3706,7 +3707,14 @@ end_with_restore_list:
 			SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                         OPTION_SETUP_TABLES_DONE,
 			result, unit, select_lex);
-      res= ha_autocommit_or_rollback(thd, res);
+      DBUG_PRINT("info",("res: %d  report_error: %d",
+                        res, thd->net.report_error));
+      if (res)
+      {
+        result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
+        result->abort();
+      }
+      /* ha_autocommit_or_rollback() performed by multi_delete::send_eof() */
       delete result;
     }
     else
@@ -4081,7 +4089,6 @@ end_with_restore_list:
         check_global_access(thd,CREATE_USER_ACL))
       break;
     res= mysql_revoke_all(thd, lex->users_list);
-    /* LATER: res= ha_autocommit_or_rollback(thd, res); */
     if (!res)
     {
       if (mysql_bin_log.is_open())
@@ -4153,7 +4160,6 @@ end_with_restore_list:
                                  lex->type == TYPE_ENUM_PROCEDURE, 
                                  lex->users_list, grants,
                                  lex->sql_command == SQLCOM_REVOKE, 0);
-        /* LATER: res= ha_autocommit_or_rollback(thd, res); */
       }
       else
       {
@@ -4165,7 +4171,6 @@ end_with_restore_list:
         res= mysql_table_grant(thd, all_tables, lex->users_list,
 			       lex->columns, lex->grant,
 			       lex->sql_command == SQLCOM_REVOKE);
-        /* LATER: res= ha_autocommit_or_rollback(thd, res); */
       }
       if (!res && mysql_bin_log.is_open())
       {
@@ -4186,7 +4191,6 @@ end_with_restore_list:
       {
 	res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
 			  lex->sql_command == SQLCOM_REVOKE);
-        /* LATER: res= ha_autocommit_or_rollback(thd, res); */
       }
       if (!res)
       {

--- 1.197/sql/sql_update.cc	2006-09-08 16:23:27 -07:00
+++ 1.198/sql/sql_update.cc	2006-09-08 16:23:27 -07:00
@@ -137,7 +137,6 @@ int mysql_update(THD *thd,
   READ_RECORD	info;
   SELECT_LEX    *select_lex= &thd->lex->select_lex;
   bool need_reopen;
-  int tx_error= 0;
   DBUG_ENTER("mysql_update");
 
   LINT_INIT(timestamp_query_id);
@@ -552,8 +551,7 @@ int mysql_update(THD *thd,
 
   /* WARNING: error == 0 *is* an error */
   /* On success, error == -1 */
-  tx_error= (error >= 0) ? 1 : 0;
-  if (ha_autocommit_or_rollback(thd, tx_error))
+  if (ha_autocommit_or_rollback(thd, (error >= 0)))
   {
     error= 1;
   }
@@ -928,6 +926,14 @@ bool mysql_multi_update(THD *thd,
                       options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
                       OPTION_SETUP_TABLES_DONE,
                       result, unit, select_lex);
+  DBUG_PRINT("info",("error: %d  report_error: %d", error,
+		     thd->net.report_error));
+  if (error)
+  {
+    /* If we had a another error reported earlier then this will be ignored */
+    result->send_error(ER_UNKNOWN_ERROR, ER(ER_UNKNOWN_ERROR));
+    result->abort();
+  }
   delete result;
   thd->abort_on_warning= 0;
   brc= (error ? TRUE : FALSE);
@@ -943,7 +949,7 @@ multi_update::multi_update(TABLE_LIST *t
   :all_tables(table_list), leaves(leaves_list), update_tables(0),
    tmp_tables(0), updated(0), found(0), fields(field_list),
    values(value_list), table_count(0), copy_field(0),
-   handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(0),
+   handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1),
    transactional_tables(1), ignore(ignore_arg)
 {}
 
@@ -1367,12 +1373,11 @@ void multi_update::send_error(uint errco
   /* First send error what ever it is ... */
   my_error(errcode, MYF(0), err);
 
-  /* If nothing updated return */
-  if (!updated)
-    return;
-
-  /* Something already updated so we have to invalidate cache */
-  query_cache_invalidate3(thd, update_tables, 1);
+  if (updated)
+  {
+    /* 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.

--- 1.132/sql/sql_union.cc	2006-09-08 16:23:27 -07:00
+++ 1.133/sql/sql_union.cc	2006-09-08 16:23:27 -07:00
@@ -73,6 +73,12 @@ bool select_union::send_data(List<Item> 
 }
 
 
+void select_union::send_error(uint errcode, const char *err)
+{
+  my_message(errcode, err, MYF(0));
+}
+
+
 bool select_union::send_eof()
 {
   return 0;

--- 1.34/mysql-test/t/disabled.def	2006-09-08 16:23:27 -07:00
+++ 1.35/mysql-test/t/disabled.def	2006-09-08 16:23:27 -07:00
@@ -13,4 +13,3 @@
 ndb_load        : Bug#17233
 engine_mix_bdb_ndb : Bug#21590
 engine_mix_myisam_ndb : Bug#21590
-autocommit_ndb : Bug#21667

--- 1.276/sql/ha_ndbcluster.cc	2006-09-08 16:23:27 -07:00
+++ 1.277/sql/ha_ndbcluster.cc	2006-09-08 16:23:27 -07:00
@@ -3692,6 +3692,7 @@ int ha_ndbcluster::external_lock(THD *th
         DBUG_PRINT("trans",("ending non-updating transaction"));
         ndb->closeTransaction(m_active_trans);
         thd_ndb->stmt= NULL;
+        trans_unregister_ha(thd, FALSE, &ndbcluster_hton);
       }
     }
     m_table_info= NULL;
@@ -3793,37 +3794,36 @@ int ndbcluster_commit(THD *thd, bool all
   DBUG_PRINT("transaction",("%s",
                             trans == thd_ndb->stmt ?
                             "stmt" : "all"));
-  if (ndb && trans)
+  DBUG_ASSERT(ndb && trans);
+
+  if (execute_commit(thd,trans) != 0)
   {
-    if (execute_commit(thd,trans) != 0)
-    {
-      const NdbError err= trans->getNdbError();
-      const NdbOperation *error_op= trans->getNdbErrorOperation();
-      ERR_PRINT(err);
-      res= ndb_to_mysql_error(&err);
-      if (res != -1)
-        ndbcluster_print_error(res, error_op);
-    }
-    ndb->closeTransaction(trans);
+    const NdbError err= trans->getNdbError();
+    const NdbOperation *error_op= trans->getNdbErrorOperation();
+    ERR_PRINT(err);
+    res= ndb_to_mysql_error(&err);
+    if (res != -1)
+      ndbcluster_print_error(res, error_op);
+  }
+  ndb->closeTransaction(trans);
 
-    if (all)
-      thd_ndb->all= NULL;
-    else
-      thd_ndb->stmt= NULL;
-
-    /* Clear commit_count for tables changed by transaction */
-    NDB_SHARE* share;
-    List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
-    while ((share= it++))
-    {
-      pthread_mutex_lock(&share->mutex);
-      DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %d ", share->table_name, share->commit_count));
-      share->commit_count= 0;
-      share->commit_count_lock++;
-      pthread_mutex_unlock(&share->mutex);
-    }
-    thd_ndb->changed_tables.empty();
+  if (all)
+    thd_ndb->all= NULL;
+  else
+    thd_ndb->stmt= NULL;
+
+  /* Clear commit_count for tables changed by transaction */
+  NDB_SHARE* share;
+  List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
+  while ((share= it++))
+  {
+    pthread_mutex_lock(&share->mutex);
+    DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %d ", share->table_name, share->commit_count));
+    share->commit_count= 0;
+    share->commit_count_lock++;
+    pthread_mutex_unlock(&share->mutex);
   }
+  thd_ndb->changed_tables.empty();
 
   DBUG_RETURN(res);
 }
@@ -3844,27 +3844,26 @@ int ndbcluster_rollback(THD *thd, bool a
   DBUG_PRINT("transaction",("%s",
                             trans == thd_ndb->stmt ? 
                             "stmt" : "all"));
-  if (ndb && trans)
+  DBUG_ASSERT(ndb && trans);
+
+  if (trans->execute(NdbTransaction::Rollback) != 0)
   {
-    if (trans->execute(NdbTransaction::Rollback) != 0)
-    {
-      const NdbError err= trans->getNdbError();
-      const NdbOperation *error_op= trans->getNdbErrorOperation();
-      ERR_PRINT(err);     
-      res= ndb_to_mysql_error(&err);
-      if (res != -1) 
-        ndbcluster_print_error(res, error_op);
-    }
-    ndb->closeTransaction(trans);
+    const NdbError err= trans->getNdbError();
+    const NdbOperation *error_op= trans->getNdbErrorOperation();
+    ERR_PRINT(err);     
+    res= ndb_to_mysql_error(&err);
+    if (res != -1) 
+      ndbcluster_print_error(res, error_op);
+  }
+  ndb->closeTransaction(trans);
 
-    if (all)
-      thd_ndb->all= NULL;
-    else
-      thd_ndb->stmt= NULL;
+  if (all)
+    thd_ndb->all= NULL;
+  else
+    thd_ndb->stmt= NULL;
 
-    /* Clear list of tables changed by transaction */
-    thd_ndb->changed_tables.empty();
-  }
+  /* Clear list of tables changed by transaction */
+  thd_ndb->changed_tables.empty();
 
   DBUG_RETURN(res);
 }

--- 1.1/mysql-test/include/autocommit_common.inc	2006-09-08 16:23:27 -07:00
+++ 1.2/mysql-test/include/autocommit_common.inc	2006-09-08 16:23:27 -07:00
@@ -14,7 +14,8 @@ drop table if exists t1;
 drop table if exists t2;
 drop table if exists t3;
 drop function if exists f2;
-drop procedure if exists p1;
+drop procedure if exists bug12713_call;
+drop procedure if exists bug12713_dump_spvars;
 --enable_warnings
 
 eval create table t1 (a int) engine = $engine_type;
@@ -34,19 +35,24 @@ begin
   return x;
 end//
 
-create procedure p1 ()
-begin
-  insert into t2 (a) values (24);
-  insert into t2 (a) values (24);
-end//
-
 delimiter ;//
 
 set autocommit=0;
 
-## In each case, statement rollback is expected
+##============================================================================
+## Design notes
+##
+## In each case, statement rollback is expected.
 ## for transactional engines, the rollback should be properly executed
-## for non transactional engines, the rollback may cause warnings
+## for non transactional engines, the rollback may cause warnings.
+##
+## The test pattern is as follows
+## - insert 1000+N
+## - statement with a side effect, that fails to insert N twice
+## - a statement rollback is expected (expecting 1 row 1000+N only) in t2
+## - a rollback is performed
+## - expecting a clean table t2.
+##============================================================================
 
 insert into t2 (a) values (1001);
 --error ER_DUP_ENTRY
@@ -239,19 +245,95 @@ commit;
 ## then will rollback the second insert only (24) (statement rollback)
 ## then will rollback the complete transaction (transaction rollback)
 
+delimiter //;
+
+create procedure bug12713_call ()
+begin
+  insert into t2 (a) values (24);
+  insert into t2 (a) values (24);
+end//
+
+delimiter ;//
+
 insert into t2 (a) values (1024);
 --error ER_DUP_ENTRY
-call p1();
+call bug12713_call();
+select * from t2;
+rollback;
+select * from t2;
+commit;
+
+##============================================================================
+## Testing select_to_file
+##============================================================================
+
+--system rm -f $MYSQLTEST_VARDIR/tmp/autocommit_out
+insert into t2 (a) values (1025);
+
+--replace_result $MYSQLTEST_VARDIR ..
+--error ER_DUP_ENTRY
+eval select f2(25) into outfile "$MYSQLTEST_VARDIR/tmp/autocommit_out" from t1;
+
+## See Bug#22035 about that error 13
+--replace_result $MYSQLTEST_VARDIR ..
+--error 13
+eval load data infile "$MYSQLTEST_VARDIR/tmp/autocommit_out" into table t1 (a);
+
 select * from t2;
 rollback;
 select * from t2;
 commit;
 
+##============================================================================
+## Testing select_dumpvar
+##============================================================================
+
+insert into t2 (a) values (1026);
+--error ER_DUP_ENTRY
+select f2(26) into @foo;
+select * from t2;
+rollback;
+select * from t2;
+commit;
+
+##============================================================================
+## Testing Select_fetch_into_spvars
+##============================================================================
+
+delimiter //;
+
+create procedure bug12713_dump_spvars ()
+begin
+  declare foo int;
+
+  declare continue handler for sqlexception
+  begin
+    select "Exception trapped";
+  end;
+
+  select f2(27) into foo;
+  select * from t2;
+end//
+
+delimiter ;//
+
+insert into t2 (a) values (1027);
+call bug12713_dump_spvars ();
+rollback;
+select * from t2;
+commit;
+
+
+##============================================================================
+## Cleanup
+##============================================================================
+
 set autocommit=1;
 
 drop table t1;
 drop table t2;
 drop table t3;
 drop function f2;
-drop procedure p1;
+drop procedure bug12713_call;
+drop procedure bug12713_dump_spvars;
 

--- 1.1/mysql-test/include/engine_mix_common.inc	2006-09-08 16:23:27 -07:00
+++ 1.2/mysql-test/include/engine_mix_common.inc	2006-09-08 16:23:27 -07:00
@@ -103,16 +103,6 @@ commit;
 delete from t2;
 commit;
 
-## This one needs adjustment (in the test)
-## --error ER_DUP_ENTRY
-## delete from t1 where ((a + 3) = (a + f2_soft(3, a)));
-## select * from t2;
-## rollback;
-## select * from t2;
-## commit;
-## delete from t2;
-## commit;
-
 --error ER_DUP_ENTRY
 select f2_soft(4, a) from t1 ;
 select * from t2;

--- 1.1/mysql-test/r/autocommit_bdb.result	2006-09-08 16:23:27 -07:00
+++ 1.2/mysql-test/r/autocommit_bdb.result	2006-09-08 16:23:27 -07:00
@@ -3,7 +3,8 @@ drop table if exists t1;
 drop table if exists t2;
 drop table if exists t3;
 drop function if exists f2;
-drop procedure if exists p1;
+drop procedure if exists bug12713_call;
+drop procedure if exists bug12713_dump_spvars;
 create table t1 (a int) engine = BerkeleyDB;
 create table t2 (a int unique) engine = BerkeleyDB;
 create table t3 (a int) engine = BerkeleyDB;
@@ -15,11 +16,6 @@ insert into t2 (a) values (x);
 insert into t2 (a) values (x);
 return x;
 end//
-create procedure p1 ()
-begin
-insert into t2 (a) values (24);
-insert into t2 (a) values (24);
-end//
 set autocommit=0;
 insert into t2 (a) values (1001);
 insert into t1 (a) values (f2(1));
@@ -58,8 +54,6 @@ select * from t2;
 a
 1004
 rollback;
-Warnings:
-Warning	1196	Some non-transactional changed tables couldn't be rolled back
 select * from t2;
 a
 commit;
@@ -254,8 +248,13 @@ rollback;
 select * from t2;
 a
 commit;
+create procedure bug12713_call ()
+begin
+insert into t2 (a) values (24);
+insert into t2 (a) values (24);
+end//
 insert into t2 (a) values (1024);
-call p1();
+call bug12713_call();
 ERROR 23000: Duplicate entry '24' for key 1
 select * from t2;
 a
@@ -265,9 +264,52 @@ rollback;
 select * from t2;
 a
 commit;
+insert into t2 (a) values (1025);
+select f2(25) into outfile "../tmp/autocommit_out" from t1;
+ERROR 23000: Duplicate entry '25' for key 1
+load data infile "../tmp/autocommit_out" into table t1 (a);
+ERROR HY000: Can't get stat of '../tmp/autocommit_out' (Errcode: 2)
+select * from t2;
+a
+1025
+rollback;
+select * from t2;
+a
+commit;
+insert into t2 (a) values (1026);
+select f2(26) into @foo;
+ERROR 23000: Duplicate entry '26' for key 1
+select * from t2;
+a
+1026
+rollback;
+select * from t2;
+a
+commit;
+create procedure bug12713_dump_spvars ()
+begin
+declare foo int;
+declare continue handler for sqlexception
+begin
+select "Exception trapped";
+end;
+select f2(27) into foo;
+select * from t2;
+end//
+insert into t2 (a) values (1027);
+call bug12713_dump_spvars ();
+Exception trapped
+Exception trapped
+a
+1027
+rollback;
+select * from t2;
+a
+commit;
 set autocommit=1;
 drop table t1;
 drop table t2;
 drop table t3;
 drop function f2;
-drop procedure p1;
+drop procedure bug12713_call;
+drop procedure bug12713_dump_spvars;

--- 1.1/mysql-test/r/autocommit_innodb.result	2006-09-08 16:23:27 -07:00
+++ 1.2/mysql-test/r/autocommit_innodb.result	2006-09-08 16:23:27 -07:00
@@ -3,7 +3,8 @@ drop table if exists t1;
 drop table if exists t2;
 drop table if exists t3;
 drop function if exists f2;
-drop procedure if exists p1;
+drop procedure if exists bug12713_call;
+drop procedure if exists bug12713_dump_spvars;
 create table t1 (a int) engine = InnoDB;
 create table t2 (a int unique) engine = InnoDB;
 create table t3 (a int) engine = InnoDB;
@@ -15,11 +16,6 @@ insert into t2 (a) values (x);
 insert into t2 (a) values (x);
 return x;
 end//
-create procedure p1 ()
-begin
-insert into t2 (a) values (24);
-insert into t2 (a) values (24);
-end//
 set autocommit=0;
 insert into t2 (a) values (1001);
 insert into t1 (a) values (f2(1));
@@ -58,8 +54,6 @@ select * from t2;
 a
 1004
 rollback;
-Warnings:
-Warning	1196	Some non-transactional changed tables couldn't be rolled back
 select * from t2;
 a
 commit;
@@ -254,8 +248,13 @@ rollback;
 select * from t2;
 a
 commit;
+create procedure bug12713_call ()
+begin
+insert into t2 (a) values (24);
+insert into t2 (a) values (24);
+end//
 insert into t2 (a) values (1024);
-call p1();
+call bug12713_call();
 ERROR 23000: Duplicate entry '24' for key 1
 select * from t2;
 a
@@ -265,9 +264,52 @@ rollback;
 select * from t2;
 a
 commit;
+insert into t2 (a) values (1025);
+select f2(25) into outfile "../tmp/autocommit_out" from t1;
+ERROR 23000: Duplicate entry '25' for key 1
+load data infile "../tmp/autocommit_out" into table t1 (a);
+ERROR HY000: Can't get stat of '../tmp/autocommit_out' (Errcode: 2)
+select * from t2;
+a
+1025
+rollback;
+select * from t2;
+a
+commit;
+insert into t2 (a) values (1026);
+select f2(26) into @foo;
+ERROR 23000: Duplicate entry '26' for key 1
+select * from t2;
+a
+1026
+rollback;
+select * from t2;
+a
+commit;
+create procedure bug12713_dump_spvars ()
+begin
+declare foo int;
+declare continue handler for sqlexception
+begin
+select "Exception trapped";
+end;
+select f2(27) into foo;
+select * from t2;
+end//
+insert into t2 (a) values (1027);
+call bug12713_dump_spvars ();
+Exception trapped
+Exception trapped
+a
+1027
+rollback;
+select * from t2;
+a
+commit;
 set autocommit=1;
 drop table t1;
 drop table t2;
 drop table t3;
 drop function f2;
-drop procedure p1;
+drop procedure bug12713_call;
+drop procedure bug12713_dump_spvars;

--- 1.1/mysql-test/r/autocommit_ndb.result	2006-09-08 16:23:27 -07:00
+++ 1.3/BitKeeper/deleted/.del-autocommit_ndb.result	2006-09-08 16:23:27 -07:00
@@ -58,8 +58,6 @@ select * from t2;
 a
 1004
 rollback;
-Warnings:
-Warning	1196	Some non-transactional changed tables couldn't be rolled back
 select * from t2;
 a
 commit;

--- 1.12/sql/sql_do.cc	2006-09-08 16:23:27 -07:00
+++ 1.13/sql/sql_do.cc	2006-09-08 16:23:27 -07:00
@@ -21,8 +21,8 @@
 
 bool mysql_do(THD *thd, List<Item> &values)
 {
-  int tx_error= 0;
-  bool result= FALSE;
+  int tx_error;
+  bool result;
   List_iterator<Item> li(values);
   Item *value;
   DBUG_ENTER("mysql_do");

--- 1.43/sql/sp_rcontext.cc	2006-09-08 16:23:27 -07:00
+++ 1.44/sql/sp_rcontext.cc	2006-09-08 16:23:27 -07:00
@@ -607,3 +607,19 @@ bool Select_fetch_into_spvars::send_data
   }
   return FALSE;
 }
+
+
+void Select_fetch_into_spvars::send_error(uint errcode, const char *err)
+{
+  my_message(errcode, err, MYF(0));
+
+  (void) complete_statement(errcode);
+}
+
+
+bool Select_fetch_into_spvars::send_eof()
+{
+  int error= complete_statement(0);
+  return (error ? TRUE : FALSE);
+}
+

--- 1.33/sql/sp_rcontext.h	2006-09-08 16:23:27 -07:00
+++ 1.34/sql/sp_rcontext.h	2006-09-08 16:23:27 -07:00
@@ -278,7 +278,8 @@ public:
   uint get_field_count() { return field_count; }
   void set_spvar_list(List<struct sp_variable> *vars) { spvar_list= vars; }
 
-  virtual bool send_eof() { return FALSE; }
+  virtual void send_error(uint errcode, const char *err);
+  virtual bool send_eof();
   virtual bool send_data(List<Item> &items);
   virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
 };
Thread
bk commit into 5.0 tree (malff:1.2258)marc.alff9 Sep