List:Commits« Previous MessageNext Message »
From:Alfranio Correia Date:March 20 2009 12:40pm
Subject:bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2802)
Bug#39393
View as plain text  
#At file:///home/acorreia/workspace.sun/repository.mysql/bzrwork/bug-39393/mysql-5.1-bugteam/ based on revid:sergey.glukhov@stripped

 2802 Alfranio Correia	2009-03-20
      BUG#39393 slave-skip-errors does not work when using ROW based replication
                  
      RBR was not considering the option --slave-skip-errors.
                  
      To fix the problem, we are reporting the ignored ERROR(s) as warnings thus avoiding 
      stopping the SQL Thread. Besides, it fixes the output of "SHOW VARIABLES LIKE 
      'slave_skip_errors'" which was showing nothing when the value "all" was assigned 
      to --slave-skip-errors.
      
      @include/my_sys.h
      @mysys/my_error.c
        added functions to create messages in a buffer without printing them out.
      @sql/ha_ndbcluster.h
      @sql/ha_ndbcluster.cc
        refactored its interface so specific errors in the cluster are easily
        reported through the handler.
      @sql/ha_partition.cc
      @sql/ha_partition.h
      @sql/partition_info.cc
      @sql/partition_info.h
        refactored its interface so specific errors in the cluster engine 
        are easily reported through the handler.
      @sql/handler.h
      @sql/handler.cc
        refactored its interface so errors can be easily checked and reported
        through its interfaces.
      @sql/log_event.cc
        skipped rbr errors when the option skip-slave-errors is set.
      @sql/slave.cc
        fixed the output of for SHOW VARIABLES LIKE 'slave_skip_errors'".
added:
  mysql-test/suite/rpl/r/rpl_skiperrors_rbr.result
  mysql-test/suite/rpl/t/rpl_skiperrors_rbr-slave.opt
  mysql-test/suite/rpl/t/rpl_skiperrors_rbr.test
modified:
  include/my_sys.h
  mysys/my_error.c
  sql/ha_ndbcluster.cc
  sql/ha_ndbcluster.h
  sql/ha_partition.cc
  sql/ha_partition.h
  sql/handler.cc
  sql/handler.h
  sql/log_event.cc
  sql/partition_info.cc
  sql/partition_info.h
  sql/slave.cc

=== modified file 'include/my_sys.h'
--- a/include/my_sys.h	2009-02-05 06:16:00 +0000
+++ b/include/my_sys.h	2009-03-20 12:40:23 +0000
@@ -645,6 +645,9 @@ extern int my_sync(File fd, myf my_flags
 extern int my_sync_dir(const char *dir_name, myf my_flags);
 extern int my_sync_dir_by_file(const char *file_name, myf my_flags);
 extern int my_error _VARARGS((int nr,myf MyFlags, ...));
+extern void my_buffer_error _VARARGS((int nr, char* ebuff, size_t size, ...));
+extern void my_buffer_format _VARARGS((char* ebuff, size_t size,
+                                       const char* format, ...));
 extern int my_printf_error _VARARGS((uint my_err, const char *format,
 				     myf MyFlags, ...))
 				    ATTRIBUTE_FORMAT(printf, 2, 4);

=== added file 'mysql-test/suite/rpl/r/rpl_skiperrors_rbr.result'
--- a/mysql-test/suite/rpl/r/rpl_skiperrors_rbr.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_skiperrors_rbr.result	2009-03-20 12:40:23 +0000
@@ -0,0 +1,94 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1(id INT NOT NULL PRIMARY KEY, data INT) Engine=InnoDB;
+INSERT INTO t1 VALUES(1, 1);
+SET SQL_LOG_BIN=0;
+DELETE FROM t1 WHERE id = 1;
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES(1, 2);
+
+SELECT *, "SLAVE DATA" FROM t1 ORDER BY id;
+id	data	SLAVE DATA
+1	1	SLAVE DATA
+SELECT *, "MASTER DATA" FROM t1 ORDER BY id;
+id	data	MASTER DATA
+1	2	MASTER DATA
+DELETE FROM t1;
+start transaction;
+INSERT INTO t1 VALUES(1, 1);
+INSERT INTO t1 VALUES(10, 1);
+SET SQL_LOG_BIN=0;
+DELETE FROM t1 WHERE id = 10;
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES(10, 2);
+INSERT INTO t1 VALUES(3, 2);
+commit;
+
+start transaction;
+INSERT INTO t1 VALUES(4, 3);
+INSERT INTO t1 VALUES(5, 3);
+SET SQL_LOG_BIN=0;
+DELETE FROM t1 WHERE id = 5;
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES(5, 4);
+INSERT INTO t1 VALUES(6, 4);
+rollback;
+
+SELECT *, "SLAVE DATA" FROM t1 ORDER BY id;
+id	data	SLAVE DATA
+1	1	SLAVE DATA
+3	2	SLAVE DATA
+10	1	SLAVE DATA
+SELECT *, "MASTER DATA" FROM t1 ORDER BY id;
+id	data	MASTER DATA
+1	1	MASTER DATA
+3	2	MASTER DATA
+10	2	MASTER DATA
+DELETE FROM t1;
+INSERT INTO t1 VALUES(1, 1);
+INSERT INTO t1 VALUES(2, 1);
+INSERT INTO t1 VALUES(3, 1);
+INSERT INTO t1 VALUES(4, 1);
+SET SQL_LOG_BIN=0;
+DELETE FROM t1 WHERE id = 4;
+SET SQL_LOG_BIN=1;
+UPDATE t1 SET id= id + 3, data = 2;
+
+SELECT *, "SLAVE DATA" FROM t1 ORDER BY id;
+id	data	SLAVE DATA
+1	1	SLAVE DATA
+4	1	SLAVE DATA
+5	2	SLAVE DATA
+6	2	SLAVE DATA
+SELECT *, "MASTER DATA" FROM t1 ORDER BY id;
+id	data	MASTER DATA
+4	2	MASTER DATA
+5	2	MASTER DATA
+6	2	MASTER DATA
+CREATE TABLE t2(id INT NOT NULL PRIMARY KEY, data INT)  Engine=MyIsam;
+INSERT INTO t2 VALUES(1, 1);
+INSERT INTO t2 VALUES(2, 1);
+INSERT INTO t2 VALUES(3, 1);
+INSERT INTO t2 VALUES(4, 1);
+SET SQL_LOG_BIN=0;
+DELETE FROM t2 WHERE id = 4;
+SET SQL_LOG_BIN=1;
+UPDATE t2 SET id= id + 3, data = 2;
+
+SELECT *, "SLAVE DATA" FROM t2 ORDER BY id;
+id	data	SLAVE DATA
+1	1	SLAVE DATA
+4	1	SLAVE DATA
+5	2	SLAVE DATA
+6	2	SLAVE DATA
+SELECT *, "MASTER DATA" FROM t2 ORDER BY id;
+id	data	MASTER DATA
+4	2	MASTER DATA
+5	2	MASTER DATA
+6	2	MASTER DATA
+DROP TABLE t1;
+DROP TABLE t2;

=== added file 'mysql-test/suite/rpl/t/rpl_skiperrors_rbr-slave.opt'
--- a/mysql-test/suite/rpl/t/rpl_skiperrors_rbr-slave.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_skiperrors_rbr-slave.opt	2009-03-20 12:40:23 +0000
@@ -0,0 +1 @@
+--slave_skip_errors=all

=== added file 'mysql-test/suite/rpl/t/rpl_skiperrors_rbr.test'
--- a/mysql-test/suite/rpl/t/rpl_skiperrors_rbr.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_skiperrors_rbr.test	2009-03-20 12:40:23 +0000
@@ -0,0 +1,163 @@
+#################################################################
+#   This test cases checks if slave-skip-errors works when 
+#   using ROW based by generating forcing duplicate keys
+#   in the SLAVE. 
+#
+#   The following scenarios are checked:
+#
+#   1 - InnoDB without transactions
+#   2 - InnoDB with transactions, both commit and rollback.
+#   3 - InnoDB with an UPDATE on a SET of rows.
+#   4 - MyIsam with an UPDATE on a SET of rows.
+#
+#################################################################
+
+--source include/have_binlog_format_row.inc
+--source include/have_innodb.inc
+--source include/master-slave.inc
+
+#################################################################
+#                  1 - (InnoDB) Duplicate key
+#################################################################
+connection master;
+
+CREATE TABLE t1(id INT NOT NULL PRIMARY KEY, data INT) Engine=InnoDB;
+
+INSERT INTO t1 VALUES(1, 1);
+
+SET SQL_LOG_BIN=0;
+DELETE FROM t1 WHERE id = 1;
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES(1, 2);
+
+sync_slave_with_master;
+
+let $error= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
+echo $error;
+
+connection slave;
+
+SELECT *, "SLAVE DATA" FROM t1 ORDER BY id;
+
+connection master;
+
+SELECT *, "MASTER DATA" FROM t1 ORDER BY id;
+
+#################################################################
+#            2 - (InnoDB with Transaction) Duplicate key
+#################################################################
+connection master;
+
+DELETE FROM t1;
+
+start transaction;
+INSERT INTO t1 VALUES(1, 1);
+INSERT INTO t1 VALUES(10, 1);
+SET SQL_LOG_BIN=0;
+DELETE FROM t1 WHERE id = 10;
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES(10, 2);
+INSERT INTO t1 VALUES(3, 2);
+commit;
+
+sync_slave_with_master;
+
+let $error= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
+echo $error;
+
+connection master;
+
+start transaction;
+INSERT INTO t1 VALUES(4, 3);
+INSERT INTO t1 VALUES(5, 3);
+SET SQL_LOG_BIN=0;
+DELETE FROM t1 WHERE id = 5;
+SET SQL_LOG_BIN=1;
+INSERT INTO t1 VALUES(5, 4);
+INSERT INTO t1 VALUES(6, 4);
+rollback;
+
+sync_slave_with_master;
+
+let $error= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
+echo $error;
+
+connection master;
+
+connection slave;
+
+SELECT *, "SLAVE DATA" FROM t1 ORDER BY id;
+
+connection master;
+
+SELECT *, "MASTER DATA" FROM t1 ORDER BY id;
+
+#################################################################
+#              3 - (InnoDB with sets) Duplicate key
+#################################################################
+connection master;
+
+DELETE FROM t1;
+
+INSERT INTO t1 VALUES(1, 1);
+INSERT INTO t1 VALUES(2, 1);
+INSERT INTO t1 VALUES(3, 1);
+INSERT INTO t1 VALUES(4, 1);
+
+SET SQL_LOG_BIN=0;
+DELETE FROM t1 WHERE id = 4;
+SET SQL_LOG_BIN=1;
+UPDATE t1 SET id= id + 3, data = 2;
+
+sync_slave_with_master;
+
+let $error= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
+echo $error;
+
+connection slave;
+
+SELECT *, "SLAVE DATA" FROM t1 ORDER BY id;
+
+connection master;
+
+SELECT *, "MASTER DATA" FROM t1 ORDER BY id;
+
+#################################################################
+#                 4 - (MyIsam with sets) Duplicate key
+#################################################################
+connection master;
+
+CREATE TABLE t2(id INT NOT NULL PRIMARY KEY, data INT)  Engine=MyIsam;
+
+INSERT INTO t2 VALUES(1, 1);
+INSERT INTO t2 VALUES(2, 1);
+INSERT INTO t2 VALUES(3, 1);
+INSERT INTO t2 VALUES(4, 1);
+
+SET SQL_LOG_BIN=0;
+DELETE FROM t2 WHERE id = 4;
+SET SQL_LOG_BIN=1;
+UPDATE t2 SET id= id + 3, data = 2;
+
+sync_slave_with_master;
+
+let $error= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
+echo $error;
+
+connection slave;
+
+SELECT *, "SLAVE DATA" FROM t2 ORDER BY id;
+
+connection master;
+
+SELECT *, "MASTER DATA" FROM t2 ORDER BY id;
+
+#################################################################
+#                           Clean up
+#################################################################
+connection master;
+
+DROP TABLE t1;
+DROP TABLE t2;
+
+sync_slave_with_master;

=== modified file 'mysys/my_error.c'
--- a/mysys/my_error.c	2009-02-05 06:16:00 +0000
+++ b/mysys/my_error.c	2009-03-20 12:40:23 +0000
@@ -101,6 +101,49 @@ int my_error(int nr, myf MyFlags, ...)
 
 
 /*
+  Populates a buffer with the error message associated with the error (nr)
+  number specified as parameter.
+ */
+void my_buffer_error(int nr, char* ebuff, size_t size, ...)
+{
+  const char *format;
+  struct my_err_head *meh_p;
+  va_list args;
+  DBUG_ENTER("my_bufer_error");
+
+  /* Search for the error messages array, which could contain the message. */
+  for (meh_p= my_errmsgs_list; meh_p; meh_p= meh_p->meh_next)
+    if (nr <= meh_p->meh_last)
+      break;
+
+  /* get the error message string. Default, if NULL or empty string (""). */
+  if (! (format= (meh_p && (nr >= meh_p->meh_first)) ?
+         meh_p->meh_errmsgs[nr - meh_p->meh_first] : NULL) || ! *format)
+    (void) my_snprintf (ebuff, size, "Unknown error %d", nr);
+  else
+  {
+    va_start(args, size);
+    (void) my_vsnprintf (ebuff, size, format, args);
+    va_end(args);
+  }
+  DBUG_VOID_RETURN;
+}
+
+/*
+  Populates a buffer with an error message specified as parameter (format).
+ */
+void my_buffer_format(char* ebuff, size_t size, const char* format, ...)
+{
+  va_list args;
+  DBUG_ENTER("my_buffer_format");
+
+  va_start(args,format);
+  (void) my_vsnprintf (ebuff, size, format, args);
+  va_end(args);
+  DBUG_VOID_RETURN;
+}
+
+/*
   Error as printf
 
   SYNOPSIS

=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2008-10-23 19:27:09 +0000
+++ b/sql/ha_ndbcluster.cc	2009-03-20 12:40:23 +0000
@@ -7545,19 +7545,17 @@ static int ndbcluster_end(handlerton *ht
   DBUG_RETURN(0);
 }
 
-void ha_ndbcluster::print_error(int error, myf errflag)
+int ha_ndbcluster::process_error(int error, char* ebuff, int size, myf* srvflag)
 {
-  DBUG_ENTER("ha_ndbcluster::print_error");
-  DBUG_PRINT("enter", ("error: %d", error));
-
+  DBUG_ENTER("ha_ndbcluster::process_error");
+  int ret= error;
   if (error == HA_ERR_NO_PARTITION_FOUND)
-    m_part_info->print_no_partition_found(table);
+    ret= m_part_info->process_no_partition_found(table, ebuff, size, srvflag);
   else
-    handler::print_error(error, errflag);
-  DBUG_VOID_RETURN;
+    ret= handler::process_error(error, ebuff, size, srvflag);
+  DBUG_RETURN(ret);
 }
 
-
 /**
   Static error print function called from static handler method
   ndbcluster_commit and ndbcluster_rollback.

=== modified file 'sql/ha_ndbcluster.h'
--- a/sql/ha_ndbcluster.h	2008-02-04 14:40:04 +0000
+++ b/sql/ha_ndbcluster.h	2009-03-20 12:40:23 +0000
@@ -279,7 +279,7 @@ class ha_ndbcluster: public handler
   int external_lock(THD *thd, int lock_type);
   void unlock_row();
   int start_stmt(THD *thd, thr_lock_type lock_type);
-  void print_error(int error, myf errflag);
+  int process_error(int error, char* ebuff, int size, myf* errflag);
   const char * table_type() const;
   const char ** bas_ext() const;
   ulonglong table_flags(void) const;

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2009-01-07 22:30:10 +0000
+++ b/sql/ha_partition.cc	2009-03-20 12:40:23 +0000
@@ -5831,22 +5831,21 @@ enum row_type ha_partition::get_row_type
   return type;
 }
 
-
-void ha_partition::print_error(int error, myf errflag)
+int ha_partition::process_error(int error, char* ebuff, int size, myf* srvflag)
 {
-  DBUG_ENTER("ha_partition::print_error");
+  DBUG_ENTER("ha_partition::process_error");
+  int ret= error;
 
   /* Should probably look for my own errors first */
   DBUG_PRINT("enter", ("error: %d", error));
 
-  if (error == HA_ERR_NO_PARTITION_FOUND)
-    m_part_info->print_no_partition_found(table);
+  if (error == HA_ERR_NO_PARTITION_FOUND) 
+    ret= m_part_info->process_no_partition_found(table, ebuff, size, srvflag);
   else
-    m_file[m_last_part]->print_error(error, errflag);
-  DBUG_VOID_RETURN;
+    ret= m_file[m_last_part]->process_error(error, ebuff, size, srvflag);
+  DBUG_RETURN(ret);
 }
 
-
 bool ha_partition::get_error_message(int error, String *buf)
 {
   DBUG_ENTER("ha_partition::get_error_message");

=== modified file 'sql/ha_partition.h'
--- a/sql/ha_partition.h	2009-01-05 16:10:20 +0000
+++ b/sql/ha_partition.h	2009-03-20 12:40:23 +0000
@@ -600,7 +600,8 @@ public:
   /*
      Handler specific error messages
   */
-  virtual void print_error(int error, myf errflag);
+  int process_error(int error, char* ebuff, int size, myf* srvflag);
+
   virtual bool get_error_message(int error, String * buf);
   /*
    -------------------------------------------------------------------------

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2009-02-10 08:37:27 +0000
+++ b/sql/handler.cc	2009-03-20 12:40:23 +0000
@@ -2526,9 +2526,22 @@ void handler::ha_release_auto_increment(
   }
 }
 
-
 void handler::print_keydup_error(uint key_nr, const char *msg)
 {
+  char ebuff[MYSQL_ERRMSG_SIZE];
+  DBUG_ENTER("handler::print_keydup_error");
+
+  process_keydup_error(key_nr, msg, ebuff, MYSQL_ERRMSG_SIZE);
+  my_message(ER_DUP_ENTRY, ebuff, MYF(0));
+
+  DBUG_VOID_RETURN;
+}
+
+void handler::process_keydup_error(uint key_nr, const char *msg,
+                                       char* ebuff, int size)
+{
+  DBUG_ENTER("handler::process_keydup_error");
+
   /* Write the duplicated key in the error message */
   char key[MAX_KEY_LENGTH];
   String str(key,sizeof(key),system_charset_info);
@@ -2537,7 +2550,7 @@ void handler::print_keydup_error(uint ke
   {
     /* Key is unknown */
     str.copy("", 0, system_charset_info);
-    my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
+    my_buffer_format(ebuff, size, msg, str.c_ptr(), "*UNKNOWN*");
   }
   else
   {
@@ -2549,14 +2562,26 @@ void handler::print_keydup_error(uint ke
       str.length(max_length-4);
       str.append(STRING_WITH_LEN("..."));
     }
-    my_printf_error(ER_DUP_ENTRY, msg,
-		    MYF(0), str.c_ptr_safe(), table->key_info[key_nr].name);
+    my_buffer_format(ebuff, size, msg, str.c_ptr_safe(), 
+                     table->key_info[key_nr].name);
   }
+  DBUG_VOID_RETURN;
 }
 
+void handler::print_error(int error, myf errflag)
+{
+  DBUG_ENTER("handler::print_error");
+
+  char ebuff[MYSQL_ERRMSG_SIZE];
+  myf srvflag= errflag;
+  int srverror= process_error(error, ebuff, MYSQL_ERRMSG_SIZE, &srvflag);
+  my_message(srverror, ebuff, srvflag);
+
+  DBUG_VOID_RETURN;
+}
 
 /**
-  Print error that we got from handler function.
+  Process error that we got from handler function.
 
   @note
     In case of delete table it's only safe to use the following parts of
@@ -2564,39 +2589,42 @@ void handler::print_keydup_error(uint ke
     - table->s->path
     - table->alias
 */
-void handler::print_error(int error, myf errflag)
+int handler::process_error(int error, char* ebuff, int size, myf* srvflag)
 {
-  DBUG_ENTER("handler::print_error");
+  DBUG_ENTER("handler::process_error");
   DBUG_PRINT("enter",("error: %d",error));
+  DBUG_ASSERT(ebuff != 0 && size >= 0 && srvflag != 0);
 
-  int textno=ER_GET_ERRNO;
+  int textno= ER_GET_ERRNO;
   switch (error) {
   case EACCES:
-    textno=ER_OPEN_AS_READONLY;
+    textno= ER_OPEN_AS_READONLY;
     break;
   case EAGAIN:
-    textno=ER_FILE_USED;
+    textno= ER_FILE_USED;
     break;
   case ENOENT:
-    textno=ER_FILE_NOT_FOUND;
+    textno= ER_FILE_NOT_FOUND;
     break;
   case HA_ERR_KEY_NOT_FOUND:
   case HA_ERR_NO_ACTIVE_RECORD:
   case HA_ERR_END_OF_FILE:
-    textno=ER_KEY_NOT_FOUND;
+    textno= ER_KEY_NOT_FOUND;
     break;
   case HA_ERR_WRONG_MRG_TABLE_DEF:
-    textno=ER_WRONG_MRG_TABLE;
+    textno= ER_WRONG_MRG_TABLE;
     break;
   case HA_ERR_FOUND_DUPP_KEY:
   {
     uint key_nr=get_dup_key(error);
     if ((int) key_nr >= 0)
     {
-      print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME));
-      DBUG_VOID_RETURN;
+      textno= ER_DUP_ENTRY;
+      process_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME), ebuff, size);
+      (*srvflag)= MYF(0);
+      DBUG_RETURN(textno);
     }
-    textno=ER_DUP_KEY;
+    textno= ER_DUP_KEY;
     break;
   }
   case HA_ERR_FOREIGN_DUPLICATE_KEY:
@@ -2604,6 +2632,7 @@ void handler::print_error(int error, myf
     uint key_nr= get_dup_key(error);
     if ((int) key_nr >= 0)
     {
+      textno= ER_FOREIGN_DUPLICATE_KEY;
       uint max_length;
       /* Write the key in the error message */
       char key[MAX_KEY_LENGTH];
@@ -2611,110 +2640,127 @@ void handler::print_error(int error, myf
       /* Table is opened and defined at this point */
       key_unpack(&str,table,(uint) key_nr);
       max_length= (MYSQL_ERRMSG_SIZE-
-                   (uint) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
+                   (uint) strlen(ER(textno)));
       if (str.length() >= max_length)
       {
         str.length(max_length-4);
         str.append(STRING_WITH_LEN("..."));
       }
-      my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table_share->table_name.str,
-        str.c_ptr_safe(), key_nr+1);
-      DBUG_VOID_RETURN;
-    }
+      (*srvflag)= MYF(0);
+      my_buffer_error(textno, ebuff, size, table_share->table_name.str, 
+                          str.c_ptr_safe(), key_nr+1);
+      DBUG_RETURN(textno);
+    } 
     textno= ER_DUP_KEY;
     break;
   }
   case HA_ERR_NULL_IN_SPATIAL:
-    my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0));
-    DBUG_VOID_RETURN;
+    textno= ER_CANT_CREATE_GEOMETRY_OBJECT;
+    (*srvflag)= MYF(0);
+    my_buffer_error(textno, ebuff, size);
+    DBUG_RETURN(textno);
+    break;
   case HA_ERR_FOUND_DUPP_UNIQUE:
-    textno=ER_DUP_UNIQUE;
+    textno= ER_DUP_UNIQUE;
     break;
   case HA_ERR_RECORD_CHANGED:
-    textno=ER_CHECKREAD;
+    textno= ER_CHECKREAD;
     break;
   case HA_ERR_CRASHED:
-    textno=ER_NOT_KEYFILE;
+    textno= ER_NOT_KEYFILE;
     break;
   case HA_ERR_WRONG_IN_RECORD:
     textno= ER_CRASHED_ON_USAGE;
     break;
   case HA_ERR_CRASHED_ON_USAGE:
-    textno=ER_CRASHED_ON_USAGE;
+    textno= ER_CRASHED_ON_USAGE;
     break;
   case HA_ERR_NOT_A_TABLE:
     textno= error;
     break;
   case HA_ERR_CRASHED_ON_REPAIR:
-    textno=ER_CRASHED_ON_REPAIR;
+    textno= ER_CRASHED_ON_REPAIR;
     break;
   case HA_ERR_OUT_OF_MEM:
-    textno=ER_OUT_OF_RESOURCES;
+    textno= ER_OUT_OF_RESOURCES;
     break;
   case HA_ERR_WRONG_COMMAND:
-    textno=ER_ILLEGAL_HA;
+    textno= ER_ILLEGAL_HA;
     break;
   case HA_ERR_OLD_FILE:
-    textno=ER_OLD_KEYFILE;
+    textno= ER_OLD_KEYFILE;
     break;
   case HA_ERR_UNSUPPORTED:
-    textno=ER_UNSUPPORTED_EXTENSION;
+    textno= ER_UNSUPPORTED_EXTENSION;
     break;
   case HA_ERR_RECORD_FILE_FULL:
   case HA_ERR_INDEX_FILE_FULL:
   {
-    textno=ER_RECORD_FILE_FULL;
+    textno= ER_RECORD_FILE_FULL;
     /* Write the error message to error log */
-    errflag|= ME_NOREFRESH;
+    if (srvflag)
+      (*srvflag)|= ME_NOREFRESH;
     break;
   }
   case HA_ERR_LOCK_WAIT_TIMEOUT:
-    textno=ER_LOCK_WAIT_TIMEOUT;
+    textno= ER_LOCK_WAIT_TIMEOUT;
     break;
   case HA_ERR_LOCK_TABLE_FULL:
-    textno=ER_LOCK_TABLE_FULL;
+    textno= ER_LOCK_TABLE_FULL;
     break;
   case HA_ERR_LOCK_DEADLOCK:
-    textno=ER_LOCK_DEADLOCK;
+    textno= ER_LOCK_DEADLOCK;
     break;
   case HA_ERR_READ_ONLY_TRANSACTION:
-    textno=ER_READ_ONLY_TRANSACTION;
+    textno= ER_READ_ONLY_TRANSACTION;
     break;
   case HA_ERR_CANNOT_ADD_FOREIGN:
-    textno=ER_CANNOT_ADD_FOREIGN;
+    textno= ER_CANNOT_ADD_FOREIGN;
     break;
   case HA_ERR_ROW_IS_REFERENCED:
   {
     String str;
+    textno= ER_ROW_IS_REFERENCED_2;
     get_error_message(error, &str);
-    my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
-    DBUG_VOID_RETURN;
+    (*srvflag)= MYF(0);
+    my_buffer_error(textno, ebuff, size, str.c_ptr_safe());
+    DBUG_RETURN(textno);
+    break;
   }
   case HA_ERR_NO_REFERENCED_ROW:
   {
     String str;
+    textno= ER_NO_REFERENCED_ROW_2;
     get_error_message(error, &str);
-    my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
-    DBUG_VOID_RETURN;
+    (*srvflag)= MYF(0);
+    my_buffer_error(textno, ebuff, size, str.c_ptr_safe());
+    DBUG_RETURN(textno);
+    break;
   }
   case HA_ERR_TABLE_DEF_CHANGED:
-    textno=ER_TABLE_DEF_CHANGED;
+    textno= ER_TABLE_DEF_CHANGED;
     break;
   case HA_ERR_NO_SUCH_TABLE:
-    my_error(ER_NO_SUCH_TABLE, MYF(0), table_share->db.str,
-             table_share->table_name.str);
-    DBUG_VOID_RETURN;
+    textno= ER_NO_SUCH_TABLE;
+    (*srvflag)= MYF(0);
+    my_buffer_error(textno, ebuff, size, table_share->db.str,
+                        table_share->table_name.str);
+    DBUG_RETURN(textno);
+    break;
   case HA_ERR_RBR_LOGGING_FAILED:
     textno= ER_BINLOG_ROW_LOGGING_FAILED;
     break;
   case HA_ERR_DROP_INDEX_FK:
   {
+    textno= ER_DROP_INDEX_FK;
     const char *ptr= "???";
     uint key_nr= get_dup_key(error);
     if ((int) key_nr >= 0)
       ptr= table->key_info[key_nr].name;
-    my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
-    DBUG_VOID_RETURN;
+    (*srvflag)= MYF(0);
+    my_buffer_error(textno, ebuff, size, ptr);
+    DBUG_RETURN(textno);
+    break;
   }
   case HA_ERR_TABLE_NEEDS_UPGRADE:
     textno=ER_TABLE_NEEDS_UPGRADE;
@@ -2732,24 +2778,26 @@ void handler::print_error(int error, myf
     {
       /* The error was "unknown" to this function.
 	 Ask handler if it has got a message for this error */
-      bool temporary= FALSE;
       String str;
-      temporary= get_error_message(error, &str);
-      if (!str.is_empty())
+      bool temporary= get_error_message(error, &str);
+      textno= (str.is_empty() ? ER_GET_ERRNO :
+              (temporary ? ER_GET_TEMPORARY_ERRMSG : ER_GET_ERRMSG));
+      if (textno != ER_GET_ERRNO)
       {
-	const char* engine= table_type();
-	if (temporary)
-	  my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine);
-	else
-	  my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine);
+        const char* engine= table_type();
+        (*srvflag)= MYF(0);
+        my_buffer_error(textno, ebuff, size, error, str.ptr(), engine);
       }
       else
-	my_error(ER_GET_ERRNO,errflag,error);
-      DBUG_VOID_RETURN;
+      {
+        my_buffer_error(textno, ebuff, size, error);
+      }
+      DBUG_RETURN(textno);
+      break;
     }
   }
-  my_error(textno, errflag, table_share->table_name.str, error);
-  DBUG_VOID_RETURN;
+  my_buffer_error(textno, ebuff, size, table_share->table_name.str, error);
+  DBUG_RETURN(textno);
 }
 
 

=== modified file 'sql/handler.h'
--- a/sql/handler.h	2008-12-10 20:14:50 +0000
+++ b/sql/handler.h	2009-03-20 12:40:23 +0000
@@ -1262,8 +1262,11 @@ public:
 
   void adjust_next_insert_id_after_explicit_value(ulonglong nr);
   int update_auto_increment();
+  void process_keydup_error(uint key_nr, const char *msg,
+                            char* ebuff, int size);
   void print_keydup_error(uint key_nr, const char *msg);
-  virtual void print_error(int error, myf errflag);
+  virtual int process_error(int error, char* ebuff, int size, myf* srvflag);
+  void print_error(int error, myf errflag);
   virtual bool get_error_message(int error, String *buf);
   uint get_dup_key(int error);
   virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share)

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2009-02-04 11:08:27 +0000
+++ b/sql/log_event.cc	2009-03-20 12:40:23 +0000
@@ -277,6 +277,47 @@ static void clear_all_errors(THD *thd, R
   rli->clear_error();
 }
 
+inline int idempotent_error_code(int err_code)
+{
+  int ret= 0;
+
+  switch (err_code)
+  {
+    case 0:
+      ret= 1;
+    break;
+    /*
+      The following list of "idempotent" errors
+      means that an error from the list might happen
+      because of idempotent (more than once)
+      applying of a binlog file.
+      Notice, that binlog has a  ddl operation its
+      second applying may cause
+
+      case HA_ERR_TABLE_DEF_CHANGED:
+      case HA_ERR_CANNOT_ADD_FOREIGN:
+
+      which are not included into to the list.
+
+      Note that HA_ERR_RECORD_DELETED is not in the list since
+      do_exec_row() should not return that error code.
+    */
+    case HA_ERR_RECORD_CHANGED:
+    case HA_ERR_KEY_NOT_FOUND:
+    case HA_ERR_END_OF_FILE:
+    case HA_ERR_FOUND_DUPP_KEY:
+    case HA_ERR_FOUND_DUPP_UNIQUE:
+    case HA_ERR_FOREIGN_DUPLICATE_KEY:
+    case HA_ERR_NO_REFERENCED_ROW:
+    case HA_ERR_ROW_IS_REFERENCED:
+      ret= 1;
+    break;
+    default:
+      ret= 0;
+    break;
+  }
+  return (ret);
+}
 
 /**
   Ignore error code specified on command line.
@@ -7151,7 +7192,9 @@ 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)
+          simplifications. 
+          We should not honour --slave-skip-errors at this point as we are
+          having severe errors which should not be skiped.
         */
         rli->report(ERROR_LEVEL, actual_error,
                     "Error '%s' on opening tables",
@@ -7177,6 +7220,10 @@ int Rows_log_event::do_apply_event(Relay
       {
         if (ptr->m_tabledef.compatible_with(rli, ptr->table))
         {
+          /*
+            We should not honour --slave-skip-errors at this point as we are
+            having severe errors which should not be skiped.
+          */
           mysql_unlock_tables(thd, thd->lock);
           thd->lock= 0;
           thd->is_slave_error= 1;
@@ -7214,7 +7261,7 @@ int Rows_log_event::do_apply_event(Relay
     m_table= const_cast<Relay_log_info*>(rli)->m_table_map.get_table(m_table_id);
 
   DBUG_PRINT("debug", ("m_table: 0x%lx, m_table_id: %lu", (ulong) m_table, m_table_id));
-
+  
   if (table)
   {
     /*
@@ -7284,48 +7331,32 @@ int Rows_log_event::do_apply_event(Relay
       DBUG_ASSERT(error != HA_ERR_RECORD_DELETED);
 
       table->in_use = old_thd;
-      switch (error)
-      {
-      case 0:
-	break;
-      /*
-        The following list of "idempotent" errors
-        means that an error from the list might happen
-        because of idempotent (more than once) 
-        applying of a binlog file.
-        Notice, that binlog has a  ddl operation its
-        second applying may cause
-
-        case HA_ERR_TABLE_DEF_CHANGED:
-        case HA_ERR_CANNOT_ADD_FOREIGN:
 
-        which are not included into to the list.
-
-        Note that HA_ERR_RECORD_DELETED is not in the list since
-        do_exec_row() should not return that error code.
-      */
-      case HA_ERR_RECORD_CHANGED:
-      case HA_ERR_KEY_NOT_FOUND:
-      case HA_ERR_END_OF_FILE:
-      case HA_ERR_FOUND_DUPP_KEY:
-      case HA_ERR_FOUND_DUPP_UNIQUE:
-      case HA_ERR_FOREIGN_DUPLICATE_KEY:
-      case HA_ERR_NO_REFERENCED_ROW:
-      case HA_ERR_ROW_IS_REFERENCED:
-
-        if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1)
-        {
-          if (global_system_variables.log_warnings)
-            slave_rows_error_report(WARNING_LEVEL, error, rli, thd, table,
-                                    get_type_str(),
-                                    RPL_LOG_NAME, (ulong) log_pos);
-          error= 0;
-        }
-        break;
-        
-      default:
-	thd->is_slave_error= 1;
-	break;
+      DBUG_PRINT("info",("error (0) %d %d \n", error, thd->is_error() ? thd->main_da.sql_errno() : 0));
+      if (error)
+      {
+          int srvflag;
+          char ebuff[MYSQL_ERRMSG_SIZE];
+          uint actual_error_code = (thd->is_error() ? thd->main_da.sql_errno() :
+                                    table->file->process_error(error, ebuff,
+                                                               MYSQL_ERRMSG_SIZE,
+                                                               &srvflag));
+          if (ignored_error_code(actual_error_code) ||
+              (idempotent_error_code(error) &&
+               bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT)))
+          {
+            if (global_system_variables.log_warnings)
+            {
+              sql_print_warning(ebuff);
+              slave_rows_error_report(WARNING_LEVEL, error, rli, thd, table,
+                                      get_type_str(),
+                                      RPL_LOG_NAME, (ulong) log_pos);
+            }
+            clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
+            thd->killed= THD::NOT_KILLED;
+            thd->is_slave_error= 0;
+            error= 0;
+          }
       }
 
       /*
@@ -7353,6 +7384,9 @@ int Rows_log_event::do_apply_event(Relay
     DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event",
                     const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
     error= do_after_row_operations(rli, error);
+
+    DBUG_PRINT("info",("error (1) %d %d \n", error, thd->is_error() ? thd->main_da.sql_errno() : 0));
+
     if (!cache_stmt)
     {
       DBUG_PRINT("info", ("Marked that we need to keep log"));
@@ -7366,29 +7400,39 @@ int Rows_log_event::do_apply_event(Relay
   */
   if (rli->tables_to_lock && get_flags(STMT_END_F))
     const_cast<Relay_log_info*>(rli)->clear_tables_to_lock();
-  
-  if (error)
-  {                     /* error has occured during the transaction */
-    slave_rows_error_report(ERROR_LEVEL, error, rli, thd, table,
-                            get_type_str(), RPL_LOG_NAME, (ulong) log_pos);
-  }
+
   if (error)
   {
-    /*
-      If one day we honour --skip-slave-errors in row-based replication, and
-      the error should be skipped, then we would clear mappings, rollback,
-      close tables, but the slave SQL thread would not stop and then may
-      assume the mapping is still available, the tables are still open...
-      So then we should clear mappings/rollback/close here only if this is a
-      STMT_END_F.
-      For now we code, knowing that error is not skippable and so slave SQL
-      thread is certainly going to stop.
-      rollback at the caller along with sbr.
-    */
-    thd->reset_current_stmt_binlog_row_based();
-    const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
-    thd->is_slave_error= 1;
-    DBUG_RETURN(error);
+    DBUG_PRINT("info",("error (2) %d %d \n", error, thd->is_error() ? thd->main_da.sql_errno() : 0));
+    int srvflag;
+    char ebuff[MYSQL_ERRMSG_SIZE];
+    uint actual_error_code = (thd->is_error() ? thd->main_da.sql_errno() :
+                              table->file->process_error(error, ebuff,
+                                                         MYSQL_ERRMSG_SIZE,
+                                                         &srvflag));
+    if (ignored_error_code(actual_error_code))
+    {
+      if (global_system_variables.log_warnings)
+      {
+        sql_print_warning(ebuff);
+        slave_rows_error_report(WARNING_LEVEL, error, rli, thd, table,
+                                get_type_str(),
+                                RPL_LOG_NAME, (ulong) log_pos);
+      }
+      clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
+      thd->killed= THD::NOT_KILLED;
+      error= 0;
+      thd->is_slave_error= 0;
+    }
+    else 
+    {
+      slave_rows_error_report(ERROR_LEVEL, error, rli, thd, table,
+                               get_type_str(),
+                               RPL_LOG_NAME, (ulong) log_pos);
+      thd->reset_current_stmt_binlog_row_based();
+      const_cast<Relay_log_info*>(rli)->cleanup_context(thd, error);
+      thd->is_slave_error= 1;
+    }
   }
 
   /*
@@ -7396,7 +7440,8 @@ int Rows_log_event::do_apply_event(Relay
     since we have no access to table there, we do the setting of
     last_event_start_time here instead.
   */
-  if (table && (table->s->primary_key == MAX_KEY) &&
+  if (!error && 
+      table && (table->s->primary_key == MAX_KEY) &&
       !cache_stmt && get_flags(STMT_END_F) == RLE_NO_FLAGS)
   {
     /*
@@ -7418,7 +7463,7 @@ int Rows_log_event::do_apply_event(Relay
     const_cast<Relay_log_info*>(rli)->last_event_start_time= my_time(0);
   }
 
-  DBUG_RETURN(0);
+  DBUG_RETURN(error);
 }
 
 Log_event::enum_skip_reason

=== modified file 'sql/partition_info.cc'
--- a/sql/partition_info.cc	2008-12-02 10:18:01 +0000
+++ b/sql/partition_info.cc	2009-03-20 12:40:23 +0000
@@ -1075,22 +1075,41 @@ end:
   DBUG_RETURN(result);
 }
 
+void partition_info::print_no_partition_found(TABLE *table) 
+{
+  DBUG_ENTER("partition_info::print_no_partition_found");
+
+  char ebuff[MYSQL_ERRMSG_SIZE];
+  myf srvflag= MYF(0);
+  int srverror= process_no_partition_found(table, ebuff, MYSQL_ERRMSG_SIZE,
+                                           &srvflag);
+  my_message(srverror, ebuff, srvflag);
+
+  DBUG_VOID_RETURN;
+}
 
 /*
-  Print error for no partition found
+  Process error for no partition found
 
   SYNOPSIS
-    print_no_partition_found()
+    process_no_partition_found()
     table                        Table object
+    ebuff                        char* buffer
+    srvflag                      MYF flags
 
   RETURN VALUES
 */
-
-void partition_info::print_no_partition_found(TABLE *table)
+int partition_info::process_no_partition_found(TABLE *table, char* ebuff, 
+                                               int size, myf* srvflag)
 {
   char buf[100];
   char *buf_ptr= (char*)&buf;
   TABLE_LIST table_list;
+  int textno= ER_NO_PARTITION_FOR_GIVEN_VALUE;
+
+  DBUG_ENTER("partition_info::process_no_partition_found");
+
+  DBUG_ASSERT(ebuff != 0 && size >= 0 && srvflag != 0);
 
   bzero(&table_list, sizeof(table_list));
   table_list.db= table->s->db.str;
@@ -1098,8 +1117,7 @@ void partition_info::print_no_partition_
 
   if (check_single_table_access(current_thd,
                                 SELECT_ACL, &table_list, TRUE))
-    my_message(ER_NO_PARTITION_FOR_GIVEN_VALUE,
-               ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT), MYF(0));
+    my_buffer_format(ebuff, size, ER(ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT));
   else
   {
     my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
@@ -1108,9 +1126,13 @@ void partition_info::print_no_partition_
     else
       longlong2str(err_value, buf,
                    part_expr->unsigned_flag ? 10 : -10);
-    my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr);
+
+    my_buffer_error(textno, ebuff, size, buf_ptr);
     dbug_tmp_restore_column_map(table->read_set, old_map);
   }
+  (*srvflag)= MYF(0);
+
+  DBUG_RETURN(textno);
 }
 /*
   Set up buffers and arrays for fields requiring preparation

=== modified file 'sql/partition_info.h'
--- a/sql/partition_info.h	2008-11-10 20:21:49 +0000
+++ b/sql/partition_info.h	2009-03-20 12:40:23 +0000
@@ -276,6 +276,8 @@ public:
   bool check_partition_info(THD *thd, handlerton **eng_type,
                             handler *file, HA_CREATE_INFO *info,
                             bool check_partition_function);
+  int process_no_partition_found(TABLE *table, char* ebuff, int size,
+                                 myf* srvflag);
   void print_no_partition_found(TABLE *table);
   bool set_up_charset_field_preps();
 private:

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2009-01-09 12:49:24 +0000
+++ b/sql/slave.cc	2009-03-20 12:40:23 +0000
@@ -361,6 +361,7 @@ void init_slave_skip_errors(const char* 
   if (!my_strnncoll(system_charset_info,(uchar*)arg,4,(const uchar*)"all",4))
   {
     bitmap_set_all(&slave_error_mask);
+    print_slave_skip_errors();
     DBUG_VOID_RETURN;
   }
   for (p= arg ; *p; )

Thread
bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2802)Bug#39393Alfranio Correia20 Mar
  • Re: bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2802)Bug#39393He Zhenxing25 Mar
    • Re: bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2802)Bug#39393Alfranio Correia25 Mar
      • Re: bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2802)Bug#39393He Zhenxing26 Mar
      • Re: bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2802)Bug#39393Andrei Elkin27 Mar
        • Re: bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2802)Bug#39393Alfranio Correia27 Mar