Skip to content

Commit 3cf7353

Browse files
MDEV-38140: InnoDB index corruption after UPDATE affecting virtual
columns Issue: - Purge thread attempts to purge a secondary index record that is not delete-marked. Root Cause: - When a secondary index includes a virtual column whose v_pos is greater than the number of fields in the clustered index record, the virtual column is incorrectly skipped while reading from the undo record. - This leads the purge logic to incorrectly assume it is safe to purge the secondary index record. - The code also confuses the nth virtual column with the nth stored column when writing ordering columns at the end of the undo record. Fix: - In trx_undo_update_rec_get_update(): Skip a virtual column only when v_pos == FIL_NULL, not when v_pos is greater than the number of fields. - In trx_undo_page_report_modify(): Ensure ordering columns are written based on the correct stored-column positions, without confusing them with virtual-column positions.
1 parent d0ae38c commit 3cf7353

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

mysql-test/suite/innodb/r/innodb-virtual-columns.result

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,20 @@ SELECT * FROM t1;
351351
a b c
352352
1 foo 1
353353
DROP TABLE t1;
354+
CREATE TABLE t1 (
355+
id int primary key,value varchar(2),
356+
vcomplete int AS (cast(substr(value,1,1) as int)),
357+
va int AS (null),vb int AS (null),vc int AS (null),
358+
vresult char(1) AS (substr(value,2)),
359+
KEY key1(vresult,vcomplete)
360+
) ENGINE=InnoDB;
361+
BEGIN;
362+
INSERT INTO t1(id,value) VALUES (1,'0F');
363+
UPDATE t1 SET value = '1S';
364+
UPDATE t1 SET value = '0F';
365+
COMMIT;
366+
SET GLOBAL innodb_max_purge_lag_wait=0;
367+
SELECT * FROM t1;
368+
id value vcomplete va vb vc vresult
369+
1 0F 0 NULL NULL NULL F
370+
DROP TABLE t1;

mysql-test/suite/innodb/t/innodb-virtual-columns.test

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,3 +317,26 @@ INSERT INTO t1 (a,b) VALUES (1,'foo');
317317
ALTER TABLE t1 ADD FULLTEXT KEY(b);
318318
SELECT * FROM t1;
319319
DROP TABLE t1;
320+
321+
#
322+
# MDEV-38140 : InnoDB index corruption after UPDATE affecting virtual columns
323+
#
324+
325+
CREATE TABLE t1 (
326+
id int primary key,value varchar(2),
327+
vcomplete int AS (cast(substr(value,1,1) as int)),
328+
va int AS (null),vb int AS (null),vc int AS (null),
329+
vresult char(1) AS (substr(value,2)),
330+
KEY key1(vresult,vcomplete)
331+
) ENGINE=InnoDB;
332+
333+
BEGIN;
334+
INSERT INTO t1(id,value) VALUES (1,'0F');
335+
UPDATE t1 SET value = '1S';
336+
UPDATE t1 SET value = '0F';
337+
COMMIT;
338+
339+
SET GLOBAL innodb_max_purge_lag_wait=0;
340+
SELECT * FROM t1;
341+
342+
DROP TABLE t1;

storage/innobase/trx/trx0rec.cc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,9 +1222,12 @@ trx_undo_page_report_modify(
12221222
columns that were updated. */
12231223

12241224
for (i = 0; i < update->n_fields; i++) {
1225+
const upd_field_t* fld =
1226+
upd_get_nth_field(update, i);
1227+
if (upd_fld_is_virtual_col(fld))
1228+
continue;
12251229
const ulint field_no
1226-
= upd_get_nth_field(update, i)
1227-
->field_no;
1230+
= fld->field_no;
12281231
if (field_no >= index->n_fields
12291232
|| dict_index_get_nth_field(
12301233
index, field_no)->col
@@ -1524,7 +1527,7 @@ trx_undo_update_rec_get_update(
15241527
&field_no);
15251528
first_v_col = false;
15261529
/* This column could be dropped or no longer indexed */
1527-
if (field_no >= index->n_fields) {
1530+
if (field_no == FIL_NULL) {
15281531
/* Mark this is no longer needed */
15291532
upd_field->field_no = REC_MAX_N_FIELDS;
15301533

0 commit comments

Comments
 (0)