From 8b985570806343755685e66b8110b53b8d91ab41 Mon Sep 17 00:00:00 2001 From: Dave Gosselin Date: Wed, 1 Jul 2026 15:58:10 -0400 Subject: [PATCH 1/2] MDEV-33524: marked_for_read assertion with virtual column vcol.vcol_misc deadlocks under --view-protocol at the FLUSH TABLES WITH READ LOCK block. The main connection holds the global read lock. The SELECT COUNT(*) FROM t1 query becomes CREATE OR REPLACE VIEW on a separate connection, and that DDL blocks on the read lock and never returns. So the same mysqltest client never reaches unlock tables. The fix is to wrap only that one SELECT in the view_protocol guards. --- mysql-test/suite/vcol/t/vcol_misc.test | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index 2709ff5b46535..eda88f4b12476 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -207,7 +207,13 @@ SELECT COUNT(*) FROM t1; INSERT INTO t1 (a,tsv) VALUES (5,DEFAULT); INSERT DELAYED INTO t1 (a,tsv) VALUES (6,DEFAULT); FLUSH TABLES WITH READ LOCK; +# Under view protocol the following SELECT is issued as CREATE VIEW on a +# separate connection. That statement blocks on the global read lock held +# here and would not return until the UNLOCK TABLES below, which the same +# client cannot reach while it waits. Run it directly to avoid the deadlock. +--disable_view_protocol SELECT COUNT(*) FROM t1; +--enable_view_protocol set GLOBAL debug_dbug= @old_debug; unlock tables; DROP TABLE t1; From a16a45a455ba5e45c3e1b214a426166dd52ebf84 Mon Sep 17 00:00:00 2001 From: Dave Gosselin Date: Wed, 1 Jul 2026 13:06:50 -0400 Subject: [PATCH 2/2] MDEV-33524: marked_for_read assertion with virtual column A couple of things interact in this scenario. 1. A virtual column whose value depends on session state, such as a VCOL calling DATE_FORMAT, has fix_fields (via fix_expr) run on it again before each INSERT. For a table reused from the cache this runs in Vcol_expr_context before setup_tables sets the table map. The test first opens t1 with a SELECT that fails before setup_tables, leaving it cached with map zero. 2. When the connection character set needs conversion, CONCAT (more generally, any charset aggregation) wraps that column in a charset converter. The converter evaluates any argument reported as constant, so it calls val_str() on the column as part of fix_fields, before a row exists and without the column in the read set. On DEBUG builds this fails the marked_for_read assertion; otherwise it reads an unread column. Consequently: When a table instance is opened, fix_fields runs with table->map already nonzero, but the fix_fields (via fix_expr) call from vcol_fix_expr did not have it nonzero; so set table->map=1 during Vcol_expr_context::init. The original Vcol_expr_context::init() (MDEV-24176) called init_lex_with_single_table, which set table->map= 1 as a side effect. A later merge of 10.2 into 10.3 (6f6c74b0d18) replaced that call with a backup of table->expr_arena, dropping the side effect. The destructor of the Vcol_expr_context will reset the map back to its original value. --- mysql-test/suite/vcol/r/vcol_misc.result | 10 ++++++++++ mysql-test/suite/vcol/t/vcol_misc.test | 15 +++++++++++++++ sql/table.cc | 1 + 3 files changed, 26 insertions(+) diff --git a/mysql-test/suite/vcol/r/vcol_misc.result b/mysql-test/suite/vcol/r/vcol_misc.result index 1a16fd1a3944e..b6ce12f690ecc 100644 --- a/mysql-test/suite/vcol/r/vcol_misc.result +++ b/mysql-test/suite/vcol/r/vcol_misc.result @@ -591,3 +591,13 @@ DROP TABLE t; # # End of 10.5 tests # +# +# Start of 10.11 tests +# +SET character_set_connection=ucs2; +CREATE TABLE t1 (d1 date not null, d2 date, gd text as (concat(d1,if(d1 <> d2, date_format(d2, 'to %y-%m-%d '), ''))) ); +SELECT (SELECT 1 FROM foo) FROM t1; +ERROR 42S02: Table 'test.foo' doesn't exist +INSERT INTO t1 (d1) VALUES ('2009-07-02'); +DROP TABLE t1; +# End of 10.11 tests diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index eda88f4b12476..4a64b74853e55 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -566,3 +566,18 @@ DROP TABLE t; --echo # --echo # End of 10.5 tests --echo # + +--echo # +--echo # Start of 10.11 tests +--echo # + +# Charset difference required which inserts a charset converter, forcing the column value read later. +SET character_set_connection=ucs2; +CREATE TABLE t1 (d1 date not null, d2 date, gd text as (concat(d1,if(d1 <> d2, date_format(d2, 'to %y-%m-%d '), ''))) ); +# Necessary to get table t1 into the cache. Without this SELECT, the crash is not evident. +--ERROR ER_NO_SUCH_TABLE +SELECT (SELECT 1 FROM foo) FROM t1; +INSERT INTO t1 (d1) VALUES ('2009-07-02'); +DROP TABLE t1; + +--echo # End of 10.11 tests diff --git a/sql/table.cc b/sql/table.cc index 2b283fd93e1b8..036b3e3e1e037 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3723,6 +3723,7 @@ bool Vcol_expr_context::init() thd->set_n_backup_active_arena(table->expr_arena, &backup_arena); thd->stmt_arena= thd; + table->map= 1; inited= true; return false; }