diff --git a/mysql-test/suite/vcol/r/vcol_syntax.result b/mysql-test/suite/vcol/r/vcol_syntax.result index 1c3a7566f48..615b7013647 100644 --- a/mysql-test/suite/vcol/r/vcol_syntax.result +++ b/mysql-test/suite/vcol/r/vcol_syntax.result @@ -248,3 +248,106 @@ select unix_timestamp(f), unix_timestamp(g) from t; unix_timestamp(f) unix_timestamp(g) 1 2 drop table t; +# +# MDEV-40041 Assertion `fixed()' failed in Item_func_connection_id::val_int on INSERT w/ TRIGGER +# +create table t (c int); +lock table t write; +create or replace table t (a int as (connection_id())); +create trigger a before insert on t for each row set @a:=1; +insert into t values (''); +Warnings: +Warning 1906 The value specified for generated column 'a' in table 't' has been ignored +Warning 1366 Incorrect integer value: '' for column `test`.`t`.`a` at row 1 +select a = connection_id() from t; +a = connection_id() +1 +unlock tables; +drop table t; +# Simpler variant: table and trigger exist before LOCK TABLES +create table t1 (a int as (connection_id())); +create trigger tr1 before insert on t1 for each row set @a:=1; +lock table t1 write; +insert into t1 values (''); +Warnings: +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +Warning 1366 Incorrect integer value: '' for column `test`.`t1`.`a` at row 1 +select a = connection_id() from t1; +a = connection_id() +1 +unlock tables; +drop table t1; +# Trigger writes to another locked table with session vcol +create table t1 (a int); +create table t2 (a int primary key, b int as (connection_id())); +create trigger tr1 before insert on t1 for each row insert into t2 values (new.a, ''); +lock table t1 write, t2 write; +# Trigger fires for each row +insert into t1 values (1), (2), (3); +select a, b = connection_id() from t2; +a b = connection_id() +1 1 +2 1 +3 1 +# Duplicate key in trigger +insert into t1 values (1); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +# Direct INSERT after failed trigger, then duplicate key in trigger +insert into t2 (a) values (4); +select a, b = connection_id() from t2; +a b = connection_id() +1 1 +2 1 +3 1 +4 1 +insert into t1 values (4); +ERROR 23000: Duplicate entry '4' for key 'PRIMARY' +select a, b = connection_id() from t2; +a b = connection_id() +1 1 +2 1 +3 1 +4 1 +unlock tables; +drop tables t1, t2; +# Trigger fails, later statements use the same locked table +create table t1 (a int as (connection_id()), b int); +create trigger tr1 before insert on t1 for each row +if new.b = 0 then signal sqlstate '45000'; end if| +create trigger tr2 after insert on t1 for each row +if new.b = -1 then signal sqlstate '45000'; end if| +lock table t1 write; +# BEFORE trigger fails +insert into t1 (b) values (0); +ERROR 45000: Unhandled user-defined exception condition +select a = connection_id(), b from t1; +a = connection_id() b +# AFTER trigger fails +insert into t1 (b) values (-1); +ERROR 45000: Unhandled user-defined exception condition +select a = connection_id(), b from t1; +a = connection_id() b +1 -1 +# AFTER trigger of the first row, then the second row is written +insert into t1 values ('', 1), ('', 2); +Warnings: +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +Warning 1366 Incorrect integer value: '' for column `test`.`t1`.`a` at row 1 +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +Warning 1366 Incorrect integer value: '' for column `test`.`t1`.`a` at row 2 +select a = connection_id(), b from t1; +a = connection_id() b +1 -1 +1 1 +1 2 +# BEFORE trigger fails after successful INSERT +insert into t1 (b) values (0); +ERROR 45000: Unhandled user-defined exception condition +select a = connection_id(), b from t1; +a = connection_id() b +1 -1 +1 1 +1 2 +unlock tables; +drop table t1; +# End of 10.11 tests diff --git a/mysql-test/suite/vcol/t/vcol_syntax.test b/mysql-test/suite/vcol/t/vcol_syntax.test index 4f6130a973f..aa4a85f73c0 100644 --- a/mysql-test/suite/vcol/t/vcol_syntax.test +++ b/mysql-test/suite/vcol/t/vcol_syntax.test @@ -197,3 +197,73 @@ flush table t; select unix_timestamp(f), unix_timestamp(g) from t; # Cleanup drop table t; + +--echo # +--echo # MDEV-40041 Assertion `fixed()' failed in Item_func_connection_id::val_int on INSERT w/ TRIGGER +--echo # +create table t (c int); +lock table t write; +create or replace table t (a int as (connection_id())); +create trigger a before insert on t for each row set @a:=1; +insert into t values (''); +select a = connection_id() from t; +unlock tables; +drop table t; + +--echo # Simpler variant: table and trigger exist before LOCK TABLES +create table t1 (a int as (connection_id())); +create trigger tr1 before insert on t1 for each row set @a:=1; +lock table t1 write; +insert into t1 values (''); +select a = connection_id() from t1; +unlock tables; +drop table t1; + +--echo # Trigger writes to another locked table with session vcol +create table t1 (a int); +create table t2 (a int primary key, b int as (connection_id())); +create trigger tr1 before insert on t1 for each row insert into t2 values (new.a, ''); +lock table t1 write, t2 write; +--echo # Trigger fires for each row +insert into t1 values (1), (2), (3); +select a, b = connection_id() from t2; +--echo # Duplicate key in trigger +--error ER_DUP_ENTRY +insert into t1 values (1); +--echo # Direct INSERT after failed trigger, then duplicate key in trigger +insert into t2 (a) values (4); +select a, b = connection_id() from t2; +--error ER_DUP_ENTRY +insert into t1 values (4); +select a, b = connection_id() from t2; +unlock tables; +drop tables t1, t2; + +--echo # Trigger fails, later statements use the same locked table +create table t1 (a int as (connection_id()), b int); +--delimiter | +create trigger tr1 before insert on t1 for each row + if new.b = 0 then signal sqlstate '45000'; end if| +create trigger tr2 after insert on t1 for each row + if new.b = -1 then signal sqlstate '45000'; end if| +--delimiter ; +lock table t1 write; +--echo # BEFORE trigger fails +--error ER_SIGNAL_EXCEPTION +insert into t1 (b) values (0); +select a = connection_id(), b from t1; +--echo # AFTER trigger fails +--error ER_SIGNAL_EXCEPTION +insert into t1 (b) values (-1); +select a = connection_id(), b from t1; +--echo # AFTER trigger of the first row, then the second row is written +insert into t1 values ('', 1), ('', 2); +select a = connection_id(), b from t1; +--echo # BEFORE trigger fails after successful INSERT +--error ER_SIGNAL_EXCEPTION +insert into t1 (b) values (0); +select a = connection_id(), b from t1; +unlock tables; +drop table t1; + +--echo # End of 10.11 tests diff --git a/sql/sql_base.cc b/sql/sql_base.cc index eabad77012a..74444752366 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -876,8 +876,11 @@ int close_thread_tables(THD *thd) noexcept /* For simple locking we cleanup it here because we don't close thread tables. For prelocking we close it when we do close thread tables. + Sub-statement does not cleanup: the outer statement may still use + the tables, and the top-level statement cleans up all locked tables + when it ends. */ - if (thd->locked_tables_mode != LTM_PRELOCKED) + if (thd->locked_tables_mode != LTM_PRELOCKED && !thd->in_sub_stmt) table->vcol_cleanup_expr(thd); }