Skip to content

Commit 6f78efc

Browse files
FooBarriorvuvova
authored andcommitted
MDEV-30902 Server crash in LEX::first_lists_tables_same
ONLINE ALTER TABLE uses binlog events like the replication does. Before it was never used outside of replication, so significant change was required. For example, a single event had a statement-like befavior: it locked the tables, opened it, and closed them in the end. But for ONLINE ALTER we use preopened table. A crash scenario is following: lex->query_tables was set to NULL in restore_empty_query_table_list when alter event is applied. Then lex->query_tables->prev_global was write-accessed in LEX::first_lists_tables_same, leading to a segfault. In replication restore_empty_query_table_list would mean resetting lex before next query or event. In ONLINE ALTER TABLE we reuse a locked table between the events, so we should avoid it. Here the need to reset lex state (or close the tables) can be determined by nonzero rgi->tables_to_lock_count. If no table is locked, then event doesn't own the tables. The same was already done before for rgi->slave_close_thread_tables call.
1 parent b08b78c commit 6f78efc

File tree

3 files changed

+53
-3
lines changed

3 files changed

+53
-3
lines changed

mysql-test/main/alter_table_online_debug.result

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,8 @@ insert into t values (3);
976976
set debug_sync= 'now signal goforit';
977977
xa end 'xid';
978978
xa commit 'xid' one phase;
979+
connection con1;
980+
connection default;
979981
drop table t;
980982
set debug_sync= reset;
981983
#
@@ -1158,5 +1160,21 @@ set debug_sync= reset;
11581160
set debug_dbug= @old_debug;
11591161
connection default;
11601162
#
1163+
# MDEV-30902 Server crash in LEX::first_lists_tables_same
1164+
#
1165+
create table t1 engine=myisam select 1 as x ;
1166+
create procedure p() alter table t1 engine=heap;
1167+
set debug_sync= 'alter_table_copy_end signal ended wait_for end';
1168+
call p;
1169+
connection con1;
1170+
set debug_sync= 'now wait_for ended';
1171+
insert into t1 values (2);
1172+
set debug_sync= 'now signal end';
1173+
connection default;
1174+
call p;
1175+
drop table t1;
1176+
drop procedure p;
1177+
set debug_sync=reset;
1178+
#
11611179
# End of 11.2 tests
11621180
#

mysql-test/main/alter_table_online_debug.test

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,9 @@ xa end 'xid';
11491149
xa commit 'xid' one phase;
11501150

11511151
# Cleanup
1152+
--connection con1
1153+
--reap
1154+
--connection default
11521155
drop table t;
11531156
set debug_sync= reset;
11541157

@@ -1326,6 +1329,28 @@ set debug_sync= reset;
13261329
set debug_dbug= @old_debug;
13271330
--connection default
13281331

1332+
--echo #
1333+
--echo # MDEV-30902 Server crash in LEX::first_lists_tables_same
1334+
--echo #
1335+
create table t1 engine=myisam select 1 as x ;
1336+
create procedure p() alter table t1 engine=heap;
1337+
1338+
set debug_sync= 'alter_table_copy_end signal ended wait_for end';
1339+
send call p;
1340+
1341+
--connection con1
1342+
set debug_sync= 'now wait_for ended';
1343+
insert into t1 values (2);
1344+
set debug_sync= 'now signal end';
1345+
1346+
--connection default
1347+
--reap
1348+
call p;
1349+
1350+
drop table t1;
1351+
drop procedure p;
1352+
set debug_sync=reset;
1353+
13291354
--echo #
13301355
--echo # End of 11.2 tests
13311356
--echo #

sql/log_event_server.cc

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5238,8 +5238,13 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
52385238
goto err;
52395239
}
52405240

5241-
/* remove trigger's tables */
5242-
restore_empty_query_table_list(thd->lex);
5241+
/*
5242+
Remove trigger's tables. In case of ONLINE ALTER TABLE, event doesn't own
5243+
the table (hence, no tables are locked), and therefore no cleanup should be
5244+
done after each event.
5245+
*/
5246+
if (rgi->tables_to_lock_count)
5247+
restore_empty_query_table_list(thd->lex);
52435248

52445249
if (WSREP(thd) && wsrep_thd_is_applying(thd))
52455250
query_cache_invalidate_locked_for_write(thd, rgi->tables_to_lock);
@@ -5258,9 +5263,11 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
52585263
DBUG_RETURN(error);
52595264

52605265
err:
5261-
restore_empty_query_table_list(thd->lex);
52625266
if (rgi->tables_to_lock_count)
5267+
{
5268+
restore_empty_query_table_list(thd->lex);
52635269
rgi->slave_close_thread_tables(thd);
5270+
}
52645271
thd->reset_query_timer();
52655272
DBUG_RETURN(error);
52665273
}

0 commit comments

Comments
 (0)