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

AFTER UPDATE trigger reads wrong NEW value of BLOB/TEXT virtual column in system-versioned table

    XMLWordPrintable

Details

    • Can result in unexpected behaviour
    • Q4/2026 Server Maintenance

    Description

      Reproduce

      --source include/have_innodb.inc
       
      create table t1 (id int primary key, a text, v text as (concat('v-', a)) virtual)
      with system versioning engine=innodb;
      create table log (id int, new_v text);
      create trigger tr after update on t1 for each row
        insert log values (new.id, new.v);
      insert t1 (id, a) values (1, 'old'), (2, 'old2');
      update t1 set a= 'new';
      select * from log order by id;
      select id, a, v from t1 order by id;
      drop table t1, log;
      

      Result

      select * from log order by id;
      id	new_v
      1	v-old
      2	v-old
      

      Expected

      select * from log order by id;
      id	new_v
      1	v-new
      2	v-new
      

      Notes

      The stored data is correct: SELECT id, a, v FROM t1 returns v-new for both rows. Only the value of NEW.v seen by the AFTER UPDATE trigger is wrong.

      After ha_update_row(), the UPDATE inserts the history row via vers_insert_history_row() (sql/sql_update.cc). It saves record[0] to record[2], copies the old row from record[1] to record[0] and calls TABLE::vers_update_end(). That function recomputes virtual fields with VCOL_UPDATE_FOR_WRITE, which stores the old row's value of v into Field_blob::value. The new row's blob pointer, saved in record[2], points into that same buffer. After restore_record(table, record[2]), record[0] therefore references the old row's value, and the AFTER trigger reads it as NEW.v.

      Row 2 shows v-old, which is row 1's old value and not its own (v-old2). ASAN reports no error, so the buffer is not freed; why row 2 gets row 1's old value is not yet explained.

      A possible fix is to keep the new row's blob virtual column values intact across the history row insert: either save and restore them around vers_insert_history_row(), or do not recompute into the live Field_blob::value in vers_update_end(). Other readers of record[0] after the history insert in the same row iteration are exposed to the same problem.

      Attachments

        Issue Links

          Activity

            People

              midenok Aleksey Midenkov
              midenok Aleksey Midenkov
              Oleksandr Byelkin Oleksandr Byelkin
              Votes:
              0 Vote for this issue
              Watchers:
              1 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 - 1.5h Time Not Required
                  1.5h

                  Git Integration

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