diff --git a/sql/log_event.cc b/sql/log_event.cc index 122953b48ec..1ff29f2730e 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1,5 +1,5 @@ /* - Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -8039,10 +8039,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 @@ -9097,9 +9101,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; } @@ -9108,6 +9131,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) || @@ -9231,7 +9267,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); diff --git a/sql/log_event.h b/sql/log_event.h index 460d7244d07..d8f04454a7a 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -3735,6 +3735,20 @@ protected: return ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, &m_curr_row_end, &m_master_reclength, m_rows_end); } + + /** + Helper function to check whether there is an auto increment + column on the table where the event is to be applied. + + @return true if there is an autoincrement field on the extra + columns, false otherwise. + */ + inline bool is_auto_inc_in_extra_columns() + { + DBUG_ASSERT(m_table); + return (m_table->next_number_field && + m_table->next_number_field->field_index >= m_width); + } #endif private: