From 442832071278e40a8246fddbd132a794fd216514 Mon Sep 17 00:00:00 2001 From: PranavKTiwari Date: Mon, 1 Jun 2026 18:35:16 +0530 Subject: [PATCH 1/3] MDEV-36896 : Assertion 'marked_for_read()' failed in virtual String *Field_varstring::val_str(String *, String *) Problem: Executing queries that require virtual/generated column evaluation during filesort trigger sdebug assertions due to missing columns in read_set. Cause: find_all_keys() temporarily assigns TABLE::tmp_set as both read_set and write_set. Later, TABLE::update_virtual_field() clears tmp_set before evaluating virtual column dependencies. Since all three pointers reference the same bitmap, clearing tmp_set also clears the active column maps, causing required columns to be missing during execution. Fix: Remove the bitmap_clear_all(&tmp_set) call from TABLE::update_virtual_field(). The dependency walk populates the required bits for virtual column evaluation, and clearing the shared bitmap can unintentionally invalidate the active read_set/write_set. --- .../suite/vcol/r/vcol_keys_innodb.result | 28 ++++++++++++++++ mysql-test/suite/vcol/t/vcol_keys_innodb.test | 33 +++++++++++++++++++ sql/table.cc | 1 - 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/vcol/r/vcol_keys_innodb.result b/mysql-test/suite/vcol/r/vcol_keys_innodb.result index 51e97864a2517..f6a2cb68ab7d8 100644 --- a/mysql-test/suite/vcol/r/vcol_keys_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_keys_innodb.result @@ -303,3 +303,31 @@ IF(@@innodb_sort_buffer_size < count(*)*200, 'GOOD', 'WRONG SIZE') GOOD alter table t1 drop column va; drop table t1; +# +# MDEV-36896 Assertion `marked_for_read()' failed in virtual String *Field_varstring::val_str(String *, String *) +# +SET @old_isolation_level= @@session.tx_isolation; +SET @@session.tx_isolation= 'READ-UNCOMMITTED'; +CREATE TABLE t (a VARCHAR(10),b INT,c CHAR(10) GENERATED ALWAYS AS (a) VIRTUAL,KEY(b,c)) ENGINE=InnoDB; +INSERT INTO t (a) VALUES ('A'); +SELECT * FROM t WHERE b IS NULL ORDER BY a; +a b c +A NULL A +DROP TABLE t; +CREATE TABLE t ( +a VARCHAR(10), +b INT, +c CHAR(10) GENERATED ALWAYS AS (a) VIRTUAL, +d INT GENERATED ALWAYS AS (IF(a = c, 1, 0)) VIRTUAL, +KEY(b, c) +) ENGINE=InnoDB; +INSERT INTO t (a) VALUES ('A'); +INSERT INTO t (a, b) VALUES ('B', 1); +SELECT * FROM t WHERE b IS NULL ORDER BY a; +a b c d +A NULL A 1 +DROP TABLE t; +SET @@session.tx_isolation= @old_isolation_level; +# +# End of 10.11 tests +# diff --git a/mysql-test/suite/vcol/t/vcol_keys_innodb.test b/mysql-test/suite/vcol/t/vcol_keys_innodb.test index 488a2b936d084..cb4ff8b231578 100644 --- a/mysql-test/suite/vcol/t/vcol_keys_innodb.test +++ b/mysql-test/suite/vcol/t/vcol_keys_innodb.test @@ -135,3 +135,36 @@ insert t1 (id,a,c) select seq,seq,seq from seq_1_to_330; select IF(@@innodb_sort_buffer_size < count(*)*200, 'GOOD', 'WRONG SIZE') from t1; alter table t1 drop column va; drop table t1; + + +--echo # +--echo # MDEV-36896 Assertion `marked_for_read()' failed in virtual String *Field_varstring::val_str(String *, String *) +--echo # + +SET @old_isolation_level= @@session.tx_isolation; + +SET @@session.tx_isolation= 'READ-UNCOMMITTED'; +CREATE TABLE t (a VARCHAR(10),b INT,c CHAR(10) GENERATED ALWAYS AS (a) VIRTUAL,KEY(b,c)) ENGINE=InnoDB; +INSERT INTO t (a) VALUES ('A'); +SELECT * FROM t WHERE b IS NULL ORDER BY a; + +DROP TABLE t; + +CREATE TABLE t ( + a VARCHAR(10), + b INT, + c CHAR(10) GENERATED ALWAYS AS (a) VIRTUAL, + d INT GENERATED ALWAYS AS (IF(a = c, 1, 0)) VIRTUAL, + KEY(b, c) +) ENGINE=InnoDB; + +INSERT INTO t (a) VALUES ('A'); +INSERT INTO t (a, b) VALUES ('B', 1); +SELECT * FROM t WHERE b IS NULL ORDER BY a; +DROP TABLE t; + +SET @@session.tx_isolation= @old_isolation_level; + +--echo # +--echo # End of 10.11 tests +--echo # diff --git a/sql/table.cc b/sql/table.cc index 2b283fd93e1b8..89ecb49cc214c 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9187,7 +9187,6 @@ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) TABLE::update_virtual_fields(handler *, enum_vcol_update_mode). */ in_use->set_n_backup_active_arena(expr_arena, &backup_arena); - bitmap_clear_all(&tmp_set); vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &tmp_set); DBUG_FIX_WRITE_SET(vf); vf->vcol_info->expr->save_in_field(vf, 0); From 747242c0460c1db11c81f10e1c48fcc90d758ab6 Mon Sep 17 00:00:00 2001 From: PranavKTiwari Date: Mon, 29 Jun 2026 18:43:35 +0530 Subject: [PATCH 2/3] Added logic to update the all fileds in map. --- sql/item.cc | 7 +++++-- sql/table.cc | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index d14a8da53da47..4bc3a48527da8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -980,12 +980,15 @@ bool Item_field::check_field_expression_processor(void *arg) bool Item_field::update_vcol_processor(void *arg) { MY_BITMAP *map= (MY_BITMAP *) arg; - if (field->vcol_info && - !bitmap_fast_test_and_set(map, field->field_index)) + + bitmap_fast_test_and_set(map, field->field_index); + + if (field->vcol_info) { field->vcol_info->expr->walk(&Item::update_vcol_processor, 0, arg); field->vcol_info->expr->save_in_field(field, 0); } + return 0; } diff --git a/sql/table.cc b/sql/table.cc index 89ecb49cc214c..2b283fd93e1b8 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9187,6 +9187,7 @@ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) TABLE::update_virtual_fields(handler *, enum_vcol_update_mode). */ in_use->set_n_backup_active_arena(expr_arena, &backup_arena); + bitmap_clear_all(&tmp_set); vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &tmp_set); DBUG_FIX_WRITE_SET(vf); vf->vcol_info->expr->save_in_field(vf, 0); From b52f86e99829951e9c18e2235d827e328c1d044b Mon Sep 17 00:00:00 2001 From: PranavKTiwari Date: Tue, 30 Jun 2026 15:56:02 +0530 Subject: [PATCH 3/3] Added a new bit map --- sql/item.cc | 4 +--- sql/table.cc | 8 ++++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 4bc3a48527da8..e5ecfcbef93de 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -981,9 +981,7 @@ bool Item_field::update_vcol_processor(void *arg) { MY_BITMAP *map= (MY_BITMAP *) arg; - bitmap_fast_test_and_set(map, field->field_index); - - if (field->vcol_info) + if (!bitmap_fast_test_and_set(map, field->field_index) && field->vcol_info) { field->vcol_info->expr->walk(&Item::update_vcol_processor, 0, arg); field->vcol_info->expr->save_in_field(field, 0); diff --git a/sql/table.cc b/sql/table.cc index 2b283fd93e1b8..8907e2f117f62 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9187,8 +9187,11 @@ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) TABLE::update_virtual_fields(handler *, enum_vcol_update_mode). */ in_use->set_n_backup_active_arena(expr_arena, &backup_arena); - bitmap_clear_all(&tmp_set); - vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &tmp_set); + + MY_BITMAP local_set; + my_bitmap_init(&local_set, NULL, s->fields); + bitmap_set_bit(&local_set, vf->field_index); + vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &local_set); DBUG_FIX_WRITE_SET(vf); vf->vcol_info->expr->save_in_field(vf, 0); DBUG_RESTORE_WRITE_SET(vf); @@ -9201,6 +9204,7 @@ int TABLE::update_virtual_field(Field *vf, bool ignore_warnings) // This is an internal calculation, we expect it to always succeed DBUG_ASSERT(count_errors.errors == 0); } + my_bitmap_free(&local_set); DBUG_RETURN(count_errors.errors); }