Skip to content

Commit 5392b4a

Browse files
committed
MDEV-20354 All but last insert ignored in InnoDB tables when table locked
mysql_insert() first opens all affected tables (which implicitly starts a transaction in InnoDB), then stat tables. A failure to open a stat table caused open_tables() to abort the current stmt transaction (trans_rollback_stmt()). So, from the server point of view the following ha_write_row()-s happened outside of a transactions, and the server didn't bother to commit them. The server has a mechanism to prevent a transaction being unexpectedly committed or rolled back in the middle of a statement - if an operation takes place _in a sub-statement_ it cannot change the transaction state. Operations on stat tables are exactly that - they are not allowed to change a transaction state. Put them in a sub-statement to make sure they don't.
1 parent c8ba982 commit 5392b4a

File tree

4 files changed

+38
-0
lines changed

4 files changed

+38
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
rename table mysql.table_stats to mysql.table_stats_save;
2+
flush tables;
3+
set use_stat_tables= PREFERABLY;
4+
create table t1 (a int) engine=InnoDB;
5+
start transaction;
6+
insert t1 values (1);
7+
insert t1 values (2);
8+
commit;
9+
select * from t1;
10+
a
11+
1
12+
2
13+
drop table t1;
14+
rename table mysql.table_stats_save to mysql.table_stats;
15+
flush tables;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
source include/have_innodb.inc;
2+
3+
#
4+
# MDEV-20354 All but last insert ignored in InnoDB tables when table locked
5+
#
6+
rename table mysql.table_stats to mysql.table_stats_save;
7+
flush tables;
8+
set use_stat_tables= PREFERABLY;
9+
create table t1 (a int) engine=InnoDB;
10+
start transaction;
11+
insert t1 values (1);
12+
insert t1 values (2);
13+
commit;
14+
select * from t1;
15+
drop table t1;
16+
rename table mysql.table_stats_save to mysql.table_stats;
17+
flush tables;

sql/sql_class.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,12 +1444,16 @@ class Open_tables_backup: public Open_tables_state
14441444
/**
14451445
@class Sub_statement_state
14461446
@brief Used to save context when executing a function or trigger
1447+
1448+
operations on stat tables aren't technically a sub-statement, but they are
1449+
similar in a sense that they cannot change the transaction status.
14471450
*/
14481451

14491452
/* Defines used for Sub_statement_state::in_sub_stmt */
14501453

14511454
#define SUB_STMT_TRIGGER 1
14521455
#define SUB_STMT_FUNCTION 2
1456+
#define SUB_STMT_STAT_TABLES 4
14531457

14541458

14551459
class Sub_statement_state

sql/sql_statistics.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,9 @@ inline int open_stat_tables(THD *thd, TABLE_LIST *tables,
268268
thd->push_internal_handler(&deh);
269269
init_table_list_for_stat_tables(tables, for_write);
270270
init_mdl_requests(tables);
271+
thd->in_sub_stmt|= SUB_STMT_STAT_TABLES;
271272
rc= open_system_tables_for_read(thd, tables, backup);
273+
thd->in_sub_stmt&= ~SUB_STMT_STAT_TABLES;
272274
thd->pop_internal_handler();
273275

274276

0 commit comments

Comments
 (0)