[PATCH] MDEV-24959: ER_BINLOG_ROW_LOGGING_FAILED (1534: Writing one row to the row-based binary log failed)
The Write_rows_log_event originally allocated the m_rows_buf up-front, and thus is_valid() checks that the buffer is allocated correctly. But at some point this was changed to allocate the buffer lazily on demand. This means that a a valid event can now have m_rows_buf==NULL. The is_valid() code was not changed, and thus is_valid() could return false on a valid event. This caused a bug for REPLACE INTO t() VALUES(), () which generates a write_rows event with no after image; then the m_rows_buf was never allocated and is_valid() incorrectly returned false, causing an error in some other parts of the code. Also fix a couple of missing special cases in the code for mysqlbinlog to correctly decode (in comments) row events with missing after image. Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org> --- mysql-test/main/mysqlbinlog.result | 18 ++++++++++++ mysql-test/main/mysqlbinlog.test | 45 ++++++++++++++++++++++++++++++ sql/log_event.h | 2 +- sql/log_event_client.cc | 21 ++++++++++++-- 4 files changed, 82 insertions(+), 4 deletions(-) diff --git a/mysql-test/main/mysqlbinlog.result b/mysql-test/main/mysqlbinlog.result index 4e0f570c899..5bde2b05a98 100644 --- a/mysql-test/main/mysqlbinlog.result +++ b/mysql-test/main/mysqlbinlog.result @@ -1314,3 +1314,21 @@ a b 2 2023-07-22 00:36:20.567890 DROP TABLE t; SET time_zone= default; +# +# MDEV-24959: ER_BINLOG_ROW_LOGGING_FAILED (1534: Writing one row to the row-based binary log failed) +# +SET SESSION binlog_format= ROW; +SET SESSION binlog_row_image= MINIMAL; +RESET MASTER; +CREATE TABLE t1 (a INT NOT NULL DEFAULT 0 PRIMARY KEY); +REPLACE INTO t1 () VALUES (),(); +DROP TABLE t1; +FLUSH BINARY LOGS; +SET SESSION binlog_format= STATEMENT; +SET SESSION binlog_row_image= default; +FOUND 1 /Number of rows: 2/ in mdev24959_1.txt +FOUND 1 /DROP TABLE/ in mdev24959_1.txt +FOUND 1 /Number of rows: 2/ in mdev24959_2.txt +FOUND 1 /DROP TABLE/ in mdev24959_2.txt +FOUND 1 /INSERT INTO .* VALUES/ in mdev24959_2.txt +FOUND 1 /SET /[*] no columns [*]// in mdev24959_2.txt diff --git a/mysql-test/main/mysqlbinlog.test b/mysql-test/main/mysqlbinlog.test index 0e5fd9efb70..ceb6ff2eee6 100644 --- a/mysql-test/main/mysqlbinlog.test +++ b/mysql-test/main/mysqlbinlog.test @@ -671,3 +671,48 @@ SELECT * FROM t; SELECT * FROM t; DROP TABLE t; SET time_zone= default; + + +--echo # +--echo # MDEV-24959: ER_BINLOG_ROW_LOGGING_FAILED (1534: Writing one row to the row-based binary log failed) +--echo # + +SET SESSION binlog_format= ROW; +SET SESSION binlog_row_image= MINIMAL; + +RESET MASTER; +CREATE TABLE t1 (a INT NOT NULL DEFAULT 0 PRIMARY KEY); +REPLACE INTO t1 () VALUES (),(); +DROP TABLE t1; +FLUSH BINARY LOGS; +SET SESSION binlog_format= STATEMENT; +SET SESSION binlog_row_image= default; + +--exec $MYSQL_BINLOG --base64-output=decode-rows $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mdev24959_1.txt +--exec $MYSQL_BINLOG --base64-output=decode-rows --verbose $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mdev24959_2.txt + +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mdev24959_1.txt +--let SEARCH_ABORT= NOT FOUND +--let SEARCH_PATTERN= Number of rows: 2 +--source include/search_pattern_in_file.inc + +# There was a bug that mysqlbinlog would get an error while decoding the +# update rows event with no after image and abort the dump; test that now +# the dump is complete and includes the final DROP TABLE. +--let SEARCH_PATTERN= DROP TABLE +--source include/search_pattern_in_file.inc + +--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mdev24959_2.txt +--let SEARCH_PATTERN= Number of rows: 2 +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= DROP TABLE +--source include/search_pattern_in_file.inc + +--let SEARCH_PATTERN= INSERT INTO .* VALUES +--source include/search_pattern_in_file.inc +--let SEARCH_PATTERN= SET /[*] no columns [*]/ +--source include/search_pattern_in_file.inc + +--remove_file $MYSQLTEST_VARDIR/tmp/mdev24959_1.txt +--remove_file $MYSQLTEST_VARDIR/tmp/mdev24959_2.txt diff --git a/sql/log_event.h b/sql/log_event.h index a869c6e04f1..0a1d6502932 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -5086,7 +5086,7 @@ class Rows_log_event : public Log_event */ bool is_valid() const override { - return m_rows_buf && m_cols.bitmap; + return m_cols.bitmap; } uint m_row_count; /* The number of rows added to the event */ diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc index 720cc5ab611..a04776e6404 100644 --- a/sql/log_event_client.cc +++ b/sql/log_event_client.cc @@ -1384,6 +1384,13 @@ void Rows_log_event::count_row_events(PRINT_EVENT_INFO *print_event_info) switch (general_type_code) { case WRITE_ROWS_EVENT: + /* + A write rows event containing no after image (can happen for REPLACE + INTO t() VALUES ()), count this correctly as 1 row and no 0. + */ + if (unlikely(m_rows_buf == m_rows_end)) + print_event_info->row_events++; + /* Fall through. */ case DELETE_ROWS_EVENT: row_events= 1; break; @@ -1509,6 +1516,7 @@ bool Rows_log_event::print_verbose(IO_CACHE *file, /* If the write rows event contained no values for the AI */ if (((general_type_code == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end))) { + print_event_info->row_events++; if (my_b_printf(file, "### INSERT INTO %`s.%`s VALUES ()\n", map->get_db_name(), map->get_table_name())) goto err; @@ -1542,9 +1550,16 @@ bool Rows_log_event::print_verbose(IO_CACHE *file, /* Print the second image (for UPDATE only) */ if (sql_clause2) { - if (!(length= print_verbose_one_row(file, td, print_event_info, - &m_cols_ai, value, - (const uchar*) sql_clause2))) + /* If the update rows event contained no values for the AI */ + if (unlikely(bitmap_is_clear_all(&m_cols_ai))) + { + length= (bitmap_bits_set(&m_cols_ai) + 7) / 8; + if (my_b_printf(file, "### SET /* no columns */\n")) + goto err; + } + else if (!(length= print_verbose_one_row(file, td, print_event_info, + &m_cols_ai, value, + (const uchar*) sql_clause2))) goto err; value+= length; } -- 2.39.5
participants (1)
-
Kristian Nielsen