Bug #53643 assert in Field_new_decimal::store_value on slave server
Submitted: 14 May 2010 10:43 Modified: 15 Nov 2010 13:08
Reporter: Matthias Leich Email Updates:
Status: Closed Impact on me:
Category:MySQL Server: Row Based Replication ( RBR ) Severity:S3 (Non-critical)
Version:mysql-5.1-rpl-wl5092 OS:Any
Assigned to: Luis Soares
Tags: assert, decimal
Triage: Triaged: D1 (Critical)

[14 May 2010 10:43] Matthias Leich
The assert happens in sql/field.cc line 2624
bool Field_new_decimal::store_value(const my_decimal *decimal_value)
  int error= 0;

This bug is not relevant for users of official MySQL trees.
It requires a "SET SESSION BINLOG_ROW_IMAGE = minimal;"
which is part of WL#5092. And this WL is not pushed yet.

My script:
--source include/master-slave.inc
--source include/have_innodb.inc

# The assert disappears in case                        or
# - t0 uses MyISAM instead of InnoDB                   or
# - PRIMARY KEY (col1) from t1 is removed              or
# - col3 CHAR(35) instead of col3 DECIMAL(35,0) for t1 or
# - SET SESSION BINLOG_ROW_IMAGE = minimal; is removed

INSERT INTO t0 (col1,col2) VALUES (4,7),(4,8);

  col1 INT NOT NULL,
  PRIMARY KEY (col1)


# This statement leads to an assert on slave.
REPLACE INTO t1 ( col1,col2) SELECT col1,col2 FROM t0;

Result on mysql-5.1-rpl-wl5092:
main.rpl_ml1                             [ fail ]
100514 13:03:25 [Note] next log './slave-relay-bin.000003' is currently active
mysqld: field.cc:2624: bool Field_new_decimal::store_value(const my_decimal*): Assertion `!table || (!table->write_set || bitmap_is_set(table->write_set, field_index))' failed.
100514 13:03:25 - mysqld got signal 6 ;
Thread 1 (process 5011):
#0  0x00007ffab187cce6 in pthread_kill () from /lib64/libpthread.so.0
#1  0x0000000000b2973f in my_write_core (sig=6) at stacktrace.c:329
#2  0x00000000006c01c1 in handle_segfault (sig=6) at mysqld.cc:2580
#3  <signal handler called>
#4  0x00007ffab0a855c5 in raise () from /lib64/libc.so.6
#5  0x00007ffab0a86bb3 in abort () from /lib64/libc.so.6
#6  0x00007ffab0a7e1e9 in __assert_fail () from /lib64/libc.so.6
#7  0x000000000069670b in Field_new_decimal::store_value (this=0x198f210, decimal_value=0x11795a0) at field.cc:2624
#8  0x0000000000697174 in Field_new_decimal::reset (this=0x198f210) at field.cc:2579
#9  0x00000000007d86a1 in unpack_row (rli=0x19428e0, table=0x1972d18, colcnt=3, row_data=0x18fa5bd "รน\004", cols=0x19544a0, row_end=0x1954510, master_reclength=0x19544c0, abort_on_warning=false, first_row=false) at rpl_record.cc:298
#10 0x00000000007d7697 in Rows_log_event::unpack_current_row (this=0x1954418, rli=0x19428e0, cols=0x19544a0, abort_on_warning=false) at log_event.h:3634
#11 0x00000000007c06c9 in Update_rows_log_event::do_exec_row (this=0x1954418, rli=0x19428e0) at log_event.cc:9698
#12 0x00000000007cac49 in Rows_log_event::do_apply_event (this=0x1954418, rli=0x19428e0) at log_event.cc:7646
#13 0x00000000008807f8 in Log_event::apply_event (this=0x1954418, rli=0x19428e0) at log_event.h:1125
#14 0x0000000000878115 in apply_event_and_update_pos (ev=0x1954418, thd=0x196dcf8, rli=0x19428e0) at slave.cc:2256
#15 0x000000000087998d in exec_relay_log_event (thd=0x196dcf8, rli=0x19428e0) at slave.cc:2416
#16 0x000000000087a721 in handle_slave_sql (arg=0x19414f0) at slave.cc:3196
#17 0x00007ffab1878040 in start_thread () from /lib64/libpthread.so.0
#18 0x00007ffab0b2608d in clone () from /lib64/libc.so.6
#19 0x0000000000000000 in ?? ()

How to repeat:
Please compile MySQL with debug, store the test from above
as t/rpl_ml1.test and run
./mysql-test-run --mysqld=--log_bin=on --mysqld=--binlog-format=mixed \
--skip-ndbcluster --mem rpl_ml1
[17 May 2010 15:09] Luis Soares


  While unpacking a row, the server calls f->reset() for nullable
  fields, ie, for fields that are later set to
  null (f->set_null()). This means that for the test case
  depicted, and for decimal types an assertion is faced because
  the table->write_set was not properly initialised before the
  procedure to unpack the row takes place.

  Calling Field_decimal::reset would ultimately make
  Field_decimal::store_value be called, which in its turn would
  check if the column being (re)set was marked in the
  table->write_set (this is the actual assertion).

  Given that the table->write_set was not conveniently
  initialised before unpacking, the bit for the given decimal
  column would not be set. As a consequence, the assertion would
  be triggered.


  The table->write_set was not properly initialised because it
  was being calculated from the event's read_set bitmap instead
  of the write_set bitmap in some cases. Initialisation takes
  place before the rows execution loop:

  and at that point, write_set was being set from m_cols instead
  of m_cols_ai. This would work for Write_rows_event or
  Delete_event (the former just has one image, after image, and
  the m_cols is actually the write_set, while the latter also
  just has one image, before image, and m_cols is the read_set -
  for deletes the write_set is useless). The problem surfaces in
  the Update_rows_event, which uses both m_cols and m_cols_ai
  which can be different (as this case proves it), and therefore,
  table->read/write_set must be initialised according to the
  proper bitmap.


  N1. Some fields types would not trigger this assertion because
      their reset method does not call store_value. Instead a
      simple assignment or memory cleanup is done. For example,
      for TINYINT:

        int reset(void) { ptr[0]=0; return 0; }

  N2. I don't think this is dependant of the engine for the
      reasons stated above. I have triggered the assertion even
      when using MyISAM in t0.

  N3. col3 CHAR(35) instead of col3 DECIMAL(35,0) for t1 does not
      trigger this assertion because the Field_string::reset does
      not resort to store_value for resetting the field.

  N4. If removing the PRIMARY KEY the REPLACE behaves as an
      INSERT and Write_rows_event(s) are used instead of Updates,
      thence the correct bitmap would be used (as inserts were
      not vulnerable).
[17 May 2010 15:17] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:


3187 Luis Soares	2010-05-17 [merge]
      BUG#53643: assert in Field_new_decimal::store_value on slave server
      The table->write_set at the slave was improperly set before
      processing a row event. For update events, it was being
      calculated from the event's read set instead of the event's 
      In some cases, this would lead to an assertion while unpacking
      and resetting decimal fields because the corresponding bit in
      the slave's table->write_set was incorrectly set.
      We fix this by properly initializing the read_set and write_set 
      before unpacking takes place.
[8 Oct 2010 13:29] Bugs System
Pushed into mysql-next-mr (revid:alexander.nozdrin@oracle.com-20101008132832-pbzewvmi9f365ak4) (version source revid:alexander.nozdrin@oracle.com-20101008132832-pbzewvmi9f365ak4) (pib:21)
[13 Nov 2010 16:04] Bugs System
Pushed into mysql-trunk 5.6.99-m5 (revid:alexander.nozdrin@oracle.com-20101113155825-czmva9kg4n31anmu) (version source revid:vasil.dimov@oracle.com-20100629074804-359l9m9gniauxr94) (merge vers: 5.6.99-m4) (pib:21)
[15 Nov 2010 13:08] Jon Stephens
Per MLeich's comments in Description, bug does not appear in any release versions. No changelog entry required. Closed.