From 7481cf6c29f90c0df5e01cb4af12da41beeb7033 Mon Sep 17 00:00:00 2001 From: Luis Soares Date: Wed, 18 Dec 2013 11:17:24 +0000 Subject: BUG#17066269: AUTO_INC VALUE NOT PROPERLY GENERATED WITH RBR AND AUTO_INC COLUMN ONLY ON SLAVE In RBR, if the slave's table as one additional auto_inc column, then, it will insert the value 0 instead of generating the next auto_inc number. We fix this by checking that if an auto_inc extra column exists, when compared to column data of the row event, we explicitly set it to NULL and flag the engine that a nulled auto_inc column will be inserted. --- sql/log_event.cc | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 7d18b447084..8ce81f3bc83 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8030,10 +8030,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) /* Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc Don't allow generation of auto_increment value when processing - rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. + rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. The exception + to this rule happens when the auto_inc column exists on some + extra columns on the slave. In that case, do not force + MODE_NO_AUTO_VALUE_ON_ZERO. */ ulong saved_sql_mode= thd->variables.sql_mode; - thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; + if (!is_auto_inc_in_extra_columns()) + thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; // row processing loop @@ -9088,9 +9092,28 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability * table->auto_increment_field_not_null and SQL_MODE(if includes * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function. * SQL_MODE of slave sql thread is always consistency with master's. - * In RBR, auto_increment fields never are NULL. + * In RBR, auto_increment fields never are NULL, except if the auto_inc + * column exists only on the slave side (i.e., in an extra column + * on the slave's table). */ - m_table->auto_increment_field_not_null= TRUE; + if (!is_auto_inc_in_extra_columns()) + m_table->auto_increment_field_not_null= TRUE; + else + { + /* + Here we have checked that there is an extra field + on this server's table that has an auto_inc column. + + Mark that the auto_increment field is null and mark + the read and write set bits. + + (There can only be one AUTO_INC column, it is always + indexed and it cannot have a DEFAULT value). + */ + m_table->auto_increment_field_not_null= FALSE; + m_table->mark_auto_increment_column(); + } + return error; } @@ -9099,6 +9122,19 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability * int error) { int local_error= 0; + + /** + Clear the write_set bit for auto_inc field that only + existed on the destination table as an extra column. + */ + if (is_auto_inc_in_extra_columns()) + { + bitmap_clear_bit(m_table->write_set, m_table->next_number_field->field_index); + bitmap_clear_bit( m_table->read_set, m_table->next_number_field->field_index); + + if (get_flags(STMT_END_F)) + m_table->file->ha_release_auto_increment(); + } m_table->next_number_field=0; m_table->auto_increment_field_not_null= FALSE; if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) || @@ -9222,7 +9258,13 @@ Rows_log_event::write_row(const Relay_log_info *const rli, ulong estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row); m_table->file->ha_start_bulk_insert(estimated_rows); } - + + /* + Explicitly set the auto_inc to null to make sure that + it gets an auto_generated value. + */ + if (is_auto_inc_in_extra_columns()) + m_table->next_number_field->set_null(); #ifndef DBUG_OFF DBUG_DUMP("record[0]", table->record[0], table->s->reclength); -- cgit v1.2.1 From 8765bec5a2a17a8a0c7ce30fff7c9cdf67df3bd7 Mon Sep 17 00:00:00 2001 From: Sujatha Sivakumar Date: Fri, 10 Jan 2014 15:11:56 +0530 Subject: Bug#17081415:>=4GB ROW EVENT CRASHES SERVER WITH WILD MEMCPY OF ROW DATA Problem: ======== Inserting a row larger than 4G when server uses RBR leads to crash. Analysis: ======== Row-based binary logging logs changes in individual table rows. During the execution of DML statements in RBR the actual row data will be stored within "m_rows_buf" buffer and this buffer contents will be written to binary log. "m_rows_buf" is prepared within the following function "Rows_log_event::do_add_row_data". When a huge row is specified as in this bug scenario where row size is 4294971520 > UINT_MAX (4294967295) then the "m_rows_buf" is reallocated to accommodate the row data and then the row is copied to the buffer. During this realloc call, the length is getting type casted to "uint" which results in overflow. Because of the overflow the reallocated memory happens to be incorrect than what was requested and it results in a crash during copy of rowdata to buffer. Hence rows of size > 4GB cannot be written to binary log. By default the event_length can be stored within 4 bytes which in turn restricts an event's size to grow. Hence large rows cannot be replicated using row based replication. Fix: === An error is generated if the row size exceeds 4GB value. sql/log_event.cc: An error is generated if the row size exceeds 4GB value. Debug simulations are added to test the fix. --- sql/log_event.cc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 1ff29f2730e..8724239b6d3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7767,8 +7767,31 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length) if (static_cast(m_rows_end - m_rows_cur) <= length) { size_t const block_size= 1024; - my_ptrdiff_t const cur_size= m_rows_cur - m_rows_buf; - my_ptrdiff_t const new_alloc= + ulong cur_size= m_rows_cur - m_rows_buf; + DBUG_EXECUTE_IF("simulate_too_big_row_case1", + cur_size= UINT_MAX32 - (block_size * 10); + length= UINT_MAX32 - (block_size * 10);); + DBUG_EXECUTE_IF("simulate_too_big_row_case2", + cur_size= UINT_MAX32 - (block_size * 10); + length= block_size * 10;); + DBUG_EXECUTE_IF("simulate_too_big_row_case3", + cur_size= block_size * 10; + length= UINT_MAX32 - (block_size * 10);); + DBUG_EXECUTE_IF("simulate_too_big_row_case4", + cur_size= UINT_MAX32 - (block_size * 10); + length= (block_size * 10) - block_size + 1;); + ulong remaining_space= UINT_MAX32 - cur_size; + /* Check that the new data fits within remaining space and we can add + block_size without wrapping. + */ + if (length > remaining_space || + ((length + block_size) > remaining_space)) + { + sql_print_error("The row data is greater than 4GB, which is too big to " + "write to the binary log."); + DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED); + } + ulong const new_alloc= block_size * ((cur_size + length + block_size - 1) / block_size); uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, (uint) new_alloc, -- cgit v1.2.1 From bebb3427f2fb46d257a2530b791e8c5d28f933ee Mon Sep 17 00:00:00 2001 From: Ritheesh Vedire Date: Fri, 31 Jan 2014 04:25:39 +0530 Subject: Bug#16814264: FILTER OUT THE PERFORMANCE_SCHEMA RELAY LOG EVENTS FROM RELAY LOG Performance schema tables are local to a server and they should not be allowed to be executed by the slave from the relay log. From 5.6.10, P_S events are not written into the binary log. But prior to that, from mysql 5.5 onwards, P_S events are written to the binary log by master. The following are problematic scenarios: 1. Master 5.5 -> Slave 5.5 ======================== A) RBR: Slave crashes B) SBR: P_S statements are replicated. 2.Master 5.5 -> Slave 5.6 ======================== A) RBR: SQL thd generates error B) SBR : P_S statements are replicated 3. 5.5 binlog executed on a server 5.5 using mysqlbinlog|mysql ================================================================= A) RBR: Server crash (because of BINLOG'... statement) B) SBR: P_S statements are executed 4. 5.5 binlog executed on server 5.6 using mysqlbinlog|mysql ================================================================ A) RBR: SQL error (because of BINLOG'... statement) B) SBR: P_S statements are executed. The generalized behaviour should be: a) Slave SQL thread should certainly ignore P_S events read from the relay log. b) mysqlbinlog|mysql should replay the binlog succesfully. --- sql/log_event.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sql/log_event.cc') diff --git a/sql/log_event.cc b/sql/log_event.cc index 8724239b6d3..fea7c863cbc 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -8004,6 +8004,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) DBUG_PRINT("debug", ("m_table: 0x%lx, m_table_id: %lu", (ulong) m_table, m_table_id)); + /* + A row event comprising of a P_S table + - should not be replicated (i.e executed) by the slave SQL thread. + - should not be executed by the client in the form BINLOG '...' stmts. + */ + if (table && table->s->table_category == TABLE_CATEGORY_PERFORMANCE) + table= NULL; + if (table) { bool transactional_table= table->file->has_transactions(); -- cgit v1.2.1