mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
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.
This commit is contained in:
committed by
Sergei Golubchik
parent
b08b78c5b9
commit
6f78efc01c
@ -976,6 +976,8 @@ insert into t values (3);
|
|||||||
set debug_sync= 'now signal goforit';
|
set debug_sync= 'now signal goforit';
|
||||||
xa end 'xid';
|
xa end 'xid';
|
||||||
xa commit 'xid' one phase;
|
xa commit 'xid' one phase;
|
||||||
|
connection con1;
|
||||||
|
connection default;
|
||||||
drop table t;
|
drop table t;
|
||||||
set debug_sync= reset;
|
set debug_sync= reset;
|
||||||
#
|
#
|
||||||
@ -1158,5 +1160,21 @@ set debug_sync= reset;
|
|||||||
set debug_dbug= @old_debug;
|
set debug_dbug= @old_debug;
|
||||||
connection default;
|
connection default;
|
||||||
#
|
#
|
||||||
|
# MDEV-30902 Server crash in LEX::first_lists_tables_same
|
||||||
|
#
|
||||||
|
create table t1 engine=myisam select 1 as x ;
|
||||||
|
create procedure p() alter table t1 engine=heap;
|
||||||
|
set debug_sync= 'alter_table_copy_end signal ended wait_for end';
|
||||||
|
call p;
|
||||||
|
connection con1;
|
||||||
|
set debug_sync= 'now wait_for ended';
|
||||||
|
insert into t1 values (2);
|
||||||
|
set debug_sync= 'now signal end';
|
||||||
|
connection default;
|
||||||
|
call p;
|
||||||
|
drop table t1;
|
||||||
|
drop procedure p;
|
||||||
|
set debug_sync=reset;
|
||||||
|
#
|
||||||
# End of 11.2 tests
|
# End of 11.2 tests
|
||||||
#
|
#
|
||||||
|
@ -1149,6 +1149,9 @@ xa end 'xid';
|
|||||||
xa commit 'xid' one phase;
|
xa commit 'xid' one phase;
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
|
--connection con1
|
||||||
|
--reap
|
||||||
|
--connection default
|
||||||
drop table t;
|
drop table t;
|
||||||
set debug_sync= reset;
|
set debug_sync= reset;
|
||||||
|
|
||||||
@ -1326,6 +1329,28 @@ set debug_sync= reset;
|
|||||||
set debug_dbug= @old_debug;
|
set debug_dbug= @old_debug;
|
||||||
--connection default
|
--connection default
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-30902 Server crash in LEX::first_lists_tables_same
|
||||||
|
--echo #
|
||||||
|
create table t1 engine=myisam select 1 as x ;
|
||||||
|
create procedure p() alter table t1 engine=heap;
|
||||||
|
|
||||||
|
set debug_sync= 'alter_table_copy_end signal ended wait_for end';
|
||||||
|
send call p;
|
||||||
|
|
||||||
|
--connection con1
|
||||||
|
set debug_sync= 'now wait_for ended';
|
||||||
|
insert into t1 values (2);
|
||||||
|
set debug_sync= 'now signal end';
|
||||||
|
|
||||||
|
--connection default
|
||||||
|
--reap
|
||||||
|
call p;
|
||||||
|
|
||||||
|
drop table t1;
|
||||||
|
drop procedure p;
|
||||||
|
set debug_sync=reset;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 11.2 tests
|
--echo # End of 11.2 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -5238,8 +5238,13 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove trigger's tables */
|
/*
|
||||||
restore_empty_query_table_list(thd->lex);
|
Remove trigger's tables. In case of ONLINE ALTER TABLE, event doesn't own
|
||||||
|
the table (hence, no tables are locked), and therefore no cleanup should be
|
||||||
|
done after each event.
|
||||||
|
*/
|
||||||
|
if (rgi->tables_to_lock_count)
|
||||||
|
restore_empty_query_table_list(thd->lex);
|
||||||
|
|
||||||
if (WSREP(thd) && wsrep_thd_is_applying(thd))
|
if (WSREP(thd) && wsrep_thd_is_applying(thd))
|
||||||
query_cache_invalidate_locked_for_write(thd, rgi->tables_to_lock);
|
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)
|
|||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
restore_empty_query_table_list(thd->lex);
|
|
||||||
if (rgi->tables_to_lock_count)
|
if (rgi->tables_to_lock_count)
|
||||||
|
{
|
||||||
|
restore_empty_query_table_list(thd->lex);
|
||||||
rgi->slave_close_thread_tables(thd);
|
rgi->slave_close_thread_tables(thd);
|
||||||
|
}
|
||||||
thd->reset_query_timer();
|
thd->reset_query_timer();
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user