Bug #104838 mysql binlog can't deserialize
Submitted: 6 Sep 2021 9:33 Modified: 6 Sep 2021 9:39
Reporter: Jialei Lee Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Replication Severity:S3 (Non-critical)
Version:8.21.4 OS:Any
Assigned to: CPU Architecture:Any

[6 Sep 2021 9:33] Jialei Lee
Description:
In mysql8.0, I created a table named "20210103_一二三四五六七八九十TST一二三四五六七00". its character length is only 31 characters, while the byte length is 65. When I parse the binlog file, it will report an error "ROLLBACK /* added by mysqlbinlog */ /*!*/;".
If this instance has a slave node, the slave will also report error.The slave status information is as follows:

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 172.16.7.28
                  Master_User: rdsRepl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000010
          Read_Master_Log_Pos: 196
               Relay_Log_File: rds_mysql-relay-bin.000002
                Relay_Log_Pos: 371
        Relay_Master_Log_File: mysql-bin.000008
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 13121
                   Last_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, the server was unable to fetch a keyring key required to open an encrypted relay log file, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 196
              Relay_Log_Space: 3130
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 13121
               Last_SQL_Error: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, the server was unable to fetch a keyring key required to open an encrypted relay log file, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave.
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 2197345845
                  Master_UUID: ff54011e-0edc-11ec-83f7-fa163e12b3f6
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: 
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 210906 16:28:13
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: ff54011e-0edc-11ec-83f7-fa163e12b3f6:32
            Executed_Gtid_Set: ff54011e-0edc-11ec-83f7-fa163e12b3f6:1-31
                Auto_Position: 1
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
       Master_public_key_path: 
        Get_master_public_key: 0
            Network_Namespace: 
1 row in set (0.00 sec)

How to repeat:
Create a table name with non English characters, and the number of bytes occupied by a single character is greater than 1.
When the number of bytes of the created table name is greater than 64 but the number of characters is less than 64, and a DML statement is performed, its binlog file cannot be parsed normally; And will cause replication exceptions

Suggested fix:
In mysql8.0 code, the constructor of "Table_map_event", I see the following code added:
	  READER_TRY_SET(m_dblen, read<uint8_t>);
	  if (m_dblen > 64 /* NAME_CHAR_LEN */)
		READER_THROW("Database name length too long.")
	  ptr_dbnam = READER_TRY_CALL(ptr, m_dblen + 1);
	  m_dbnam = std::string(ptr_dbnam, m_dblen);

	  READER_TRY_SET(m_tbllen, read<uint8_t>);
	  if (m_tbllen > 64 /* NAME_CHAR_LEN */)
		READER_THROW("Table name length too long.")
	  ptr_tblnam = READER_TRY_CALL(ptr, m_tbllen + 1);
	  m_tblnam = std::string(ptr_tblnam, m_tbllen);
There is no similar length check in MySQL 5.7. I suspect that the table name length of log event is assigned incorrectly. For example, a function similar to strlen is used to obtain the length of the table name instead of the number of characters after character encoding and decoding.
[6 Sep 2021 9:39] MySQL Verification Team
Hello Jialei Lee,

Thank you for the report and feedback.
Imho this is duplicate of Bug #104798, please Bug #104798.

regards,
Umesh