1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-40041 Assertion `fixed()' failed in Item_func_connection_id::val_int on INSERT w/ TRIGGER

Under LOCK TABLES close_thread_tables() cleans up session-dependent
virtual column expressions (vcol_cleanup_expr()) of all tables in
thd->open_tables, because they are not closed at the end of the
statement. A trigger sub-statement also calls close_thread_tables() at
its end, so a BEFORE INSERT trigger cleaned up the expressions of the
table the outer INSERT was still writing to. Then
TABLE::update_virtual_fields() evaluated the unfixed CONNECTION_ID()
and failed the assertion.

The fix skips vcol_cleanup_expr() in close_thread_tables() when in
sub-statement. The outer statement cleans up the expressions when it
closes its tables.
This commit is contained in:
Aleksey Midenkov
2026-10-13 15:31:47 +03:00
parent 29a5c93f5b
commit 4a1e64f722
3 changed files with 177 additions and 1 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}