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

Stored generated BLOB column is wrong on REPLACE into versioned table

    XMLWordPrintable

Details

    • Unexpected results
    • Q4/2026 Server Maintenance

    Description

      Reproduce

      --source include/have_innodb.inc
       
      create table t1 (id int primary key, a text charset latin1,
        s text charset utf8mb4 as (concat('s-', a)) stored, key (s(10)))
      with system versioning engine=innodb;
      insert t1 (id, a) values (1, 'old'), (2, 'old-and-longer');
      --echo # UPDATE (vers_insert_history_row)
      update t1 set a= 'new';
      --echo # REPLACE (delete_row<true>)
      replace t1 (id, a) values (2, 'final');
      check table t1 extended;
      select id, a, s, s = concat('s-', a) as ok from t1 for system_time all
      order by id, a;
      drop table t1;
      

      Result

      check table t1 extended;
      Table	Op	Msg_type	Msg_text
      test.t1	check	status	OK
      select id, a, s, s = concat('s-', a) as ok from t1 for system_time all
      order by id, a;
      id	a	s	ok
      1	new	s-new	1
      1	old	s-old	1
      2	final	s-newal	0
      2	new	s-new	1
      2	old-and-longer	s-old-and-longer	1
      

      Expected

      id	a	s	ok
      1	new	s-new	1
      1	old	s-old	1
      2	final	s-final	1
      2	new	s-new	1
      2	old-and-longer	s-old-and-longer	1
      

      The current row written by REPLACE must have s = 's-final'. It gets the first bytes of the history row's value 's-new' written over 's-final'. CHECK TABLE does not detect it, because the index on s holds the same wrong value.

      Notes

      REPLACE into a system-versioned table turns the conflicting row into history in TABLE::delete_row<true>(): it saves the new row into record[2], restores the conflicting row from record[1] and calls vers_update_end(). Its VCOL_UPDATE_FOR_WRITE computation recomputes the stored generated column of the history row into Field_blob::value, the buffer that s of the new row in record[2] points to. Field_blob::store() copies into value here because of the character set conversion (latin1 to utf8mb4).

      The same mechanism was fixed for virtual (non-stored) blob columns in MDEV-39306 and MDEV-41493: remember_blob_values() saves Field_blob::value around vers_update_end(). The guard covers only non-stored columns (virtual_not_stored_blob_fields), so stored generated blob columns stay affected.

      The UPDATE in the test case writes the history row with vers_insert_history_row(), which has the same sequence, but its result is correct here.

      Attachments

        Issue Links

          Activity

            People

              midenok Aleksey Midenkov
              midenok Aleksey Midenkov
              Aleksey Midenkov Aleksey Midenkov
              Oleksandr Byelkin Oleksandr Byelkin
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - 1.55d
                  1.55d
                  Remaining:
                  Remaining Estimate - 0d
                  0d
                  Logged:
                  Time Spent - 1h Time Not Required
                  1h

                  Git Integration

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