List:Commits« Previous MessageNext Message »
From:konstantin Date:November 3 2007 12:26pm
Subject:bk commit into 5.1 tree (kostja:1.2606) 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-03 15:26:04+03:00, kostja@bodhi.(none) +45 -0
  Do not send OK/EOF packets to the client till the end of statement.
  Massive change to use an API instead of direct access to private
  members of the error stack in THD.
  
  Draft, and that applies to the changeset comments as well.
  
  This is a pre-requisite for Bug#12713.

  include/mysql_com.h@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +7 -9
    Rename unused members of NET: no_send_ok, no_send_error, report_error.
    Rename last_error to client_last_error and last_errno to client_last_errno
    to avoid potential bugs introduced by merged changes.

  include/mysql_h.ic@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +5 -5
    Update the ABI file. Renames do not break binary compatibility.

  libmysql/libmysql.c@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +19 -19
    Rename last_error to client_last_error, last_errno to client_last_errno.
    Remove net.report_error

  libmysql/manager.c@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +1 -1
    Rename net.last_errno to net.client_last_errno

  libmysqld/lib_sql.cc@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +19 -21
    Rename net.last_errno to net.client_last_errno.

  libmysqld/libmysqld.c@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +2 -2
    Rename net.last_errno to net.client_last_errno.

  mysql-test/r/events.result@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +2 -1
    Update to reflect the change in mysql_rm_db().

  server-tools/instance-manager/mysql_connection.cc@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +1 -1
    Rename net.last_errno to net.client_last_errno.

  sql-common/client.c@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +32 -29
    Rename last_error to client_last_error, last_errno to client_last_errno.

  sql/ha_ndbcluster_binlog.cc@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +19 -5
    Add asserts. Use getters to access statement status information.
    Add a comment why run_query() is broken. Reset the diagnostics area
    in the end of run_query() to fulfill the invariant that the diagnostics_area
    is never assigned twice per statement.

  sql/ha_partition.cc@stripped, 2007-11-03 15:25:55+03:00, kostja@bodhi.(none) +1 -0
    fatal_error() doesn't set an error by itself. Perhaps we should
    remove this method as such and have a flag in my_error to set fatal_error().
    Meanwhile, inspect all places in the server that call fatal_error()
    without having called my_error() and update them.

  sql/item_func.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +0 -1
    There is no net.last_error anymore. Remove the obsolete assignment.

  sql/log_event.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +31 -21
    Use getters to access statement error status information.

  sql/log_event_old.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +8 -8
    Use getters to access statement error status information.

  sql/mysqld.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +27 -20
    Previously my_message_sql() in case of a stored procedure continue handler
    would not set an error in THD. Since the current statement
    should be aborted, even if there is a continue handler, find_handler()
    had a hack to nevertheless set thd->net.report_error. 
    Remove the hack, set an error in my_message_sql even if the continue
    handler is found. The error will be cleared anyway when the handler
    is executed. This is one step to ensure the invariant that if thd->is_error()
    we have a message in thd->main_da.message().

  sql/net_serv.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +29 -29
    Use a full-blown my_error in net_serv.cc to report an error,
    instead of just setting net->last_errno. This ensures the invariant that
    whenever there is an error, we have a message in thd->main_da.message().
    
    Remove assignments of removed NET members.

  sql/opt_range.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +1 -1
    Use my_error() instead of just raising thd->net.report_error. 
    This ensures the invariant that whenever we have an error, there is
    a message in thd->main_da.message().

  sql/opt_sum.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +2 -0
    Move invocation of fatal_error() right next to the place where
    we set the error message. That makes it easier to track that whenever
    fatal_error() is called, there is a message in THD.

  sql/protocol.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +150 -67
    Rename send_ok and send_eof to net_send_ok and net_send_eof. These
    functions write directly to the network and are not for use anywhere
    outside the client/server protocol code. 
    
    Remove the code that was responsible for cases when either there is 
    no error code, or no error message, or both, set in the diagnostics area.
    
    Instead the calling code ensures that they are always present. Asserts
    are added to enforce the invariant.
    
    Instead of a direct access to thd->server_status and thd->total_warn_count
    use function parameters, since these from now on don't always come directly
    from THD.
    
    Introduce net_end_statement(), the one replacement API for send_ok,
    send_eof or net_send_error.
    
    Implement Protocol::end_partial_result_set to use in select_send::abort()
    when there is a continue handler. 

  sql/protocol.h@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +2 -3
    Update declarations.

  sql/repl_failsafe.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +3 -1
    Use getters to access statement status information in THD.
    Rename net.last_error to net.client_last_error.

  sql/rpl_record.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +3 -2
    Set an error message in prepare_record() if there is no default
    value for the field -- later we do print this message to the client.

  sql/rpl_rli.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +2 -2
    Use getters to access statement status information in THD.

  sql/slave.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +30 -16
    Instead of hacks with no_send_ok clear the diagnostics area in the end of
    mysql_rm_table.

  sql/sp_head.cc@stripped, 2007-11-03 15:25:56+03:00, kostja@bodhi.(none) +9 -7
    Instead of hacks with no_send_error work with the diagnostics area interface
    to suppress sending of OK/ERROR packets to the client from stored procedure
    statements.

  sql/sp_rcontext.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +1 -21
    Remove hacks with thd->net.report_error.

  sql/sql_acl.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +1 -4
    Use getters to access error status information in THD.

  sql/sql_base.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +22 -5
    Access thd->main_da.sql_errno() only if there is an error. This fixes
    a bug when auto-discovery was effectively disabled under pre-locking.

  sql/sql_binlog.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +0 -15
    Remove hacks with no_send_ok/no_send_error.

  sql/sql_cache.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +1 -0
    Disable sending of OK/ERROR/EOF packet in the end of dispatch_command
    if the response has been served from the query cache. This raises an 
    important question whether we should store EOF packet in the query cache
    or generate it anew for each statement (we should generate it anew), but
    this is to be addressed separately, sometime in the future.

  sql/sql_class.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +114 -23
    Implement class Diagnostics_area.
    Fix a subtle bug in select_send::send_data when on slave an error in
    Item::send was ignored in the return value of send_data.
    The bug became visible due to asserts that the diagnostics area is
    never double assigned.

  sql/sql_class.h@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +150 -6
    Declare class Diagnostics_area. Remove the hack with no_send_ok from
    Substatement_state.
    Provide inline implementations of send_ok/send_eof.

  sql/sql_connect.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +10 -23
    Remove hacks with no_send_error. 
    Since now an error in THD is always set if net->error, it's not necessary
    to check both net->error and thd->is_error().
    Use thd->main_da.message() instead of net->lsat_errno.
    Remove the hack with is_slave_error in sys_init_connect. Since now we do not
    reset the diagnostics area in net_send_error (it's reset at the beginning
    of the next statement), we can access it even after execute_init_command.

  sql/sql_db.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +3 -2
    Update the code to satisfy the invariant that the diagnostics area is never
    assigned twice.

  sql/sql_derived.cc@stripped, 2007-11-03 15:25:57+03:00, kostja@bodhi.(none) +3 -2
    Use getters to access error information.

  sql/sql_insert.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +10 -6
    Use getters to access error information in THD.

  sql/sql_parse.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +36 -46
    Remove hacks with no_send_error. Deploy net_end_statement().
    
    The story of COM_SHUTDOWN is amazing. The server would become very talkative
    during shutdown, only some hacks with no_send_error woudl save us
    from complete breakage of the client/server protocol.
    
    Consistently use select_send::abort() whenever there is an error, 
    and select_send::send_eof() in case of success.
    The issue became visible due to added asserts.

  sql/sql_partition.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +1 -0
    Always set an error in THD whenever there is a call to fatal_error().

  sql/sql_prepare.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +17 -10
    Deploy class Diagnostics_area.

  sql/sql_select.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +1 -1
    Call fatal_error directly in opt_sum_query.
    Call my_error whenever we call thd->fatal_error().

  sql/sql_servers.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +1 -1
    Use getters to access error information in THD.

  sql/sql_show.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +32 -23
    Use getters to access error information in THD.
    Add comments.

  sql/sql_table.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +20 -9
    Replace hacks with no_send_ok with functionality of the diagnostics area.

  sql/table.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +14 -13
    Use getters to access error information in THD.

  sql/tztime.cc@stripped, 2007-11-03 15:25:58+03:00, kostja@bodhi.(none) +1 -1
    Use a getter to access error information in THD.

diff -Nrup a/include/mysql_com.h b/include/mysql_com.h
--- a/include/mysql_com.h	2007-10-15 15:45:15 +04:00
+++ b/include/mysql_com.h	2007-11-03 15:25:55 +03:00
@@ -202,14 +202,10 @@ typedef struct st_net {
   unsigned int *return_status;
   unsigned char reading_or_writing;
   char save_char;
-  my_bool no_send_ok;  /* For SPs and other things that do multiple stmts */
+  my_bool unused0; /* Please remove with the next incompatible ABI change */
   my_bool unused; /* Please remove with the next incompatible ABI change */
   my_bool compress;
-  /*
-    Set if OK packet is already sent, and we do not need to send error
-    messages
-  */
-  my_bool no_send_error;
+  my_bool unused1;
   /*
     Pointer to query object in query cache, do not equal NULL (0) for
     queries in cache that have not stored its results yet
@@ -220,11 +216,13 @@ typedef struct st_net {
     functions and methods to maintain proper locking.
   */
   unsigned char *query_cache_query;
-  unsigned int last_errno;
+  unsigned int client_last_errno;
   unsigned char error;
-  my_bool report_error; /* We should report error (we have unreported error) */
+  my_bool unused2;
   my_bool return_errno;
-  char last_error[MYSQL_ERRMSG_SIZE], sqlstate[SQLSTATE_LENGTH+1];
+  /* The below to should be moved ot st_mysql. */
+  char client_last_error[MYSQL_ERRMSG_SIZE];
+  char sqlstate[SQLSTATE_LENGTH+1];
   void *extension;
 } NET;
 
diff -Nrup a/include/mysql_h.ic b/include/mysql_h.ic
--- a/include/mysql_h.ic	2007-10-16 20:21:38 +04:00
+++ b/include/mysql_h.ic	2007-11-03 15:25:55 +03:00
@@ -537,16 +537,16 @@ struct __attribute__((aligned(__alignof_
     unsigned int * return_status;
     unsigned char reading_or_writing;
     char save_char;
-    my_bool no_send_ok;
+    my_bool unused0;
     my_bool unused;
     my_bool compress;
-    my_bool no_send_error;
+    my_bool unused1;
     unsigned char * query_cache_query;
-    unsigned int last_errno;
+    unsigned int client_last_errno;
     unsigned char error;
-    my_bool report_error;
+    my_bool unused2;
     my_bool return_errno;
-    char last_error[512];
+    char client_last_error[512];
     char sqlstate[(5 + 1)];
     void * extension;
   };
diff -Nrup a/libmysql/libmysql.c b/libmysql/libmysql.c
--- a/libmysql/libmysql.c	2007-10-31 17:30:41 +03:00
+++ b/libmysql/libmysql.c	2007-11-03 15:25:55 +03:00
@@ -440,11 +440,11 @@ static void expand_error(MYSQL* mysql, i
   char tmp[MYSQL_ERRMSG_SIZE];
   char *p;
   uint err_length;
-  strmake(tmp, mysql->net.last_error, MYSQL_ERRMSG_SIZE-1);
-  p = strmake(mysql->net.last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
-  err_length= (uint) (p - mysql->net.last_error);
+  strmake(tmp, mysql->net.client_last_error, MYSQL_ERRMSG_SIZE-1);
+  p = strmake(mysql->net.client_last_error, ER(error), MYSQL_ERRMSG_SIZE-1);
+  err_length= (uint) (p - mysql->net.client_last_error);
   strmake(p, tmp, MYSQL_ERRMSG_SIZE-1 - err_length);
-  mysql->net.last_errno = error;
+  mysql->net.client_last_errno = error;
 }
 
 /*
@@ -870,9 +870,9 @@ my_bool handle_local_infile(MYSQL *mysql
     VOID(my_net_write(net,(const uchar*) "",0)); /* Server needs one packet */
     net_flush(net);
     strmov(net->sqlstate, unknown_sqlstate);
-    net->last_errno= (*options->local_infile_error)(li_ptr,
-						    net->last_error,
-						    sizeof(net->last_error)-1);
+    net->client_last_errno=
+      (*options->local_infile_error)(li_ptr, net->client_last_error,
+                                     sizeof(net->client_last_error)-1);
     goto err;
   }
 
@@ -899,9 +899,9 @@ my_bool handle_local_infile(MYSQL *mysql
 
   if (readcount < 0)
   {
-    net->last_errno= (*options->local_infile_error)(li_ptr,
-						    net->last_error,
-						    sizeof(net->last_error)-1);
+    net->client_last_errno=
+      (*options->local_infile_error)(li_ptr, net->client_last_error,
+                                     sizeof(net->client_last_error)-1);
     goto err;
   }
 
@@ -1395,7 +1395,7 @@ const char *cli_read_statistics(MYSQL *m
   if (!mysql->net.read_pos[0])
   {
     set_mysql_error(mysql, CR_WRONG_HOST_INFO, unknown_sqlstate);
-    return mysql->net.last_error;
+    return mysql->net.client_last_error;
   }
   return (char*) mysql->net.read_pos;
 }
@@ -1406,7 +1406,7 @@ mysql_stat(MYSQL *mysql)
 {
   DBUG_ENTER("mysql_stat");
   if (simple_command(mysql,COM_STATISTICS,0,0,0))
-    DBUG_RETURN(mysql->net.last_error);
+    DBUG_RETURN(mysql->net.client_last_error);
   DBUG_RETURN((*mysql->methods->read_statistics)(mysql));
 }
 
@@ -1829,7 +1829,7 @@ static my_bool reset_stmt_handle(MYSQL_S
   RETURN VALUES
     0   Success.
     1   Error, i.e. out of memory or requested packet size is bigger
-        than max_allowed_packet. The error code is stored in net->last_errno.
+        than max_allowed_packet. The error code is stored in net->client_last_errno.
 */
 
 static my_bool my_realloc_str(NET *net, ulong length)
@@ -1843,7 +1843,7 @@ static my_bool my_realloc_str(NET *net, 
     if (res)
     {
       strmov(net->sqlstate, unknown_sqlstate);
-      strmov(net->last_error, ER(net->last_errno));
+      strmov(net->client_last_error, ER(net->client_last_errno));
     }
     net->write_pos= net->buff+ buf_length;
   }
@@ -1894,13 +1894,13 @@ void set_stmt_error(MYSQL_STMT * stmt, i
 void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net)
 {
   DBUG_ENTER("set_stmt_errmsg");
-  DBUG_PRINT("enter", ("error: %d/%s '%s'", net->last_errno, net->sqlstate,
-                       net->last_error));
+  DBUG_PRINT("enter", ("error: %d/%s '%s'", net->client_last_errno, net->sqlstate,
+                       net->client_last_error));
   DBUG_ASSERT(stmt != 0);
 
-  stmt->last_errno= net->last_errno;
-  if (net->last_error && net->last_error[0])
-    strmov(stmt->last_error, net->last_error);
+  stmt->last_errno= net->client_last_errno;
+  if (net->client_last_error && net->client_last_error[0])
+    strmov(stmt->last_error, net->client_last_error);
   strmov(stmt->sqlstate, net->sqlstate);
 
   DBUG_VOID_RETURN;
diff -Nrup a/libmysql/manager.c b/libmysql/manager.c
--- a/libmysql/manager.c	2007-08-13 17:11:09 +04:00
+++ b/libmysql/manager.c	2007-11-03 15:25:55 +03:00
@@ -160,7 +160,7 @@ MYSQL_MANAGER*  STDCALL mysql_manager_co
   msg_len=strlen(msg_buf);
   if (my_net_write(&con->net,(uchar*) msg_buf,msg_len) || net_flush(&con->net))
   {
-    con->last_errno=con->net.last_errno;
+    con->last_errno=con->net.client_last_errno;
     strmov(con->last_error,"Write error on socket");
     goto err;
   }
diff -Nrup a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
--- a/libmysqld/lib_sql.cc	2007-10-31 17:16:51 +03:00
+++ b/libmysqld/lib_sql.cc	2007-11-03 15:25:55 +03:00
@@ -61,8 +61,8 @@ void embedded_get_error(MYSQL *mysql, MY
 {
   NET *net= &mysql->net;
   struct embedded_query_result *ei= data->embedded_info;
-  net->last_errno= ei->last_errno;
-  strmake(net->last_error, ei->info, sizeof(net->last_error));
+  net->client_last_errno= ei->last_errno;
+  strmake(net->client_last_error, ei->info, sizeof(net->client_last_error)-1);
   memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate));
   my_free(data, MYF(0));
 }
@@ -109,12 +109,11 @@ emb_advanced_command(MYSQL *mysql, enum 
     arg_length= header_length;
   }
 
-  thd->net.no_send_error= 0;
   result= dispatch_command(command, thd, (char *) arg, arg_length);
   thd->cur_data= 0;
 
   if (!skip_check)
-    result= thd->net.last_errno ? -1 : 0;
+    result= thd->is_error() ? -1 : 0;
 
   return result;
 }
@@ -369,7 +368,7 @@ static void emb_free_embedded_thd(MYSQL 
 static const char * emb_read_statistics(MYSQL *mysql)
 {
   THD *thd= (THD*)mysql->thd;
-  return thd->net.last_error;
+  return thd->is_error() ? thd->main_da.message() : "";
 }
 
 
@@ -673,8 +672,7 @@ int check_embedded_connection(MYSQL *mys
 err:
   {
     NET *net= &mysql->net;
-    memcpy(net->last_error, thd->net.last_error, sizeof(net->last_error));
-    memcpy(net->sqlstate, thd->net.sqlstate, sizeof(net->sqlstate));
+    strmake(net->client_last_error, thd->main_da.message(), sizeof(net->client_last_error)-1);
   }
   return result;
 }
@@ -697,9 +695,8 @@ void THD::clear_data_list()
 
 void THD::clear_error()
 {
-  net.last_error[0]= 0;
-  net.last_errno= 0;
-  net.report_error= 0;
+  if (main_da.is_error())
+    main_da.reset_diagnostics_area();
 }
 
 static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
@@ -775,7 +772,8 @@ MYSQL_DATA *THD::alloc_new_dataset()
 
 */
 
-static void write_eof_packet(THD *thd)
+static void write_eof_packet(THD *thd, uint server_status,
+                             uint total_warn_count)
 {
   if (!thd->mysql)            // bootstrap file handling
     return;
@@ -786,13 +784,13 @@ static void write_eof_packet(THD *thd)
   */
   if (thd->is_fatal_error)
     thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
-  thd->cur_data->embedded_info->server_status= thd->server_status;
+  thd->cur_data->embedded_info->server_status= server_status;
   /*
     Don't send warn count during SP execution, as the warn_list
     is cleared between substatements, and mysqltest gets confused
   */
   thd->cur_data->embedded_info->warning_count=
-    (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
+    (thd->spcont ? 0 : min(total_warn_count, 65535));
 }
 
 
@@ -948,7 +946,7 @@ bool Protocol::send_fields(List<Item> *l
   }
 
   if (flags & SEND_EOF)
-    write_eof_packet(thd);
+    write_eof_packet(thd, thd->server_status, thd->total_warn_count);
 
   DBUG_RETURN(prepare_for_send(list));
  err:
@@ -989,16 +987,16 @@ bool Protocol_binary::write()
 }
 
 void
-send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message)
+net_send_ok(THD *thd,
+            uint server_status, uint total_warn_count,
+            ha_rows affected_rows, ulonglong id, const char *message)
 {
   DBUG_ENTER("send_ok");
   MYSQL_DATA *data;
   MYSQL *mysql= thd->mysql;
-  
+
   if (!mysql)            // bootstrap file handling
     DBUG_VOID_RETURN;
-  if (thd->net.no_send_ok)	// hack for re-parsing queries
-    DBUG_VOID_RETURN;
   if (!(data= thd->alloc_new_dataset()))
     return;
   data->embedded_info->affected_rows= affected_rows;
@@ -1007,15 +1005,15 @@ send_ok(THD *thd,ha_rows affected_rows,u
     strmake(data->embedded_info->info, message,
             sizeof(data->embedded_info->info)-1);
 
-  write_eof_packet(thd);
+  write_eof_packet(thd, server_status, total_warn_count);
   thd->cur_data= 0;
   DBUG_VOID_RETURN;
 }
 
 void
-send_eof(THD *thd)
+net_send_eof(THD *thd, uint server_status, uint total_warn_count)
 {
-  write_eof_packet(thd);
+  write_eof_packet(thd, server_status, total_warn_count);
   thd->cur_data= 0;
 }
 
diff -Nrup a/libmysqld/libmysqld.c b/libmysqld/libmysqld.c
--- a/libmysqld/libmysqld.c	2007-03-28 22:05:00 +04:00
+++ b/libmysqld/libmysqld.c	2007-11-03 15:25:55 +03:00
@@ -209,8 +209,8 @@ mysql_real_connect(MYSQL *mysql,const ch
   DBUG_RETURN(mysql);
 
 error:
-  DBUG_PRINT("error",("message: %u (%s)", mysql->net.last_errno,
-		      mysql->net.last_error));
+  DBUG_PRINT("error",("message: %u (%s)", mysql->net.client_last_errno,
+		      mysql->net.client_last_error));
   {
     /* Free alloced memory */
     my_bool free_me=mysql->free_me;
diff -Nrup a/mysql-test/r/events.result b/mysql-test/r/events.result
--- a/mysql-test/r/events.result	2007-08-31 18:49:39 +04:00
+++ b/mysql-test/r/events.result	2007-11-03 15:25:55 +03:00
@@ -403,9 +403,10 @@ ERROR 42S02: Table 'mysql.event' doesn't
 DROP DATABASE IF EXISTS mysqltest_no_such_database;
 Warnings:
 Note	1008	Can't drop database 'mysqltest_no_such_database'; database doesn't exist
-Error	1146	Table 'mysql.event' doesn't exist
 CREATE DATABASE mysqltest_db2;
 DROP DATABASE mysqltest_db2;
+Warnings:
+Error	1146	Table 'mysql.event' doesn't exist
 OK, there is an unnecessary warning about the non-existent table 
 but it's not easy to fix and no one complained about it.
 A similar warning is printed if mysql.proc is missing.
diff -Nrup a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc
--- a/server-tools/instance-manager/mysql_connection.cc	2007-06-05 19:31:39 +04:00
+++ b/server-tools/instance-manager/mysql_connection.cc	2007-11-03 15:25:55 +03:00
@@ -257,7 +257,7 @@ int Mysql_connection::do_command()
       return 1;
     if (thread_registry->is_shutdown())
       return 1;
-    net_send_error(&net, net.last_errno);
+    net_send_error(&net, net.client_last_errno);
     net.error= 0;
     return 0;
   }
diff -Nrup a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
--- a/sql/ha_ndbcluster_binlog.cc	2007-10-30 20:08:11 +03:00
+++ b/sql/ha_ndbcluster_binlog.cc	2007-11-03 15:25:55 +03:00
@@ -257,6 +257,10 @@ static void run_query(THD *thd, char *bu
     thd->options&= ~OPTION_BIN_LOG;
     
   DBUG_PRINT("query", ("%s", thd->query));
+
+  DBUG_ASSERT(!thd->in_sub_stmt);
+  DBUG_ASSERT(!thd->prelocked_mode);
+
   mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
 
   if (no_print_error && thd->is_slave_error)
@@ -265,14 +269,24 @@ static void run_query(THD *thd, char *bu
     Thd_ndb *thd_ndb= get_thd_ndb(thd);
     for (i= 0; no_print_error[i]; i++)
       if ((thd_ndb->m_error_code == no_print_error[i]) ||
-          (thd->net.last_errno == (unsigned)no_print_error[i]))
+          (thd->main_da.sql_errno() == (unsigned)no_print_error[i]))
         break;
     if (!no_print_error[i])
       sql_print_error("NDB: %s: error %s %d(ndb: %d) %d %d",
-                      buf, thd->net.last_error, thd->net.last_errno,
+                      buf, thd->main_da.message(), thd->main_da.sql_errno(),
                       thd_ndb->m_error_code,
-                      (int) thd->is_error(), thd->is_slave_error);
+                      thd->is_error(), thd->is_slave_error);
   }
+  /*
+    XXX: this code is broken. mysql_parse()/mysql_reset_thd_for_next_command()
+    can not be called from within a statement, and 
+    run_query() is used for all kinds of administrative operations.
+    This particular reset is a temprorary hack to avoid an assert
+    for double assignment of the diagnostics area when run_query()
+    is called from ndbcluster_reset_logs(), which is called from 
+    mysql_flush(). 
+  */
+  thd->main_da.reset_diagnostics_area();
 
   thd->options= save_thd_options;
   thd->query_length= save_query_length;
@@ -2301,8 +2315,8 @@ static int open_ndb_binlog_index(THD *th
   if (open_tables(thd, &tables, &counter, MYSQL_LOCK_IGNORE_FLUSH))
   {
     sql_print_error("NDB Binlog: Opening ndb_binlog_index: %d, '%s'",
-                    thd->net.last_errno,
-                    thd->net.last_error ? thd->net.last_error : "");
+                    thd->main_da.sql_errno(),
+                    thd->main_da.message());
     thd->proc_info= save_proc_info;
     return -1;
   }
diff -Nrup a/sql/ha_partition.cc b/sql/ha_partition.cc
--- a/sql/ha_partition.cc	2007-10-23 18:02:24 +04:00
+++ b/sql/ha_partition.cc	2007-11-03 15:25:55 +03:00
@@ -1752,6 +1752,7 @@ partition_element *ha_partition::find_pa
       return part_elem;
   }
   DBUG_ASSERT(0);
+  my_error(ER_OUT_OF_RESOURCES, MYF(0));
   current_thd->fatal_error();                   // Abort
   return NULL;
 }
diff -Nrup a/sql/item_func.cc b/sql/item_func.cc
--- a/sql/item_func.cc	2007-11-01 15:41:45 +03:00
+++ b/sql/item_func.cc	2007-11-03 15:25:56 +03:00
@@ -2948,7 +2948,6 @@ udf_handler::fix_fields(THD *thd, Item_r
         }
       }
     }
-    thd->net.last_error[0]=0;
     Udf_func_init init= u_d->func_init;
     if ((error=(uchar) init(&initid, &f_args, init_msg_buff)))
     {
diff -Nrup a/sql/log_event.cc b/sql/log_event.cc
--- a/sql/log_event.cc	2007-10-20 01:20:34 +04:00
+++ b/sql/log_event.cc	2007-11-03 15:25:56 +03:00
@@ -1510,7 +1510,8 @@ Query_log_event::Query_log_event(THD* th
   if (killed_status_arg == THD::KILLED_NO_VALUE)
     killed_status_arg= thd_arg->killed;
   error_code=
-    (killed_status_arg == THD::NOT_KILLED) ? thd_arg->net.last_errno :
+    (killed_status_arg == THD::NOT_KILLED) ?
+    (thd_arg->is_error() ? thd_arg->main_da.sql_errno() : 0) :
     ((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ? 0 :
      thd_arg->killed_errno());
   
@@ -2112,7 +2113,7 @@ START SLAVE; . Query: '%s'", expected_er
     }
 
     /* If the query was not ignored, it is printed to the general log */
-    if (thd->net.last_errno != ER_SLAVE_IGNORED_TABLE)
+    if (!thd->is_error() || thd->main_da.sql_errno() != ER_SLAVE_IGNORED_TABLE)
       general_log_write(thd, COM_QUERY, thd->query, thd->query_length);
 
 compare_errors:
@@ -2121,9 +2122,10 @@ compare_errors:
       If we expected a non-zero error code, and we don't get the same error
       code, and none of them should be ignored.
     */
-    DBUG_PRINT("info",("expected_error: %d  last_errno: %d",
- 		       expected_error, thd->net.last_errno));
-    if ((expected_error != (actual_error= thd->net.last_errno)) &&
+    actual_error= thd->is_error() ?  thd->main_da.sql_errno() : 0;
+    DBUG_PRINT("info",("expected_error: %d  sql_errno: %d",
+ 		       expected_error, actual_error));
+    if ((expected_error != actual_error) &&
  	expected_error &&
  	!ignored_error_code(actual_error) &&
  	!ignored_error_code(expected_error))
@@ -2135,7 +2137,7 @@ Error on master: '%s' (%d), Error on sla
 Default database: '%s'. Query: '%s'",
                       ER_SAFE(expected_error),
                       expected_error,
-                      actual_error ? thd->net.last_error: "no error",
+                      actual_error ? thd->main_da.message() : "no error",
                       actual_error,
                       print_slave_db_safe(db), query_arg);
       thd->is_slave_error= 1;
@@ -2157,7 +2159,7 @@ Default database: '%s'. Query: '%s'",
     {
       rli->report(ERROR_LEVEL, actual_error,
                       "Error '%s' on query. Default database: '%s'. Query: '%s'",
-                      (actual_error ? thd->net.last_error :
+                      (actual_error ? thd->main_da.message():
                        "unexpected success or fatal error"),
                       print_slave_db_safe(thd->db), query_arg);
       thd->is_slave_error= 1;
@@ -3475,8 +3477,11 @@ error:
     /* this err/sql_errno code is copy-paste from net_send_error() */
     const char *err;
     int sql_errno;
-    if ((err=thd->net.last_error)[0])
-      sql_errno=thd->net.last_errno;
+    if (thd->is_error())
+    {
+      err= thd->main_da.message();
+      sql_errno= thd->main_da.sql_errno();
+    }
     else
     {
       sql_errno=ER_UNKNOWN_ERROR;
@@ -5957,10 +5962,10 @@ int Rows_log_event::do_apply_event(Relay
             Error reporting borrowed from Query_log_event with many excessive
             simplifications (we don't honour --slave-skip-errors)
           */
-          uint actual_error= thd->net.last_errno;
+          uint actual_error= thd->main_da.sql_errno();
           rli->report(ERROR_LEVEL, actual_error,
                       "Error '%s' in %s event: when locking tables",
-                      (actual_error ? thd->net.last_error :
+                      (actual_error ? thd->main_da.message():
                        "unexpected success or fatal error"),
                       get_type_str());
           thd->is_fatal_error= 1;
@@ -6001,10 +6006,10 @@ int Rows_log_event::do_apply_event(Relay
             Error reporting borrowed from Query_log_event with many excessive
             simplifications (we don't honour --slave-skip-errors)
           */
-          uint actual_error= thd->net.last_errno;
+          uint actual_error= thd->main_da.sql_errno();
           rli->report(ERROR_LEVEL, actual_error,
                       "Error '%s' on reopening tables",
-                      (actual_error ? thd->net.last_error :
+                      (actual_error ? thd->main_da.message() :
                        "unexpected success or fatal error"));
           thd->is_slave_error= 1;
         }
@@ -6155,10 +6160,11 @@ int Rows_log_event::do_apply_event(Relay
 	break;
 
       default:
-	rli->report(ERROR_LEVEL, thd->net.last_errno,
+	rli->report(ERROR_LEVEL,
+                    thd->is_error() ? thd->main_da.sql_errno() : 0,
                     "Error in %s event: row application failed. %s",
                     get_type_str(),
-                    thd->net.last_error ? thd->net.last_error : "");
+                    thd->is_error() ? thd->main_da.message() : "");
 	thd->is_slave_error= 1;
 	break;
       }
@@ -6201,12 +6207,13 @@ int Rows_log_event::do_apply_event(Relay
 
   if (error)
   {                     /* error has occured during the transaction */
-    rli->report(ERROR_LEVEL, thd->net.last_errno,
+    rli->report(ERROR_LEVEL,
+                thd->is_error() ? thd->main_da.sql_errno() : 0,
                 "Error in %s event: error during transaction execution "
                 "on table %s.%s. %s",
                 get_type_str(), table->s->db.str,
                 table->s->table_name.str,
-                thd->net.last_error ? thd->net.last_error : "");
+                thd->is_error() ? thd->main_da.message() : "");
 
     /*
       If one day we honour --skip-slave-errors in row-based replication, and
@@ -6810,10 +6817,10 @@ int Table_map_log_event::do_apply_event(
           Error reporting borrowed from Query_log_event with many excessive
           simplifications (we don't honour --slave-skip-errors)
         */
-        uint actual_error= thd->net.last_errno;
+        uint actual_error= thd->main_da.sql_errno();
         rli->report(ERROR_LEVEL, actual_error,
                     "Error '%s' on opening table `%s`.`%s`",
-                    (actual_error ? thd->net.last_error :
+                    (actual_error ? thd->main_da.message() :
                      "unexpected success or fatal error"),
                     table_list->db, table_list->table_name);
         thd->is_slave_error= 1;
@@ -7344,8 +7351,11 @@ Write_rows_log_event::do_exec_row(const 
   DBUG_ASSERT(m_table != NULL);
   int error= write_row(rli, TRUE /* overwrite */);
   
-  if (error && !thd->net.last_errno)
-    thd->net.last_errno= error;
+  if (error && !thd->is_error())
+  {
+    DBUG_ASSERT(0);
+    my_error(ER_UNKNOWN_ERROR, MYF(0));
+  }
       
   return error; 
 }
diff -Nrup a/sql/log_event_old.cc b/sql/log_event_old.cc
--- a/sql/log_event_old.cc	2007-10-20 01:20:35 +04:00
+++ b/sql/log_event_old.cc	2007-11-03 15:25:56 +03:00
@@ -74,10 +74,10 @@ Old_rows_log_event::do_apply_event(Rows_
             Error reporting borrowed from Query_log_event with many excessive
             simplifications (we don't honour --slave-skip-errors)
           */
-          uint actual_error= thd->net.last_errno;
+          uint actual_error= thd->main_da.sql_errno();
           rli->report(ERROR_LEVEL, actual_error,
                       "Error '%s' in %s event: when locking tables",
-                      (actual_error ? thd->net.last_error :
+                      (actual_error ? thd->main_da.message() :
                        "unexpected success or fatal error"),
                       ev->get_type_str());
           thd->is_fatal_error= 1;
@@ -118,10 +118,10 @@ Old_rows_log_event::do_apply_event(Rows_
             Error reporting borrowed from Query_log_event with many excessive
             simplifications (we don't honour --slave-skip-errors)
           */
-          uint actual_error= thd->net.last_errno;
+          uint actual_error= thd->main_da.sql_errno();
           rli->report(ERROR_LEVEL, actual_error,
                       "Error '%s' on reopening tables",
-                      (actual_error ? thd->net.last_error :
+                      (actual_error ? thd->main_da.message() :
                        "unexpected success or fatal error"));
           thd->is_slave_error= 1;
         }
@@ -251,10 +251,10 @@ Old_rows_log_event::do_apply_event(Rows_
   break;
 
       default:
-  rli->report(ERROR_LEVEL, thd->net.last_errno,
+  rli->report(ERROR_LEVEL, thd->main_da.sql_errno(),
                     "Error in %s event: row application failed. %s",
                     ev->get_type_str(),
-                    thd->net.last_error ? thd->net.last_error : "");
+                    thd->is_error() ? thd->main_da.message() : "");
   thd->is_slave_error= 1;
   break;
       }
@@ -280,12 +280,12 @@ Old_rows_log_event::do_apply_event(Rows_
 
   if (error)
   {                     /* error has occured during the transaction */
-    rli->report(ERROR_LEVEL, thd->net.last_errno,
+    rli->report(ERROR_LEVEL, thd->main_da.sql_errno(),
                 "Error in %s event: error during transaction execution "
                 "on table %s.%s. %s",
                 ev->get_type_str(), table->s->db.str,
                 table->s->table_name.str,
-                thd->net.last_error ? thd->net.last_error : "");
+                thd->is_error() ? thd->main_da.message() : "");
 
     /*
       If one day we honour --skip-slave-errors in row-based replication, and
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc	2007-11-01 00:10:56 +03:00
+++ b/sql/mysqld.cc	2007-11-03 15:25:56 +03:00
@@ -2587,20 +2587,6 @@ int my_message_sql(uint error, const cha
                           MYSQL_ERROR::WARN_LEVEL_ERROR))
       DBUG_RETURN(0);
 
-    if (thd->spcont &&
-        thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
-    {
-      DBUG_RETURN(0);
-    }
-
-    thd->is_slave_error=  1; // needed to catch query errors during replication
-
-    if (!thd->no_warnings_for_error)
-      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
-    /*
-      thd->lex->current_select == 0 if lex structure is not inited
-      (not query command (COM_QUERY))
-    */
     if (thd->lex->current_select &&
 	thd->lex->current_select->no_error && !thd->is_fatal_error)
     {
@@ -2613,15 +2599,36 @@ int my_message_sql(uint error, const cha
     }
     else
     {
-      NET *net= &thd->net;
-      net->report_error= 1;
-      query_cache_abort(net);
-      if (!net->last_error[0])			// Return only first message
+      if (! thd->main_da.is_error())            // Return only first message
       {
-	strmake(net->last_error, str, sizeof(net->last_error)-1);
-	net->last_errno= error ? error : ER_UNKNOWN_ERROR;
+        if (error == 0)
+          error= ER_UNKNOWN_ERROR;
+        if (str == NULL)
+          str= ER(error);
+        thd->main_da.set_error_status(thd, error, str);
       }
+      query_cache_abort(&thd->net);
     }
+    /*
+      If a continue handler is found, the error message will be cleared
+      by the stored procedures code.
+    */
+    if (thd->spcont &&
+        thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
+    {
+      /*
+        Do not push any warnings, a handled error must be completely
+        silenced.
+      */
+      DBUG_RETURN(0);
+    }
+
+    if (!thd->no_warnings_for_error)
+      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
+    /*
+      thd->lex->current_select == 0 if lex structure is not inited
+      (not query command (COM_QUERY))
+    */
   }
   if (!thd || MyFlags & ME_NOREFRESH)
     sql_print_error("%s: %s",my_progname,str); /* purecov: inspected */
diff -Nrup a/sql/net_serv.cc b/sql/net_serv.cc
--- a/sql/net_serv.cc	2007-10-15 15:49:05 +04:00
+++ b/sql/net_serv.cc	2007-11-03 15:25:56 +03:00
@@ -123,20 +123,18 @@ my_bool my_net_init(NET *net, Vio* vio)
 				     MYF(MY_WME))))
     DBUG_RETURN(1);
   net->buff_end=net->buff+net->max_packet;
-  net->no_send_ok= net->no_send_error= 0;
   net->error=0; net->return_errno=0; net->return_status=0;
   net->pkt_nr=net->compress_pkt_nr=0;
   net->write_pos=net->read_pos = net->buff;
-  net->last_error[0]=0;
+  net->client_last_error[0]=0;
   net->compress=0; net->reading_or_writing=0;
   net->where_b = net->remain_in_buf=0;
-  net->last_errno=0;
+  net->client_last_errno=0;
 #ifdef USE_QUERY_CACHE
   query_cache_init_query(net);
 #else
   net->query_cache_query= 0;
 #endif
-  net->report_error= 0;
 
   if (vio != 0)					/* If real connection */
   {
@@ -176,9 +174,12 @@ my_bool net_realloc(NET *net, size_t len
   {
     DBUG_PRINT("error", ("Packet too large. Max size: %lu",
                          net->max_packet_size));
+    /* @todo: 1 and 2 codes are identical. */
     net->error= 1;
-    net->report_error= 1;
-    net->last_errno= ER_NET_PACKET_TOO_LARGE;
+    net->client_last_errno= ER_NET_PACKET_TOO_LARGE;
+#ifdef MYSQL_SERVER
+    my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
+#endif
     DBUG_RETURN(1);
   }
   pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); 
@@ -190,9 +191,10 @@ my_bool net_realloc(NET *net, size_t len
                                   NET_HEADER_SIZE + COMP_HEADER_SIZE,
                                   MYF(MY_WME))))
   {
+    /* @todo: 1 and 2 codes are identical. */
     net->error= 1;
-    net->report_error= 1;
-    net->last_errno= ER_OUT_OF_RESOURCES;
+    net->client_last_errno= ER_OUT_OF_RESOURCES;
+    /* In the server the error is reported by MY_WME flag. */
     DBUG_RETURN(1);
   }
   net->buff=net->write_pos=buff;
@@ -582,12 +584,9 @@ net_real_write(NET *net,const uchar *pac
     if (!(b= (uchar*) my_malloc(len + NET_HEADER_SIZE +
                                 COMP_HEADER_SIZE, MYF(MY_WME))))
     {
-#ifdef MYSQL_SERVER
-      net->last_errno= ER_OUT_OF_RESOURCES;
       net->error= 2;
-      /* TODO is it needed to set this variable if we have no socket */
-      net->report_error= 1;
-#endif
+      net->client_last_errno= ER_OUT_OF_RESOURCES;
+      /* In the server, the error is reported by MY_WME flag. */
       net->reading_or_writing= 0;
       DBUG_RETURN(1);
     }
@@ -638,11 +637,11 @@ net_real_write(NET *net,const uchar *pac
 		    "%s: my_net_write: fcntl returned error %d, aborting thread\n",
 		    my_progname,vio_errno(net->vio));
 #endif /* EXTRA_DEBUG */
-#ifdef MYSQL_SERVER	    
-	    net->last_errno= ER_NET_ERROR_ON_WRITE;
-#endif
 	    net->error= 2;                     /* Close socket */
-            net->report_error= 1;
+            net->client_last_errno= ER_NET_PACKET_TOO_LARGE;
+#ifdef MYSQL_SERVER
+            my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
+#endif
 	    goto end;
 	  }
 	  retry_count=0;
@@ -669,10 +668,10 @@ net_real_write(NET *net,const uchar *pac
       }
 #endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
       net->error= 2;				/* Close socket */
-      net->report_error= 1;
+      net->client_last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+                               ER_NET_ERROR_ON_WRITE);
 #ifdef MYSQL_SERVER
-      net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
-			ER_NET_ERROR_ON_WRITE);
+      my_error(net->client_last_errno, MYF(0));
 #endif /* MYSQL_SERVER */
       break;
     }
@@ -849,9 +848,9 @@ my_real_read(NET *net, size_t *complen)
 #endif /* EXTRA_DEBUG */
 		len= packet_error;
 		net->error= 2;                 /* Close socket */
-	        net->report_error= 1;
+	        net->client_last_errno= ER_NET_FCNTL_ERROR;
 #ifdef MYSQL_SERVER
-		net->last_errno= ER_NET_FCNTL_ERROR;
+		my_error(ER_NET_FCNTL_ERROR, MYF(0));
 #endif
 		goto end;
 	      }
@@ -881,10 +880,11 @@ my_real_read(NET *net, size_t *complen)
 			      remain, vio_errno(net->vio), (long) length));
 	  len= packet_error;
 	  net->error= 2;				/* Close socket */
-	  net->report_error= 1;
+          net->client_last_errno= (vio_was_interrupted(net->vio) ?
+                                   ER_NET_READ_INTERRUPTED :
+                                   ER_NET_READ_ERROR);
 #ifdef MYSQL_SERVER
-	  net->last_errno= (vio_was_interrupted(net->vio) ? ER_NET_READ_INTERRUPTED :
-			    ER_NET_READ_ERROR);
+          my_error(net->client_last_errno, MYF(0));
 #endif
 	  goto end;
 	}
@@ -915,9 +915,9 @@ my_real_read(NET *net, size_t *complen)
 #endif
 	  }
 	  len= packet_error;
-	  net->report_error= 1;
+          /* Not a NET error on the client. XXX: why? */
 #ifdef MYSQL_SERVER
-	  net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
+	  my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
 #endif
 	  goto end;
 	}
@@ -1101,9 +1101,9 @@ my_net_read(NET *net)
 			&complen))
       {
 	net->error= 2;			/* caller will close socket */
-	net->report_error= 1;
+        net->client_last_errno= ER_NET_UNCOMPRESS_ERROR;
 #ifdef MYSQL_SERVER
-	net->last_errno=ER_NET_UNCOMPRESS_ERROR;
+	my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0));
 #endif
 	return packet_error;
       }
diff -Nrup a/sql/opt_range.cc b/sql/opt_range.cc
--- a/sql/opt_range.cc	2007-10-23 15:32:35 +04:00
+++ b/sql/opt_range.cc	2007-11-03 15:25:56 +03:00
@@ -1271,7 +1271,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_
       the storage engine calls in question happen to never fail with the 
       existing storage engines. 
     */
-    thd->net.report_error= 1; /* purecov: inspected */
+    my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */
     /* Caller will free the memory */
     goto failure;  /* purecov: inspected */
   }
diff -Nrup a/sql/opt_sum.cc b/sql/opt_sum.cc
--- a/sql/opt_sum.cc	2007-08-13 17:11:12 +04:00
+++ b/sql/opt_sum.cc	2007-11-03 15:25:56 +03:00
@@ -170,6 +170,7 @@ int opt_sum_query(TABLE_LIST *tables, Li
       if(error)
       {
         tl->table->file->print_error(error, MYF(0));
+        tl->table->in_use->fatal_error();
         return error;
       }
       count*= tl->table->file->stats.records;
@@ -417,6 +418,7 @@ int opt_sum_query(TABLE_LIST *tables, Li
 	      return HA_ERR_KEY_NOT_FOUND;	     // No rows matching WHERE
 	    /* HA_ERR_LOCK_DEADLOCK or some other error */
  	    table->file->print_error(error, MYF(0));
+            table->in_use->fatal_error();
             return(error);
 	  }
           removed_tables|= table->map;
diff -Nrup a/sql/protocol.cc b/sql/protocol.cc
--- a/sql/protocol.cc	2007-11-01 00:10:56 +03:00
+++ b/sql/protocol.cc	2007-11-03 15:25:56 +03:00
@@ -23,13 +23,20 @@
 #endif
 
 #include "mysql_priv.h"
-#include "sp_rcontext.h"
 #include <stdarg.h>
 
 static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
+/* Declared non-static only because of the embedded library. */
 void net_send_error_packet(THD *thd, uint sql_errno, const char *err);
+void
+net_send_ok(THD *thd,
+            uint server_status, uint total_warn_count,
+            ha_rows affected_rows, ulonglong id, const char *message);
+void
+net_send_eof(THD *thd, uint server_status, uint total_warn_count);
 #ifndef EMBEDDED_LIBRARY
-static void write_eof_packet(THD *thd, NET *net);
+static void write_eof_packet(THD *thd, NET *net,
+                             uint server_status, uint total_warn_count);
 #endif
 
 #ifndef EMBEDDED_LIBRARY
@@ -68,53 +75,23 @@ bool Protocol_binary::net_store_data(con
 void net_send_error(THD *thd, uint sql_errno, const char *err)
 {
   NET *net= &thd->net;
-  bool generate_warning= thd->killed != THD::KILL_CONNECTION;
   DBUG_ENTER("net_send_error");
-  DBUG_PRINT("enter",("sql_errno: %d  err: %s", sql_errno,
-		      err ? err : net->last_error[0] ?
-		      net->last_error : "NULL"));
 
   DBUG_ASSERT(!thd->spcont);
+  DBUG_ASSERT(sql_errno);
+  DBUG_ASSERT(err && err[0]);
 
-  if (net && net->no_send_error)
-  {
-    thd->clear_error();
-    thd->is_fatal_error= 0;			// Error message is given
-    DBUG_PRINT("info", ("sending error messages prohibited"));
-    DBUG_VOID_RETURN;
-  }
+  DBUG_PRINT("enter",("sql_errno: %d  err: %s", sql_errno, err));
 
-  thd->is_slave_error=  1; // needed to catch query errors during replication
-  if (!err)
-  {
-    if (sql_errno)
-      err=ER(sql_errno);
-    else
-    {
-      if ((err=net->last_error)[0])
-      {
-	sql_errno=net->last_errno;
-        generate_warning= 0;            // This warning has already been given
-      }
-      else
-      {
-	sql_errno=ER_UNKNOWN_ERROR;
-	err=ER(sql_errno);	 /* purecov: inspected */
-      }
-    }
-  }
-
-  if (generate_warning)
-  {
-    /* Error that we have not got with my_error() */
-    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, sql_errno, err);
-  }
+  /*
+    It's one case when we can push an error even though there is
+    an OK or EOF already
+  */
+  thd->main_da.can_overwrite_status= TRUE;
 
   net_send_error_packet(thd, sql_errno, err);
 
-  thd->is_fatal_error= 0;			// Error message is given
-  thd->net.report_error= 0;
-
+  thd->main_da.can_overwrite_status= FALSE;
   /* Abort multi-result sets */
   thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
   DBUG_VOID_RETURN;
@@ -143,23 +120,21 @@ void net_send_error(THD *thd, uint sql_e
     warning_count	Stored in 2 bytes; New in 4.1 protocol
     message		Stored as packed length (1-9 bytes) + message
 			Is not stored if no message
-
-   If net->no_send_ok return without sending packet
 */    
 
 #ifndef EMBEDDED_LIBRARY
 void
-send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
+net_send_ok(THD *thd,
+            uint server_status, uint total_warn_count,
+            ha_rows affected_rows, ulonglong id, const char *message)
 {
   NET *net= &thd->net;
   uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
   DBUG_ENTER("send_ok");
 
-  if (net->no_send_ok || !net->vio)	// hack for re-parsing queries
+  if (! net->vio)	// hack for re-parsing queries
   {
-    DBUG_PRINT("info", ("no send ok: %s, vio present: %s",
-                        (net->no_send_ok ? "YES" : "NO"),
-                        (net->vio ? "YES" : "NO")));
+    DBUG_PRINT("info", ("vio present: NO"));
     DBUG_VOID_RETURN;
   }
 
@@ -172,28 +147,29 @@ send_ok(THD *thd, ha_rows affected_rows,
 	       ("affected_rows: %lu  id: %lu  status: %u  warning_count: %u",
 		(ulong) affected_rows,		
 		(ulong) id,
-		(uint) (thd->server_status & 0xffff),
-		(uint) thd->total_warn_count));
-    int2store(pos,thd->server_status);
+		(uint) (server_status & 0xffff),
+		(uint) total_warn_count));
+    int2store(pos, server_status);
     pos+=2;
 
     /* We can only return up to 65535 warnings in two bytes */
-    uint tmp= min(thd->total_warn_count, 65535);
+    uint tmp= min(total_warn_count, 65535);
     int2store(pos, tmp);
     pos+= 2;
   }
   else if (net->return_status)			// For 4.0 protocol
   {
-    int2store(pos,thd->server_status);
+    int2store(pos, server_status);
     pos+=2;
   }
-  if (message)
+  thd->main_da.can_overwrite_status= TRUE;
+
+  if (message && message[0])
     pos= net_store_data(pos, (uchar*) message, strlen(message));
   VOID(my_net_write(net, buff, (size_t) (pos-buff)));
   VOID(net_flush(net));
-  /* We can't anymore send an error to the client */
-  thd->net.report_error= 0;
-  thd->net.no_send_error= 1;
+
+  thd->main_da.can_overwrite_status= FALSE;
   DBUG_PRINT("info", ("OK sent, so no more error sending allowed"));
 
   DBUG_VOID_RETURN;
@@ -205,7 +181,7 @@ static uchar eof_buff[1]= { (uchar) 254 
   Send eof (= end of result set) to the client
 
   SYNOPSIS
-    send_eof()
+    net_send_eof()
     thd			Thread handler
     no_flush		Set to 1 if there will be more data to the client,
 			like in send_fields().
@@ -224,15 +200,17 @@ static uchar eof_buff[1]= { (uchar) 254 
 */    
 
 void
-send_eof(THD *thd)
+net_send_eof(THD *thd, uint server_status, uint total_warn_count)
 {
   NET *net= &thd->net;
-  DBUG_ENTER("send_eof");
+  DBUG_ENTER("net_send_eof");
+  /* Set to TRUE if no active vio, to work well in case of --init-file */
   if (net->vio != 0)
   {
-    write_eof_packet(thd, net);
+    thd->main_da.can_overwrite_status= TRUE;
+    write_eof_packet(thd, net, server_status, total_warn_count);
     VOID(net_flush(net));
-    thd->net.no_send_error= 1;
+    thd->main_da.can_overwrite_status= FALSE;
     DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
   }
   DBUG_VOID_RETURN;
@@ -244,7 +222,9 @@ send_eof(THD *thd)
   write it to the network output buffer.
 */
 
-static void write_eof_packet(THD *thd, NET *net)
+static void write_eof_packet(THD *thd, NET *net,
+                             uint server_status,
+                             uint total_warn_count)
 {
   if (thd->client_capabilities & CLIENT_PROTOCOL_41)
   {
@@ -253,7 +233,7 @@ static void write_eof_packet(THD *thd, N
       Don't send warn count during SP execution, as the warn_list
       is cleared between substatements, and mysqltest gets confused
     */
-    uint tmp= (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
+    uint tmp= min(total_warn_count, 65535);
     buff[0]= 254;
     int2store(buff+1, tmp);
     /*
@@ -262,8 +242,8 @@ static void write_eof_packet(THD *thd, N
       other queries (see the if test in dispatch_command / COM_QUERY)
     */
     if (thd->is_fatal_error)
-      thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
-    int2store(buff+3, thd->server_status);
+      server_status&= ~SERVER_MORE_RESULTS_EXISTS;
+    int2store(buff+3, server_status);
     VOID(my_net_write(net, buff, 5));
   }
   else
@@ -354,6 +334,91 @@ static uchar *net_store_length_fast(ucha
   return packet+2;
 }
 
+/**
+  Send the status of the current statement execution over network.
+
+  @param  thd   in fact, carries two parameters, NET for the transport and
+                Diagnostics_area as the source of status information.
+
+  In MySQL, there are two types of SQL statements: those that return
+  a result set and those that return status information only.
+
+  If a statement returns a result set, it consists of 3 parts:
+  - result set meta-data
+  - variable number of result set rows (can be 0)
+  - followed and terminated by EOF or ERROR packet
+
+  Once the  client has seen the meta-data information, it always
+  expects an EOF or ERROR to terminate the result set. If ERROR is
+  received, the result set rows are normally discarded (this is up
+  to the client implementation, however, libmysql does discard them).
+  EOF, on the contrary, means "successfully evaluated the entire
+  result set". Since we don't know how many rows belong to a result
+  set until it's evaluated, EOF/ERROR is the indicator of the end
+  of the row stream. Note, that we can not buffer result set rows
+  on the server -- there may be an arbitrary number of rows. But
+  we do buffer the last packet (EOF/ERROR) in the Diagnostics_area and
+  delay sending it till the very end of execution (here), to be able to
+  change EOF to an ERROR if commit failed or some other error occurred.
+
+  A statement that does not return a result set doesn't send result
+  set meta-data either. It is followed by one of:
+  - OK packet
+  - ERROR packet.
+  Similarly to the EOF/ERROR of the previous statement type, OK/ERROR
+  packet is "buffered" in the diagnostics area and sent to the client
+  in the end of statement.
+
+  @pre  The diagnostics area is assigned or disabled. It can not be empty
+        -- we assume that every SQL statement or COM_* command
+        generates OK, ERROR, or EOF status.
+
+  @post The status information is encoded to protocol format and sent to the
+        client.
+
+
+  @return We conventionally return void, since the only type of error
+          that can happen is a NET error, and that one will become visible
+          when we attempt to read from the NET the next command.
+          Diagnostics_area::is_sent is set for debugging purposes only.
+*/
+
+void net_end_statement(THD *thd)
+{
+  DBUG_ASSERT(! thd->main_da.is_sent);
+
+  /* Can never be true, but do not take chances in production */
+  if (thd->main_da.is_sent)
+    return;
+
+  switch (thd->main_da.status()) {
+  case Diagnostics_area::DA_ERROR:
+    /* The query failed, send error to log and abort bootstrap */
+    net_send_error(thd, thd->main_da.sql_errno(),
+                   thd->main_da.message());
+    break;
+  case Diagnostics_area::DA_EOF:
+    net_send_eof(thd, thd->main_da.server_status(),
+                 thd->main_da.total_warn_count());
+    break;
+  case Diagnostics_area::DA_OK:
+    net_send_ok(thd, thd->main_da.server_status(),
+                thd->main_da.total_warn_count(),
+                thd->main_da.affected_rows(), thd->main_da.last_insert_id(),
+                thd->main_da.message());
+    break;
+  case Diagnostics_area::DA_DISABLED:
+    break;
+  case Diagnostics_area::DA_EMPTY:
+  default:
+    DBUG_ASSERT(0);
+    net_send_ok(thd, thd->server_status, thd->total_warn_count,
+                0, 0, NULL);
+    break;
+  }
+  thd->main_da.is_sent= TRUE;
+}
+
 
 /****************************************************************************
   Functions used by the protocol functions (like send_ok) to store strings
@@ -402,6 +467,17 @@ void Protocol::init(THD *thd_arg)
 #endif
 }
 
+/**
+  Finish the result set with EOF packet, as is expected by the client,
+  if there is an error evaluating the next row and a continue handler
+  for the error.
+*/
+
+void Protocol::end_partial_result_set(THD *thd)
+{
+  net_send_eof(thd, thd->server_status, 0 /* no warnings, we're inside SP */);
+}
+
 
 bool Protocol::flush()
 {
@@ -567,7 +643,14 @@ bool Protocol::send_fields(List<Item> *l
   }
 
   if (flags & SEND_EOF)
-    write_eof_packet(thd, &thd->net);
+  {
+    /*
+      Mark the end of meta-data result set, and store thd->server_status,
+      to show that there is no cursor.
+      Send no warning information, as it will be sent at statement end.
+    */
+    write_eof_packet(thd, &thd->net, thd->server_status, 0 /* no warnings */);
+  }
   DBUG_RETURN(prepare_for_send(list));
 
 err:
diff -Nrup a/sql/protocol.h b/sql/protocol.h
--- a/sql/protocol.h	2007-11-01 00:10:56 +03:00
+++ b/sql/protocol.h	2007-11-03 15:25:56 +03:00
@@ -75,6 +75,7 @@ public:
     return 0;
   }
   virtual bool flush();
+  virtual void end_partial_result_set(THD *thd);
   virtual void prepare_for_resend()=0;
 
   virtual bool store_null()=0;
@@ -173,9 +174,7 @@ public:
 
 void send_warning(THD *thd, uint sql_errno, const char *err=0);
 void net_send_error(THD *thd, uint sql_errno=0, const char *err=0);
-void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
-	     const char *info=0);
-void send_eof(THD *thd);
+void net_end_statement(THD *thd);
 bool send_old_password_request(THD *thd);
 uchar *net_store_data(uchar *to,const uchar *from, size_t length);
 uchar *net_store_data(uchar *to,int32 from);
diff -Nrup a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
--- a/sql/repl_failsafe.cc	2007-08-16 10:52:43 +04:00
+++ b/sql/repl_failsafe.cc	2007-11-03 15:25:56 +03:00
@@ -685,7 +685,7 @@ int connect_to_master(THD *thd, MYSQL* m
 
   if (!mi->host || !*mi->host)			/* empty host */
   {
-    strmov(mysql->net.last_error, "Master is not configured");
+    strmov(mysql->net.client_last_error, "Master is not configured");
     DBUG_RETURN(1);
   }
   mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
@@ -880,6 +880,8 @@ bool load_master_data(THD* thd)
 	cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
 	goto err;
       }
+      /* Clear the result of mysql_create_db */
+      thd->main_da.reset_diagnostics_area();
 
       if (mysql_select_db(&mysql, db) ||
 	  mysql_real_query(&mysql, STRING_WITH_LEN("SHOW TABLES")) ||
diff -Nrup a/sql/rpl_record.cc b/sql/rpl_record.cc
--- a/sql/rpl_record.cc	2007-09-14 21:29:17 +04:00
+++ b/sql/rpl_record.cc	2007-11-03 15:25:56 +03:00
@@ -345,12 +345,13 @@ int prepare_record(const Slave_reporting
     if (check && ((f->flags & mask) == mask))
     {
       DBUG_ASSERT(log);
-      log->report(ERROR_LEVEL, ER_NO_DEFAULT_FOR_FIELD,
+      error= ER_NO_DEFAULT_FOR_FIELD;
+      log->report(ERROR_LEVEL, error,
                   "Field `%s` of table `%s`.`%s` "
                   "has no default value and cannot be NULL",
                   f->field_name, table->s->db.str,
                   table->s->table_name.str);
-      error = ER_NO_DEFAULT_FOR_FIELD;
+      my_error(error, MYF(0), f->field_name);
     }
     else
       f->set_default();
diff -Nrup a/sql/rpl_rli.cc b/sql/rpl_rli.cc
--- a/sql/rpl_rli.cc	2007-08-16 09:37:41 +04:00
+++ b/sql/rpl_rli.cc	2007-11-03 15:25:56 +03:00
@@ -166,7 +166,7 @@ int init_relay_log_info(Relay_log_info* 
     {
       sql_print_error("Failed to create a new relay log info file (\
 file '%s', errno %d)", fname, my_errno);
-      msg= current_thd->net.last_error;
+      msg= current_thd->main_da.message();
       goto err;
     }
     if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
@@ -174,7 +174,7 @@ file '%s', errno %d)", fname, my_errno);
     {
       sql_print_error("Failed to create a cache on relay log info file '%s'",
                       fname);
-      msg= current_thd->net.last_error;
+      msg= current_thd->main_da.message();
       goto err;
     }
 
diff -Nrup a/sql/slave.cc b/sql/slave.cc
--- a/sql/slave.cc	2007-11-01 23:52:51 +03:00
+++ b/sql/slave.cc	2007-11-03 15:25:56 +03:00
@@ -981,17 +981,24 @@ static int create_table_from_dump(THD* t
   }
   thd->query= query;
   thd->is_slave_error = 0;
-  thd->net.no_send_ok = 1;
 
   bzero((char*) &tables,sizeof(tables));
   tables.db = (char*)db;
   tables.alias= tables.table_name= (char*)table_name;
 
   /* Drop the table if 'overwrite' is true */
-  if (overwrite && mysql_rm_table(thd,&tables,1,0)) /* drop if exists */
+  if (overwrite)
   {
-    sql_print_error("create_table_from_dump: failed to drop the table");
-    goto err;
+    if (mysql_rm_table(thd,&tables,1,0)) /* drop if exists */
+    {
+      sql_print_error("create_table_from_dump: failed to drop the table");
+      goto err;
+    }
+    else
+    {
+      /* clear the OK result of mysql_rm_table */
+      thd->main_da.reset_diagnostics_area();
+    }
   }
 
   /* Create the table. We do not want to log the "create table" statement */
@@ -1049,7 +1056,6 @@ static int create_table_from_dump(THD* t
 
 err:
   close_thread_tables(thd);
-  thd->net.no_send_ok = 0;
   DBUG_RETURN(error);
 }
 
@@ -1101,7 +1107,6 @@ int fetch_master_table(THD *thd, const c
   error = 0;
 
  err:
-  thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump
   if (!called_connected)
     mysql_close(mysql);
   if (errmsg && thd->vio_ok())
@@ -1717,12 +1722,20 @@ static int has_temporary_error(THD *thd)
     DBUG_RETURN(0);
 
   /*
+    If there is no message in THD, we can't say if it's a temporary
+    error or not. This is currently the case for Incident_log_event,
+    which sets no message. Return FALSE.
+  */
+  if (!thd->is_error())
+    DBUG_RETURN(0);
+
+  /*
     Temporary error codes:
     currently, InnoDB deadlock detected by InnoDB or lock
     wait timeout (innodb_lock_wait_timeout exceeded
   */
-  if (thd->net.last_errno == ER_LOCK_DEADLOCK ||
-      thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT)
+  if (thd->main_da.sql_errno() == ER_LOCK_DEADLOCK ||
+      thd->main_da.sql_errno() == ER_LOCK_WAIT_TIMEOUT)
     DBUG_RETURN(1);
 
 #ifdef HAVE_NDB_BINLOG
@@ -2529,20 +2542,21 @@ Slave SQL thread aborted. Can't execute 
         */
         uint32 const last_errno= rli->last_error().number;
 
-        DBUG_PRINT("info", ("thd->net.last_errno=%d; rli->last_error.number=%d",
-                            thd->net.last_errno, last_errno));
-        if (thd->net.last_errno != 0)
+        if (thd->is_error())
         {
-          char const *const errmsg=
-            thd->net.last_error ? thd->net.last_error : "<no message>";
+          char const *const errmsg= thd->main_da.message();
+
+          DBUG_PRINT("info",
+                     ("thd->main_da.sql_errno()=%d; rli->last_error.number=%d",
+                      thd->main_da.sql_errno(), last_errno));
           if (last_errno == 0)
           {
-            rli->report(ERROR_LEVEL, thd->net.last_errno, errmsg);
+            rli->report(ERROR_LEVEL, thd->main_da.sql_errno(), errmsg);
           }
-          else if (last_errno != thd->net.last_errno)
+          else if (last_errno != thd->main_da.sql_errno())
           {
             sql_print_error("Slave (additional info): %s Error_code: %d",
-                            errmsg, thd->net.last_errno);
+                            errmsg, thd->main_da.sql_errno());
           }
         }
 
diff -Nrup a/sql/sp_head.cc b/sql/sp_head.cc
--- a/sql/sp_head.cc	2007-11-01 23:52:51 +03:00
+++ b/sql/sp_head.cc	2007-11-03 15:25:56 +03:00
@@ -1192,12 +1192,6 @@ sp_head::execute(THD *thd)
     
     err_status= i->execute(thd, &ip);
 
-    /*
-      If this SP instruction have sent eof, it has caused no_send_error to be
-      set. Clear it back to allow the next instruction to send error. (multi-
-      statement execution code clears no_send_error between statements too)
-    */
-    thd->net.no_send_error= 0;
     if (i->free_list)
       cleanup_items(i->free_list);
     
@@ -2739,14 +2733,22 @@ sp_instr_stmt::execute(THD *thd, uint *n
 					  thd->query, thd->query_length) <= 0)
     {
       res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
+
+      if (thd->main_da.is_eof())
+        net_end_statement(thd);
+
+      query_cache_end_of_result(thd);
+
       if (!res && unlikely(thd->enable_slow_log))
         log_slow_statement(thd);
-      query_cache_end_of_result(thd);
     }
     else
       *nextp= m_ip+1;
     thd->query= query;
     thd->query_length= query_length;
+
+    if (!thd->is_error())
+      thd->main_da.reset_diagnostics_area();
   }
   DBUG_RETURN(res);
 }
diff -Nrup a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
--- a/sql/sp_rcontext.cc	2007-08-05 09:11:23 +04:00
+++ b/sql/sp_rcontext.cc	2007-11-03 15:25:57 +03:00
@@ -287,7 +287,6 @@ sp_rcontext::find_handler(THD *thd, uint
     sql_errno     The error code
     level         Warning level
     thd           The current thread
-                  - thd->net.report_error is an optional output.
 
   RETURN
     TRUE       if a handler was found.
@@ -298,7 +297,6 @@ sp_rcontext::handle_error(uint sql_errno
                           MYSQL_ERROR::enum_warning_level level,
                           THD *thd)
 {
-  bool handled= FALSE;
   MYSQL_ERROR::enum_warning_level elevated_level= level;
 
 
@@ -310,25 +308,7 @@ sp_rcontext::handle_error(uint sql_errno
     elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
   }
 
-  if (find_handler(thd, sql_errno, elevated_level))
-  {
-    if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
-    {
-      /*
-         Forces to abort the current instruction execution.
-         NOTE: This code is altering the original meaning of
-         the net.report_error flag (send an error to the client).
-         In the context of stored procedures with error handlers,
-         the flag is reused to cause error propagation,
-         until the error handler is reached.
-         No messages will be sent to the client in that context.
-      */
-      thd->net.report_error= 1;
-    }
-    handled= TRUE;
-  }
-
-  return handled;
+  return find_handler(thd, sql_errno, elevated_level);
 }
 
 void
diff -Nrup a/sql/sql_acl.cc b/sql/sql_acl.cc
--- a/sql/sql_acl.cc	2007-10-31 15:22:16 +03:00
+++ b/sql/sql_acl.cc	2007-11-03 15:25:57 +03:00
@@ -694,7 +694,7 @@ my_bool acl_reload(THD *thd)
   if (simple_open_n_lock_tables(thd, tables))
   {
     sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
-		    thd->net.last_error);
+		    thd->main_da.message());
     goto end;
   }
 
@@ -5600,9 +5600,6 @@ bool mysql_drop_user(THD *thd, List <LEX
 
   if (result)
     my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe());
-
-  DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno));
-  DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error));
 
   write_bin_log(thd, FALSE, thd->query, thd->query_length);
 
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc	2007-11-01 23:52:51 +03:00
+++ b/sql/sql_base.cc	2007-11-03 15:25:57 +03:00
@@ -492,9 +492,22 @@ static TABLE_SHARE
   int tmp;
   DBUG_ENTER("get_table_share_with_create");
 
-  if ((share= get_table_share(thd, table_list, key, key_length, 
-                              db_flags, error)) ||
-      thd->net.last_errno != ER_NO_SUCH_TABLE)
+  share= get_table_share(thd, table_list, key, key_length, db_flags, error);
+  /*
+    - if share is not NULL, we found an existing share.
+    - if share is NULL, and there is no error, we're inside
+      pre-locking, which silences 'ER_NO_SUCH_TABLE' errors
+      with the intention to silently drop tables that do not exist
+      from the pre-locking list. In this case we still need to try
+      auto-discover before returning a NULL share.
+    - if share is NULL and the error is ER_NO_SUCH_TABLE, this is
+      the same as above, only that the error was not silenced. Once again,
+      we need to try to auto-discover the share.
+    - if share is still NULL, it's a real error and we need to abort.
+      @todo Rework alternative ways to deal with ER_NO_SUCH TABLE
+  */
+  if (share || thd->is_error() && thd->main_da.sql_errno() != ER_NO_SUCH_TABLE)
+
     DBUG_RETURN(share);
 
   /* Table didn't exist. Check if some engine can provide it */
@@ -503,9 +516,13 @@ static TABLE_SHARE
   {
     /*
       No such table in any engine.
-      Hide "Table doesn't exist" errors if table belong to view
+      Hide "Table doesn't exist" errors if the table belongs to a view.
+      The check for thd->is_error() is necessary to not push an
+      unwanted error in case of pre-locking, which silences
+      "no such table" errors.
+      @todo Rework alternative ways to deal with ER_NO_SUCH TABLE
     */
-    if (table_list->belong_to_view)
+    if (thd->is_error() && table_list->belong_to_view)
     {
       TABLE_LIST *view= table_list->belong_to_view;
       thd->clear_error();
diff -Nrup a/sql/sql_binlog.cc b/sql/sql_binlog.cc
--- a/sql/sql_binlog.cc	2007-08-16 09:37:42 +04:00
+++ b/sql/sql_binlog.cc	2007-11-03 15:25:57 +03:00
@@ -37,12 +37,6 @@ void mysql_client_binlog_statement(THD* 
                             thd->lex->comment.length : 2048),
                      thd->lex->comment.str));
 
-  /*
-    Temporarily turn off send_ok, since different events handle this
-    differently
-  */
-  my_bool nsok= thd->net.no_send_ok;
-  thd->net.no_send_ok= TRUE;
 
   size_t coded_len= thd->lex->comment.length + 1;
   size_t decoded_len= base64_needed_decoded_length(coded_len);
@@ -190,20 +184,11 @@ void mysql_client_binlog_statement(THD* 
     }
   }
 
-  /*
-    Restore setting of no_send_ok
-  */
-  thd->net.no_send_ok= nsok;
 
   DBUG_PRINT("info",("binlog base64 execution finished successfully"));
   send_ok(thd);
 
 end:
-  /*
-    Restore setting of no_send_ok
-  */
-  thd->net.no_send_ok= nsok;
-
   delete desc;
   my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
   DBUG_VOID_RETURN;
diff -Nrup a/sql/sql_cache.cc b/sql/sql_cache.cc
--- a/sql/sql_cache.cc	2007-10-29 17:46:43 +03:00
+++ b/sql/sql_cache.cc	2007-11-03 15:25:57 +03:00
@@ -1403,6 +1403,7 @@ def_week_frmt: %lu",                    
 
   thd->limit_found_rows = query->found_rows();
   thd->status_var.last_query_cost= 0.0;
+  thd->main_da.disable_status();
 
   BLOCK_UNLOCK_RD(query_block);
   DBUG_RETURN(1);				// Result sent to client
diff -Nrup a/sql/sql_class.cc b/sql/sql_class.cc
--- a/sql/sql_class.cc	2007-10-31 18:33:06 +03:00
+++ b/sql/sql_class.cc	2007-11-03 15:25:57 +03:00
@@ -352,6 +352,110 @@ char *thd_security_context(THD *thd, cha
 }
 
 
+void
+Diagnostics_area::reset_diagnostics_area()
+{
+#ifdef DBUG_OFF
+  can_overwrite_status= FALSE;
+  /** Don't take chances in production */
+  m_message[0]= '\0';
+  m_sql_errno= 0;
+  m_server_status= 0;
+  m_affected_rows= 0;
+  m_last_insert_id= 0;
+  m_total_warn_count= 0;
+#endif
+  is_sent= FALSE;
+  /** Tiny reset in debug mode to see garbage right away */
+  m_status= DA_EMPTY;
+}
+
+
+/** Set OK status.  */
+
+void
+Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg,
+                                ulong last_insert_id_arg,
+                                const char *message_arg)
+{
+  DBUG_ASSERT(! is_set());
+#ifdef DBUG_OFF
+  /* In production, refuse to overwrite an error with an OK packet. */
+  if (is_error())
+    return;
+#endif
+  /** Only allowed to report success if has not yet reported an error */
+
+  m_server_status= thd->server_status;
+  m_total_warn_count= thd->total_warn_count;
+  m_affected_rows= affected_rows_arg;
+  m_last_insert_id= last_insert_id_arg;
+  if (message_arg)
+    strmake(m_message, message_arg, sizeof(m_message));
+  else
+    m_message[0]= '\0';
+  m_status= DA_OK;
+}
+
+/** Set EOF status */
+
+void
+Diagnostics_area::set_eof_status(THD *thd)
+{
+  /** Only allowed to report eof if has not yet reported an error */
+
+  DBUG_ASSERT(! is_set());
+#ifdef DBUG_OFF
+  /* In production, refuse to overwrite an error with an EOF packet. */
+  if (is_error())
+    return;
+#endif
+
+  m_server_status= thd->server_status;
+  /*
+    If inside a stored procedure, do not return the total
+    number of warnings, since they are not available to the client
+    anyway.
+  */
+  m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count;
+
+  m_status= DA_EOF;
+}
+
+/* Set ERROR status */
+
+void
+Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg,
+                                   const char *message_arg)
+{
+  /*
+    Only allowed to report error if has not yet reported a success
+    The only exception is when we flush the message to the client,
+    an error can happen during the flush.
+  */
+  DBUG_ASSERT(! is_set() || can_overwrite_status);
+
+  m_sql_errno= sql_errno_arg;
+  strmake(m_message, message_arg, sizeof(m_message));
+
+  m_status= DA_ERROR;
+}
+
+/**
+  Mark the diagnostics area as 'DISABLED'.
+
+  This is used in rare cases when the COM_ command at hand sends a response
+  in a custom format. One example is the query cache, another is
+  COM_STMT_PREPARE.
+*/
+
+void
+Diagnostics_area::disable_status()
+{
+  DBUG_ASSERT(! is_set());
+  m_status= DA_DISABLED;
+}
+
 
 THD::THD()
    :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
@@ -431,7 +535,6 @@ THD::THD()
   net.vio=0;
 #endif
   client_capabilities= 0;                       // minimalistic client
-  net.last_error[0]=0;                          // If error on boot
 #ifdef HAVE_QUERY_CACHE
   query_cache_init_query(&net);                 // If error on boot
 #endif
@@ -1313,7 +1416,7 @@ void select_send::abort()
 {
   DBUG_ENTER("select_send::abort");
   if (is_result_set_started && thd->spcont &&
-      thd->spcont->find_handler(thd, thd->net.last_errno,
+      thd->spcont->find_handler(thd, thd->main_da.sql_errno(),
                                 MYSQL_ERROR::WARN_LEVEL_ERROR))
   {
     /*
@@ -1326,9 +1429,6 @@ void select_send::abort()
       otherwise the client will hang due to the violation of the
       client/server protocol.
     */
-    thd->net.report_error= 0;
-    send_eof();
-    thd->net.report_error= 1; // Abort SP
   }
   DBUG_VOID_RETURN;
 }
@@ -1380,12 +1480,14 @@ bool select_send::send_data(List<Item> &
     }
   }
   thd->sent_row_count++;
-  if (!thd->vio_ok())
-    DBUG_RETURN(0);
-  if (! thd->is_error())
+  if (thd->is_error())
+  {
+    protocol->remove_last_row();
+    DBUG_RETURN(1);
+  }
+  if (thd->vio_ok())
     DBUG_RETURN(protocol->write());
-  protocol->remove_last_row();
-  DBUG_RETURN(1);
+  DBUG_RETURN(0);
 }
 
 bool select_send::send_eof()
@@ -1403,14 +1505,8 @@ bool select_send::send_eof()
     mysql_unlock_tables(thd, thd->lock);
     thd->lock=0;
   }
-  if (! thd->is_error())
-  {
-    ::send_eof(thd);
-    is_result_set_started= 0;
-    return 0;
-  }
-  else
-    return 1;
+  ::send_eof(thd);
+  is_result_set_started= 0;
 }
 
 
@@ -2664,7 +2760,6 @@ void THD::reset_sub_statement_state(Sub_
 {
   backup->options=         options;
   backup->in_sub_stmt=     in_sub_stmt;
-  backup->no_send_ok=      net.no_send_ok;
   backup->enable_slow_log= enable_slow_log;
   backup->limit_found_rows= limit_found_rows;
   backup->examined_row_count= examined_row_count;
@@ -2695,9 +2790,6 @@ void THD::reset_sub_statement_state(Sub_
   cuted_fields= 0;
   transaction.savepoints= 0;
   first_successful_insert_id_in_cur_stmt= 0;
-
-  /* Surpress OK packets in case if we will execute statements */
-  net.no_send_ok= TRUE;
 }
 
 
@@ -2720,7 +2812,6 @@ void THD::restore_sub_statement_state(Su
   transaction.savepoints= backup->savepoints;
   options=          backup->options;
   in_sub_stmt=      backup->in_sub_stmt;
-  net.no_send_ok=   backup->no_send_ok;
   enable_slow_log=  backup->enable_slow_log;
   first_successful_insert_id_in_prev_stmt= 
     backup->first_successful_insert_id_in_prev_stmt;
diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
--- a/sql/sql_class.h	2007-10-31 18:33:06 +03:00
+++ b/sql/sql_class.h	2007-11-03 15:25:57 +03:00
@@ -913,7 +913,6 @@ public:
   uint in_sub_stmt;
   bool enable_slow_log;
   bool last_insert_id_used;
-  my_bool no_send_ok;
   SAVEPOINT *savepoints;
 };
 
@@ -974,6 +973,122 @@ public:
                             THD *thd) = 0;
 };
 
+/**
+  Stores status of the currently executed statement.
+  Cleared at the beginning of the statement, and then
+  can hold either OK, ERROR, or EOF status.
+  Can not be assigned twice per statement.
+*/
+
+class Diagnostics_area
+{
+public:
+  enum enum_diagnostics_status
+  {
+    /** The area is cleared at start of a statement. */
+    DA_EMPTY= 0,
+    /** Set whenever one calls send_ok() */
+    DA_OK,
+    /** Set whenever one calls send_eof() */
+    DA_EOF,
+    /** Set whenever one calls my_error() or my_message() */
+    DA_ERROR,
+    /** Set in case of a custom response, such as one from COM_STMT_PREPARE */
+    DA_DISABLED
+  };
+  /** True if status information is sent to the client */
+  bool is_sent;
+  /** Set to make set_error_status after set_{ok,eof}_status possible */
+  bool can_overwrite_status;
+
+  void set_ok_status(THD *thd, ha_rows affected_rows_arg,
+                     ulong last_insert_id_arg,
+                     const char *message);
+  void set_eof_status(THD *thd);
+  void set_error_status(THD *thd, uint sql_errno_arg, const char *message_arg);
+
+  void disable_status();
+
+  void reset_diagnostics_area();
+
+  bool is_set() const { return m_status != DA_EMPTY; }
+  bool is_error() const { return m_status == DA_ERROR; }
+  bool is_eof() const { return m_status == DA_EOF; }
+  bool is_ok() const { return m_status == DA_OK; }
+  bool is_disabled() const { return m_status == DA_DISABLED; }
+  enum_diagnostics_status status() const { return m_status; }
+
+  const char *message() const
+  { DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK); return m_message; }
+
+  uint sql_errno() const
+  { DBUG_ASSERT(m_status == DA_ERROR); return m_sql_errno; }
+
+  uint server_status() const
+  {
+    DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
+    return m_server_status;
+  }
+
+  ha_rows affected_rows() const
+  { DBUG_ASSERT(m_status == DA_OK); return m_affected_rows; }
+
+  ulong last_insert_id() const
+  { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
+
+  uint total_warn_count() const
+  {
+    DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
+    return m_total_warn_count;
+  }
+
+  Diagnostics_area() { reset_diagnostics_area(); }
+
+private:
+  /** Message buffer. Can be used by OK or ERROR status. */
+  char m_message[MYSQL_ERRMSG_SIZE];
+  /**
+    SQL error number. One of ER_ codes from share/errmsg.txt.
+    Set by set_error_status.
+  */
+  uint m_sql_errno;
+
+  /**
+    Copied from thd->server_status when the diagnostics area is assigned.
+    We need this member as some places in the code use the following pattern:
+    thd->server_status|= ...
+    send_eof(thd);
+    thd->server_status&= ~...
+    Assigned by OK, EOF or ERROR.
+  */
+  uint m_server_status;
+  /**
+    The number of rows affected by the last statement. This is
+    semantically close to thd->row_count_func, but has a different
+    life cycle. thd->row_count_func stores the value returned by
+    function ROW_COUNT() and is cleared only by statements that
+    update its value, such as INSERT, UPDATE, DELETE and few others.
+    This member is cleared at the beginning of the next statement.
+
+    We could possibly merge the two, but life cycle of thd->row_count_func
+    can not be changed.
+  */
+  ha_rows    m_affected_rows;
+  /**
+    Similarly to the previous member, this is a replacement of
+    thd->first_successful_insert_id_in_prev_stmt, which is used
+    to implement LAST_INSERT_ID().
+  */
+  ulong      m_last_insert_id;
+  /** The total number of warnings. */
+  uint	     m_total_warn_count;
+  enum_diagnostics_status m_status;
+  /**
+    @todo: the following THD members belong here:
+    - warn_list, warn_count,
+  */
+};
+
 
 /**
   @class THD
@@ -1387,6 +1502,7 @@ public:
   List	     <MYSQL_ERROR> warn_list;
   uint	     warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
   uint	     total_warn_count;
+  Diagnostics_area main_da;
   /*
     Id of current query. Statement can be reused to execute several queries
     query_id is global in context of the whole MySQL server.
@@ -1697,12 +1813,18 @@ public:
   CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
   int send_explain_fields(select_result *result);
 #ifndef EMBEDDED_LIBRARY
+  /**
+    Clear the current error, if any.
+    We do not clear is_fatal_error or is_fatal_sub_stmt_error since we
+    assume this is never called if the fatal error is set.
+    @todo: To silence an error, one should use Internal_error_handler
+    mechanism. This function should be removed.
+  */
   inline void clear_error()
   {
     DBUG_ENTER("clear_error");
-    net.last_error[0]= 0;
-    net.last_errno= 0;
-    net.report_error= 0;
+    if (main_da.is_error())
+      main_da.reset_diagnostics_area();
     is_slave_error= 0;
     DBUG_VOID_RETURN;
   }
@@ -1711,10 +1833,14 @@ public:
   void clear_error();
   inline bool vio_ok() const { return true; }
 #endif
+  /**
+    Mark the current error as fatal. Warning: this does not
+    set any error, it sets a property of the error, so must be
+    followed or prefixed with my_error().
+  */
   inline void fatal_error()
   {
     is_fatal_error= 1;
-    net.report_error= 1;
     DBUG_PRINT("error",("Fatal error set"));
   }
   /**
@@ -1730,7 +1856,7 @@ public:
 
     To raise this flag, use my_error().
   */
-  inline bool is_error() const { return net.report_error; }
+  inline bool is_error() const { return main_da.is_error(); }
   inline CHARSET_INFO *charset() { return variables.character_set_client; }
   void update_charset();
 
@@ -1953,6 +2079,24 @@ private:
   MEM_ROOT main_mem_root;
 };
 
+
+/** A short cut for thd->main_da.set_ok_status() */
+
+inline void
+send_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0,
+        const char *message= NULL)
+{
+  thd->main_da.set_ok_status(thd, affected_rows, id, message);
+}
+
+
+/** A short cut for thd->main_da.set_eof_status() */
+
+inline void
+send_eof(THD *thd)
+{
+  thd->main_da.set_eof_status(thd);
+}
 
 #define tmp_disable_binlog(A)       \
   {ulonglong tmp_disable_binlog__save_options= (A)->options; \
diff -Nrup a/sql/sql_connect.cc b/sql/sql_connect.cc
--- a/sql/sql_connect.cc	2007-11-02 01:44:06 +03:00
+++ b/sql/sql_connect.cc	2007-11-03 15:25:57 +03:00
@@ -948,19 +948,20 @@ bool setup_connection_thread_globals(THD
 bool login_connection(THD *thd)
 {
   NET *net= &thd->net;
+  int error;
   DBUG_ENTER("login_connection");
   DBUG_PRINT("info", ("login_connection called by thread %lu",
                       thd->thread_id));
 
-  net->no_send_error= 0;
-
   /* Use "connect_timeout" value during connection phase */
   my_net_set_read_timeout(net, connect_timeout);
   my_net_set_write_timeout(net, connect_timeout);
 
-  if (check_connection(thd))
+  error= check_connection(thd);
+  net_end_statement(thd);
+
+  if (error)
   {						// Wrong permissions
-    net_send_error(thd);
 #ifdef __NT__
     if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
       my_sleep(1000);				/* must wait after eof() */
@@ -989,13 +990,12 @@ void end_connection(THD *thd)
   if (thd->user_connect)
     decrease_user_connections(thd->user_connect);
 
-  if (thd->killed ||
-      net->error && net->vio != 0 && thd->is_error())
+  if (thd->killed || net->error && net->vio != 0)
   {
     statistic_increment(aborted_threads,&LOCK_status);
   }
 
-  if (net->error && net->vio != 0 && thd->is_error())
+  if (net->error && net->vio != 0)
   {
     if (!thd->killed && thd->variables.log_warnings > 1)
     {
@@ -1005,11 +1005,9 @@ void end_connection(THD *thd)
                         thd->thread_id,(thd->db ? thd->db : "unconnected"),
                         sctx->user ? sctx->user : "unauthenticated",
                         sctx->host_or_ip,
-                        (net->last_errno ? ER(net->last_errno) :
+                        (thd->main_da.is_error() ? thd->main_da.message() :
                          ER(ER_UNKNOWN_ERROR)));
     }
-
-    net_send_error(thd, net->last_errno, NullS);
   }
 }
 
@@ -1045,24 +1043,14 @@ static void prepare_new_connection_state
   if (sys_init_connect.value_length && !(sctx->master_access & SUPER_ACL))
   {
     execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect);
-    /*
-      execute_init_command calls net_send_error.
-      If there was an error during execution of the init statements, 
-      the error at this moment is present in thd->net.last_error and also
-      thd->is_slave_error and thd->net.report_error are set.
-      net_send_error sends the contents of thd->net.last_error and
-      clears thd->net.report_error. It doesn't, however, clean
-      thd->is_slave_error or thd->net.last_error. Here we make use of this
-      fact.
-    */
-    if (thd->is_slave_error)
+    if (thd->is_error())
     {
       thd->killed= THD::KILL_CONNECTION;
       sql_print_warning(ER(ER_NEW_ABORTING_CONNECTION),
                         thd->thread_id,(thd->db ? thd->db : "unconnected"),
                         sctx->user ? sctx->user : "unauthenticated",
                         sctx->host_or_ip, "init_connect command failed");
-      sql_print_warning("%s", thd->net.last_error);
+      sql_print_warning("%s", thd->main_da.message());
     }
     thd->proc_info=0;
     thd->set_time();
@@ -1128,7 +1116,6 @@ pthread_handler_t handle_one_connection(
     while (!net->error && net->vio != 0 &&
            !(thd->killed == THD::KILL_CONNECTION))
     {
-      net->no_send_error= 0;
       if (do_command(thd))
 	break;
     }
diff -Nrup a/sql/sql_db.cc b/sql/sql_db.cc
--- a/sql/sql_db.cc	2007-09-11 02:10:32 +04:00
+++ b/sql/sql_db.cc	2007-11-03 15:25:57 +03:00
@@ -914,6 +914,8 @@ bool mysql_rm_db(THD *thd,char *db,bool 
     {
       ha_drop_database(path);
       query_cache_invalidate1(db);
+      (void) sp_drop_db_routines(thd, db); /* QQ Ignore errors for now  */
+      Events::drop_schema_events(thd, db);
       error = 0;
     }
   }
@@ -949,6 +951,7 @@ bool mysql_rm_db(THD *thd,char *db,bool 
       /* These DDL methods and logging protected with LOCK_mysql_create_db */
       mysql_bin_log.write(&qinfo);
     }
+    thd->clear_error();
     thd->server_status|= SERVER_STATUS_DB_DROPPED;
     send_ok(thd, (ulong) deleted);
     thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
@@ -992,8 +995,6 @@ bool mysql_rm_db(THD *thd,char *db,bool 
   }
 
 exit:
-  (void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now  */
-  Events::drop_schema_events(thd, db);
   /*
     If this database was the client's selected database, we silently
     change the client's selected database to nothing (to have an empty
diff -Nrup a/sql/sql_derived.cc b/sql/sql_derived.cc
--- a/sql/sql_derived.cc	2007-04-23 15:16:45 +04:00
+++ b/sql/sql_derived.cc	2007-11-03 15:25:57 +03:00
@@ -147,8 +147,9 @@ exit:
     /* Hide "Unknown column" or "Unknown function" error */
     if (orig_table_list->view)
     {
-      if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
-          thd->net.last_errno == ER_SP_DOES_NOT_EXIST)
+      if (thd->is_error() &&
+          (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
+          thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST))
       {
         thd->clear_error();
         my_error(ER_VIEW_INVALID, MYF(0), orig_table_list->db,
diff -Nrup a/sql/sql_insert.cc b/sql/sql_insert.cc
--- a/sql/sql_insert.cc	2007-11-01 23:52:52 +03:00
+++ b/sql/sql_insert.cc	2007-11-03 15:25:58 +03:00
@@ -1917,7 +1917,7 @@ bool delayed_get_table(THD *thd, TABLE_L
             main thread. Use of my_message will enable stored
             procedures continue handlers.
           */
-          my_message(di->thd.net.last_errno, di->thd.net.last_error,
+          my_message(di->thd.main_da.sql_errno(), di->thd.main_da.message(),
                      MYF(0));
 	}
 	di->unlock();
@@ -1994,7 +1994,7 @@ TABLE *Delayed_insert::get_local_table(T
       goto error;
     if (dead)
     {
-      my_message(thd.net.last_errno, thd.net.last_error, MYF(0));
+      my_message(thd.main_da.sql_errno(), thd.main_da.message(), MYF(0));
       goto error;
     }
   }
@@ -2253,7 +2253,9 @@ pthread_handler_t handle_delayed_insert(
 #if !defined( __WIN__) /* Win32 calls this in pthread_create */
   if (my_thread_init())
   {
-    strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
+    /* Can't use my_error since store_globals has not yet been called */
+    thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
+                                  ER(ER_OUT_OF_RESOURCES));
     goto end;
   }
 #endif
@@ -2262,8 +2264,10 @@ pthread_handler_t handle_delayed_insert(
   thd->thread_stack= (char*) &thd;
   if (init_thr_lock() || thd->store_globals())
   {
+    /* Can't use my_error since store_globals has perhaps failed */
+    thd->main_da.set_error_status(thd, ER_OUT_OF_RESOURCES,
+                                  ER(ER_OUT_OF_RESOURCES));
     thd->fatal_error();
-    strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
     goto err;
   }
 
@@ -2651,7 +2655,7 @@ bool Delayed_insert::handle_inserts(void
 	{
 	  /* This should never happen */
 	  table->file->print_error(error,MYF(0));
-	  sql_print_error("%s",thd.net.last_error);
+	  sql_print_error("%s", thd.main_da.message());
           DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed in loop"));
 	  goto err;
 	}
@@ -2692,7 +2696,7 @@ bool Delayed_insert::handle_inserts(void
   if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
   {						// This shouldn't happen
     table->file->print_error(error,MYF(0));
-    sql_print_error("%s",thd.net.last_error);
+    sql_print_error("%s", thd.main_da.message());
     DBUG_PRINT("error", ("HA_EXTRA_NO_CACHE failed after loop"));
     goto err;
   }
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc	2007-11-02 01:48:11 +03:00
+++ b/sql/sql_parse.cc	2007-11-03 15:25:58 +03:00
@@ -328,7 +328,6 @@ void execute_init_command(THD *thd, sys_
   */
   save_vio= thd->net.vio;
   thd->net.vio= 0;
-  thd->net.no_send_error= 0;
   dispatch_command(COM_QUERY, thd,
                    init_command_var->value,
                    init_command_var->value_length);
@@ -397,8 +396,8 @@ pthread_handler_t handle_bootstrap(void 
       /* purecov: begin tested */
       if (net_realloc(&(thd->net), 2 * thd->net.max_packet))
       {
-        net_send_error(thd, ER_NET_PACKET_TOO_LARGE, NullS);
-        thd->fatal_error();
+        net_end_statement(thd);
+        bootstrap_error= 1;
         break;
       }
       buff= (char*) thd->net.buff;
@@ -406,7 +405,7 @@ pthread_handler_t handle_bootstrap(void 
       length+= (ulong) strlen(buff + length);
       /* purecov: end */
     }
-    if (thd->is_fatal_error)
+    if (bootstrap_error)
       break;                                    /* purecov: inspected */
 
     while (length && (my_isspace(thd->charset(), buff[length-1]) ||
@@ -433,16 +432,11 @@ pthread_handler_t handle_bootstrap(void 
     mysql_parse(thd, thd->query, length, & found_semicolon);
     close_thread_tables(thd);			// Free tables
 
-    if (thd->is_fatal_error)
-      break;
+    bootstrap_error= thd->is_error();
+    net_end_statement(thd);
 
-    if (thd->is_error())
-    {
-      /* The query failed, send error to log and abort bootstrap */
-      net_send_error(thd);
-      thd->fatal_error();
+    if (bootstrap_error)
       break;
-    }
 
     free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
 #ifdef USING_TRANSACTIONS
@@ -451,9 +445,6 @@ pthread_handler_t handle_bootstrap(void 
   }
 
 end:
-  /* Remember the exit code of bootstrap */
-  bootstrap_error= thd->is_fatal_error;
-
   net_end(&thd->net);
   thd->cleanup();
   delete thd;
@@ -672,7 +663,12 @@ bool do_command(THD *thd)
   */
   my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
 
+  /*
+    XXX: this code is here only to clear possible errors of init_connect. 
+    Consider moving to init_connect() instead.
+  */
   thd->clear_error();				// Clear error message
+  thd->main_da.reset_diagnostics_area();
 
   net_new_transaction(net);
   if ((packet_length=my_net_read(net)) == packet_error)
@@ -683,10 +679,13 @@ bool do_command(THD *thd)
 
     /* Check if we can continue without closing the connection */
 
+    /* The error must be set */
+    DBUG_ASSERT(thd->is_error());
+    net_end_statement(thd);
+
     if (net->error != 3)
       DBUG_RETURN(TRUE);			// We have to close it.
 
-    net_send_error(thd, net->last_errno, NullS);
     net->error= 0;
     DBUG_RETURN(FALSE);
   }
@@ -825,7 +824,8 @@ bool dispatch_command(enum enum_server_c
     db.length= db_len;
     tbl_name= strmake(db.str, packet + 1, db_len)+1;
     strmake(tbl_name, packet + db_len + 2, tbl_len);
-    mysql_table_dump(thd, &db, tbl_name);
+    if (mysql_table_dump(thd, &db, tbl_name) == 0)
+      thd->main_da.disable_status();
     break;
   }
   case COM_CHANGE_USER:
@@ -989,7 +989,9 @@ bool dispatch_command(enum enum_server_c
     while (!thd->killed && found_semicolon && ! thd->is_error())
     {
       char *next_packet= (char*) found_semicolon;
-      net->no_send_error= 0;
+
+      net_end_statement(thd);
+      query_cache_end_of_result(thd);
       /*
         Multiple queries exits, execute them individually
       */
@@ -1090,6 +1092,7 @@ bool dispatch_command(enum enum_server_c
     /* We don't calculate statistics for this command */
     general_log_print(thd, command, NullS);
     net->error=0;				// Don't give 'abort' message
+    thd->main_da.disable_status();              // Don't send anything back
     error=TRUE;					// End server
     break;
 
@@ -1206,16 +1209,6 @@ bool dispatch_command(enum enum_server_c
     DBUG_PRINT("quit",("Got shutdown command for level %u", level));
     general_log_print(thd, command, NullS);
     send_eof(thd);
-#ifdef __WIN__
-    sleep(1);					// must wait after eof()
-#endif
-    /*
-      The client is next going to send a COM_QUIT request (as part of
-      mysql_close()). Make the life simpler for the client by sending
-      the response for the coming COM_QUIT in advance
-    */
-    send_eof(thd);
-    close_connection(thd, 0, 1);
     close_thread_tables(thd);			// Free before kill
     kill_mysql();
     error=TRUE;
@@ -1228,13 +1221,8 @@ bool dispatch_command(enum enum_server_c
     ulong uptime;
     uint length;
     ulonglong queries_per_second1000;
-#ifndef EMBEDDED_LIBRARY
     char buff[250];
     uint buff_len= sizeof(buff);
-#else
-    char *buff= thd->net.last_error;
-    uint buff_len= sizeof(thd->net.last_error);
-#endif
 
     general_log_print(thd, command, NullS);
     status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]);
@@ -1256,6 +1244,10 @@ bool dispatch_command(enum enum_server_c
                         cached_open_tables(),
                         (uint) (queries_per_second1000 / 1000),
                         (uint) (queries_per_second1000 % 1000));
+#ifdef EMBEDDED_LIBRARY
+    /* Store the buffer in permanent memory */
+    send_ok(thd, 0, 0, buff);
+#endif
 #ifdef SAFEMALLOC
     if (sf_malloc_cur_memory)				// Using SAFEMALLOC
     {
@@ -1268,7 +1260,8 @@ bool dispatch_command(enum enum_server_c
 #endif
 #ifndef EMBEDDED_LIBRARY
     VOID(my_net_write(net, (uchar*) buff, length));
-      VOID(net_flush(net));
+    VOID(net_flush(net));
+    thd->main_da.disable_status();
 #endif
     break;
   }
@@ -1348,10 +1341,11 @@ bool dispatch_command(enum enum_server_c
     thd->transaction.xid_state.xid.null();
 
   /* report error issued during command execution */
-  if (thd->killed_errno() && ! thd->is_error())
+  if (thd->killed_errno() && ! thd->main_da.is_set())
     thd->send_kill_message();
-  if (thd->is_error())
-    net_send_error(thd);
+
+  net_end_statement(thd);
+  query_cache_end_of_result(thd);
 
   log_slow_statement(thd);
 
@@ -1721,7 +1715,6 @@ mysql_execute_command(THD *thd)
   SELECT_LEX_UNIT *unit= &lex->unit;
   /* Saved variable value */
   DBUG_ENTER("mysql_execute_command");
-  thd->net.no_send_error= 0;
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   thd->work_part_info= 0;
 #endif
@@ -3867,8 +3860,6 @@ create_sp_error:
             goto error;
         }
 
-	my_bool save_no_send_ok= thd->net.no_send_ok;
-	thd->net.no_send_ok= TRUE;
 	if (sp->m_flags & sp_head::MULTI_RESULTS)
 	{
 	  if (! (thd->client_capabilities & CLIENT_MULTI_RESULTS))
@@ -3878,7 +3869,6 @@ create_sp_error:
               back
             */
 	    my_error(ER_SP_BADSELECT, MYF(0), sp->m_qname.str);
-	    thd->net.no_send_ok= save_no_send_ok;
 	    goto error;
 	  }
           /*
@@ -3894,7 +3884,6 @@ create_sp_error:
 	if (check_routine_access(thd, EXECUTE_ACL,
 				 sp->m_db.str, sp->m_name.str, TRUE, FALSE))
 	{
-	  thd->net.no_send_ok= save_no_send_ok;
 	  goto error;
 	}
 #endif
@@ -3919,7 +3908,6 @@ create_sp_error:
 
 	thd->variables.select_limit= select_limit;
 
-	thd->net.no_send_ok= save_no_send_ok;
         thd->server_status&= ~bits_to_be_cleared;
 
 	if (!res)
@@ -4560,7 +4548,10 @@ static bool execute_sqlcom_select(THD *t
         push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                      ER_YES, str.ptr());
       }
-      result->send_eof();
+      if (res)
+        result->abort();
+      else
+        result->send_eof();
       delete result;
     }
     else
@@ -5241,6 +5232,7 @@ void mysql_reset_thd_for_next_command(TH
       thd->user_var_events_alloc= thd->mem_root;
     }
     thd->clear_error();
+    thd->main_da.reset_diagnostics_area();
     thd->total_warn_count=0;			// Warnings for this query
     thd->rand_used= 0;
     thd->sent_row_count= thd->examined_row_count= 0;
@@ -5482,7 +5474,6 @@ void mysql_parse(THD *thd, const char *i
           /* Actually execute the query */
           lex->set_trg_event_type_for_tables();
           mysql_execute_command(thd);
-          query_cache_end_of_result(thd);
 	}
       }
     }
@@ -6453,7 +6444,6 @@ bool reload_acl_and_cache(THD *thd, ulon
     if (reset_master(thd))
     {
       result=1;
-      thd->fatal_error();                       // Ensure client get error
     }
   }
 #endif
diff -Nrup a/sql/sql_partition.cc b/sql/sql_partition.cc
--- a/sql/sql_partition.cc	2007-10-09 18:16:37 +04:00
+++ b/sql/sql_partition.cc	2007-11-03 15:25:58 +03:00
@@ -2055,6 +2055,7 @@ char *generate_partition_syntax(partitio
     default:
       DBUG_ASSERT(0);
       /* We really shouldn't get here, no use in continuing from here */
+      my_error(ER_OUT_OF_RESOURCES, MYF(0));
       current_thd->fatal_error();
       DBUG_RETURN(NULL);
   }
diff -Nrup a/sql/sql_prepare.cc b/sql/sql_prepare.cc
--- a/sql/sql_prepare.cc	2007-10-30 20:08:12 +03:00
+++ b/sql/sql_prepare.cc	2007-11-03 15:25:58 +03:00
@@ -230,6 +230,8 @@ static bool send_prep_stmt(Prepared_stat
   NET *net= &stmt->thd->net;
   uchar buff[12];
   uint tmp;
+  int error;
+  THD *thd= stmt->thd;
   DBUG_ENTER("send_prep_stmt");
 
   buff[0]= 0;                                   /* OK packet indicator */
@@ -244,11 +246,16 @@ static bool send_prep_stmt(Prepared_stat
     Send types and names of placeholders to the client
     XXX: fix this nasty upcast from List<Item_param> to List<Item>
   */
-  DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) ||
-              (stmt->param_count &&
-               stmt->thd->protocol_text.send_fields((List<Item> *)
-                                                    &stmt->lex->param_list,
-                                                    Protocol::SEND_EOF)));
+  error= my_net_write(net, buff, sizeof(buff));
+  if (stmt->param_count && ! error)
+  {
+    error= thd->protocol_text.send_fields((List<Item> *)
+                                          &stmt->lex->param_list,
+                                          Protocol::SEND_EOF);
+  }
+  /* Flag that a response has already been sent */
+  thd->main_da.disable_status();
+  DBUG_RETURN(error);
 }
 #else
 static bool send_prep_stmt(Prepared_statement *stmt,
@@ -259,6 +266,7 @@ static bool send_prep_stmt(Prepared_stat
   thd->client_stmt_id= stmt->id;
   thd->client_param_count= stmt->param_count;
   thd->clear_error();
+  thd->main_da.disable_status();
 
   return 0;
 }
@@ -2526,6 +2534,8 @@ void mysql_stmt_close(THD *thd, char *pa
   DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE));
   (void) stmt->deallocate();
 
+  thd->main_da.disable_status();
+
   DBUG_VOID_RETURN;
 }
 
@@ -2590,6 +2600,8 @@ void mysql_stmt_get_longdata(THD *thd, c
   DBUG_ENTER("mysql_stmt_get_longdata");
 
   status_var_increment(thd->status_var.com_stmt_send_long_data);
+
+  thd->main_da.disable_status();
 #ifndef EMBEDDED_LIBRARY
   /* Minimal size of long data packet is 6 bytes */
   if (packet_length < MYSQL_LONG_DATA_HEADER)
@@ -2664,11 +2676,7 @@ bool Select_fetch_protocol_binary::send_
 
 bool Select_fetch_protocol_binary::send_eof()
 {
-  Protocol *save_protocol= thd->protocol;
-
-  thd->protocol= &protocol;
   ::send_eof(thd);
-  thd->protocol= save_protocol;
   return FALSE;
 }
 
@@ -3097,7 +3105,6 @@ bool Prepared_statement::execute(String 
                                           thd->query_length) <= 0)
     {
       error= mysql_execute_command(thd);
-      query_cache_end_of_result(thd);
     }
   }
 
diff -Nrup a/sql/sql_select.cc b/sql/sql_select.cc
--- a/sql/sql_select.cc	2007-11-01 17:07:59 +03:00
+++ b/sql/sql_select.cc	2007-11-03 15:25:58 +03:00
@@ -890,7 +890,6 @@ JOIN::optimize()
       }
       if (res > 1)
       {
-        thd->fatal_error();
         error= res;
         DBUG_PRINT("error",("Error from opt_sum_query"));
 	DBUG_RETURN(1);
@@ -14436,6 +14435,7 @@ calc_group_buffer(JOIN *join,ORDER *grou
       default:
         /* This case should never be choosen */
         DBUG_ASSERT(0);
+        my_error(ER_OUT_OF_RESOURCES, MYF(0));
         join->thd->fatal_error();
       }
     }
diff -Nrup a/sql/sql_servers.cc b/sql/sql_servers.cc
--- a/sql/sql_servers.cc	2007-08-13 17:11:14 +04:00
+++ b/sql/sql_servers.cc	2007-11-03 15:25:58 +03:00
@@ -238,7 +238,7 @@ bool servers_reload(THD *thd)
   if (simple_open_n_lock_tables(thd, tables))
   {
     sql_print_error("Can't open and lock privilege tables: %s",
-		    thd->net.last_error);
+		    thd->main_da.message());
     goto end;
   }
 
diff -Nrup a/sql/sql_show.cc b/sql/sql_show.cc
--- a/sql/sql_show.cc	2007-10-23 12:20:49 +04:00
+++ b/sql/sql_show.cc	2007-11-03 15:25:58 +03:00
@@ -576,7 +576,8 @@ mysqld_show_create(THD *thd, TABLE_LIST 
   /* Only one table for now, but VIEW can involve several tables */
   if (open_normal_and_derived_tables(thd, table_list, 0))
   {
-    if (!table_list->view || thd->net.last_errno != ER_VIEW_INVALID)
+    if (!table_list->view ||
+        thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID)
       DBUG_RETURN(TRUE);
 
     /*
@@ -784,10 +785,9 @@ mysqld_list_fields(THD *thd, TABLE_LIST 
   }
   restore_record(table, s->default_values);              // Get empty record
   table->use_all_columns();
-  if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS |
-                                              Protocol::SEND_EOF))
+  if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS))
     DBUG_VOID_RETURN;
-  thd->protocol->flush();
+  send_eof(thd);
   DBUG_VOID_RETURN;
 }
 
@@ -2917,7 +2917,7 @@ static int fill_schema_table_names(THD *
     default:
       DBUG_ASSERT(0);
     }
-    if (thd->net.last_errno == ER_NO_SUCH_TABLE)
+    if (thd->is_error() && thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
     {
       thd->clear_error();
       return 0;
@@ -3265,8 +3265,16 @@ int get_all_tables(THD *thd, TABLE_LIST 
             res= open_normal_and_derived_tables(thd, show_table_list,
                                                 MYSQL_LOCK_IGNORE_FLUSH);
             lex->sql_command= save_sql_command;
-            
-            if (thd->net.last_errno == ER_NO_SUCH_TABLE)
+            /*
+              XXX:  show_table_list has a flag i_is_requested,
+              and when it's set, open_normal_and_derived_tables()
+              can return an error without setting an error message
+              in THD, which is a hack. This is why we have to
+              check for res, then for thd->is_error() only then
+              for thd->main_da.sql_errno().
+            */
+            if (res && thd->is_error() &&
+                thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
             {
               /*
                 Hide error for not existing table.
@@ -3420,7 +3428,7 @@ static int get_schema_tables_record(THD 
     /*
       there was errors during opening tables
     */
-    const char *error= thd->net.last_error;
+    const char *error= thd->main_da.message();
     if (tables->view)
       table->field[3]->store(STRING_WITH_LEN("VIEW"), cs);
     else if (tables->schema_table)
@@ -3622,7 +3630,7 @@ static int get_schema_column_record(THD 
         rather than in SHOW COLUMNS
       */ 
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                   thd->net.last_errno, thd->net.last_error);
+                   thd->main_da.sql_errno(), thd->main_da.message());
       thd->clear_error();
       res= 0;
     }
@@ -4093,9 +4101,9 @@ static int get_schema_stat_record(THD *t
         I.e. we are in SELECT FROM INFORMATION_SCHEMA.STATISTICS
         rather than in SHOW KEYS
       */
-      if (thd->net.last_errno)
+      if (thd->is_error())
         push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                     thd->net.last_errno, thd->net.last_error);
+                     thd->main_da.sql_errno(), thd->main_da.message());
       thd->clear_error();
       res= 0;
     }
@@ -4285,9 +4293,9 @@ static int get_schema_views_record(THD *
 
     if (schema_table_store_record(thd, table))
       DBUG_RETURN(1);
-    if (res && thd->net.last_errno)
+    if (res && thd->is_error())
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
-                   thd->net.last_errno, thd->net.last_error);
+                   thd->main_da.sql_errno(), thd->main_da.message());
   }
   if (res) 
     thd->clear_error();
@@ -4318,9 +4326,9 @@ static int get_schema_constraints_record
   DBUG_ENTER("get_schema_constraints_record");
   if (res)
   {
-    if (thd->net.last_errno)
+    if (thd->is_error())
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                   thd->net.last_errno, thd->net.last_error);
+                   thd->main_da.sql_errno(), thd->main_da.message());
     thd->clear_error();
     DBUG_RETURN(0);
   }
@@ -4423,9 +4431,9 @@ static int get_schema_triggers_record(TH
   */
   if (res)
   {
-    if (thd->net.last_errno)
+    if (thd->is_error())
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                   thd->net.last_errno, thd->net.last_error);
+                   thd->main_da.sql_errno(), thd->main_da.message());
     thd->clear_error();
     DBUG_RETURN(0);
   }
@@ -4506,9 +4514,9 @@ static int get_schema_key_column_usage_r
   DBUG_ENTER("get_schema_key_column_usage_record");
   if (res)
   {
-    if (thd->net.last_errno)
+    if (thd->is_error())
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                   thd->net.last_errno, thd->net.last_error);
+                   thd->main_da.sql_errno(), thd->main_da.message());
     thd->clear_error();
     DBUG_RETURN(0);
   }
@@ -4701,9 +4709,9 @@ static int get_schema_partitions_record(
 
   if (res)
   {
-    if (thd->net.last_errno)
+    if (thd->is_error())
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                   thd->net.last_errno, thd->net.last_error);
+                   thd->main_da.sql_errno(), thd->main_da.message());
     thd->clear_error();
     DBUG_RETURN(0);
   }
@@ -4746,6 +4754,7 @@ static int get_schema_partitions_record(
       break;
     default:
       DBUG_ASSERT(0);
+      my_error(ER_OUT_OF_RESOURCES, MYF(0));
       current_thd->fatal_error();
       DBUG_RETURN(1);
     }
@@ -5238,9 +5247,9 @@ get_referential_constraints_record(THD *
 
   if (res)
   {
-    if (thd->net.last_errno)
+    if (thd->is_error())
       push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                   thd->net.last_errno, thd->net.last_error);
+                   thd->main_da.sql_errno(), thd->main_da.message());
     thd->clear_error();
     DBUG_RETURN(0);
   }
diff -Nrup a/sql/sql_table.cc b/sql/sql_table.cc
--- a/sql/sql_table.cc	2007-11-02 01:48:11 +03:00
+++ b/sql/sql_table.cc	2007-11-03 15:25:58 +03:00
@@ -4163,17 +4163,21 @@ static bool mysql_admin_table(THD* thd, 
           (table->table->file->ha_check_for_upgrade(check_opt) ==
            HA_ADMIN_NEEDS_ALTER))
       {
-        my_bool save_no_send_ok= thd->net.no_send_ok;
         ha_autocommit_or_rollback(thd, 1);
         close_thread_tables(thd);
         tmp_disable_binlog(thd); // binlogging is done by caller if wanted
-        thd->net.no_send_ok= TRUE;
         result_code= mysql_recreate_table(thd, table);
-        thd->net.no_send_ok= save_no_send_ok;
         reenable_binlog(thd);
+        /*
+          mysql_recreate_table() can push OK or ERROR.
+          Clear 'OK' status. If there is an error, keep it:
+          we will store the error message in a result set row 
+          and then clear.
+        */
+        if (thd->main_da.is_ok())
+          thd->main_da.reset_diagnostics_area();
         goto send_result;
       }
-
     }
 
     result_code = (table->table->file->*operator_func)(thd, check_opt);
@@ -4265,7 +4269,6 @@ send_result_message:
 
     case HA_ADMIN_TRY_ALTER:
     {
-      my_bool save_no_send_ok= thd->net.no_send_ok;
       /*
         This is currently used only by InnoDB. ha_innobase::optimize() answers
         "try with alter", so here we close the table, do an ALTER TABLE,
@@ -4277,10 +4280,16 @@ send_result_message:
                  *save_next_global= table->next_global;
       table->next_local= table->next_global= 0;
       tmp_disable_binlog(thd); // binlogging is done by caller if wanted
-      thd->net.no_send_ok= TRUE;
       result_code= mysql_recreate_table(thd, table);
-      thd->net.no_send_ok= save_no_send_ok;
       reenable_binlog(thd);
+      /*
+        mysql_recreate_table() can push OK or ERROR.
+        Clear 'OK' status. If there is an error, keep it:
+        we will store the error message in a result set row 
+        and then clear.
+      */
+      if (thd->main_da.is_ok())
+        thd->main_da.reset_diagnostics_area();
       ha_autocommit_or_rollback(thd, 0);
       close_thread_tables(thd);
       if (!result_code) // recreation went ok
@@ -4291,9 +4300,10 @@ send_result_message:
       }
       if (result_code) // either mysql_recreate_table or analyze failed
       {
-        const char *err_msg;
-        if ((err_msg= thd->net.last_error))
+        DBUG_ASSERT(thd->is_error());
+        if (thd->is_error())
         {
+          const char *err_msg= thd->main_da.message();
           if (!thd->vio_ok())
           {
             sql_print_error(err_msg);
@@ -4309,6 +4319,7 @@ send_result_message:
             protocol->store(table_name, system_charset_info);
             protocol->store(operator_name, system_charset_info);
           }
+          thd->clear_error();
         }
       }
       result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
diff -Nrup a/sql/table.cc b/sql/table.cc
--- a/sql/table.cc	2007-10-23 18:02:26 +04:00
+++ b/sql/table.cc	2007-11-03 15:25:58 +03:00
@@ -3265,31 +3265,32 @@ bool TABLE_LIST::prep_check_option(THD *
 }
 
 
-/*
+/**
   Hide errors which show view underlying table information
 
-  SYNOPSIS
-    TABLE_LIST::hide_view_error()
-    thd     thread handler
+  @param[in,out]  thd     thread handler
 
+  @pre This method can be called only if there is an error.
 */
 
 void TABLE_LIST::hide_view_error(THD *thd)
 {
   /* Hide "Unknown column" or "Unknown function" error */
-  if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
-      thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
-      thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
-      thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR ||
-      thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR ||
-      thd->net.last_errno == ER_TABLE_NOT_LOCKED ||
-      thd->net.last_errno == ER_NO_SUCH_TABLE)
+  DBUG_ASSERT(thd->is_error());
+
+  if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
+      thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST ||
+      thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR ||
+      thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR ||
+      thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR ||
+      thd->main_da.sql_errno() == ER_TABLE_NOT_LOCKED ||
+      thd->main_da.sql_errno() == ER_NO_SUCH_TABLE)
   {
     TABLE_LIST *top= top_table();
-    thd->clear_error(); 
+    thd->clear_error();
     my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
   }
-  else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
+  else if (thd->main_da.sql_errno() == ER_NO_DEFAULT_FOR_FIELD)
   {
     TABLE_LIST *top= top_table();
     thd->clear_error();
diff -Nrup a/sql/tztime.cc b/sql/tztime.cc
--- a/sql/tztime.cc	2007-08-13 17:11:14 +04:00
+++ b/sql/tztime.cc	2007-11-03 15:25:58 +03:00
@@ -1641,7 +1641,7 @@ my_tz_init(THD *org_thd, const char *def
   if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
   {
     sql_print_warning("Can't open and lock time zone table: %s "
-                      "trying to live without them", thd->net.last_error);
+                      "trying to live without them", thd->main_da.message());
     /* We will try emulate that everything is ok */
     return_val= time_zone_tables_exist= 0;
     goto end_with_setting_default_tz;
diff -Nrup a/sql-common/client.c b/sql-common/client.c
--- a/sql-common/client.c	2007-11-01 00:55:23 +03:00
+++ b/sql-common/client.c	2007-11-03 15:25:58 +03:00
@@ -289,8 +289,8 @@ void set_mysql_error(MYSQL *mysql, int e
   DBUG_ASSERT(mysql != 0);
 
   net= &mysql->net;
-  net->last_errno= errcode;
-  strmov(net->last_error, ER(errcode));
+  net->client_last_errno= errcode;
+  strmov(net->client_last_error, ER(errcode));
   strmov(net->sqlstate, sqlstate);
 
   DBUG_VOID_RETURN;
@@ -304,8 +304,8 @@ void set_mysql_error(MYSQL *mysql, int e
 
 void net_clear_error(NET *net)
 {
-  net->last_errno= 0;
-  net->last_error[0]= '\0';
+  net->client_last_errno= 0;
+  net->client_last_error[0]= '\0';
   strmov(net->sqlstate, not_error_sqlstate);
 }
 
@@ -331,9 +331,9 @@ static void set_mysql_extended_error(MYS
   DBUG_ASSERT(mysql != 0);
 
   net= &mysql->net;
-  net->last_errno= errcode;
+  net->client_last_errno= errcode;
   va_start(args, format);
-  my_vsnprintf(net->last_error, sizeof(net->last_error)-1,
+  my_vsnprintf(net->client_last_error, sizeof(net->client_last_error)-1,
                format, args);
   va_end(args);
   strmov(net->sqlstate, sqlstate);
@@ -667,7 +667,7 @@ cli_safe_read(MYSQL *mysql)
       return (packet_error);
 #endif /*MYSQL_SERVER*/
     end_server(mysql);
-    set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
+    set_mysql_error(mysql, net->client_last_errno == ER_NET_PACKET_TOO_LARGE ?
                     CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate);
     return (packet_error);
   }
@@ -676,7 +676,7 @@ cli_safe_read(MYSQL *mysql)
     if (len > 3)
     {
       char *pos=(char*) net->read_pos+1;
-      net->last_errno=uint2korr(pos);
+      net->client_last_errno=uint2korr(pos);
       pos+=2;
       len-=2;
       if (protocol_41(mysql) && pos[0] == '#')
@@ -684,8 +684,8 @@ cli_safe_read(MYSQL *mysql)
 	strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
 	pos+= SQLSTATE_LENGTH+1;
       }
-      (void) strmake(net->last_error,(char*) pos,
-		     min((uint) len,(uint) sizeof(net->last_error)-1));
+      (void) strmake(net->client_last_error,(char*) pos,
+		     min((uint) len,(uint) sizeof(net->client_last_error)-1));
     }
     else
       set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
@@ -701,7 +701,9 @@ cli_safe_read(MYSQL *mysql)
     mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
 
     DBUG_PRINT("error",("Got error: %d/%s (%s)",
-			net->last_errno, net->sqlstate, net->last_error));
+			net->client_last_errno,
+                        net->sqlstate,
+                        net->client_last_error));
     return(packet_error);
   }
   return len;
@@ -744,7 +746,6 @@ cli_advanced_command(MYSQL *mysql, enum 
   }
 
   net_clear_error(net);
-  net->report_error=0;
   mysql->info=0;
   mysql->affected_rows= ~(my_ulonglong) 0;
   /*
@@ -759,7 +760,7 @@ cli_advanced_command(MYSQL *mysql, enum 
   {
     DBUG_PRINT("error",("Can't send command to server. Error: %d",
 			socket_errno));
-    if (net->last_errno == ER_NET_PACKET_TOO_LARGE)
+    if (net->client_last_errno == ER_NET_PACKET_TOO_LARGE)
     {
       set_mysql_error(mysql, CR_NET_PACKET_TOO_LARGE, unknown_sqlstate);
       goto end;
@@ -845,7 +846,7 @@ static my_bool is_NT(void)
   RETURN VALUE
     0  success
    !0  network error or the server is not commercial.
-       Error code is saved in mysql->net.last_errno.
+       Error code is saved in mysql->net.client_last_errno.
 */
 
 static int check_license(MYSQL *mysql)
@@ -858,7 +859,7 @@ static int check_license(MYSQL *mysql)
 
   if (mysql_real_query(mysql, query, sizeof(query)-1))
   {
-    if (net->last_errno == ER_UNKNOWN_SYSTEM_VARIABLE)
+    if (net->client_last_errno == ER_UNKNOWN_SYSTEM_VARIABLE)
     {
       set_mysql_extended_error(mysql, CR_WRONG_LICENSE, unknown_sqlstate,
                                ER(CR_WRONG_LICENSE), required_license);
@@ -873,7 +874,7 @@ static int check_license(MYSQL *mysql)
     two is ever true for server variables now), or column value
     mismatch, set wrong license error.
   */
-  if (!net->last_errno &&
+  if (!net->client_last_errno &&
       (!row || !row[0] ||
        strncmp(row[0], required_license, sizeof(required_license))))
   {
@@ -881,7 +882,7 @@ static int check_license(MYSQL *mysql)
                              ER(CR_WRONG_LICENSE), required_license);
   }
   mysql_free_result(res);
-  return net->last_errno;
+  return net->client_last_errno;
 }
 #endif /* CHECK_LICENSE */
 
@@ -2085,7 +2086,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
 
   if ((pkt_length=cli_safe_read(mysql)) == packet_error)
   {
-    if (mysql->net.last_errno == CR_SERVER_LOST)
+    if (mysql->net.client_last_errno == CR_SERVER_LOST)
       set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
                                ER(CR_SERVER_LOST_EXTENDED),
                                "reading initial communication packet",
@@ -2319,7 +2320,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
 
   if ((pkt_length=cli_safe_read(mysql)) == packet_error)
   {
-    if (mysql->net.last_errno == CR_SERVER_LOST)
+    if (mysql->net.client_last_errno == CR_SERVER_LOST)
       set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
                                ER(CR_SERVER_LOST_EXTENDED),
                                "reading authorization packet",
@@ -2347,7 +2348,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
     /* Read what server thinks about out new auth message report */
     if (cli_safe_read(mysql) == packet_error)
     {
-      if (mysql->net.last_errno == CR_SERVER_LOST)
+      if (mysql->net.client_last_errno == CR_SERVER_LOST)
         set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
                                  ER(CR_SERVER_LOST_EXTENDED),
                                  "reading final connect information",
@@ -2366,7 +2367,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
 
   if (db && mysql_select_db(mysql, db))
   {
-    if (mysql->net.last_errno == CR_SERVER_LOST)
+    if (mysql->net.client_last_errno == CR_SERVER_LOST)
         set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
                                  ER(CR_SERVER_LOST_EXTENDED),
                                  "Setting intital database",
@@ -2410,7 +2411,9 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
 error:
   reset_sigpipe(mysql);
   DBUG_PRINT("error",("message: %u/%s (%s)",
-		      net->last_errno, net->sqlstate, net->last_error));
+		      net->client_last_errno,
+                      net->sqlstate,
+                      net->client_last_error));
   {
     /* Free alloced memory */
     end_server(mysql);
@@ -2468,8 +2471,8 @@ my_bool mysql_reconnect(MYSQL *mysql)
 			  mysql->db, mysql->port, mysql->unix_socket,
 			  mysql->client_flag | CLIENT_REMEMBER_OPTIONS))
   {
-    mysql->net.last_errno= tmp_mysql.net.last_errno;
-    strmov(mysql->net.last_error, tmp_mysql.net.last_error);
+    mysql->net.client_last_errno= tmp_mysql.net.client_last_errno;
+    strmov(mysql->net.client_last_error, tmp_mysql.net.client_last_error);
     strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
     DBUG_RETURN(1);
   }
@@ -2478,8 +2481,8 @@ my_bool mysql_reconnect(MYSQL *mysql)
     DBUG_PRINT("error", ("mysql_set_character_set() failed"));
     bzero((char*) &tmp_mysql.options,sizeof(tmp_mysql.options));
     mysql_close(&tmp_mysql);
-    mysql->net.last_errno= tmp_mysql.net.last_errno;
-    strmov(mysql->net.last_error, tmp_mysql.net.last_error);
+    mysql->net.client_last_errno= tmp_mysql.net.client_last_errno;
+    strmov(mysql->net.client_last_error, tmp_mysql.net.client_last_error);
     strmov(mysql->net.sqlstate, tmp_mysql.net.sqlstate);
     DBUG_RETURN(1);
   }
@@ -3072,13 +3075,13 @@ unsigned int STDCALL mysql_num_fields(MY
 
 uint STDCALL mysql_errno(MYSQL *mysql)
 {
-  return mysql->net.last_errno;
+  return mysql->net.client_last_errno;
 }
 
 
 const char * STDCALL mysql_error(MYSQL *mysql)
 {
-  return mysql->net.last_error;
+  return mysql->net.client_last_error;
 }
 
 
@@ -3147,7 +3150,7 @@ int STDCALL mysql_set_character_set(MYSQ
                              ER(CR_CANT_READ_CHARSET), cs_name, cs_dir_name);
   }
   charsets_dir= save_csdir;
-  return mysql->net.last_errno;
+  return mysql->net.client_last_errno;
 }
 
 
Thread
bk commit into 5.1 tree (kostja:1.2606) BUG#12713konstantin3 Nov