1--source include/count_sessions.inc
2
3call mtr.add_suppression("Table 't1' is marked as crashed and should be repaired");
4
5set @save_table_definition_cache=@@table_definition_cache;
6
7--echo #
8--echo # Tests for corrupted MyISAM tables and MyISAMMRG tables with corrupted
9--echo # children..
10--echo #
11--echo # Run with --myisam-recover=force option.
12--echo #
13--echo # Preparation: we need to make sure that the merge parent
14--echo # is never left in the table cache when closed, since this may
15--echo # have effect on merge children.
16--echo # For that, we set the table cache to minimal size and populate it
17--echo # in a concurrent connection.
18connect(con1,localhost,root,,test,,);
19connection con1;
20--echo #
21--echo # Minimal values.
22--echo #
23
24call mtr.add_suppression("Got an error from thread_id=.*ha_myisam.cc:");
25call mtr.add_suppression("MySQL thread id .*, query id .* localhost.*root Checking table");
26call mtr.add_suppression(" '\..test.t1'");
27
28set @save_table_open_cache=@@table_open_cache;
29set global table_open_cache=256;
30set global table_definition_cache=400;
31--disable_warnings
32drop procedure if exists p_create;
33--enable_warnings
34delimiter |;
35create procedure p_create()
36begin
37  declare i int default 1;
38  set @lock_table_stmt="lock table ";
39  set @drop_table_stmt="drop table ";
40  while i < @@global.table_definition_cache + 1 do
41    set @table_name=concat("t_", i);
42    set @opt_comma=if(i=1, "", ", ");
43    set @lock_table_stmt=concat(@lock_table_stmt, @opt_comma,
44                                @table_name, " read");
45    set @drop_table_stmt=concat(@drop_table_stmt, @opt_comma, @table_name);
46    set @create_table_stmt=concat("create table if not exists ",
47                                  @table_name, " (a int)");
48    prepare stmt from @create_table_stmt;
49    execute stmt;
50    deallocate prepare stmt;
51    set i= i+1;
52  end while;
53end|
54delimiter ;|
55call p_create();
56drop procedure p_create;
57--disable_query_log
58let $lock=`select @lock_table_stmt`;
59eval $lock;
60--enable_query_log
61connection default;
62--echo #
63--echo # We have to disable the ps-protocol, to avoid
64--echo # "Prepared statement needs to be re-prepared" errors
65--echo # -- table def versions change all the time with full table cache.
66--echo #
67--disable_ps_protocol
68--disable_warnings
69drop table if exists t1, t1_mrg, t1_copy;
70--enable_warnings
71let $MYSQLD_DATADIR=`select @@datadir`;
72--echo #
73--echo # Prepare a MERGE engine table, that refers to a corrupted
74--echo # child.
75--echo #
76create table t1 (a int, key(a)) engine=myisam;
77create table t1_mrg (a int) union (t1) engine=merge;
78--echo #
79--echo # Create a table with a corrupted index file:
80--echo # save an old index file, insert more rows,
81--echo # overwrite the new index file with the old one.
82--echo #
83insert into  t1 (a) values (1), (2), (3);
84flush table t1;
85--copy_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/t1_copy.MYI
86insert into  t1 (a) values (4), (5), (6);
87flush table t1;
88--remove_file $MYSQLD_DATADIR/test/t1.MYI
89--copy_file $MYSQLD_DATADIR/test/t1_copy.MYI $MYSQLD_DATADIR/test/t1.MYI
90--remove_file $MYSQLD_DATADIR/test/t1_copy.MYI
91--echo # check table is needed to mark the table as crashed.
92check table t1;
93--echo #
94--echo # At this point we have a merge table t1_mrg pointing to t1,
95--echo # and t1 is corrupted, and will be auto-repaired at open.
96--echo # Check that this doesn't lead to memory corruption.
97--echo #
98--replace_regex /'.*[\/\\]/'/
99select * from t1_mrg;
100--echo #
101--echo # Cleanup
102--echo #
103drop table t1, t1_mrg;
104connection con1;
105unlock tables;
106prepare stmt from @drop_table_stmt;
107execute stmt;
108deallocate prepare stmt;
109set @@global.table_open_cache=@save_table_open_cache;
110disconnect con1;
111connection default;
112--enable_ps_protocol
113set @@global.table_definition_cache=@save_table_definition_cache;
114
115--echo #
116--echo # 18075170 - sql node restart required to avoid deadlock after
117--echo #            restore
118--echo #
119--echo # Check that auto-repair for MyISAM tables can now happen in the
120--echo # middle of transaction, without aborting it.
121--enable_prepare_warnings
122
123connection default;
124
125create table t1 (a int, key(a)) engine=myisam;
126create table t2 (a int);
127insert into t2 values (1);
128
129--echo # Create a table with a corrupted index file:
130--echo # save an old index file, insert more rows,
131--echo # overwrite the new index file with the old one.
132insert into  t1 (a) values (1);
133flush table t1;
134--copy_file $MYSQLD_DATADIR/test/t1.MYI $MYSQLD_DATADIR/test/t1_copy.MYI
135insert into  t1 (a) values (4);
136flush table t1;
137--remove_file $MYSQLD_DATADIR/test/t1.MYI
138--copy_file $MYSQLD_DATADIR/test/t1_copy.MYI $MYSQLD_DATADIR/test/t1.MYI
139--remove_file $MYSQLD_DATADIR/test/t1_copy.MYI
140
141--echo # Check table is needed to mark the table as crashed.
142check table t1;
143
144--echo # At this point we have a corrupt t1
145set autocommit = 0;
146select * from t2;
147--echo # Without fix select from t1 will break the transaction. After the fix
148--echo # transaction should be active and should hold lock on table t2. Alter
149--echo # table from con2 will wait only if the transaction is not broken.
150--replace_regex /'.*[\/\\]/'/
151select * from t1;
152
153connect(con2, localhost, root);
154--SEND ALTER TABLE t2 ADD val INT
155
156connection default;
157--echo # With fix we should have alter table waiting for t2 lock here.
158let $wait_condition=
159  SELECT count(*) = 1 FROM information_schema.processlist WHERE state
160  LIKE "Waiting%" AND info = "ALTER TABLE t2 ADD val INT";
161
162--source include/wait_condition.inc
163ROLLBACK;
164SET autocommit = 1;
165
166connection con2;
167--REAP
168
169connection default;
170disconnect con2;
171
172--echo # Cleanup
173drop table t1, t2;
174
175# Wait till all disconnects are completed
176-- source include/wait_until_count_sessions.inc
177