Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-30321

blob data corrupted by row_merge_write_blob_to_tmp_file()

    XMLWordPrintable

Details

    Description

      In

      static dberr_t row_merge_write_blob_to_tmp_file()
      

      the line

      dberr_t err= os_file_write(
          IORequestWrite, "(bulk insert)", blob_file->fd,
          field->data, blob_file->offset * srv_page_size, len);
      
      

      https://github.com/MariaDB/server/blob/11.0/storage/innobase/row/row0merge.cc#L1069

      uses the file offset

      blob_file->offset * srv_page_size
      

      but the "* srv_page_size" part is not writen to the tuple field:

        uint64_t val= blob_file->offset;
        ...
        /* Write offset for next 8 bytes */
        mach_write_to_8(data + 8, val);
      

      and the offset is also not updated for this:

      blob_file->offset+= field->len;
      

      thus when row_merge_copy_blob_from_file() reads the blob data, it reads from a wrong location

      As I understand it the "* srv_page_size" make so sense here and should be removed.
      Because it is multiplication it will work "correctly" if blob_file->offset is 0, so it seems to work for the first blob, and will be broken for all following blobs.

      This is most likely the cause the issue I reported here:
      https://jira.mariadb.org/browse/MDEV-29453

      Here is a query which will trigger the bug:

      SET UNIQUE_CHECKS=0;
      SET FOREIGN_KEY_CHECKS=0;
       
      /* Required condition: Tuple data size is greater than srv_sort_buf_size */
      /* default: innodb_sort_buffer_size = 1048576 */
       
      DROP DATABASE IF EXISTS `debug`;
      CREATE DATABASE IF NOT EXISTS `debug`;
      USE `debug`;
       
      DROP TABLE IF EXISTS `d1`;
      CREATE TABLE `d1` (
        `id` INT NOT NULL AUTO_INCREMENT,
        `data` LONGBLOB NOT NULL,
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB;
       
      INSERT INTO `d1` VALUES 
        (DEFAULT, REPEAT('X', @@innodb_sort_buffer_size)),
        (DEFAULT, REPEAT('X', @@innodb_sort_buffer_size))
      ;
       
      SELECT COUNT(*) AS nb_corrupted_rows FROM debug.d1 WHERE data != REPEAT('X', @@innodb_sort_buffer_size);
      
      

      nb_corrupted_rows will be 1 on mariadb >= 10.7 and 0 for mariadb <= 10.6

      pull request: https://github.com/MariaDB/server/pull/2400

      Attachments

        Issue Links

          Activity

            People

              thiru Thirunarayanan Balathandayuthapani
              Roosz Michael Roosz
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.