From f7552313d4e54a1cbfa5cb9bb9d06a55df7d0e95 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Thu, 9 Nov 2023 16:26:11 +0300 Subject: [PATCH] MDEV-29932 Invalid expr in cleanup_session_expr() upon INSERT DELAYED There are two TABLE objects in each thread: first one is created in delayed thread by Delayed_insert::open_and_lock_table(), second one is created in connection thread by Delayed_insert::get_local_table(). It is copied from the delayed thread table. When the second table is copied copy-assignment operator copies vcol_refix_list which is already filled with an item from delayed thread. Then get_local_table() adds its own item. Thus both tables contains the same list with two items which is wrong. Then connection thread finishes and its item freed. Then delayed thread tries to access it in vcol_cleanup_expr(). The fix just clears vcol_refix_list in the copied table. Another problem is that copied table contains the same mem_root, any allocations on it will be invalid if the original table is freed (and that is indeterministic as it is done in another thread). Since copied table is allocated in connection THD and lives not longer than thd->mem_root we may assign its mem_root from thd->mem_root. Third, it doesn't make sense to do open_and_lock_tables() on NULL pointer. --- mysql-test/suite/vcol/r/vcol_syntax.result | 10 ++++++++++ mysql-test/suite/vcol/t/vcol_syntax.test | 10 ++++++++++ sql/sql_insert.cc | 5 ++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/vcol/r/vcol_syntax.result b/mysql-test/suite/vcol/r/vcol_syntax.result index f1a850e8f7c11..09d471ddd1786 100644 --- a/mysql-test/suite/vcol/r/vcol_syntax.result +++ b/mysql-test/suite/vcol/r/vcol_syntax.result @@ -234,3 +234,13 @@ Warning 1292 Incorrect datetime value: '1' for column `test`.`t`.`c2` at row 1 Warning 1292 Incorrect datetime value: '0' for column `test`.`t`.`c2` at row 1 drop trigger tr; drop table t; +# +# MDEV-29932 Invalid expr in cleanup_session_expr() upon INSERT DELAYED +# +create table t (f timestamp default from_unixtime(1), g timestamp as (from_unixtime(2))); +insert delayed into t values (); +flush table t; +select unix_timestamp(f), unix_timestamp(g) from t; +unix_timestamp(f) unix_timestamp(g) +1 2 +drop table t; diff --git a/mysql-test/suite/vcol/t/vcol_syntax.test b/mysql-test/suite/vcol/t/vcol_syntax.test index cb741bc6deff3..da3ce15eee95e 100644 --- a/mysql-test/suite/vcol/t/vcol_syntax.test +++ b/mysql-test/suite/vcol/t/vcol_syntax.test @@ -185,3 +185,13 @@ insert into t values (1, 1, 1); drop trigger tr; drop table t; + +--echo # +--echo # MDEV-29932 Invalid expr in cleanup_session_expr() upon INSERT DELAYED +--echo # +create table t (f timestamp default from_unixtime(1), g timestamp as (from_unixtime(2))); +insert delayed into t values (); +flush table t; +select unix_timestamp(f), unix_timestamp(g) from t; +# Cleanup +drop table t; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c3acce2f4a5a4..1bc2d9ccb00b9 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -579,7 +579,8 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) Open tables used for sub-selects or in stored functions, will also cache these functions. */ - if (open_and_lock_tables(thd, table_list->next_global, TRUE, 0)) + if (table_list->next_global && + open_and_lock_tables(thd, table_list->next_global, TRUE, 0)) { end_delayed_insert(thd); error= TRUE; @@ -2632,6 +2633,8 @@ TABLE *Delayed_insert::get_local_table(THD* client_thd) /* Copy the TABLE object. */ copy= new (copy_tmp) TABLE; *copy= *table; + copy->vcol_refix_list.empty(); + copy->mem_root= *client_thd->mem_root; /* We don't need to change the file handler here */ /* Assign the pointers for the field pointers array and the record. */