Commit eec2ee94 authored by Luis Soares's avatar Luis Soares

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.
parent a5eccbc3
...@@ -8030,9 +8030,13 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) ...@@ -8030,9 +8030,13 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
/* /*
Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc
Don't allow generation of auto_increment value when processing 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; ulong saved_sql_mode= thd->variables.sql_mode;
if (!is_auto_inc_in_extra_columns())
thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO;
// row processing loop // row processing loop
...@@ -9088,9 +9092,28 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability ...@@ -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 * table->auto_increment_field_not_null and SQL_MODE(if includes
* MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function. * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function.
* SQL_MODE of slave sql thread is always consistency with master's. * 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).
*/ */
if (!is_auto_inc_in_extra_columns())
m_table->auto_increment_field_not_null= TRUE; 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; return error;
} }
...@@ -9099,6 +9122,19 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability * ...@@ -9099,6 +9122,19 @@ Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *
int error) int error)
{ {
int local_error= 0; 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->next_number_field=0;
m_table->auto_increment_field_not_null= FALSE; m_table->auto_increment_field_not_null= FALSE;
if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) || if ((slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT) ||
...@@ -9223,6 +9259,12 @@ Rows_log_event::write_row(const Relay_log_info *const rli, ...@@ -9223,6 +9259,12 @@ Rows_log_event::write_row(const Relay_log_info *const rli,
m_table->file->ha_start_bulk_insert(estimated_rows); 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 #ifndef DBUG_OFF
DBUG_DUMP("record[0]", table->record[0], table->s->reclength); DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
......
...@@ -3739,6 +3739,20 @@ protected: ...@@ -3739,6 +3739,20 @@ protected:
ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
return result; return result;
} }
/**
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 #endif
private: private:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment