List:Commits« Previous MessageNext Message »
From:Konstantin Osipov Date:November 14 2008 8:47pm
Subject:bzr push into mysql-6.0-runtime branch (kostja:2744 to 2745) WL#4264
View as plain text  
 2745 Konstantin Osipov	2008-11-14
      A pre-requisite patch for WL#4264 "Backup: Stabilize Service Interface"
      Move all warning-related information to Warning_info structure,
      to be able to reset and restore this structure.
modified:
  libmysqld/emb_qcache.cc
  libmysqld/lib_sql.cc
  mysql-test/r/query_cache.result
  sql/backup/kernel.cc
  sql/event_scheduler.cc
  sql/field.cc
  sql/ha_ndbcluster_binlog.cc
  sql/handler.cc
  sql/log.cc
  sql/log_event.cc
  sql/mysqld.cc
  sql/protocol.cc
  sql/set_var.cc
  sql/slave.cc
  sql/sp.cc
  sql/sp_rcontext.cc
  sql/sp_rcontext.h
  sql/sql_acl.cc
  sql/sql_base.cc
  sql/sql_class.cc
  sql/sql_class.h
  sql/sql_error.cc
  sql/sql_error.h
  sql/sql_insert.cc
  sql/sql_load.cc
  sql/sql_parse.cc
  sql/sql_prepare.cc
  sql/sql_select.cc
  sql/sql_show.cc
  sql/sql_table.cc
  sql/sql_update.cc
  sql/time.cc
  sql/unireg.cc

 2744 Alexander Nozdrin	2008-11-12 [merge]
      Pull from 6.0
modified:
  mysys/my_init.c
  sql/sql_cache.cc

=== modified file 'libmysqld/emb_qcache.cc'
--- a/libmysqld/emb_qcache.cc	2008-07-10 23:45:24 +0000
+++ b/libmysqld/emb_qcache.cc	2008-11-14 20:45:00 +0000
@@ -483,7 +483,8 @@ int emb_load_querycache_result(THD *thd,
   *prev_row= NULL;
   data->embedded_info->prev_ptr= prev_row;
 return_ok:
-  net_send_eof(thd, thd->server_status, thd->total_warn_count);
+  net_send_eof(thd, thd->server_status,
+               thd->warning_info.statement_warn_count());
   DBUG_RETURN(0);
 err:
   DBUG_RETURN(1);

=== modified file 'libmysqld/lib_sql.cc'
--- a/libmysqld/lib_sql.cc	2008-09-04 18:30:34 +0000
+++ b/libmysqld/lib_sql.cc	2008-11-14 20:45:00 +0000
@@ -208,7 +208,7 @@ static my_bool emb_read_prepare_result(M
   stmt->stmt_id= thd->client_stmt_id;
   stmt->param_count= thd->client_param_count;
   stmt->field_count= 0;
-  mysql->warning_count= thd->total_warn_count;
+  mysql->warning_count= thd->warning_info.statement_warn_count();
 
   if (thd->first_data)
   {
@@ -797,7 +797,7 @@ MYSQL_DATA *THD::alloc_new_dataset()
 
 static
 void
-write_eof_packet(THD *thd, uint server_status, uint total_warn_count)
+write_eof_packet(THD *thd, uint server_status, uint statement_warn_count)
 {
   if (!thd->mysql)            // bootstrap file handling
     return;
@@ -814,7 +814,7 @@ write_eof_packet(THD *thd, uint server_s
     is cleared between substatements, and mysqltest gets confused
   */
   thd->cur_data->embedded_info->warning_count=
-    (thd->spcont ? 0 : min(total_warn_count, 65535));
+    (thd->spcont ? 0 : min(statement_warn_count, 65535));
 }
 
 
@@ -970,7 +970,8 @@ bool Protocol::send_result_set_metadata(
   }
 
   if (flags & SEND_EOF)
-    write_eof_packet(thd, thd->server_status, thd->total_warn_count);
+    write_eof_packet(thd, thd->server_status,
+                     thd->warning_info.statement_warn_count());
 
   DBUG_RETURN(prepare_for_send(list->elements));
  err:
@@ -1030,7 +1031,7 @@ bool Protocol_binary::write()
 
 void
 net_send_ok(THD *thd,
-            uint server_status, uint total_warn_count,
+            uint server_status, uint statement_warn_count,
             ha_rows affected_rows, ulonglong id, const char *message)
 {
   DBUG_ENTER("emb_net_send_ok");
@@ -1047,7 +1048,7 @@ net_send_ok(THD *thd,
     strmake(data->embedded_info->info, message,
             sizeof(data->embedded_info->info)-1);
 
-  write_eof_packet(thd, server_status, total_warn_count);
+  write_eof_packet(thd, server_status, statement_warn_count);
   thd->cur_data= 0;
   DBUG_VOID_RETURN;
 }
@@ -1062,9 +1063,9 @@ net_send_ok(THD *thd,
 */
 
 void
-net_send_eof(THD *thd, uint server_status, uint total_warn_count)
+net_send_eof(THD *thd, uint server_status, uint statement_warn_count)
 {
-  write_eof_packet(thd, server_status, total_warn_count);
+  write_eof_packet(thd, server_status, statement_warn_count);
   thd->cur_data= 0;
 }
 

=== modified file 'mysql-test/r/query_cache.result'
--- a/mysql-test/r/query_cache.result	2008-10-20 09:16:47 +0000
+++ b/mysql-test/r/query_cache.result	2008-11-14 20:45:00 +0000
@@ -942,19 +942,19 @@ COUNT(*)
 0
 Warnings:
 Warning	1292	Incorrect datetime value: '20050327 invalid' for column 'date' at row 1
-Warning	1292	Incorrect datetime value: '20050327 invalid' for column 'date' at row 0
+Warning	1292	Incorrect datetime value: '20050327 invalid' for column 'date' at row 1
 SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050328 invalid';
 COUNT(*)
 0
 Warnings:
 Warning	1292	Incorrect datetime value: '20050328 invalid' for column 'date' at row 1
-Warning	1292	Incorrect datetime value: '20050328 invalid' for column 'date' at row 0
+Warning	1292	Incorrect datetime value: '20050328 invalid' for column 'date' at row 1
 SELECT COUNT(*) FROM t1 WHERE date BETWEEN '20050326' AND '20050327 invalid';
 COUNT(*)
 0
 Warnings:
 Warning	1292	Incorrect datetime value: '20050327 invalid' for column 'date' at row 1
-Warning	1292	Incorrect datetime value: '20050327 invalid' for column 'date' at row 0
+Warning	1292	Incorrect datetime value: '20050327 invalid' for column 'date' at row 1
 show status like "Qcache_queries_in_cache";
 Variable_name	Value
 Qcache_queries_in_cache	0

=== modified file 'sql/backup/kernel.cc'
--- a/sql/backup/kernel.cc	2008-11-06 18:39:27 +0000
+++ b/sql/backup/kernel.cc	2008-11-14 20:45:00 +0000
@@ -490,7 +490,7 @@ int Backup_restore_ctx::prepare(String *
   
   // Prepare error reporting context.
   
-  mysql_reset_errors(m_thd, 0);                 // Never errors
+  m_thd->warning_info.opt_clear_warning_info(m_thd->query_id); // Never errors
   m_thd->no_warnings_for_error= FALSE;
 
   save_errors();                                // Never errors

=== modified file 'sql/event_scheduler.cc'
--- a/sql/event_scheduler.cc	2008-10-21 08:51:31 +0000
+++ b/sql/event_scheduler.cc	2008-11-14 20:45:00 +0000
@@ -74,7 +74,7 @@ Event_worker_thread::print_warnings(THD 
 {
   MYSQL_ERROR *err;
   DBUG_ENTER("evex_print_warnings");
-  if (!thd->warn_list.elements)
+  if (thd->warning_info.is_empty())
     DBUG_VOID_RETURN;
 
   char msg_buf[10 * STRING_BUFFER_USUAL_SIZE];
@@ -90,7 +90,7 @@ Event_worker_thread::print_warnings(THD 
   prefix.append(et->name.str, et->name.length, system_charset_info);
   prefix.append("] ", 2);
 
-  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+  List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
   while ((err= it++))
   {
     String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2008-11-06 18:39:27 +0000
+++ b/sql/field.cc	2008-11-14 20:45:00 +0000
@@ -1116,7 +1116,7 @@ int Field_num::check_int(CHARSET_INFO *c
                         ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, 
                         ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
                         "integer", tmp.c_ptr(), field_name,
-                        (ulong) table->in_use->row_count);
+                        table->in_use->warning_info.current_row_for_warning());
     return 1;
   }
   /* Test if we have garbage at the end of the given string. */
@@ -2599,7 +2599,7 @@ int Field_new_decimal::store(const char 
                         ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
                         ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
                         "decimal", from_as_str.c_ptr(), field_name,
-                        (ulong) table->in_use->row_count);
+                        table->in_use->warning_info.current_row_for_warning());
 
     DBUG_RETURN(err);
   }
@@ -2622,7 +2622,7 @@ int Field_new_decimal::store(const char 
                         ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
                         ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
                           "decimal", from_as_str.c_ptr(), field_name,
-                        (ulong) table->in_use->row_count);
+                        table->in_use->warning_info.current_row_for_warning());
     my_decimal_set_zero(&decimal_value);
 
     break;
@@ -2659,7 +2659,7 @@ int Field_new_decimal::store(double nr)
     if (check_overflow(err))
       set_value_on_overflow(&decimal_value, decimal_value.sign());
     /* Only issue a warning if store_value doesn't issue an warning */
-    table->in_use->got_warning= 0;
+    table->in_use->got_warning= FALSE;
   }
   if (store_value(&decimal_value))
     err= 1;
@@ -2681,7 +2681,7 @@ int Field_new_decimal::store(longlong nr
     if (check_overflow(err))
       set_value_on_overflow(&decimal_value, decimal_value.sign());
     /* Only issue a warning if store_value doesn't issue an warning */
-    table->in_use->got_warning= 0;
+    table->in_use->got_warning= FALSE;
   }
   if (store_value(&decimal_value))
     err= 1;
@@ -5168,7 +5168,7 @@ bool Field_time::get_date(MYSQL_TIME *lt
     push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                         ER_WARN_DATA_OUT_OF_RANGE,
                         ER(ER_WARN_DATA_OUT_OF_RANGE), field_name,
-                        thd->row_count);
+                        thd->warning_info.current_row_for_warning());
     return 1;
   }
   tmp=(long) sint3korr(ptr);
@@ -6158,6 +6158,7 @@ check_string_copy_error(Field_str *field
 {
   const char *pos, *end_orig;
   char tmp[64], *t;
+  THD *thd= field->table->in_use;
   
   if (!(pos= well_formed_error_pos) &&
       !(pos= cannot_convert_error_pos))
@@ -6198,12 +6199,12 @@ check_string_copy_error(Field_str *field
     *t++= '.';
   }
   *t= '\0';
-  push_warning_printf(field->table->in_use,
+  push_warning_printf(thd,
                       MYSQL_ERROR::WARN_LEVEL_WARN,
                       ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
                       ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
                       "string", tmp, field->field_name,
-                      (ulong) field->table->in_use->row_count);
+                      thd->warning_info.current_row_for_warning());
   return TRUE;
 }
 
@@ -10107,7 +10108,7 @@ Field::set_warning(MYSQL_ERROR::enum_war
   {
     thd->cuted_fields+= cuted_increment;
     push_warning_printf(thd, level, code, ER(code), field_name,
-                        thd->row_count);
+                        thd->warning_info.current_row_for_warning());
     return 0;
   }
   return level >= MYSQL_ERROR::WARN_LEVEL_WARN;

=== modified file 'sql/ha_ndbcluster_binlog.cc'
--- a/sql/ha_ndbcluster_binlog.cc	2008-07-14 12:49:19 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2008-11-14 20:45:00 +0000
@@ -1899,7 +1899,7 @@ ndb_binlog_thread_handle_schema_event(TH
                             "my_errno: %d",
                             schema->db, schema->name, schema->query,
                             schema->node_id, my_errno);
-            List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+            List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
             MYSQL_ERROR *err;
             while ((err= it++))
               sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
@@ -2259,7 +2259,7 @@ ndb_binlog_thread_handle_schema_event_po
                             "binlog schema event '%s' from node %d. my_errno: %d",
                             schema->db, schema->name, schema->query,
                             schema->node_id, my_errno);
-            List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+            List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
             MYSQL_ERROR *err;
             while ((err= it++))
               sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);
@@ -2438,7 +2438,7 @@ ndb_binlog_thread_handle_schema_event_po
                             "binlog schema event '%s' from node %d. my_errno: %d",
                             schema->db, schema->name, schema->query,
                             schema->node_id, my_errno);
-            List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+            List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
             MYSQL_ERROR *err;
             while ((err= it++))
               sql_print_warning("NDB Binlog: (%d)%s", err->code, err->msg);

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2008-11-06 18:46:03 +0000
+++ b/sql/handler.cc	2008-11-14 20:45:00 +0000
@@ -1862,20 +1862,20 @@ const char *get_canonical_filename(handl
 struct Ha_delete_table_error_handler: public Internal_error_handler
 {
 public:
-  virtual bool handle_error(uint sql_errno,
-                            const char *message,
+  virtual bool handle_error(THD *thd,
                             MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+                            uint sql_errno,
+                            const char *message);
   char buff[MYSQL_ERRMSG_SIZE];
 };
 
 
 bool
 Ha_delete_table_error_handler::
-handle_error(uint sql_errno,
-             const char *message,
+handle_error(THD *thd,
              MYSQL_ERROR::enum_warning_level level,
-             THD *thd)
+             uint sql_errno,
+             const char *message)
 {
   /* Grab the error message */
   strmake(buff, message, sizeof(buff)-1);

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2008-11-06 18:39:27 +0000
+++ b/sql/log.cc	2008-11-14 20:45:00 +0000
@@ -83,17 +83,18 @@ public:
 
   virtual ~Silence_log_table_errors() {}
 
-  virtual bool handle_error(uint sql_errno, const char *message,
+  virtual bool handle_error(THD *thd,
                             MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+                            uint sql_errno, const char *message);
   const char *message() const { return m_message; }
 };
 
 bool
-Silence_log_table_errors::handle_error(uint /* sql_errno */,
-                                       const char *message_arg,
-                                       MYSQL_ERROR::enum_warning_level /* level */,
-                                       THD * /* thd */)
+Silence_log_table_errors::
+handle_error(THD * /* thd */,
+             MYSQL_ERROR::enum_warning_level /* level */,
+             uint /* sql_errno */,
+             const char *message_arg)
 {
   strmake(m_message, message_arg, sizeof(m_message)-1);
   return TRUE;

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2008-11-06 18:46:03 +0000
+++ b/sql/log_event.cc	2008-11-14 20:45:00 +0000
@@ -133,7 +133,7 @@ static void inline slave_rows_error_repo
   char buff[MAX_SLAVE_ERRMSG], *slider;
   const char *buff_end= buff + sizeof(buff);
   uint len;
-  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+  List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
   MYSQL_ERROR *err;
   buff[0]= 0;
 
@@ -4369,13 +4369,7 @@ int Load_log_event::do_apply_event(NET* 
     pthread_mutex_lock(&LOCK_thread_count);
     thd->query_id = next_query_id();
     pthread_mutex_unlock(&LOCK_thread_count);
-    /*
-      Initing thd->row_count is not necessary in theory as this variable has no
-      influence in the case of the slave SQL thread (it is used to generate a
-      "data truncated" warning but which is absorbed and never gets to the
-      error log); still we init it to avoid a Valgrind message.
-    */
-    mysql_reset_errors(thd, 0);
+    thd->warning_info.opt_clear_warning_info(thd->query_id);
 
     TABLE_LIST tables;
     bzero((char*) &tables,sizeof(tables));

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2008-11-10 09:53:30 +0000
+++ b/sql/mysqld.cc	2008-11-14 20:45:00 +0000
@@ -3022,7 +3022,7 @@ void my_message_sql(uint error, const ch
       TODO: There are two exceptions mechanism (THD and sp_rcontext),
       this could be improved by having a common stack of handlers.
     */
-    if (thd->handle_error(error, str, level))
+    if (thd->handle_error(level, error, str))
       DBUG_VOID_RETURN;
 
     if (level == MYSQL_ERROR::WARN_LEVEL_WARN)
@@ -3060,7 +3060,7 @@ void my_message_sql(uint error, const ch
     */
     if (!thd->is_fatal_error && thd->spcont &&
         ! (MyFlags & ME_NO_SP_HANDLER) &&
-        thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
+        thd->spcont->handle_error(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error))
     {
       /*
         Do not push any warnings, a handled error must be completely

=== modified file 'sql/protocol.cc'
--- a/sql/protocol.cc	2008-10-20 09:16:47 +0000
+++ b/sql/protocol.cc	2008-11-14 20:45:00 +0000
@@ -31,10 +31,10 @@ static const unsigned int PACKET_BUFFER_
 /* 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 *, uint, uint, ha_rows, ulonglong, const char *);
-void net_send_eof(THD *thd, uint server_status, uint total_warn_count);
+void net_send_eof(THD *thd, uint server_status, uint statement_warn_count);
 #ifndef EMBEDDED_LIBRARY
 static void write_eof_packet(THD *thd, NET *net,
-                             uint server_status, uint total_warn_count);
+                             uint server_status, uint statement_warn_count);
 #endif
 
 #ifndef EMBEDDED_LIBRARY
@@ -178,7 +178,7 @@ void net_send_error(THD *thd, uint sql_e
 #ifndef EMBEDDED_LIBRARY
 void
 net_send_ok(THD *thd,
-            uint server_status, uint total_warn_count,
+            uint server_status, uint statement_warn_count,
             ha_rows affected_rows, ulonglong id, const char *message)
 {
   NET *net= &thd->net;
@@ -201,12 +201,12 @@ net_send_ok(THD *thd,
 		(ulong) affected_rows,		
 		(ulong) id,
 		(uint) (server_status & 0xffff),
-		(uint) total_warn_count));
+		(uint) statement_warn_count));
     int2store(pos, server_status);
     pos+=2;
 
     /* We can only return up to 65535 warnings in two bytes */
-    uint tmp= min(total_warn_count, 65535);
+    uint tmp= min(statement_warn_count, 65535);
     int2store(pos, tmp);
     pos+= 2;
   }
@@ -250,7 +250,7 @@ static uchar eof_buff[1]= { (uchar) 254 
 */    
 
 void
-net_send_eof(THD *thd, uint server_status, uint total_warn_count)
+net_send_eof(THD *thd, uint server_status, uint statement_warn_count)
 {
   NET *net= &thd->net;
   DBUG_ENTER("net_send_eof");
@@ -258,7 +258,7 @@ net_send_eof(THD *thd, uint server_statu
   if (net->vio != 0)
   {
     thd->main_da.can_overwrite_status= TRUE;
-    write_eof_packet(thd, net, server_status, total_warn_count);
+    write_eof_packet(thd, net, server_status, statement_warn_count);
     (void) net_flush(net);
     thd->main_da.can_overwrite_status= FALSE;
     DBUG_PRINT("info", ("EOF sent, so no more error sending allowed"));
@@ -274,7 +274,7 @@ net_send_eof(THD *thd, uint server_statu
 
 static void write_eof_packet(THD *thd, NET *net,
                              uint server_status,
-                             uint total_warn_count)
+                             uint statement_warn_count)
 {
   if (thd->client_capabilities & CLIENT_PROTOCOL_41)
   {
@@ -283,7 +283,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= min(total_warn_count, 65535);
+    uint tmp= min(statement_warn_count, 65535);
     buff[0]= 254;
     int2store(buff+1, tmp);
     /*
@@ -450,12 +450,12 @@ void net_end_statement(THD *thd)
   case Diagnostics_area::DA_EOF:
     net_send_eof(thd,
                  thd->main_da.server_status(),
-                 thd->main_da.total_warn_count());
+                 thd->main_da.statement_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.statement_warn_count(),
                 thd->main_da.affected_rows(),
                 thd->main_da.last_insert_id(),
                 thd->main_da.message());
@@ -465,8 +465,7 @@ void net_end_statement(THD *thd)
   case Diagnostics_area::DA_EMPTY:
   default:
     DBUG_ASSERT(0);
-    net_send_ok(thd, thd->server_status, thd->total_warn_count,
-                0, 0, NULL);
+    net_send_ok(thd, thd->server_status, 0, 0, 0, NULL);
     break;
   }
   thd->main_da.is_sent= TRUE;
@@ -702,7 +701,8 @@ bool Protocol::send_result_set_metadata(
       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, thd->total_warn_count);
+    write_eof_packet(thd, &thd->net, thd->server_status,
+                     thd->warning_info.statement_warn_count());
   }
   DBUG_RETURN(prepare_for_send(list->elements));
 

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2008-11-07 14:01:59 +0000
+++ b/sql/set_var.cc	2008-11-14 20:45:00 +0000
@@ -3434,17 +3434,14 @@ static int check_pseudo_thread_id(THD *t
 
 static uchar *get_warning_count(THD *thd)
 {
-  thd->sys_var_tmp.long_value=
-    (thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
-     thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] +
-     thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
+  thd->sys_var_tmp.long_value= thd->warning_info.warn_count();
+
   return (uchar*) &thd->sys_var_tmp.long_value;
 }
 
 static uchar *get_error_count(THD *thd)
 {
-  thd->sys_var_tmp.long_value= 
-    thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
+  thd->sys_var_tmp.long_value= thd->warning_info.error_count();
   return (uchar*) &thd->sys_var_tmp.long_value;
 }
 

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2008-11-06 18:39:27 +0000
+++ b/sql/slave.cc	2008-11-14 20:45:00 +0000
@@ -1670,7 +1670,7 @@ static int has_temporary_error(THD *thd)
   /*
     currently temporary error set in ndbcluster
   */
-  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+  List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
   MYSQL_ERROR *err;
   while ((err= it++))
   {
@@ -2610,7 +2610,7 @@ Slave SQL thread aborted. Can't execute 
         }
 
         /* Print any warnings issued */
-        List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+        List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
         MYSQL_ERROR *err;
         /*
           Added controlled slave thread cancel for replication

=== modified file 'sql/sp.cc'
--- a/sql/sp.cc	2008-07-15 16:29:51 +0000
+++ b/sql/sp.cc	2008-11-14 20:45:00 +0000
@@ -496,15 +496,15 @@ db_find_routine(THD *thd, int type, sp_n
 struct Silence_deprecated_warning : public Internal_error_handler
 {
 public:
-  virtual bool handle_error(uint sql_errno, const char *message,
+  virtual bool handle_error(THD *thd,
                             MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+                            uint sql_errno, const char *message);
 };
 
 bool
-Silence_deprecated_warning::handle_error(uint sql_errno, const char *message,
-                                         MYSQL_ERROR::enum_warning_level level,
-                                         THD *thd)
+Silence_deprecated_warning::
+handle_error(THD *thd, MYSQL_ERROR::enum_warning_level level,
+             uint sql_errno, const char *message)
 {
   if (sql_errno == ER_WARN_DEPRECATED_SYNTAX &&
       level == MYSQL_ERROR::WARN_LEVEL_WARN)
@@ -1329,7 +1329,7 @@ sp_exist_routines(THD *thd, TABLE_LIST *
                                      &thd->sp_proc_cache, FALSE) != NULL ||
                      sp_find_routine(thd, TYPE_ENUM_FUNCTION, name,
                                      &thd->sp_func_cache, FALSE) != NULL;
-    mysql_reset_errors(thd, TRUE);
+    thd->warning_info.clear_warning_info(thd->query_id);
     if (sp_object_found)
     {
       if (any)

=== modified file 'sql/sp_rcontext.cc'
--- a/sql/sp_rcontext.cc	2008-08-15 17:31:50 +0000
+++ b/sql/sp_rcontext.cc	2008-11-14 20:45:00 +0000
@@ -293,9 +293,8 @@ sp_rcontext::find_handler(THD *thd, uint
     FALSE      if no handler was found.
 */
 bool
-sp_rcontext::handle_error(uint sql_errno,
-                          MYSQL_ERROR::enum_warning_level level,
-                          THD *thd)
+sp_rcontext::handle_error(THD *thd, MYSQL_ERROR::enum_warning_level level,
+                          uint sql_errno)
 {
   MYSQL_ERROR::enum_warning_level elevated_level= level;
 

=== modified file 'sql/sp_rcontext.h'
--- a/sql/sp_rcontext.h	2008-08-15 17:31:50 +0000
+++ b/sql/sp_rcontext.h	2008-11-14 20:45:00 +0000
@@ -116,9 +116,8 @@ class sp_rcontext : public Sql_alloc
 
   // If there is an error handler for this error, handle it and return TRUE.
   bool
-  handle_error(uint sql_errno,
-               MYSQL_ERROR::enum_warning_level level,
-               THD *thd);
+  handle_error(THD *thd, MYSQL_ERROR::enum_warning_level level,
+               uint sql_errno);
 
   // Returns handler type and sets *ip to location if one was found
   inline int

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2008-10-20 19:13:22 +0000
+++ b/sql/sql_acl.cc	2008-11-14 20:45:00 +0000
@@ -6144,9 +6144,9 @@ public:
   virtual ~Silence_routine_definer_errors()
   {}
 
-  virtual bool handle_error(uint sql_errno, const char *message,
+  virtual bool handle_error(THD *thd,
                             MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+                            uint sql_errno, const char *message);
 
   bool has_errors() { return is_grave; }
 
@@ -6155,10 +6155,9 @@ private:
 };
 
 bool
-Silence_routine_definer_errors::handle_error(uint sql_errno,
-                                       const char *message,
-                                       MYSQL_ERROR::enum_warning_level level,
-                                       THD *thd)
+Silence_routine_definer_errors::
+handle_error(THD *thd, MYSQL_ERROR::enum_warning_level level,
+             uint sql_errno, const char *message)
 {
   if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
   {

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2008-11-06 18:39:27 +0000
+++ b/sql/sql_base.cc	2008-11-14 20:45:00 +0000
@@ -45,9 +45,9 @@ public:
 
   virtual ~Prelock_error_handler() {}
 
-  virtual bool handle_error(uint sql_errno, const char *message,
+  virtual bool handle_error(THD *thd,
                             MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+                            uint sql_errno, const char *message);
 
   bool safely_trapped_errors();
 
@@ -58,10 +58,10 @@ private:
 
 
 bool
-Prelock_error_handler::handle_error(uint sql_errno,
-                                    const char * /* message */,
+Prelock_error_handler::handle_error(THD * /* thd */,
                                     MYSQL_ERROR::enum_warning_level /* level */,
-                                    THD * /* thd */)
+                                    uint sql_errno,
+                                    const char * /* message */)
 {
   if (sql_errno == ER_NO_SUCH_TABLE)
   {
@@ -602,7 +602,7 @@ static TABLE_SHARE
     DBUG_RETURN(0);
   }
   /* Table existed in engine. Let's open it */
-  mysql_reset_errors(thd, 1);                   // Clear warnings
+  thd->warning_info.clear_warning_info(thd->query_id);
   thd->clear_error();                           // Clear error message
   DBUG_RETURN(get_table_share(thd, table_list, key, key_length,
                               db_flags, error));
@@ -3483,7 +3483,7 @@ recover_from_failed_open_table_attempt(T
       ha_create_table_from_engine(thd, table->db, table->table_name);
       pthread_mutex_unlock(&LOCK_open);
 
-      mysql_reset_errors(thd, 1);         // Clear warnings
+      thd->warning_info.clear_warning_info(thd->query_id);
       thd->clear_error();                 // Clear error message
       mdl_release_lock(&thd->mdl_context, table->mdl_lock_data);
       mdl_remove_lock(&thd->mdl_context, table->mdl_lock_data);

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2008-11-07 14:04:18 +0000
+++ b/sql/sql_class.cc	2008-11-14 20:45:00 +0000
@@ -304,7 +304,7 @@ int thd_tx_isolation(const THD *thd)
 extern "C"
 void thd_inc_row_count(THD *thd)
 {
-  thd->row_count++;
+  thd->warning_info.inc_current_row_for_warning();
 }
 
 
@@ -407,7 +407,7 @@ Diagnostics_area::reset_diagnostics_area
   m_server_status= 0;
   m_affected_rows= 0;
   m_last_insert_id= 0;
-  m_total_warn_count= 0;
+  m_statement_warn_count= 0;
 #endif
   is_sent= FALSE;
   /** Tiny reset in debug mode to see garbage right away */
@@ -436,7 +436,7 @@ Diagnostics_area::set_ok_status(THD *thd
     return;
 
   m_server_status= thd->server_status;
-  m_total_warn_count= thd->total_warn_count;
+  m_statement_warn_count= thd->warning_info.statement_warn_count();
   m_affected_rows= affected_rows_arg;
   m_last_insert_id= last_insert_id_arg;
   if (message_arg)
@@ -471,7 +471,8 @@ Diagnostics_area::set_eof_status(THD *th
     number of warnings, since they are not available to the client
     anyway.
   */
-  m_total_warn_count= thd->spcont ? 0 : thd->total_warn_count;
+  m_statement_warn_count= (thd->spcont ?
+                           0 : thd->warning_info.statement_warn_count());
 
   m_status= DA_EOF;
   DBUG_VOID_RETURN;
@@ -525,6 +526,59 @@ Diagnostics_area::disable_status()
 }
 
 
+Warning_info::Warning_info(query_id_t warn_id_arg)
+  :m_statement_warn_count(0),
+  m_current_row_for_warning(1),
+  m_warn_id(warn_id_arg)
+{
+  /* Initialize sub structures */
+  init_sql_alloc(&m_warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
+  m_warn_list.empty();
+  bzero((char*) m_warn_count, sizeof(m_warn_count));
+}
+
+
+Warning_info::~Warning_info()
+{
+  free_root(&m_warn_root,MYF(0));
+}
+
+
+/**
+  Reset the warning information of this connection.
+*/
+
+void Warning_info::clear_warning_info(query_id_t warn_id_arg)
+{
+  m_warn_id= warn_id_arg;
+  free_root(&m_warn_root, MYF(0));
+  bzero((char*) m_warn_count, sizeof(m_warn_count));
+  m_warn_list.empty();
+  m_statement_warn_count= 0;
+  m_current_row_for_warning= 1; /* Start counting from the first row */
+}
+
+
+/**
+  Add a warning to the list of warnings. Increment the respective
+  counters.
+*/
+
+void Warning_info::push_warning(THD *thd,
+                                MYSQL_ERROR::enum_warning_level level,
+                                uint code, const char *msg)
+{
+  if (m_warn_list.elements < thd->variables.max_error_count)
+  {
+    MYSQL_ERROR *err;
+    if ((err= new (&m_warn_root) MYSQL_ERROR(&m_warn_root, level, code, msg)))
+      m_warn_list.push_back(err, &m_warn_root);
+  }
+  m_warn_count[(uint) level]++;
+  m_statement_warn_count++;
+}
+
+
 THD::THD()
    :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION,
               /* statement id */ 0),
@@ -538,6 +592,7 @@ THD::THD()
    first_successful_insert_id_in_prev_stmt_for_binlog(0),
    first_successful_insert_id_in_cur_stmt(0),
    stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
+   warning_info(0),
    global_read_lock(0),
    is_fatal_error(0),
    transaction_rollback_request(0),
@@ -584,7 +639,8 @@ THD::THD()
   hash_clear(&handler_tables_hash);
   tmp_table=0;
   used_tables=0;
-  cuted_fields= sent_row_count= row_count= 0L;
+  cuted_fields= 0L;
+  sent_row_count= 0L;
   limit_found_rows= 0;
   row_count_func= -1;
   statement_id_counter= 0UL;
@@ -603,7 +659,6 @@ THD::THD()
   one_shot_set= 0;
   file_id = 0;
   query_id= 0;
-  warn_id= 0;
   db_charset= global_system_variables.collation_database;
   bzero(ha_data, sizeof(ha_data));
   mysys_var=0;
@@ -644,8 +699,6 @@ THD::THD()
   init_open_tables_state(this, refresh_version);
 
   init();
-  /* Initialize sub structures */
-  init_sql_alloc(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE);
 #if defined(ENABLED_PROFILING)
   profiling.set_thd(this);
 #endif
@@ -691,13 +744,11 @@ void THD::push_internal_handler(Internal
 }
 
 
-bool THD::handle_error(uint sql_errno, const char *message,
-                       MYSQL_ERROR::enum_warning_level level)
+bool THD::handle_error(MYSQL_ERROR::enum_warning_level level,
+                       uint sql_errno, const char *message)
 {
   if (m_internal_handler)
-  {
-    return m_internal_handler->handle_error(sql_errno, message, level, this);
-  }
+    return m_internal_handler->handle_error(this, level, sql_errno, message);
 
   return FALSE;                                 // 'FALSE', as per coding style
 }
@@ -791,9 +842,6 @@ void THD::init(void)
 			TL_WRITE_LOW_PRIORITY :
 			TL_WRITE);
   session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
-  warn_list.empty();
-  bzero((char*) warn_count, sizeof(warn_count));
-  total_warn_count= 0;
   update_charset();
   reset_current_stmt_binlog_row_based();
   bzero((char *) &status_var, sizeof(status_var));
@@ -962,7 +1010,6 @@ THD::~THD()
   DBUG_PRINT("info", ("freeing security context"));
   main_security_ctx.destroy();
   safeFree(db);
-  free_root(&warn_root,MYF(0));
   free_root(&transaction.mem_root,MYF(0));
   mysys_var=0;					// Safety (shouldn't be needed)
   pthread_mutex_destroy(&LOCK_delete);

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2008-11-06 18:39:27 +0000
+++ b/sql/sql_class.h	2008-11-14 20:45:00 +0000
@@ -1133,10 +1133,10 @@ public:
     @param thd the calling thread
     @return true if the error is handled
   */
-  virtual bool handle_error(uint sql_errno,
-                            const char *message,
+  virtual bool handle_error(THD *thd,
                             MYSQL_ERROR::enum_warning_level level,
-                            THD *thd) = 0;
+                            uint sql_errno,
+                            const char *message) = 0;
 };
 
 
@@ -1203,10 +1203,10 @@ public:
   ulonglong last_insert_id() const
   { DBUG_ASSERT(m_status == DA_OK); return m_last_insert_id; }
 
-  uint total_warn_count() const
+  uint statement_warn_count() const
   {
     DBUG_ASSERT(m_status == DA_OK || m_status == DA_EOF);
-    return m_total_warn_count;
+    return m_statement_warn_count;
   }
 
   Diagnostics_area() { reset_diagnostics_area(); }
@@ -1247,8 +1247,13 @@ private:
     to implement LAST_INSERT_ID().
   */
   ulonglong   m_last_insert_id;
-  /** The total number of warnings. */
-  uint	     m_total_warn_count;
+  /**
+    Number of warnings of this last statement. May differ from
+    the number of warnings returned by SHOW WARNINGS e.g. in case
+    the statement doesn't clear the warnings, and doesn't generate
+    them.
+  */
+  uint	     m_statement_warn_count;
   enum_diagnostics_status m_status;
   /**
     @todo: the following THD members belong here:
@@ -1256,6 +1261,120 @@ private:
   */
 };
 
+
+/**
+  Information about warnings of the current connection.
+*/
+
+class Warning_info
+{
+  /** A memory root to allocate warnings and errors */
+  MEM_ROOT           m_warn_root;
+  /** List of warnings of all severities (levels). */
+  List <MYSQL_ERROR> m_warn_list;
+  /** A break down of the number of warnings per severity (level). */
+  uint	             m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
+  /**
+    The number of warnings of the current statement. Warning_info
+    life cycle differs from statement life cycle -- it may span
+    multiple statements. In that case we get
+    m_statement_warn_count 0, whereas m_warn_list is not empty.
+  */
+  uint	             m_statement_warn_count;
+  /*
+    Row counter, to print in errors and warnings. Not increased in
+    create_sort_index(); may differ from examined_row_count.
+  */
+  ulong              m_current_row_for_warning;
+  /** Used to optionally clear warnings only once per statement.  */
+  query_id_t         m_warn_id;
+
+private:
+  Warning_info(const Warning_info &rhs); /* Not implemented */
+  Warning_info& operator=(const Warning_info &rhs); /* Not implemented */
+public:
+
+  Warning_info(query_id_t warn_id_arg);
+  /* Do nothing - used to initialize a backup info */
+  Warning_info() { clear_alloc_root(&m_warn_root); }
+  ~Warning_info();
+
+  /**
+    Reset the warning information. Clear all warnings,
+    the number of warnings, reset current row counter
+    to point to the first row.
+  */
+  void clear_warning_info(query_id_t warn_id_arg);
+  /**
+    Only clear warning info if haven't yet done that already
+    for the current query. Allows to be issued at any time
+    during the query, without risk of clearing some warnings
+    that have been generated by the current statement.
+
+    @todo: This is a sign of sloppy coding. Instead we need to
+    designate one place in a statement life cycle where we call
+    clear_warning_info().
+  */
+  void opt_clear_warning_info(query_id_t query_id)
+  {
+    if (query_id != m_warn_id)
+      clear_warning_info(query_id);
+  }
+
+  /**
+    Reset between two COM_ commands. Warnings are preserved
+    between commands, but statement_warn_count indicates
+    the number of warnings of this particular statement only.
+  */
+  void reset_for_next_command() { m_statement_warn_count= 0; }
+
+  /**
+    Used for @@warning_count system variable, which prints
+    the number of rows returned by SHOW WARNINGS.
+  */
+  ulong warn_count() const
+  {
+    /*
+      This may be higher than warn_list.elements if we have
+      had more warnings than thd->variables.max_error_count.
+    */
+    return (m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
+            m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR] +
+            m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
+  }
+
+  /**
+    This is for iteration purposes. We return a non-constant reference
+    since List doesn't have constant iterators.
+  */
+  List<MYSQL_ERROR> &warn_list() { return m_warn_list; }
+
+  /**
+    The number of errors, or number of rows returned by SHOW ERRORS,
+    also the value of session variable @@error_count.
+  */
+  ulong error_count() const
+  {
+    return m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
+  }
+
+  /** Do we have any errors and warnings that we can *show*? */
+  bool is_empty() const { return m_warn_list.elements == 0; }
+
+  /** Increment the current row counter to point at the next row. */
+  void inc_current_row_for_warning() { m_current_row_for_warning++; }
+  /** Reset the current row counter. Start counting from the first row. */
+  void reset_current_row_for_warning() { m_current_row_for_warning= 1; }
+  /** Return the current counter value. */
+  ulong current_row_for_warning() const { return m_current_row_for_warning; }
+
+  ulong statement_warn_count() const { return m_statement_warn_count; }
+
+  /** Add a new warning to the current list. */
+  void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
+                    uint code, const char *msg);
+};
+
 /**
   Tables that were locked with LOCK TABLES statement.
 
@@ -1380,7 +1499,6 @@ public:
   Query_cache_tls query_cache_tls;
 #endif
   NET	  net;				// client connection descriptor
-  MEM_ROOT warn_root;			// For warnings and errors
   Protocol *protocol;			// Current protocol
   Protocol_text   protocol_text;	// Normal protocol
   Protocol_binary protocol_binary;	// Binary protocol
@@ -1786,15 +1904,7 @@ public:
   table_map  used_tables;
   USER_CONN *user_connect;
   CHARSET_INFO *db_charset;
-  /*
-    FIXME: this, and some other variables like 'count_cuted_fields'
-    maybe should be statement/cursor local, that is, moved to Statement
-    class. With current implementation warnings produced in each prepared
-    statement/cursor settle here.
-  */
-  List	     <MYSQL_ERROR> warn_list;
-  uint	     warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
-  uint	     total_warn_count;
+  Warning_info warning_info;
   Diagnostics_area main_da;
 #if defined(ENABLED_PROFILING)
   PROFILING  profiling;
@@ -1808,7 +1918,7 @@ public:
     from table are necessary for this select, to check if it's necessary to
     update auto-updatable fields (like auto_increment and timestamp).
   */
-  query_id_t query_id, warn_id;
+  query_id_t query_id;
   ulong      col_access;
 
 #ifdef ERROR_INJECT_SUPPORT
@@ -1817,11 +1927,6 @@ public:
   /* Statement id is thread-wide. This counter is used to generate ids */
   ulong      statement_id_counter;
   ulong	     rand_saved_seed1, rand_saved_seed2;
-  /*
-    Row counter, mainly for errors and warnings. Not increased in
-    create_sort_index(); may differ from examined_row_count.
-  */
-  ulong      row_count;
   pthread_t  real_id;                           /* For debugging */
   my_thread_id  thread_id;
   uint	     tmp_table, global_read_lock;
@@ -2393,8 +2498,8 @@ public:
     @param level the error level
     @return true if the error is handled
   */
-  virtual bool handle_error(uint sql_errno, const char *message,
-                            MYSQL_ERROR::enum_warning_level level);
+  virtual bool handle_error(MYSQL_ERROR::enum_warning_level level,
+                            uint sql_errno, const char *message);
 
   /**
     Remove the error handler last pushed.

=== modified file 'sql/sql_error.cc'
--- a/sql/sql_error.cc	2008-10-08 15:37:32 +0000
+++ b/sql/sql_error.cc	2008-11-14 20:45:00 +0000
@@ -44,51 +44,15 @@ This file contains the implementation of
 #include "mysql_priv.h"
 #include "sp_rcontext.h"
 
-/*
-  Store a new message in an error object
-
-  This is used to in group_concat() to register how many warnings we actually
-  got after the query has been executed.
-*/
+/* Store a new message in an error object. */
 
-void MYSQL_ERROR::set_msg(THD *thd, const char *msg_arg)
+void MYSQL_ERROR::set_msg(MEM_ROOT *warn_root, const char *msg_arg)
 {
-  msg= strdup_root(&thd->warn_root, msg_arg);
+  msg= strdup_root(warn_root, msg_arg);
 }
 
 
 /*
-  Reset all warnings for the thread
-
-  SYNOPSIS
-    mysql_reset_errors()
-    thd			Thread handle
-    force               Reset warnings even if it has been done before
-
-  IMPLEMENTATION
-    Don't reset warnings if this has already been called for this query.
-    This may happen if one gets a warning during the parsing stage,
-    in which case push_warnings() has already called this function.
-*/  
-
-void mysql_reset_errors(THD *thd, bool force)
-{
-  DBUG_ENTER("mysql_reset_errors");
-  if (thd->query_id != thd->warn_id || force)
-  {
-    thd->warn_id= thd->query_id;
-    free_root(&thd->warn_root,MYF(0));
-    bzero((char*) thd->warn_count, sizeof(thd->warn_count));
-    if (force)
-      thd->total_warn_count= 0;
-    thd->warn_list.empty();
-    thd->row_count= 1; // by default point to row 1
-  }
-  DBUG_VOID_RETURN;
-}
-
-
-/* 
   Push the warning/error to error list if there is still room in the list
 
   SYNOPSIS
@@ -102,7 +66,6 @@ void mysql_reset_errors(THD *thd, bool f
 void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, 
                           uint code, const char *msg)
 {
-  MYSQL_ERROR *err= 0;
   DBUG_ENTER("push_warning");
   DBUG_PRINT("enter", ("code: %d, msg: %s", code, msg));
 
@@ -113,8 +76,9 @@ void push_warning(THD *thd, MYSQL_ERROR:
       !(thd->options & OPTION_SQL_NOTES))
     DBUG_VOID_RETURN;
 
-  if (thd->query_id != thd->warn_id && !thd->spcont)
-    mysql_reset_errors(thd, 0);
+  if (! thd->spcont)
+    thd->warning_info.opt_clear_warning_info(thd->query_id);
+
   thd->got_warning= 1;
 
   /* Abort if we are using strict mode and we are not using IGNORE */
@@ -137,25 +101,18 @@ void push_warning(THD *thd, MYSQL_ERROR:
     level= MYSQL_ERROR::WARN_LEVEL_ERROR;
   }
 
-  if (thd->handle_error(code, msg, level))
+  if (thd->handle_error(level, code, msg))
     DBUG_VOID_RETURN;
 
   if (thd->spcont &&
-      thd->spcont->handle_error(code, level, thd))
+      thd->spcont->handle_error(thd, level, code))
   {
     DBUG_VOID_RETURN;
   }
   query_cache_abort(&thd->query_cache_tls);
 
+  thd->warning_info.push_warning(thd, level, code, msg);
 
-  if (thd->warn_list.elements < thd->variables.max_error_count)
-  {
-    /* We have to use warn_root, as mem_root is freed after each query */
-    if ((err= new (&thd->warn_root) MYSQL_ERROR(thd, code, level, msg)))
-      thd->warn_list.push_back(err, &thd->warn_root);
-  }
-  thd->warn_count[(uint) level]++;
-  thd->total_warn_count++;
   DBUG_VOID_RETURN;
 }
 
@@ -234,7 +191,7 @@ bool mysqld_show_warnings(THD *thd, ulon
 
   unit->set_limit(sel);
 
-  List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+  List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
   while ((err= it++))
   {
     /* Skip levels that the user is not interested in */

=== modified file 'sql/sql_error.h'
--- a/sql/sql_error.h	2008-07-29 22:03:57 +0000
+++ b/sql/sql_error.h	2008-11-14 20:45:00 +0000
@@ -19,27 +19,26 @@ public:
   enum enum_warning_level
   { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END};
 
-  uint code;
   enum_warning_level level;
+  uint code;
   char *msg;
-  
-  MYSQL_ERROR(THD *thd, uint code_arg, enum_warning_level level_arg,
-	      const char *msg_arg)
-    :code(code_arg), level(level_arg)
+
+  MYSQL_ERROR(MEM_ROOT *warn_root,
+              enum_warning_level level_arg, uint code_arg, const char *msg_arg)
+    :level(level_arg), code(code_arg)
   {
     if (msg_arg)
-      set_msg(thd, msg_arg);
+      set_msg(warn_root, msg_arg);
   }
 
 private:
-  void set_msg(THD *thd, const char *msg_arg);
+  void set_msg(MEM_ROOT *warn_root, const char *msg_arg);
 };
 
 void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
                   uint code, const char *msg);
 void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
 			 uint code, const char *format, ...);
-void mysql_reset_errors(THD *thd, bool force);
 bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
 
 extern const LEX_STRING warning_level_names[];

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2008-11-06 18:39:27 +0000
+++ b/sql/sql_insert.cc	2008-11-14 20:45:00 +0000
@@ -835,7 +835,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
       error=write_record(thd, table ,&info);
     if (error)
       break;
-    thd->row_count++;
+    thd->warning_info.inc_current_row_for_warning();
   }
 
   free_underlaid_joins(thd, &thd->lex->select_lex);

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2008-09-17 16:14:21 +0000
+++ b/sql/sql_load.cc	2008-11-14 20:45:00 +0000
@@ -644,7 +644,8 @@ read_fixed_length(THD *thd, COPY_INFO &i
         thd->cuted_fields++;			/* Not enough fields */
         push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                             ER_WARN_TOO_FEW_RECORDS, 
-                            ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
+                            ER(ER_WARN_TOO_FEW_RECORDS),
+                            thd->warning_info.current_row_for_warning());
         if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
             ((Field_timestamp*) field)->set_time();
       }
@@ -667,7 +668,8 @@ read_fixed_length(THD *thd, COPY_INFO &i
       thd->cuted_fields++;			/* To long row */
       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                           ER_WARN_TOO_MANY_RECORDS, 
-                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
+                          ER(ER_WARN_TOO_MANY_RECORDS),
+                          thd->warning_info.current_row_for_warning());
     }
 
     if (thd->killed ||
@@ -702,9 +704,10 @@ read_fixed_length(THD *thd, COPY_INFO &i
       thd->cuted_fields++;			/* To long row */
       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                           ER_WARN_TOO_MANY_RECORDS, 
-                          ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); 
+                          ER(ER_WARN_TOO_MANY_RECORDS),
+                          thd->warning_info.current_row_for_warning());
     }
-    thd->row_count++;
+    thd->warning_info.inc_current_row_for_warning();
 continue_loop:;
   }
   DBUG_RETURN(test(read_info.error));
@@ -768,7 +771,7 @@ read_sep_field(THD *thd, COPY_INFO &info
           if (field->reset())
           {
             my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name,
-                     thd->row_count);
+                     thd->warning_info.current_row_for_warning());
             DBUG_RETURN(1);
           }
           field->set_null();
@@ -836,7 +839,7 @@ read_sep_field(THD *thd, COPY_INFO &info
           if (field->reset())
           {
             my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name,
-                     thd->row_count);
+                     thd->warning_info.current_row_for_warning());
             DBUG_RETURN(1);
           }
           if (!field->maybe_null() && field->type() == FIELD_TYPE_TIMESTAMP)
@@ -850,7 +853,8 @@ read_sep_field(THD *thd, COPY_INFO &info
           thd->cuted_fields++;
           push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                               ER_WARN_TOO_FEW_RECORDS,
-                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
+                              ER(ER_WARN_TOO_FEW_RECORDS),
+                              thd->warning_info.current_row_for_warning());
         }
         else if (item->type() == Item::STRING_ITEM)
         {
@@ -896,11 +900,11 @@ read_sep_field(THD *thd, COPY_INFO &info
       thd->cuted_fields++;			/* To long row */
       push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
                           ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), 
-                          thd->row_count);   
+                          thd->warning_info.current_row_for_warning());
       if (thd->killed)
         DBUG_RETURN(1);
     }
-    thd->row_count++;
+    thd->warning_info.inc_current_row_for_warning();
 continue_loop:;
   }
   DBUG_RETURN(test(read_info.error));
@@ -1033,7 +1037,8 @@ read_xml_field(THD *thd, COPY_INFO &info
           thd->cuted_fields++;
           push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                               ER_WARN_TOO_FEW_RECORDS,
-                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
+                              ER(ER_WARN_TOO_FEW_RECORDS),
+                              thd->warning_info.current_row_for_warning());
         }
         else
           ((Item_user_var_as_out_param *)item)->set_null_value(cs);
@@ -1064,7 +1069,7 @@ read_xml_field(THD *thd, COPY_INFO &info
       its default value at the beginning of each loop iteration.
     */
     thd->transaction.stmt.modified_non_trans_table= no_trans_update_stmt;
-    thd->row_count++;
+    thd->warning_info.inc_current_row_for_warning();
     continue_loop:;
   }
   DBUG_RETURN(test(read_info.error));

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2008-11-06 18:39:27 +0000
+++ b/sql/sql_parse.cc	2008-11-14 20:45:00 +0000
@@ -1412,7 +1412,7 @@ bool dispatch_command(enum enum_server_c
                         0,0,0,0,
                         thd->query,thd->query_length,
                         thd->variables.character_set_client,
-                        thd->row_count);  
+                        thd->warning_info.current_row_for_warning());
   }
 
   log_slow_statement(thd);
@@ -1851,7 +1851,7 @@ mysql_execute_command(THD *thd)
     Don't reset warnings when executing a stored routine.
   */
   if ((all_tables || !lex->is_single_level_stmt()) && !thd->spcont)
-    mysql_reset_errors(thd, 0);
+    thd->warning_info.opt_clear_warning_info(thd->query_id);
 
 #ifdef HAVE_REPLICATION
   if (unlikely(thd->slave_thread))
@@ -4126,12 +4126,6 @@ create_sp_error:
           So just execute the statement.
         */
 	res= sp->execute_procedure(thd, &lex->value_list);
-	/*
-          If warnings have been cleared, we have to clear total_warn_count
-          too, otherwise the clients get confused.
-	 */
-	if (thd->warn_list.is_empty())
-	  thd->total_warn_count= 0;
 
 	thd->variables.select_limit= select_limit;
 
@@ -4162,7 +4156,7 @@ create_sp_error:
       else
         sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, lex->spname,
                             &thd->sp_func_cache, FALSE);
-      mysql_reset_errors(thd, 0);
+      thd->warning_info.opt_clear_warning_info(thd->query_id);
       if (! sp)
       {
 	if (lex->spname->m_db.str)
@@ -4282,7 +4276,7 @@ create_sp_error:
       }
 
       sp_result= sp_routine_exists_in_table(thd, type, lex->spname);
-      mysql_reset_errors(thd, 0);
+      thd->warning_info.opt_clear_warning_info(thd->query_id);
       if (sp_result == SP_OK)
       {
         char *db= lex->spname->m_db.str;
@@ -5373,7 +5367,7 @@ void mysql_reset_thd_for_next_command(TH
   }
   thd->clear_error();
   thd->main_da.reset_diagnostics_area();
-  thd->total_warn_count=0;			// Warnings for this query
+  thd->warning_info.reset_for_next_command();
   thd->rand_used= 0;
   thd->sent_row_count= thd->examined_row_count= 0;
   thd->thd_marker.emb_on_expr_nest= NULL;

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2008-11-06 18:39:27 +0000
+++ b/sql/sql_prepare.cc	2008-11-14 20:45:00 +0000
@@ -248,7 +248,7 @@ static bool send_prep_stmt(Prepared_stat
   int2store(buff+5, columns);
   int2store(buff+7, stmt->param_count);
   buff[9]= 0;                                   // Guard against a 4.1 client
-  tmp= min(stmt->thd->total_warn_count, 65535);
+  tmp= min(stmt->thd->warning_info.statement_warn_count(), 65535);
   int2store(buff+10, tmp);
 
   /*
@@ -1839,7 +1839,7 @@ static bool check_prepared_statement(Pre
 
   /* Reset warning count for each query that uses tables */
   if ((tables || !lex->is_single_level_stmt()) && !thd->spcont)
-    mysql_reset_errors(thd, 0);
+    thd->warning_info.opt_clear_warning_info(thd->query_id);
 
   switch (sql_command) {
   case SQLCOM_REPLACE:
@@ -3293,12 +3293,12 @@ Prepared_statement::reprepare()
 #endif
     /*
       Clear possible warnings during reprepare, it has to be completely
-      transparent to the user. We use mysql_reset_errors() since
+      transparent to the user. We use mysql_reset_warnings() since
       there were no separate query id issued for re-prepare.
       Sic: we can't simply silence warnings during reprepare, because if
       it's failed, we need to return all the warnings to the user.
     */
-    mysql_reset_errors(thd, TRUE);
+    thd->warning_info.clear_warning_info(thd->query_id);
   }
   return error;
 }

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2008-11-06 18:39:27 +0000
+++ b/sql/sql_select.cc	2008-11-14 20:45:00 +0000
@@ -13454,7 +13454,6 @@ do_select(JOIN *join,List<Item> *fields,
         so we don't touch it here.
       */
       join->examined_rows++;
-      join->thd->row_count++;
       DBUG_ASSERT(join->examined_rows <= 1);
     }
     else if (join->send_row_on_empty_set())
@@ -13718,7 +13717,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab
       /* Set first_unmatched for the last inner table of this group */
       join_tab->last_inner->first_unmatched= join_tab;
     }
-    join->thd->row_count= 0;
+    join->thd->warning_info.reset_current_row_for_warning();
 
     error= (*join_tab->read_first_record)(join_tab);
     rc= evaluate_join_record(join, join_tab, error);
@@ -13962,7 +13961,6 @@ evaluate_join_record(JOIN *join, JOIN_TA
       (See above join->return_tab= tab).
     */
     join->examined_rows++;
-    join->thd->row_count++;
     DBUG_PRINT("counts", ("join->examined_rows++: %lu",
                           (ulong) join->examined_rows));
 
@@ -13971,6 +13969,7 @@ evaluate_join_record(JOIN *join, JOIN_TA
       enum enum_nested_loop_state rc;
       /* A match from join_tab is found for the current partial join. */
       rc= (*join_tab->next_select)(join, join_tab+1, 0);
+      join->thd->warning_info.inc_current_row_for_warning();
       if (rc != NESTED_LOOP_OK && rc != NESTED_LOOP_NO_MORE_ROWS)
         return rc;
       if (return_tab < join->return_tab)
@@ -13987,7 +13986,10 @@ evaluate_join_record(JOIN *join, JOIN_TA
         return NESTED_LOOP_NO_MORE_ROWS;
     }
     else
+    {
+      join->thd->warning_info.inc_current_row_for_warning();
       join_tab->read_record.file->unlock_row();
+    }
   }
   else
   {
@@ -13996,7 +13998,7 @@ evaluate_join_record(JOIN *join, JOIN_TA
       with the beginning coinciding with the current partial join.
     */
     join->examined_rows++;
-    join->thd->row_count++;
+    join->thd->warning_info.inc_current_row_for_warning();
     join_tab->read_record.file->unlock_row();
   }
   return NESTED_LOOP_OK;

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2008-11-06 18:39:27 +0000
+++ b/sql/sql_show.cc	2008-11-14 20:45:00 +0000
@@ -516,7 +516,7 @@ mysqld_show_create(THD *thd, TABLE_LIST 
       issue a warning with 'warning' level status in
       case of invalid view and last error is ER_VIEW_INVALID
     */
-    mysql_reset_errors(thd, true);
+    thd->warning_info.clear_warning_info(thd->query_id);
     thd->clear_error();
 
     push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN,

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2008-11-06 18:39:27 +0000
+++ b/sql/sql_table.cc	2008-11-14 20:45:00 +0000
@@ -4289,7 +4289,7 @@ static bool mysql_admin_table(THD* thd, 
     if (!table->table)
     {
       DBUG_PRINT("admin", ("open table failed"));
-      if (!thd->warn_list.elements)
+      if (thd->warning_info.is_empty())
         push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                      ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE));
       /* if it was a view will check md5 sum */
@@ -4397,7 +4397,7 @@ send_result:
     lex->cleanup_after_one_table_open();
     thd->clear_error();  // these errors shouldn't get client
     {
-      List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+      List_iterator_fast<MYSQL_ERROR> it(thd->warning_info.warn_list());
       MYSQL_ERROR *err;
       while ((err= it++))
       {
@@ -4411,7 +4411,7 @@ send_result:
         if (protocol->write())
           goto err;
       }
-      mysql_reset_errors(thd, true);
+      thd->warning_info.clear_warning_info(thd->query_id);
     }
     protocol->prepare_for_resend();
     protocol->store(table_name, system_charset_info);
@@ -7236,7 +7236,8 @@ err:
     the table to be altered isn't empty.
     Report error here.
   */
-  if (alter_info->error_if_not_empty && thd->row_count)
+  if (alter_info->error_if_not_empty &&
+      thd->warning_info.current_row_for_warning())
   {
     const char *f_val= 0;
     enum enum_mysql_timestamp_type t_type= MYSQL_TIMESTAMP_DATE;
@@ -7408,7 +7409,7 @@ copy_data_between_tables(TABLE *from,TAB
   errpos= 4;
   if (ignore)
     to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
-  thd->row_count= 0;
+  thd->warning_info.reset_current_row_for_warning();
   restore_record(to, s->default_values);        // Create empty record
   while (!(error=info.read_record(&info)))
   {
@@ -7418,7 +7419,6 @@ copy_data_between_tables(TABLE *from,TAB
       error= 1;
       break;
     }
-    thd->row_count++;
     /* Return error if source table isn't empty. */
     if (error_if_not_empty)
     {
@@ -7468,6 +7468,7 @@ copy_data_between_tables(TABLE *from,TAB
     }
     else
       found_count++;
+    thd->warning_info.inc_current_row_for_warning();
   }
 
 err:

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2008-10-20 19:13:22 +0000
+++ b/sql/sql_update.cc	2008-11-14 20:45:00 +0000
@@ -727,7 +727,7 @@ int mysql_update(THD *thd,
     }
     else
       table->file->unlock_row();
-    thd->row_count++;
+    thd->warning_info.inc_current_row_for_warning();
   }
   dup_key_found= 0;
   /*

=== modified file 'sql/time.cc'
--- a/sql/time.cc	2008-02-13 19:27:12 +0000
+++ b/sql/time.cc	2008-11-14 20:45:00 +0000
@@ -748,7 +748,7 @@ void make_truncated_value_warning(THD *t
     cs->cset->snprintf(cs, warn_buff, sizeof(warn_buff),
                        ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
                        type_str, str.c_ptr(), field_name,
-                       (ulong) thd->row_count);
+                       (ulong) thd->warning_info.current_row_for_warning());
   else
   {
     if (time_type > MYSQL_TIMESTAMP_ERROR)

=== modified file 'sql/unireg.cc'
--- a/sql/unireg.cc	2008-11-04 08:10:49 +0000
+++ b/sql/unireg.cc	2008-11-14 20:45:00 +0000
@@ -56,10 +56,10 @@ static bool make_empty_rec(THD *thd, int
 
 struct Pack_header_error_handler: public Internal_error_handler
 {
-  virtual bool handle_error(uint sql_errno,
-                            const char *message,
+  virtual bool handle_error(THD *thd,
                             MYSQL_ERROR::enum_warning_level level,
-                            THD *thd);
+                            uint sql_errno,
+                            const char *message);
   bool is_handled;
   Pack_header_error_handler() :is_handled(FALSE) {}
 };
@@ -67,10 +67,10 @@ struct Pack_header_error_handler: public
 
 bool
 Pack_header_error_handler::
-handle_error(uint sql_errno,
-             const char * /* message */,
+handle_error(THD * /* thd */,
              MYSQL_ERROR::enum_warning_level /* level */,
-             THD * /* thd */)
+             uint sql_errno,
+             const char * /* message */)
 {
   is_handled= (sql_errno == ER_TOO_MANY_FIELDS);
   return is_handled;

Thread
bzr push into mysql-6.0-runtime branch (kostja:2744 to 2745) WL#4264Konstantin Osipov14 Nov