Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions mysql-test/suite/innodb/r/innodb-virtual-columns.result
Original file line number Diff line number Diff line change
Expand Up @@ -351,3 +351,20 @@ SELECT * FROM t1;
a b c
1 foo 1
DROP TABLE t1;
CREATE TABLE t1 (
id int primary key,value varchar(2),
vcomplete int AS (cast(substr(value,1,1) as int)),
va int AS (null),vb int AS (null),vc int AS (null),
vresult char(1) AS (substr(value,2)),
KEY key1(vresult,vcomplete)
) ENGINE=InnoDB;
BEGIN;
INSERT INTO t1(id,value) VALUES (1,'0F');
UPDATE t1 SET value = '1S';
UPDATE t1 SET value = '0F';
COMMIT;
SET GLOBAL innodb_max_purge_lag_wait=0;
SELECT * FROM t1;
id value vcomplete va vb vc vresult
1 0F 0 NULL NULL NULL F
DROP TABLE t1;
23 changes: 23 additions & 0 deletions mysql-test/suite/innodb/t/innodb-virtual-columns.test
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,26 @@ INSERT INTO t1 (a,b) VALUES (1,'foo');
ALTER TABLE t1 ADD FULLTEXT KEY(b);
SELECT * FROM t1;
DROP TABLE t1;

#
# MDEV-38140 : InnoDB index corruption after UPDATE affecting virtual columns
#

CREATE TABLE t1 (
id int primary key,value varchar(2),
vcomplete int AS (cast(substr(value,1,1) as int)),
va int AS (null),vb int AS (null),vc int AS (null),
vresult char(1) AS (substr(value,2)),
KEY key1(vresult,vcomplete)
) ENGINE=InnoDB;

BEGIN;
INSERT INTO t1(id,value) VALUES (1,'0F');
UPDATE t1 SET value = '1S';
UPDATE t1 SET value = '0F';
COMMIT;

SET GLOBAL innodb_max_purge_lag_wait=0;
SELECT * FROM t1;

DROP TABLE t1;
9 changes: 6 additions & 3 deletions storage/innobase/trx/trx0rec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1222,9 +1222,12 @@ trx_undo_page_report_modify(
columns that were updated. */

for (i = 0; i < update->n_fields; i++) {
const upd_field_t* fld =
upd_get_nth_field(update, i);
if (upd_fld_is_virtual_col(fld))
continue;
const ulint field_no
= upd_get_nth_field(update, i)
->field_no;
= fld->field_no;
if (field_no >= index->n_fields
|| dict_index_get_nth_field(
index, field_no)->col
Comment on lines 1224 to 1233
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is changing the way how UPDATE of indexed virtual columns is logged. However, there is no mention how upgrades or downgrades are being affected by this.

I see that you posted some analysis to MDEV-38140. However, you did not comment on my earlier comment regarding the function row_purge_vc_matches_cluster(). Can you please review that logic as well?

Copy link
Author

@mariadb-TafzeelShams mariadb-TafzeelShams Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is changing the way how UPDATE of indexed virtual columns is logged.

  • Hmm, actually this code part is about decision of whether to write non-virtual indexed columns to undo record. After we have completed writing the UPDATE changes of both non-virtual and virtual columns.
    (Before this code change we are incorrectly skipping writing the nth non-virtual indexed column into undo record if we already have nth virtual indexed column written as part of UPDATE changes.)

  • After completing the writing of non-virtual indexed columns we then jump to writing the virtual indexed columns.
    (Have made no changes to its logic)

However, there is no mention how upgrades or downgrades are being affected by this.

Regarding upgrades and downgrades, I don't see any issues because, even without patch we do write the non-virtual indexed columns into undo record. And while reading from undo record we handle these columns. For example in row_upd_replace_vcol()

Can you please review that logic as well?

Will do..

Expand Down Expand Up @@ -1524,7 +1527,7 @@ trx_undo_update_rec_get_update(
&field_no);
first_v_col = false;
/* This column could be dropped or no longer indexed */
if (field_no >= index->n_fields) {
if (field_no == FIL_NULL) {
/* Mark this is no longer needed */
upd_field->field_no = REC_MAX_N_FIELDS;

Expand Down