summaryrefslogtreecommitdiff
path: root/sql/log_event_old.cc
diff options
context:
space:
mode:
authorLuis Soares <luis.soares@sun.com>2010-04-21 13:47:55 +0100
committerLuis Soares <luis.soares@sun.com>2010-04-21 13:47:55 +0100
commitddb5d63346b66037b5f2cd7ede55efdc5c709844 (patch)
treef9e633c6f93a5833098da52f4c8a95e6953c5fed /sql/log_event_old.cc
parentf62105453b289ae6969b676a717b610848599cf1 (diff)
downloadmariadb-git-ddb5d63346b66037b5f2cd7ede55efdc5c709844.tar.gz
BUG#52868: Wrong handling of NULL value during update, replication out
of sync In RBR, sometimes the table->s->last_null_bit_pos can be zero. This has impact at the slave when it compares records fetched from the storage engine against records in the binary log event. If last_null_bit_pos is zero the slave, while comparing in log_event.cc:record_compare function, would set all bits in the last null_byte to 1 (assumed all 8 were unused) . Thence it would loose the ability to distinguish records that were similar in contents except for the fact that some field was null in one record, but not in the other. Ultimately this would cause wrong matches, and in the specific case depicted in the bug report the same record would be updated twice, resulting in a lost update. Additionally, in the record_compare function the slave was setting the X bit unconditionally. There are cases that the X bit does not exist in the record header. This could also lead to wrong matches between records. We fix both by conditionally resetting the bits: (i) unused null_bits are set if last_null_bit_pos > 0; (ii) X bit is set if HA_OPTION_PACK_RECORD is in use.
Diffstat (limited to 'sql/log_event_old.cc')
-rw-r--r--sql/log_event_old.cc36
1 files changed, 28 insertions, 8 deletions
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index df162761b35..60b0df5253a 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -342,12 +342,29 @@ static bool record_compare(TABLE *table)
if (table->s->null_bytes > 0)
{
for (int i = 0 ; i < 2 ; ++i)
- {
- saved_x[i]= table->record[i][0];
- saved_filler[i]= table->record[i][table->s->null_bytes - 1];
- table->record[i][0]|= 1U;
- table->record[i][table->s->null_bytes - 1]|=
- 256U - (1U << table->s->last_null_bit_pos);
+ {
+ /*
+ If we have an X bit then we need to take care of it.
+ */
+ if (!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD))
+ {
+ saved_x[i]= table->record[i][0];
+ table->record[i][0]|= 1U;
+ }
+
+ /*
+ If (last_null_bit_pos == 0 && null_bytes > 1), then:
+
+ X bit (if any) + N nullable fields + M Field_bit fields = 8 bits
+
+ Ie, the entire byte is used.
+ */
+ if (table->s->last_null_bit_pos > 0)
+ {
+ saved_filler[i]= table->record[i][table->s->null_bytes - 1];
+ table->record[i][table->s->null_bytes - 1]|=
+ 256U - (1U << table->s->last_null_bit_pos);
+ }
}
}
@@ -387,8 +404,11 @@ record_compare_exit:
{
for (int i = 0 ; i < 2 ; ++i)
{
- table->record[i][0]= saved_x[i];
- table->record[i][table->s->null_bytes - 1]= saved_filler[i];
+ if (!(table->s->db_options_in_use & HA_OPTION_PACK_RECORD))
+ table->record[i][0]= saved_x[i];
+
+ if (table->s->last_null_bit_pos > 0)
+ table->record[i][table->s->null_bytes - 1]= saved_filler[i];
}
}