Alfranio, hello.
I thought about clever Zhen Xing's comments to agree that the current patch
changes are way too intrusive, not quite expectedly to me.
Indeed, we could be content with mimicing of how the statement level
ignores errors (i might have offered that in the first place, but i
slipped, sorry).
So
Query_log_event::do_apply_event() shows what to do.
Once Rows_log_event::do_exec_row() returns with the HANDLER
error thd->is_error() must be TRUE and
thd->main_da.sql_errno() gets us the USER error.
The rest, including clearing the error, you will see in
Query_log_event::do_apply_event().
So I suggest to go this way.
It's a good refactoring you've made for idempotent error, to admit.
cheers,
Andrei
> He Zhenxing wrote:
>> Hi Alfranio,
>>
>> Thank you for the work!
>>
>> I think it is not necessary to change the handler structure, I think you
>> do not need to construct the error message from storage engines and
>> report the error as a warning, because we do not do that for SBR
>> eighter.
>>
> Hi Jasonh,
>
> I can remove the warning messages if you want but I don't see any
> problem in having it.
> However, I think we need to change the handler's interface because the
> mapping between
> the engine errors and the server error is there. And If the RBR fails we
> want to skip
> based on the server error and thus we need to call a method in the
> handler that does the
> translation but does not print out any message.
>
> So I would keep the changes but just eliminate the warning message.
> Do you agree?
>
> If you don't agree we will need at least to change the the signature of
> the ::print_error
> and other methods in the cluster and partition to avoid printing the
> message and
> at the same return the error code.
>
> Andrei, what do you think?
> Jasonh, Andrei, Do you have comments on the core of the bug and the test
> case?
>
> Cheers.
>
>
>> Alfranio Correia wrote:
>>
>>> #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; )