mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	---------------------------------------------------------- revno: 2617.69.21 committer: Konstantin Osipov <kostja@sun.com> branch nick: 5.4-4284-1-assert timestamp: Thu 2009-08-13 20:13:55 +0400 message: A fix and a test case for Bug#46610 "MySQL 5.4.4: MyISAM MRG engine crash on auto-repair of child". Also fixes Bug#42862 "Crash on failed attempt to open a children of a merge table". MERGE engine needs to extend the global table list with TABLE_LIST elements for child tables, so that they are opened and locked. Previously these table list elements were allocated in memory of ha_myisammrg object (MERGE engine handler). That would lead to access to freed memory in recover_from_failed_open_table_attempt(), which would try to recover a MERGE table child (MyISAM table) and use for that TABLE_LIST of that child. But by the time recover_from_failed_open_table_attempt() is invoked, ha_myisammrg object that owns this TABLE_LIST may be destroyed, and thus TABLE_LIST memory freed. The fix is to ensure that TABLE_LIST elements that are added to the global table list (lex->query_tables) are always allocated in thd->mem_root, which is not destroyed until end of execution. If previously TABLE_LIST elements were allocated at ha_myisammrg::open() (i.e. when the TABLE object was created and added to the table cache), now they are allocated in ha_myisammrg::add_chidlren_list() (i.e. right after "open" of the merge parent in open_tables()). We still create a list of children names at ha_myisammrg::open() to use as a basis for creation of TABLE_LISTs, that allows to avoid reading the merge handler data file on every execution.
		
			
				
	
	
		
			114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
--echo #
 | 
						|
--echo # Test of MyISAM MRG tables with corrupted children.
 | 
						|
--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 #
 | 
						|
 | 
						|
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 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=default;
 | 
						|
set @@global.table_open_cache=default;
 | 
						|
disconnect con1;
 | 
						|
connection default;
 | 
						|
--enable_ps_protocol
 |