--source include/count_sessions.inc --echo # --echo # Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted --echo # children.. --echo # --echo # Run with --myisam-recover=force option. --echo # --echo # Preparation: we need to make sure that the merge parent --echo # is never left in the table cache when closed, since this may --echo # have effect on merge children. --echo # For that, we set the table cache to minimal size and populate it --echo # in a concurrent connection. connect(con1,localhost,root,,test,,); --echo # --echo # Switching to connection con1 --echo # connection con1; --echo # --echo # Minimal values. --echo # # MERGE tables require MyISAM tables --source include/no_valgrind_without_big.inc --source include/have_myisam.inc call mtr.add_suppression("Got an error from thread_id=.*ha_myisam.cc:"); call mtr.add_suppression("MySQL thread id .*, query id .* localhost.*root Checking table"); call mtr.add_suppression(" '\..test.t1'"); set @start_table_open_cache=@@global.table_open_cache; set @start_table_definition_cache=@@global.table_definition_cache; set global table_open_cache=256; set global table_definition_cache=400; --disable_warnings drop procedure if exists p_create; --enable_warnings delimiter |; create procedure p_create() begin declare i int default 1; set @lock_table_stmt="lock table "; set @drop_table_stmt="drop table "; while i < @@global.table_definition_cache + 1 do set @table_name=concat("t_", i); set @opt_comma=if(i=1, "", ", "); set @lock_table_stmt=concat(@lock_table_stmt, @opt_comma, @table_name, " read"); set @drop_table_stmt=concat(@drop_table_stmt, @opt_comma, @table_name); set @create_table_stmt=concat("create table if not exists ", @table_name, " (a int)"); prepare stmt from @create_table_stmt; execute stmt; deallocate prepare stmt; set i= i+1; end while; end| delimiter ;| call p_create(); drop procedure p_create; --disable_query_log let $lock=`select @lock_table_stmt`; eval $lock; --enable_query_log --echo # --echo # Switching to connection 'default' --echo # connection default; --echo # --echo # We have to disable the ps-protocol, to avoid --echo # "Prepared statement needs to be re-prepared" errors --echo # -- table def versions change all the time with full table cache. --echo # --disable_ps_protocol --disable_warnings drop table if exists t1, t1_mrg, t1_copy; --enable_warnings let $MYSQLD_DATADIR=`select @@datadir`; --echo # --echo # Prepare a MERGE engine table, that refers to a corrupted --echo # child. --echo # create table t1 (a int, key(a)) engine=myisam; create table t1_mrg (a int) union (t1) engine=merge; --echo # --echo # Create a table with a corrupted index file: --echo # save an old index file, insert more rows, --echo # overwrite the new index file with the old one. --echo # insert into t1 (a) values (1), (2), (3); flush table t1; --copy_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/t1_copy.MYI insert into t1 (a) values (4), (5), (6); flush table t1; --remove_file $MYSQLD_DATADIR/test/t1.MYI --copy_file $MYSQLD_DATADIR/test/t1_copy.MYI $MYSQLD_DATADIR/test/t1.MYI --remove_file $MYSQLD_DATADIR/test/t1_copy.MYI --echo # check table is needed to mark the table as crashed. check table t1; --echo # --echo # At this point we have a merge table t1_mrg pointing to t1, --echo # and t1 is corrupted, and will be auto-repaired at open. --echo # Check that this doesn't lead to memory corruption. --echo # --replace_regex /'.*[\/\\]/'/ select * from t1_mrg; --echo # --echo # Cleanup --echo # drop table t1, t1_mrg; --echo # --echo # Switching to connection con1 --echo # connection con1; unlock tables; prepare stmt from @drop_table_stmt; execute stmt; deallocate prepare stmt; set @@global.table_definition_cache=@start_table_definition_cache; set @@global.table_open_cache=@start_table_open_cache; disconnect con1; connection default; --enable_ps_protocol --echo # --echo # 18075170 - sql node restart required to avoid deadlock after --echo # restore --echo # --echo # Check that auto-repair for MyISAM tables can now happen in the --echo # middle of transaction, without aborting it. connection default; create table t1 (a int, key(a)) engine=myisam; create table t2 (a int); insert into t2 values (1); --echo # Create a table with a corrupted index file: --echo # save an old index file, insert more rows, --echo # overwrite the new index file with the old one. insert into t1 (a) values (1); flush table t1; --copy_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/t1_copy.MYI insert into t1 (a) values (4); flush table t1; --remove_file $MYSQLD_DATADIR/test/t1.MYI --copy_file $MYSQLD_DATADIR/test/t1_copy.MYI $MYSQLD_DATADIR/test/t1.MYI --remove_file $MYSQLD_DATADIR/test/t1_copy.MYI --echo # Check table is needed to mark the table as crashed. check table t1; --echo # At this point we have a corrupt t1 set autocommit = 0; select * from t2; --echo # Without fix select from t1 will break the transaction. After the fix --echo # transaction should be active and should hold lock on table t2. Alter --echo # table from con2 will wait only if the transaction is not broken. --replace_regex /'.*[\/\\]/'/ select * from t1; connect(con2, localhost, root); --SEND ALTER TABLE t2 ADD val INT connection default; --echo # With fix we should have alter table waiting for t2 lock here. let $wait_condition= SELECT count(*) = 1 FROM information_schema.processlist WHERE state LIKE "Waiting%" AND info = "ALTER TABLE t2 ADD val INT"; --source include/wait_condition.inc ROLLBACK; SET autocommit = 1; connection con2; --REAP connection default; disconnect con2; --echo # Cleanup drop table t1, t2; # Wait till all disconnects are completed -- source include/wait_until_count_sessions.inc