#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; )