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 <kniel...@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

_______________________________________________
commits mailing list -- commits@lists.mariadb.org
To unsubscribe send an email to commits-le...@lists.mariadb.org

Reply via email to