From dc8d5bc7ba7e73cd0f651c3fabc921fe3b00a2f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 23 Nov 2007 14:41:41 +0100 Subject: BUG#32580 (mysqlbinlog cannot read binlog event generated by user variable usage): The client program 'mysqlbinlog' crashed when trying to print a User_var_log_event holding a floating-point value since the format specifier for my_b_printf() does not support floating-point format specifiers. This patch prints the floating-point number to an internal buffer, and then writes that buffer to the output instead. mysql-test/r/mysqlbinlog.result: Result file change. mysql-test/t/mysqlbinlog.test: Adding test that mysqlbinlog can write and read back User_var_log_event for real, decimal, integer, and string. These are the only types supported for user variables. sql/log_event.cc: Using my_sprintf() to print floating-point value of User_var_log_event value to a character buffer and then to the real output, since my_b_printf() does not support floating-point format. Also adding macro to give buffer size needed for printing floating-point numbers in %g format. --- sql/log_event.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 9ad85be8a91..d1ad9211d63 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -36,6 +36,16 @@ #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") + +/* + Size of buffer for printing a double in format %.g + + optional '-' + optional zero + '.' + PREC digits + 'e' + sign + + exponent digits + '\0' +*/ +#define FMT_G_BUFSIZE(PREC) (3 + (PREC) + 5 + 1) + + #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) && !defined(DBUG_OFF) && !defined(_lint) static const char *HA_ERR(int i) { @@ -4404,8 +4414,10 @@ void User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) switch (type) { case REAL_RESULT: double real_val; + char real_buf[FMT_G_BUFSIZE(14)]; float8get(real_val, val); - my_b_printf(&cache, ":=%.14g%s\n", real_val, print_event_info->delimiter); + my_sprintf(real_buf, (real_buf, "%.14g", real_val)); + my_b_printf(&cache, ":=%s%s\n", real_buf, print_event_info->delimiter); break; case INT_RESULT: char int_buf[22]; -- cgit v1.2.1 From 7ed596398becf839238e02fc6e0b30a1b8dd2b54 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 28 Nov 2007 15:35:25 +0400 Subject: bug#29562 default collation of ucs2_unicode_ci crashes slave Problem: some pieces of code relied on the default character set settings, which didn't work in case of default character set ucs2. Fix: Specifying character set explicitly, not to depend on the default settings. mysql-test/suite/rpl_ndb/r/rpl_ndb_ctype_ucs2_def.result: Recording correct test result mysql-test/suite/rpl_ndb/t/disabled.def: Enabling test sql/ha_ndbcluster_binlog.cc: Character set of the NDB helper tables should not rely of the default settings, to avoid creating tables in different character sets on master and slave. Adding explicit character set. UTF8 should be fine. character_set_client should not rely on the default character set settings, which can be ucs2. Helper SQL queries sent by NDB are all in pure ASCII. Setting client_character_set to latin1. sql/log_event.cc: Adding assert to make sure that binary log does not have queries in character set which parser does not understand (e.g. ucs2). --- sql/log_event.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index d1ad9211d63..fbb44fd8f38 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1648,6 +1648,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, DBUG_ASSERT(thd_arg->variables.character_set_client->number < 256*256); DBUG_ASSERT(thd_arg->variables.collation_connection->number < 256*256); DBUG_ASSERT(thd_arg->variables.collation_server->number < 256*256); + DBUG_ASSERT(thd_arg->variables.character_set_client->mbminlen == 1); int2store(charset, thd_arg->variables.character_set_client->number); int2store(charset+2, thd_arg->variables.collation_connection->number); int2store(charset+4, thd_arg->variables.collation_server->number); -- cgit v1.2.1 From 7a5f3f12bc45f7f1db9ba97be0337dfd256b96d3 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 5 Dec 2007 20:00:14 +0100 Subject: BUG#31583 (5.1-telco-6.1 -> 5.1.22. Slave returns Error in unknown event): In the patch for BUG#21842, the code for handling old rows events were refactored. There were a bug in the refactored code (possibly introduced after the patch for BUG#21842) that caused caused the refactored old events to read a columns bitmap after image even though there is no such bitmap for old events. As a result, the reading got out of sync, and started reading invalid data. This patch removes all trace of the after image column bitmap from the refactored old events and removes functions that are no longer needed because they are empty. sql/log_event.cc: Adding debug printouts and adding old rows events names to output so that they are not printed as unknown events. sql/log_event_old.cc: Adding debug printouts to see how the old events are partitioned when being decoded. Removing all traces of the column bitmap for the after image in the old events since there is none. Removing the following functions since they are no longer needed: - Update_rows_log_event_old::init() - Update_rows_log_event_old::~Update_rows_log_event_old() Removing unused local variable. sql/log_event_old.h: Removing all traces of the column bitmap for the after image in the old events since there is none. Removing the following functions since they are no longer needed: - Update_rows_log_event_old::init() - Update_rows_log_event_old::is_valid() - Update_rows_log_event_old::~Update_rows_log_event_old() Removing unused local variable. mysql-test/suite/bugs/r/rpl_bug31583.result: New BitKeeper file ``mysql-test/suite/bugs/r/rpl_bug31583.result'' mysql-test/suite/bugs/t/rpl_bug31583.test: New BitKeeper file ``mysql-test/suite/bugs/t/rpl_bug31583.test'' --- sql/log_event.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index d3b0f7ed3b4..c7963fe803a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -490,6 +490,9 @@ const char* Log_event::get_type_str() case USER_VAR_EVENT: return "User var"; case FORMAT_DESCRIPTION_EVENT: return "Format_desc"; case TABLE_MAP_EVENT: return "Table_map"; + case PRE_GA_WRITE_ROWS_EVENT: return "Write_rows_event_old"; + case PRE_GA_UPDATE_ROWS_EVENT: return "Update_rows_event_old"; + case PRE_GA_DELETE_ROWS_EVENT: return "Delete_rows_event_old"; case WRITE_ROWS_EVENT: return "Write_rows"; case UPDATE_ROWS_EVENT: return "Update_rows"; case DELETE_ROWS_EVENT: return "Delete_rows"; @@ -1015,6 +1018,8 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, DBUG_ENTER("Log_event::read_log_event(char*,...)"); DBUG_ASSERT(description_event != 0); DBUG_PRINT("info", ("binlog_version: %d", description_event->binlog_version)); + DBUG_DUMP("data", (unsigned char*) buf, event_len); + /* Check the integrity */ if (event_len < EVENT_LEN_OFFSET || buf[EVENT_TYPE_OFFSET] >= ENUM_END_EVENT || -- cgit v1.2.1 From 96a51b7f39be9bd664a8d242670ad1d6522c2b83 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Dec 2007 12:14:59 +0200 Subject: Bug#31552 Replication breaks when deleting rows from out-of-sync table without PK Bug#31609 Not all RBR slave errors reported as errors bug#32468 delete rows event on a table with foreign key constraint fails The first two bugs comprise idempotency issues. First, there was no error code reported under conditions of the bug description although the slave sql thread halted. Second, executions were different with and without presence of prim key in the table. Third, there was no way to instruct the slave whether to ignore an error and skip to the following event or to halt. Fourth, there are handler errors which might happen due to idempotent applying of binlog but those were not listed among the "idempotent" error list. All the named issues are addressed. Wrt to the 3rd, there is the new global system variable, changeble at run time, which controls the slave sql thread behaviour. The new variable allows further extensions to mimic the sql_mode session/global variable. To address the 4th, the new bug#32468 had to be fixed as it was staying in the way. include/my_bitmap.h: basic operations with bits of an integer type are added. mysql-test/extra/rpl_tests/rpl_foreign_key.test: regression test for bug#32468 mysql-test/extra/rpl_tests/rpl_row_basic.test: changes due to bug#31552/31609 idempotency is not default any longer mysql-test/extra/rpl_tests/rpl_row_tabledefs.test: changes due to bug#31552/31609 idempotency is not default any longer mysql-test/suite/rpl/r/rpl_foreign_key_innodb.result: results changed mysql-test/suite/rpl/r/rpl_idempotency.result: results changed mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result: results changed mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result: results changed mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result: results changed mysql-test/suite/rpl/r/rpl_row_mystery22.result: results changed mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result: results changed mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result: results changed mysql-test/suite/rpl/r/rpl_temporary_errors.result: results changed mysql-test/suite/rpl/t/rpl_idempotency.test: extenstions to the test providing testing of complements to the idempotent error set and checking how slave halts when it faces an error from the list when the mode is STRICT. mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test: changes due to bug#31552/31609 idempotency is not default any longer. mysql-test/suite/rpl/t/rpl_row_mystery22.test: changes due to bug#31552/31609 idempotency is not default any longer mysql-test/suite/rpl/t/rpl_temporary_errors.test: changes due to bug#31552/31609 idempotency is not default any longer mysql-test/suite/rpl_ndb/r/rpl_ndb_dd_advance.result: results changed mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result: results changed sql/log_event.cc: the fix for bug#32468 delete rows event on a table with foreign key constraint fails ensures the flags are set at proper time so that their values will be caught by innodb. reseting the flags is done along the common error and errorless execution path. The list of idempotent error is extended with foreign keys related items. NDB engine write events are designed with the replace sematics in mind. Therefore the corrsponding ndb handler's flag are (re)set regardless of the slave's execution mode. Rows_log_event::write_row() starts using the bool replace argument as its caller sets it depending on the event's execution mode. sql/log_event.h: adding a new member to hold the slave's mode during execution of the event. sql/mysql_priv.h: changes to link the command line option with the new global sys var. sql/mysqld.cc: introduction of the new command line option. providing its initialization to a default. changes to link the command line option with the new global sys var. sql/rpl_rli.cc: rli post-event-execution cleanup restores the default bits. sql/set_var.cc: The new "standard" sys_var_set class' and the new global system var related declarations and definitions. fix_slave_exec_mode() is used as with the update method of a new class so as at time of the command line arguments parsing. sql/set_var.h: new declarations. The class for the new global sys var is based on yet another new "standard" one. sql/share/errmsg.txt: slave_exec_mode setting error; slave inconsistency error which may be not an error when the intention is "idempotent". I.e consisting of row-based events binlog is being applied for the 2nd (more) time. sql/sql_class.h: The names for the bits of the new sever slave_exec_mode_options. mysql-test/suite/rpl/t/rpl_idempotency-master.opt: innodb is necessary mysql-test/suite/rpl/t/rpl_idempotency-slave.opt: innodb is necessary, as well as the tests start with non-default IDEMPOTENT slave execution mode. --- sql/log_event.cc | 239 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 147 insertions(+), 92 deletions(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 77cf719fde5..fc8b1904496 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -90,6 +90,28 @@ static const char *HA_ERR(int i) case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE"; case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT"; } + return 0; +} + +/** + macro to call from different branches of Rows_log_event::do_apply_event +*/ +static void inline slave_rows_error_report(enum loglevel level, int ha_error, + Relay_log_info const *rli, THD *thd, + TABLE *table, const char * type, + const char *log_name, ulong pos) +{ + const char *handler_error= HA_ERR(ha_error); + rli->report(level, thd->net.last_errno, + "Could not execute %s event on table %s.%s;" + "%s%s handler error %s; " + "the event's master log %s, end_log_pos %lu", + type, table->s->db.str, + table->s->table_name.str, + thd->net.last_error[0] != 0 ? thd->net.last_error : "", + thd->net.last_error[0] != 0 ? ";" : "", + handler_error == NULL? "" : handler_error, + log_name, pos); } #endif @@ -6060,7 +6082,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) { DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)"); int error= 0; - /* If m_table_id == ~0UL, then we have a dummy event that does not contain any data. In that case, we just remove all tables in the @@ -6106,6 +6127,24 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) */ lex_start(thd); + /* + There are a few flags that are replicated with each row event. + Make sure to set/clear them before executing the main body of + the event. + */ + if (get_flags(NO_FOREIGN_KEY_CHECKS_F)) + thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS; + else + thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS; + + if (get_flags(RELAXED_UNIQUE_CHECKS_F)) + thd->options|= OPTION_RELAXED_UNIQUE_CHECKS; + else + thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS; + /* A small test to verify that objects have consistent types */ + DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); + + while ((error= lock_tables(thd, rli->tables_to_lock, rli->tables_to_lock_count, &need_reopen))) { @@ -6240,22 +6279,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) So we call set_time(), like in SBR. Presently it changes nothing. */ thd->set_time((time_t)when); - /* - There are a few flags that are replicated with each row event. - Make sure to set/clear them before executing the main body of - the event. - */ - if (get_flags(NO_FOREIGN_KEY_CHECKS_F)) - thd->options|= OPTION_NO_FOREIGN_KEY_CHECKS; - else - thd->options&= ~OPTION_NO_FOREIGN_KEY_CHECKS; - - if (get_flags(RELAXED_UNIQUE_CHECKS_F)) - thd->options|= OPTION_RELAXED_UNIQUE_CHECKS; - else - thd->options&= ~OPTION_RELAXED_UNIQUE_CHECKS; - /* A small test to verify that objects have consistent types */ - DBUG_ASSERT(sizeof(thd->options) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS)); /* Now we are in a statement and will stay in a statement until we @@ -6288,8 +6311,9 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) if (!get_flags(COMPLETE_ROWS_F)) bitmap_intersect(table->write_set,&m_cols); + this->slave_exec_mode= slave_exec_mode_options; // fix the mode + // Do event specific preparations - error= do_before_row_operations(rli); // row processing loop @@ -6308,22 +6332,41 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) { case 0: break; - - /* Some recoverable errors */ + /* + 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. + */ case HA_ERR_RECORD_CHANGED: case HA_ERR_RECORD_DELETED: case HA_ERR_KEY_NOT_FOUND: case HA_ERR_END_OF_FILE: - /* Idempotency support: OK if tuple does not exist */ + 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: + DBUG_PRINT("info", ("error: %s", HA_ERR(error))); - error= 0; + 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: - rli->report(ERROR_LEVEL, thd->net.last_errno, - "Error in %s event: row application failed. %s", - get_type_str(), - thd->net.last_error ? thd->net.last_error : ""); thd->query_error= 1; break; } @@ -6367,16 +6410,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) */ if (rli->tables_to_lock && get_flags(STMT_END_F)) const_cast(rli)->clear_tables_to_lock(); - + if (error) { /* error has occured during the transaction */ - rli->report(ERROR_LEVEL, thd->net.last_errno, - "Error in %s event: error during transaction execution " - "on table %s.%s. %s", - get_type_str(), table->s->db.str, - table->s->table_name.str, - thd->net.last_error ? thd->net.last_error : ""); - + 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, @@ -6488,6 +6529,7 @@ Rows_log_event::do_update_pos(Relay_log_info *rli) */ thd->reset_current_stmt_binlog_row_based(); + rli->cleanup_context(thd, 0); if (error == 0) { @@ -7170,43 +7212,50 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability { int error= 0; - /* - We are using REPLACE semantics and not INSERT IGNORE semantics - when writing rows, that is: new rows replace old rows. We need to - inform the storage engine that it should use this behaviour. + /** + todo: to introduce a property for the event (handler?) which forces + applying the event in the replace (idempotent) fashion. */ + if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1 || + m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER) + { + /* + We are using REPLACE semantics and not INSERT IGNORE semantics + when writing rows, that is: new rows replace old rows. We need to + inform the storage engine that it should use this behaviour. + */ + + /* Tell the storage engine that we are using REPLACE semantics. */ + thd->lex->duplicates= DUP_REPLACE; + + /* + Pretend we're executing a REPLACE command: this is needed for + InnoDB and NDB Cluster since they are not (properly) checking the + lex->duplicates flag. + */ + thd->lex->sql_command= SQLCOM_REPLACE; + /* + Do not raise the error flag in case of hitting to an unique attribute + */ + m_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + /* + NDB specific: update from ndb master wrapped as Write_rows + so that the event should be applied to replace slave's row + */ + m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); + /* + NDB specific: if update from ndb master wrapped as Write_rows + does not find the row it's assumed idempotent binlog applying + is taking place; don't raise the error. + */ + m_table->file->extra(HA_EXTRA_IGNORE_NO_KEY); + /* + TODO: the cluster team (Tomas?) says that it's better if the engine knows + how many rows are going to be inserted, then it can allocate needed memory + from the start. + */ + } - /* Tell the storage engine that we are using REPLACE semantics. */ - thd->lex->duplicates= DUP_REPLACE; - - /* - Pretend we're executing a REPLACE command: this is needed for - InnoDB and NDB Cluster since they are not (properly) checking the - lex->duplicates flag. - */ - thd->lex->sql_command= SQLCOM_REPLACE; - /* - Do not raise the error flag in case of hitting to an unique attribute - */ - m_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - /* - NDB specific: update from ndb master wrapped as Write_rows - */ - /* - so that the event should be applied to replace slave's row - */ - m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE); - /* - NDB specific: if update from ndb master wrapped as Write_rows - does not find the row it's assumed idempotent binlog applying - is taking place; don't raise the error. - */ - m_table->file->extra(HA_EXTRA_IGNORE_NO_KEY); - /* - TODO: the cluster team (Tomas?) says that it's better if the engine knows - how many rows are going to be inserted, then it can allocate needed memory - from the start. - */ m_table->file->ha_start_bulk_insert(0); /* We need TIMESTAMP_NO_AUTO_SET otherwise ha_write_row() will not use fill @@ -7228,18 +7277,23 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability } int -Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const, +Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const, int error) { int local_error= 0; - m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); - m_table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); - /* - reseting the extra with - table->file->extra(HA_EXTRA_NO_IGNORE_NO_KEY); - fires bug#27077 - todo: explain or fix - */ + if (bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1 || + m_table->s->db_type()->db_type == DB_TYPE_NDBCLUSTER) + { + m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + m_table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); + /* + resetting the extra with + table->file->extra(HA_EXTRA_NO_IGNORE_NO_KEY); + fires bug#27077 + explanation: file->reset() performs this duty + ultimately. Still todo: fix + */ + } if ((local_error= m_table->file->ha_end_bulk_insert())) { m_table->file->print_error(local_error, MYF(0)); @@ -7358,23 +7412,22 @@ Rows_log_event::write_row(const Relay_log_info *const rli, while ((error= table->file->ha_write_row(table->record[0]))) { - if (error == HA_ERR_LOCK_DEADLOCK || error == HA_ERR_LOCK_WAIT_TIMEOUT) + if (error == HA_ERR_LOCK_DEADLOCK || + error == HA_ERR_LOCK_WAIT_TIMEOUT || + (keynum= table->file->get_dup_key(error)) < 0 || + !overwrite) { - table->file->print_error(error, MYF(0)); /* to check at exec_relay_log_event */ - DBUG_RETURN(error); - } - if ((keynum= table->file->get_dup_key(error)) < 0) - { - DBUG_PRINT("info",("Can't locate duplicate key (get_dup_key returns %d)",keynum)); - table->file->print_error(error, MYF(0)); + DBUG_PRINT("info",("get_dup_key returns %d)", keynum)); /* - We failed to retrieve the duplicate key + Deadlock, waiting for lock or just an error from the handler + such as HA_ERR_FOUND_DUPP_KEY when overwrite is false. + Retrieval of the duplicate key number may fail - either because the error was not "duplicate key" error - or because the information which key is not available */ + table->file->print_error(error, MYF(0)); DBUG_RETURN(error); } - /* We need to retrieve the old row into record[1] to be able to either update or delete the offending record. We either: @@ -7512,11 +7565,13 @@ int Write_rows_log_event::do_exec_row(const Relay_log_info *const rli) { DBUG_ASSERT(m_table != NULL); - int error= write_row(rli, TRUE /* overwrite */); - + int error= + write_row(rli, /* if 1 then overwrite */ + bit_is_set(slave_exec_mode, SLAVE_EXEC_MODE_IDEMPOTENT) == 1); + if (error && !thd->net.last_errno) thd->net.last_errno= error; - + return error; } -- cgit v1.2.1 From 32c5d070dd49943f6f2510846ba2c8a6a6f5510d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Dec 2007 20:12:29 +0100 Subject: bug#31552 manual merge and post-make-test-run changes. mysql-test/extra/rpl_tests/rpl_row_basic.test: changes due to the strict mode gets default. This hunk is being added after merging with changes from another bug fixes. mysql-test/suite/rpl/r/rpl_ignore_table.result: results changed mysql-test/suite/rpl/r/rpl_row_basic_2myisam.result: results changed mysql-test/suite/rpl/r/rpl_row_basic_3innodb.result: results changed mysql-test/suite/rpl/t/rpl_ignore_table.test: two queries on mysql db tables are replicated according to binlog_format, ie in row-based when that is requested. Due to cancelling the idempotent default row based events that previously exectuted successfully now stop the slave sql thread. We have to explicitly request the idempotent slave execution mode. mysql-test/suite/rpl_ndb/r/rpl_ndb_dd_advance.result: results changed. They are being committed only now since there was another bug which fixes my working clone did not have. mysql-test/suite/rpl_ndb/r/rpl_row_basic_7ndb.result: results changed sql/log_event.cc: typo in manual merge earlier --- sql/log_event.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 28f9afec9a0..2490e54282f 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -122,7 +122,6 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, thd->net.last_error[0] != 0 ? ";" : "", handler_error == NULL? "" : handler_error, log_name, pos); ->>>>>>> } #endif -- cgit v1.2.1 From 3473d97857d4b48be9c1d1478040ef67f09ee3be Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Dec 2007 09:32:23 +0100 Subject: bug#31552 fixing a compilation issue in the debugless build. sql/log_event.cc: relaxing compilation condition as HA_ERR is started to be used for error reporting. --- sql/log_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 2490e54282f..db0a5c2b53a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -46,7 +46,7 @@ #define FMT_G_BUFSIZE(PREC) (3 + (PREC) + 5 + 1) -#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) && !defined(DBUG_OFF) && !defined(_lint) +#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) static const char *HA_ERR(int i) { switch (i) { -- cgit v1.2.1 From 44efa9c18b949fa7078e44aef8aba75a4e8bb4db Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Dec 2007 14:40:45 +0100 Subject: BUG#26395: if crash during autocommit update to transactional table on master, slave fails Now, every transaction (including autocommit transactions) starts with a BEGIN and ends with a COMMIT/ROLLBACK in the binlog. Added a test case, and updated lots of test case result files. mysql-test/r/multi_update.result: Updated result file mysql-test/r/sp_trans_log.result: Updated result file mysql-test/suite/binlog/r/binlog_innodb.result: Updated result file mysql-test/suite/binlog/r/binlog_multi_engine.result: Updated result file mysql-test/suite/binlog/r/binlog_stm_blackhole.result: Updated result file mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: Updated result file mysql-test/suite/ndb/r/ndb_binlog_format.result: Updated result file mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result: Updated result file mysql-test/suite/rpl/r/rpl_row_charset_innodb.result: Updated result file mysql-test/suite/rpl/r/rpl_row_create_table.result: Updated result file mysql-test/suite/rpl/r/rpl_row_log_innodb.result: Updated result file mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result: Updated result file mysql-test/suite/rpl/r/rpl_truncate_3innodb.result: Updated result file mysql-test/suite/rpl/t/rpl_row_create_table.test: Updated result file mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result: Updated result file sql/log.cc: - Always write BEGIN and COMMIT around statements, even in autocommit mode. - Added comments for binlog_commit and binlog_rollback. sql/log_event.cc: Added debug trigger to avoid writing xid events to the binlog. mysql-test/suite/rpl_ndb/r/rpl_ndb_transaction.result: Results for new test case mysql-test/suite/rpl_ndb/t/rpl_ndb_transaction-master.opt: Options for new test case mysql-test/suite/rpl_ndb/t/rpl_ndb_transaction-slave.opt: Options for new test case mysql-test/suite/rpl_ndb/t/rpl_ndb_transaction.test: Added new test case. --- sql/log_event.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index f328f266c05..cdfd58535fb 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -4292,6 +4292,7 @@ Xid_log_event(const char* buf, #ifndef MYSQL_CLIENT bool Xid_log_event::write(IO_CACHE* file) { + DBUG_EXECUTE_IF("do_not_write_xid", return 0;); return write_header(file, sizeof(xid)) || my_b_safe_write(file, (uchar*) &xid, sizeof(xid)); } -- cgit v1.2.1 From 8d37a30eac38b4fffea3ab9fbea4824c3bb4f522 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Dec 2007 19:02:02 +0100 Subject: BUG#32407: Impossible to do point-in-time recovery from older binlog Problem: it is unsafe to read base64-printed events without first reading the Format_description_log_event (FD). Currently, mysqlbinlog cannot print the FD. As a side effect, another bug has also been fixed: When mysqlbinlog --start-position=X was specified, no ROLLBACK was printed. I changed this, so that ROLLBACK is always printed. This patch does several things: - Format_description_log_event (FD) now print themselves in base64 format. - mysqlbinlog is now able to print FD events. It has three modes: --base64-output=auto Print row events in base64 output, and print FD event. The FD event is printed even if it is outside the range specified with --start-position, because it would not be safe to read row events otherwise. This is the default. --base64-output=always Like --base64-output=auto, but also print base64 output for query events. This is like the old --base64-output flag, which is also a shorthand for --base64-output=always --base64-output=never Never print base64 output, generate error if row events occur in binlog. This is useful to suppress the FD event in binlogs known not to contain row events (e.g., because BINLOG statement is unsafe, requires root privileges, is not SQL, etc) - the BINLOG statement now handles FD events correctly, by setting the thread's rli's relay log's description_event_for_exec to the loaded event. In fact, executing a BINLOG statement is almost the same as reading an event from a relay log. Before my patch, the code for this was separated (exec_relay_log_event in slave.cc executes events from the relay log, mysql_client_binlog_statement in sql_binlog.cc executes BINLOG statements). I needed to augment mysql_client_binlog_statement to do parts of what exec_relay_log_event does. Hence, I did a small refactoring and moved parts of exec_relay_log_event to a new function, which I named apply_event_and_update_pos. apply_event_and_update_pos is called both from exec_relay_log_event and from mysql_client_binlog_statement. - When a non-FD event is executed in a BINLOG statement, without previously executing a FD event in a BINLOG statement, it generates an error, because that's unsafe. I took a new error code for that: ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENTS. In order to get a decent error message containing the name of the event, I added the class method char* Log_event::get_type_str(Log_event_type type), which returns a string name for the given Log_event_type. This is just like the existing char* Log_event::get_type_str(), except it is a class method that takes the log event type as parameter. I also added PRE_GA_*_ROWS_LOG_EVENT to Log_event::get_type_str(), so that names of old rows event are properly printed. - When reading an event, I added a check that the event type is known by the current Format_description_log_event. Without this, it may crash on bad input (and I was struck by this several times). - I patched the following test cases, which all contain BINLOG statements for row events which must be preceded by BINLOG statements for FD events: - rpl_bug31076 While I was here, I fixed some small things in log_event.cc: - replaced hard-coded 4 by EVENT_TYPE_OFFSET in 3 places - replaced return by DBUG_VOID_RETURN in one place - The name of the logfile can be '-' to indicate stdin. Before my patch, the code just checked if the first character is '-'; now it does a full strcmp(). Probably, all arguments that begin with a - are already handled somewhere else as flags, but I still think it is better that the code reflects what it is supposed to do, with as little dependencies as possible on other parts of the code. If we one day implement that all command line arguments after -- are files (as most unix tools do), then we need this. I also fixed the following in slave.cc: - next_event() was declared twice, and queue_event was not static but should be static (not used outside the file). client/client_priv.h: Declared the new option for base64 output. client/mysqlbinlog.cc: - Change from using the two-state command line option "default/--base64-output" to the three-state "--base64-output=[never|auto|always]" - Print the FD event even if it is outside the --start-position range. - Stop if a row event is about to be printed without a preceding FD event. - Minor fixes: * changed 4 to EVENT_TYPE_OFFSET in some places * Added comments * before, "mysqlbinlog -xyz" read from stdin; now it does not (only "mysqlbinlog -" reads stdin). mysql-test/r/mysqlbinlog2.result: Updated result file: mysqlbinlog now prints ROLLBACK always. mysql-test/suite/binlog/t/disabled.def: The test must be disabled since it reveals another bug: see BUG#33247. mysql-test/suite/rpl/r/rpl_bug31076.result: Updated result file mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result: Updated result file mysql-test/suite/rpl/t/rpl_bug31076.test: Had to add explicit Format_description_log_event before other BINLOG statements mysql-test/t/mysqlbinlog2.test: we must suppress base64 output in result file because it contains a timestamp sql/log_event.cc: - Made FD events able to print themselves - Added check that the current FD event knows about the event type, when an event is about to be read. (Hint to reviewers: I had to re-indent a big block because of this; use diff -b) * To get a decent error message, I also added a class method const char* Log_event::get_type_str(Log_event_type) which converts number to event type string without having a Log_event object. * Made Log_event::get_type_str aware of PRE_GA_*_ROWS_LOG_EVENT. - Minor fixes: * Changed return to DBUG_VOID_RETURN sql/log_event.h: - Declared enum to describe the three base64_output modes - Use the enum instead of a flag - Declare the new class method get_type_str (see log_event.cc) sql/share/errmsg.txt: Added error msg. sql/slave.cc: - Factored out part of exec_relay_log_event to the new function apply_event_and_update_pos, because that code is needed when executing BINLOG statements. (this is be functionally equivalent to the previous code, except: (1) skipping events is now optional, controlled by a parameter to the new function (2) the return value of exec_relay_log_event has changed; see next item). - Changed returned error value to always be 1. Before, it would return the error value from apply_log_event, which was unnecessary. This change is safe because the exact return value of exec_relay_log_event is never examined; it is only tested to be ==0 or !=0. - Added comments describing exec_relay_log_event and apply_event_and_update_pos. - Minor fixes: * Removed duplicate declaration of next_event, made queue_event static. * Added doxygen code to include this file. sql/slave.h: Declared the new apply_event_and_update_pos sql/sql_binlog.cc: - Made mysql_binlog_statement set the current FD event when the given event is an FD event. This entails using the new function apply_event_and_update_pos from slave.cc instead of just calling the ev->apply method. - Made mysql_binlog_statement fail if the first BINLOG statement is not an FD event. mysql-test/suite/binlog/r/binlog_base64_flag.result: New test file needs new result file mysql-test/suite/binlog/t/binlog_base64_flag.test: Added test case to verify that: - my patch fixes the bug - the new --base64-output flag works as expected - base64 events not preceded by an FD event give an error - an event of a type not known by the current FD event fails cleanly. mysql-test/suite/binlog/std_data/binlog-bug32407.000001: BitKeeper file /home/sven/bk/b32407-5.1-new-rpl-mysqlbinlog_base64/mysql-test/suite/binlog/std_data/binlog-bug32407.000001 --- sql/log_event.cc | 204 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 117 insertions(+), 87 deletions(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index cdfd58535fb..8a4fabde3e3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -491,9 +491,9 @@ static void print_set_option(IO_CACHE* file, uint32 bits_changed, Log_event::get_type_str() */ -const char* Log_event::get_type_str() +const char* Log_event::get_type_str(Log_event_type type) { - switch(get_type_code()) { + switch(type) { case START_EVENT_V3: return "Start_v3"; case STOP_EVENT: return "Stop"; case QUERY_EVENT: return "Query"; @@ -524,6 +524,11 @@ const char* Log_event::get_type_str() } } +const char* Log_event::get_type_str() +{ + return get_type_str(get_type_code()); +} + /* Log_event::Log_event() @@ -1050,94 +1055,111 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, DBUG_RETURN(NULL); // general sanity check - will fail on a partial read } - switch(buf[EVENT_TYPE_OFFSET]) { - case QUERY_EVENT: - ev = new Query_log_event(buf, event_len, description_event, QUERY_EVENT); - break; - case LOAD_EVENT: - ev = new Load_log_event(buf, event_len, description_event); - break; - case NEW_LOAD_EVENT: - ev = new Load_log_event(buf, event_len, description_event); - break; - case ROTATE_EVENT: - ev = new Rotate_log_event(buf, event_len, description_event); - break; + uint event_type= buf[EVENT_TYPE_OFFSET]; + if (event_type > description_event->number_of_event_types && + event_type != FORMAT_DESCRIPTION_EVENT) + { + /* + It is unsafe to use the description_event if its post_header_len + array does not include the event type. + */ + DBUG_PRINT("error", ("event type %d found, but the current " + "Format_description_log_event supports only %d event " + "types", event_type, + description_event->number_of_event_types)); + ev= NULL; + } + else + { + switch(event_type) { + case QUERY_EVENT: + ev = new Query_log_event(buf, event_len, description_event, QUERY_EVENT); + break; + case LOAD_EVENT: + ev = new Load_log_event(buf, event_len, description_event); + break; + case NEW_LOAD_EVENT: + ev = new Load_log_event(buf, event_len, description_event); + break; + case ROTATE_EVENT: + ev = new Rotate_log_event(buf, event_len, description_event); + break; #ifdef HAVE_REPLICATION - case SLAVE_EVENT: /* can never happen (unused event) */ - ev = new Slave_log_event(buf, event_len); - break; + case SLAVE_EVENT: /* can never happen (unused event) */ + ev = new Slave_log_event(buf, event_len); + break; #endif /* HAVE_REPLICATION */ - case CREATE_FILE_EVENT: - ev = new Create_file_log_event(buf, event_len, description_event); - break; - case APPEND_BLOCK_EVENT: - ev = new Append_block_log_event(buf, event_len, description_event); - break; - case DELETE_FILE_EVENT: - ev = new Delete_file_log_event(buf, event_len, description_event); - break; - case EXEC_LOAD_EVENT: - ev = new Execute_load_log_event(buf, event_len, description_event); - break; - case START_EVENT_V3: /* this is sent only by MySQL <=4.x */ - ev = new Start_log_event_v3(buf, description_event); - break; - case STOP_EVENT: - ev = new Stop_log_event(buf, description_event); - break; - case INTVAR_EVENT: - ev = new Intvar_log_event(buf, description_event); - break; - case XID_EVENT: - ev = new Xid_log_event(buf, description_event); - break; - case RAND_EVENT: - ev = new Rand_log_event(buf, description_event); - break; - case USER_VAR_EVENT: - ev = new User_var_log_event(buf, description_event); - break; - case FORMAT_DESCRIPTION_EVENT: - ev = new Format_description_log_event(buf, event_len, description_event); - break; + case CREATE_FILE_EVENT: + ev = new Create_file_log_event(buf, event_len, description_event); + break; + case APPEND_BLOCK_EVENT: + ev = new Append_block_log_event(buf, event_len, description_event); + break; + case DELETE_FILE_EVENT: + ev = new Delete_file_log_event(buf, event_len, description_event); + break; + case EXEC_LOAD_EVENT: + ev = new Execute_load_log_event(buf, event_len, description_event); + break; + case START_EVENT_V3: /* this is sent only by MySQL <=4.x */ + ev = new Start_log_event_v3(buf, description_event); + break; + case STOP_EVENT: + ev = new Stop_log_event(buf, description_event); + break; + case INTVAR_EVENT: + ev = new Intvar_log_event(buf, description_event); + break; + case XID_EVENT: + ev = new Xid_log_event(buf, description_event); + break; + case RAND_EVENT: + ev = new Rand_log_event(buf, description_event); + break; + case USER_VAR_EVENT: + ev = new User_var_log_event(buf, description_event); + break; + case FORMAT_DESCRIPTION_EVENT: + ev = new Format_description_log_event(buf, event_len, description_event); + break; #if defined(HAVE_REPLICATION) - case PRE_GA_WRITE_ROWS_EVENT: - ev = new Write_rows_log_event_old(buf, event_len, description_event); - break; - case PRE_GA_UPDATE_ROWS_EVENT: - ev = new Update_rows_log_event_old(buf, event_len, description_event); - break; - case PRE_GA_DELETE_ROWS_EVENT: - ev = new Delete_rows_log_event_old(buf, event_len, description_event); - break; - case WRITE_ROWS_EVENT: - ev = new Write_rows_log_event(buf, event_len, description_event); - break; - case UPDATE_ROWS_EVENT: - ev = new Update_rows_log_event(buf, event_len, description_event); - break; - case DELETE_ROWS_EVENT: - ev = new Delete_rows_log_event(buf, event_len, description_event); - break; - case TABLE_MAP_EVENT: - ev = new Table_map_log_event(buf, event_len, description_event); - break; + case PRE_GA_WRITE_ROWS_EVENT: + ev = new Write_rows_log_event_old(buf, event_len, description_event); + break; + case PRE_GA_UPDATE_ROWS_EVENT: + ev = new Update_rows_log_event_old(buf, event_len, description_event); + break; + case PRE_GA_DELETE_ROWS_EVENT: + ev = new Delete_rows_log_event_old(buf, event_len, description_event); + break; + case WRITE_ROWS_EVENT: + ev = new Write_rows_log_event(buf, event_len, description_event); + break; + case UPDATE_ROWS_EVENT: + ev = new Update_rows_log_event(buf, event_len, description_event); + break; + case DELETE_ROWS_EVENT: + ev = new Delete_rows_log_event(buf, event_len, description_event); + break; + case TABLE_MAP_EVENT: + ev = new Table_map_log_event(buf, event_len, description_event); + break; #endif - case BEGIN_LOAD_QUERY_EVENT: - ev = new Begin_load_query_log_event(buf, event_len, description_event); - break; - case EXECUTE_LOAD_QUERY_EVENT: - ev= new Execute_load_query_log_event(buf, event_len, description_event); - break; - case INCIDENT_EVENT: - ev = new Incident_log_event(buf, event_len, description_event); - break; - default: - DBUG_PRINT("error",("Unknown event code: %d", - (int) buf[EVENT_TYPE_OFFSET])); - ev= NULL; - break; + case BEGIN_LOAD_QUERY_EVENT: + ev = new Begin_load_query_log_event(buf, event_len, description_event); + break; + case EXECUTE_LOAD_QUERY_EVENT: + ev= new Execute_load_query_log_event(buf, event_len, description_event); + break; + case INCIDENT_EVENT: + ev = new Incident_log_event(buf, event_len, description_event); + break; + default: + DBUG_PRINT("error",("Unknown event code: %d", + (int) buf[EVENT_TYPE_OFFSET])); + ev= NULL; + break; + } } DBUG_PRINT("read_event", ("%s(type_code: %d; event_len: %d)", @@ -2604,6 +2626,14 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info) my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter); #endif } + if (temp_buf && + print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER && + !print_event_info->short_form) + { + my_b_printf(&cache, "BINLOG '\n"); + print_base64(&cache, print_event_info, FALSE); + print_event_info->printed_fd_event= TRUE; + } DBUG_VOID_RETURN; } #endif /* MYSQL_CLIENT */ @@ -5050,7 +5080,7 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len, Load_log_event::get_data_size() + create_file_header_len + 1); if (len < block_offset) - return; + DBUG_VOID_RETURN; block = (char*)buf + block_offset; block_len = len - block_offset; } -- cgit v1.2.1 From 0968c713aa121af45671b36da4fb546b4df56891 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Dec 2007 21:13:25 +0800 Subject: BUG#32205 Replaying statements from mysqlbinlog fails with a syntax error, replicates fine The reason of this bug is that when mysqlbinlog dumps a query, the query is written to output with a delimeter appended right after it, if the query string ends with a '--' comment, then the delimeter would be considered as part of the comment, if there are any statements after this query, then it will cause a syntax error. Start a newline before appending delimiter after a query string mysql-test/r/mysqlbinlog.result: Update result for BUG#32205 mysql-test/r/mysqlbinlog2.result: Update result for BUG#32205 mysql-test/r/user_var-binlog.result: Update result for BUG#32205 mysql-test/suite/binlog/r/binlog_stm_ctype_ucs.result: Update result for BUG#32205 mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: Update result for BUG#32205 mysql-test/suite/binlog/t/binlog_stm_mix_innodb_myisam.test: fix test for BUG#32205 mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result: Update result for BUG#32205 mysql-test/suite/rpl/r/rpl_stm_charset.result: Update result for BUG#32205 sql/log_event.cc: Start a newline before appending delimiter after a query string mysql-test/suite/binlog/r/binlog_start_comment.result: Add test for BUG#32205 mysql-test/suite/binlog/t/binlog_start_comment.test: Add test for BUG#32205 --- sql/log_event.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index f328f266c05..1914fa3ef32 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2177,7 +2177,7 @@ void Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info) print_query_header(&cache, print_event_info); my_b_write(&cache, (uchar*) query, q_len); - my_b_printf(&cache, "%s\n", print_event_info->delimiter); + my_b_printf(&cache, "\n%s\n", print_event_info->delimiter); } #endif /* MYSQL_CLIENT */ @@ -5756,12 +5756,12 @@ void Execute_load_query_log_event::print(FILE* file, my_b_printf(&cache, " REPLACE"); my_b_printf(&cache, " INTO"); my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end); - my_b_printf(&cache, "%s\n", print_event_info->delimiter); + my_b_printf(&cache, "\n%s\n", print_event_info->delimiter); } else { my_b_write(&cache, (uchar*) query, q_len); - my_b_printf(&cache, "%s\n", print_event_info->delimiter); + my_b_printf(&cache, "\n%s\n", print_event_info->delimiter); } if (!print_event_info->short_form) -- cgit v1.2.1 From ac167eca6edba627d737f72fe7ae7dfc20da91b5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Jan 2008 12:55:04 +0100 Subject: Post-merge fixes to make tests pass. mysql-test/r/binlog_start_comment.result: Result change. mysql-test/suite/rpl/r/rpl_row_tabledefs_2myisam.result: Result change. mysql-test/suite/rpl/r/rpl_row_tabledefs_3innodb.result: Result change. mysql-test/suite/rpl/r/rpl_timezone.result: Result change. mysql-test/suite/rpl_ndb/r/rpl_ndb_transaction.result: Result change. mysql-test/suite/rpl_ndb/t/rpl_ndb_transaction.test: Masking out columns with binlog positions from slave status. mysql-test/t/binlog_start_comment.test: Added missing drop table causing subsequent tests to fail. sql/log_event.cc: Changing last_err* fields to client_last_err* sql/log_event_old.cc: Changing last_err* fields to client_last_err* --- sql/log_event.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index c78c0d0862a..a8099e9db8a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -112,14 +112,14 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, const char *log_name, ulong pos) { const char *handler_error= HA_ERR(ha_error); - rli->report(level, thd->net.last_errno, + rli->report(level, thd->net.client_last_errno, "Could not execute %s event on table %s.%s;" "%s%s handler error %s; " "the event's master log %s, end_log_pos %lu", type, table->s->db.str, table->s->table_name.str, - thd->net.last_error[0] != 0 ? thd->net.last_error : "", - thd->net.last_error[0] != 0 ? ";" : "", + thd->net.client_last_error[0] != 0 ? thd->net.client_last_error : "", + thd->net.client_last_error[0] != 0 ? ";" : "", handler_error == NULL? "" : handler_error, log_name, pos); } -- cgit v1.2.1 From 3a6e84a2b36d6bf49bedc6f0e4f97b79220456d2 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 10 Jan 2008 16:39:44 +0100 Subject: BUG#27779: Slave cannot read old rows log events. Problem: Replication fails when master is mysql-5.1-wl2325-5.0-drop6 and slave is mysql-5.1-new-rpl. The reason is that, in mysql-5.1-wl2325-5.0-drop6, the event type id's were different than in mysql-5.1-new-rpl. Fix (in mysql-5.1-new-rpl): (1) detect that the server that generated the events uses the old format, by checking the server version of the format_description_log_event This patch recognizes mysql-5.1-wl2325-5.0-drop6p13-alpha, mysql-5.1-wl2325-5.0-drop6, mysql-5.1-wl2325-5.0, mysql-5.1-wl2325-no-dd. (2) if the generating server is old, map old event types to new event types using a permutation array. I've also added a test case which reads binlogs for four different versions. mysql-test/suite/binlog/std_data/binlog_old_version_5_1-telco.000001: BitKeeper file /home/sven/bk/b27779-old_row_events/5.1-new-rpl/mysql-test/suite/binlog/std_data/binlog_old_version_5_1-telco.000001 mysql-test/suite/binlog/std_data/binlog_old_version_5_1-wl2325_row.000001: BitKeeper file /home/sven/bk/b27779-old_row_events/5.1-new-rpl/mysql-test/suite/binlog/std_data/binlog_old_version_5_1-wl2325_row.000001 mysql-test/suite/binlog/std_data/binlog_old_version_5_1-wl2325_stm.000001: BitKeeper file /home/sven/bk/b27779-old_row_events/5.1-new-rpl/mysql-test/suite/binlog/std_data/binlog_old_version_5_1-wl2325_stm.000001 mysql-test/suite/binlog/std_data/binlog_old_version_5_1_17.000001: BitKeeper file /home/sven/bk/b27779-old_row_events/5.1-new-rpl/mysql-test/suite/binlog/std_data/binlog_old_version_5_1_17.000001 mysql-test/suite/binlog/std_data/binlog_old_version_5_1_23.000001: BitKeeper file /home/sven/bk/b27779-old_row_events/5.1-new-rpl/mysql-test/suite/binlog/std_data/binlog_old_version_5_1_23.000001 sql/log_event.cc: Added code to read events generated by mysql-5.1-wl2325-5.0-drop6p13-alpha, mysql-5.1-wl2325-5.0-drop6, mysql-5.1-wl2325-5.0, mysql-5.1-wl2325-no-dd. More precisely, the event type id's had different numbers in those versions. To fix, we add a permutation array which maps old_id to new_id when the format_description_log_event indicates that the originating server is of the old type. We also need to permute the post_header_len array accordingly. sql/log_event.h: sql/log_event.h@1.169, 2008-01-09 11:34:37+01:00, sven@riska.(none) +5 -1 Added declaration needed in log_event.cc. Also, the destructor of Format_description_log_event is sometimes called when post_header_len is null, so we must pass the MY_ALLOW_ZERO_PTR flag to my_free. mysql-test/suite/binlog/r/binlog_old_versions.result: Result file for new test. mysql-test/suite/binlog/t/binlog_old_versions.test: New test case that loads binlogs from several old versions. --- sql/log_event.cc | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 2 deletions(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 31c14bbd81d..45478020a36 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1071,6 +1071,29 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len, } else { + /* + In some previuos versions (see comment in + Format_description_log_event::Format_description_log_event(char*,...)), + event types were assigned different id numbers than in the + present version. In order to replicate from such versions to the + present version, we must map those event type id's to our event + type id's. The mapping is done with the event_type_permutation + array, which was set up when the Format_description_log_event + was read. + */ + if (description_event->event_type_permutation) + { + IF_DBUG({ + int new_event_type= + description_event->event_type_permutation[event_type]; + DBUG_PRINT("info", + ("converting event type %d to %d (%s)", + event_type, new_event_type, + get_type_str((Log_event_type)new_event_type))); + }); + event_type= description_event->event_type_permutation[event_type]; + } + switch(event_type) { case QUERY_EVENT: ev = new Query_log_event(buf, event_len, description_event, QUERY_EVENT); @@ -2771,7 +2794,7 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) Format_description_log_event:: Format_description_log_event(uint8 binlog_ver, const char* server_ver) - :Start_log_event_v3() + :Start_log_event_v3(), event_type_permutation(0) { binlog_version= binlog_ver; switch (binlog_ver) { @@ -2896,7 +2919,7 @@ Format_description_log_event(const char* buf, const Format_description_log_event* description_event) - :Start_log_event_v3(buf, description_event) + :Start_log_event_v3(buf, description_event), event_type_permutation(0) { DBUG_ENTER("Format_description_log_event::Format_description_log_event(char*,...)"); buf+= LOG_EVENT_MINIMAL_HEADER_LEN; @@ -2911,6 +2934,65 @@ Format_description_log_event(const char* buf, number_of_event_types* sizeof(*post_header_len), MYF(0)); calc_server_version_split(); + + /* + In some previous versions, the events were given other event type + id numbers than in the present version. When replicating from such + a version, we therefore set up an array that maps those id numbers + to the id numbers of the present server. + + If post_header_len is null, it means malloc failed, and is_valid + will fail, so there is no need to do anything. + + The trees which have wrong event id's are: + mysql-5.1-wl2325-5.0-drop6p13-alpha, mysql-5.1-wl2325-5.0-drop6, + mysql-5.1-wl2325-5.0, mysql-5.1-wl2325-no-dd (`grep -C2 + BEGIN_LOAD_QUERY_EVENT /home/bk/ * /sql/log_event.h`). The + corresponding version (`grep mysql, configure.in` in those trees) + strings are 5.2.2-a_drop6p13-alpha, 5.2.2-a_drop6p13c, + 5.1.5-a_drop5p20, 5.1.2-a_drop5p5. + */ + if (post_header_len && + (strncmp(server_version, "5.1.2-a_drop5", 13) == 0 || + strncmp(server_version, "5.1.5-a_drop5", 13) == 0 || + strncmp(server_version, "5.2.2-a_drop6", 13) == 0)) + { + if (number_of_event_types != 22) + { + DBUG_PRINT("info", (" number_of_event_types=%d", + number_of_event_types)); + /* this makes is_valid() return false. */ + my_free(post_header_len, MYF(MY_ALLOW_ZERO_PTR)); + post_header_len= NULL; + DBUG_VOID_RETURN; + } + static const uint8 perm[23]= + { + UNKNOWN_EVENT, START_EVENT_V3, QUERY_EVENT, STOP_EVENT, ROTATE_EVENT, + INTVAR_EVENT, LOAD_EVENT, SLAVE_EVENT, CREATE_FILE_EVENT, + APPEND_BLOCK_EVENT, EXEC_LOAD_EVENT, DELETE_FILE_EVENT, + NEW_LOAD_EVENT, + RAND_EVENT, USER_VAR_EVENT, + FORMAT_DESCRIPTION_EVENT, + TABLE_MAP_EVENT, + PRE_GA_WRITE_ROWS_EVENT, + PRE_GA_UPDATE_ROWS_EVENT, + PRE_GA_DELETE_ROWS_EVENT, + XID_EVENT, + BEGIN_LOAD_QUERY_EVENT, + EXECUTE_LOAD_QUERY_EVENT, + }; + event_type_permutation= perm; + /* + Since we use (permuted) event id's to index the post_header_len + array, we need to permute the post_header_len array too. + */ + uint8 post_header_len_temp[23]; + for (int i= 1; i < 23; i++) + post_header_len_temp[perm[i] - 1]= post_header_len[i - 1]; + for (int i= 0; i < 22; i++) + post_header_len[i] = post_header_len_temp[i]; + } DBUG_VOID_RETURN; } -- cgit v1.2.1 From 101c30ccc48d38c3ea98ebd89a350120a45aa591 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 Jan 2008 16:03:00 +0100 Subject: Post-merge changes. BitKeeper/deleted/.del-show_binlog_events2.inc: Delete: mysql-test/include/show_binlog_events2.inc client/mysqlbinlog.cc: char -> uchar for raw memory. sql/item_cmpfunc.cc: Adding cast to remove warning when converting negative integer to unsigned type. sql/log_event.cc: char -> uchar for raw memory. sql/log_event.h: char -> uchar for raw memory. sql/rpl_utility.cc: Adding cast to remove warning when converting negative integer to unsigned type. sql/slave.cc: char -> uchar for raw memory. sql/sql_repl.cc: char -> uchar for raw memory. sql-common/client.c: char -> uchar for raw memory. --- sql/log_event.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 45478020a36..82d29322b4a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5064,7 +5064,7 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex, const char* db_arg, const char* table_name_arg, List& fields_arg, enum enum_duplicates handle_dup, bool ignore, - char* block_arg, uint block_len_arg, bool using_trans) + uchar* block_arg, uint block_len_arg, bool using_trans) :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup, ignore, using_trans), fake_base(0), block(block_arg), event_buf(0), block_len(block_len_arg), @@ -5163,7 +5163,7 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len, create_file_header_len + 1); if (len < block_offset) DBUG_VOID_RETURN; - block = (char*)buf + block_offset; + block = (uchar*)buf + block_offset; block_len = len - block_offset; } else @@ -5321,7 +5321,7 @@ err: #ifndef MYSQL_CLIENT Append_block_log_event::Append_block_log_event(THD *thd_arg, const char *db_arg, - char *block_arg, + uchar *block_arg, uint block_len_arg, bool using_trans) :Log_event(thd_arg,0, using_trans), block(block_arg), @@ -5347,7 +5347,7 @@ Append_block_log_event::Append_block_log_event(const char* buf, uint len, if (len < total_header_len) DBUG_VOID_RETURN; file_id= uint4korr(buf + common_header_len + AB_FILE_ID_OFFSET); - block= (char*)buf + total_header_len; + block= (uchar*)buf + total_header_len; block_len= len - total_header_len; DBUG_VOID_RETURN; } @@ -5739,7 +5739,7 @@ err: #ifndef MYSQL_CLIENT Begin_load_query_log_event:: -Begin_load_query_log_event(THD* thd_arg, const char* db_arg, char* block_arg, +Begin_load_query_log_event(THD* thd_arg, const char* db_arg, uchar* block_arg, uint block_len_arg, bool using_trans) :Append_block_log_event(thd_arg, db_arg, block_arg, block_len_arg, using_trans) -- cgit v1.2.1