Skip to content

Commit db20a99

Browse files
committed
MDEV-22915: Assertion 'binlog_table_maps == 0 || locked_tables_mode == LTM_LOCK_TABLES' failed in THD::reset_for_next_command
close_thread_tables() would not flush pending row events to the binlog cache in certain conditions if LOCK TABLES was active. This could result in the row events being binlogged without STMT_END_F flag, and eventually leave the THD in an invalid state that triggered assertions later. Reviewed-by: Monty <monty@mariadb.org> Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
1 parent c8ee774 commit db20a99

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
RESET MASTER;
2+
connect con1,localhost,root,,;
3+
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
4+
CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END;
5+
LOCK TABLES t1 WRITE;
6+
LOAD DATA INFILE 'x' INTO TABLE x;
7+
ERROR HY000: Table 'x' was not locked with LOCK TABLES
8+
SET AUTOCOMMIT= OFF;
9+
INSERT INTO t1 VALUES (1);
10+
SAVEPOINT A;
11+
COMMIT;
12+
disconnect con1;
13+
connect con2,localhost,root,,;
14+
SELECT 1;
15+
1
16+
1
17+
disconnect con2;
18+
connection default;
19+
include/show_binlog_events.inc
20+
Log_name Pos Event_type Server_id End_log_pos Info
21+
master-bin.000001 # Gtid # # GTID #-#-#
22+
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) ENGINE=InnoDB
23+
master-bin.000001 # Gtid # # GTID #-#-#
24+
master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END
25+
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
26+
master-bin.000001 # Annotate_rows # # INSERT INTO t1 VALUES (1)
27+
master-bin.000001 # Table_map # # table_id: # (test.t1)
28+
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
29+
master-bin.000001 # Query # # SAVEPOINT `A`
30+
master-bin.000001 # Xid # # COMMIT /* XID */
31+
DROP TABLE t1;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--source include/have_innodb.inc
2+
--source include/have_binlog_format_row.inc
3+
4+
RESET MASTER;
5+
6+
# This sequence of statements triggered a bug, where the pending LOCK TABLES
7+
# would skip flusing the pending row event for INSERT to the trx cache. And
8+
# Then the pending event would be overwritten by the SAVEPOINT, leaving an
9+
# invalid state in the THD. And then a later connection would pick the THD
10+
# with invalid state and trigger an assertion.
11+
--connect (con1,localhost,root,,)
12+
CREATE TABLE t1 (a INT) ENGINE=InnoDB;
13+
CREATE TRIGGER tr BEFORE UPDATE ON t1 FOR EACH ROW BEGIN END;
14+
LOCK TABLES t1 WRITE;
15+
--error ER_TABLE_NOT_LOCKED
16+
LOAD DATA INFILE 'x' INTO TABLE x;
17+
SET AUTOCOMMIT= OFF;
18+
INSERT INTO t1 VALUES (1);
19+
SAVEPOINT A;
20+
COMMIT;
21+
--disconnect con1
22+
23+
--connect (con2,localhost,root,,)
24+
SELECT 1;
25+
26+
# Cleanup
27+
--disconnect con2
28+
--connection default
29+
# Show the binlog events.
30+
# When the bug occurs, the Write_rows event is missing STMT_END_F.
31+
--source include/show_binlog_events.inc
32+
33+
DROP TABLE t1;

sql/sql_base.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,8 @@ int close_thread_tables(THD *thd)
957957

958958
if (thd->locked_tables_mode == LTM_LOCK_TABLES)
959959
{
960+
if (thd->lock)
961+
(void)thd->binlog_flush_pending_rows_event(TRUE);
960962
error= 0;
961963
goto end;
962964
}

0 commit comments

Comments
 (0)