From 1afe6ff03aea2be84b3d060d78a091a040c93496 Mon Sep 17 00:00:00 2001 From: Konstantin Osipov Date: Fri, 2 Jul 2010 19:21:07 +0400 Subject: [PATCH] A test case for Bug#50788 "main.merge fails on HPUX", and a backport of relevant changes from the 6.0 version of the fix done by Ingo Struewing. The bug itself was fixed by the patch for Bug#54811. MyISAMMRG engine would try to use MMAP on its children even on platforms that don't support it and even if myisam_use_mmap option was off. This lead to an infinite hang in INSERT ... SELECT into a MyISAMMRG table when the destination MyISAM table was also selected from. A bug in duplicate detection fixed by 54811 was essential to the hang - when a duplicate is detected, the optimizer disables the use of memory mapped files, and it wasn't the case. The patch below is also to not turn on MMAP on children tables if myisam_use_mmap is off. A test case is added to cover MyISAMMRG and myisam_use_mmap option. mysql-test/r/merge_mmap.result: Result file - Bug#50788. mysql-test/t/merge_mmap-master.opt: An option file for the test for Bug#50788 -- use mmap. mysql-test/t/merge_mmap.test: Try INSERT ... SELECT into a merge table when myisam_use_mmap is on (Bug#50788). storage/myisam/mi_statrec.c: Fixed misinterpretation of the return value of my_b_read(). storage/myisammrg/ha_myisammrg.cc: Skip HA_EXTRA_MMAP if MyISAM memory mapping is disabled. --- mysql-test/r/merge_mmap.result | 64 ++++++++++++++++++++++++++++++ mysql-test/t/merge_mmap-master.opt | 1 + mysql-test/t/merge_mmap.test | 60 ++++++++++++++++++++++++++++ storage/myisam/mi_statrec.c | 13 +++++- storage/myisammrg/ha_myisammrg.cc | 2 + 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 mysql-test/r/merge_mmap.result create mode 100644 mysql-test/t/merge_mmap-master.opt create mode 100644 mysql-test/t/merge_mmap.test diff --git a/mysql-test/r/merge_mmap.result b/mysql-test/r/merge_mmap.result new file mode 100644 index 00000000000..d975a1be377 --- /dev/null +++ b/mysql-test/r/merge_mmap.result @@ -0,0 +1,64 @@ +SET GLOBAL storage_engine = MyISAM; +SET SESSION storage_engine = MyISAM; +DROP TABLE IF EXISTS t1, t2, m1, m2; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +SELECT * FROM t2; +c1 +2 +3 +4 +1 +2 +3 +4 +DROP TABLE m2, m1, t2, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +SELECT * FROM t2; +c1 +2 +3 +4 +1 +2 +3 +4 +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +End of 6.0 tests diff --git a/mysql-test/t/merge_mmap-master.opt b/mysql-test/t/merge_mmap-master.opt new file mode 100644 index 00000000000..9606fb57187 --- /dev/null +++ b/mysql-test/t/merge_mmap-master.opt @@ -0,0 +1 @@ +--myisam-use-mmap diff --git a/mysql-test/t/merge_mmap.test b/mysql-test/t/merge_mmap.test new file mode 100644 index 00000000000..3468702ca45 --- /dev/null +++ b/mysql-test/t/merge_mmap.test @@ -0,0 +1,60 @@ +# +# Test of MERGE TABLES with MyISAM memory mapping enabled (--myisam-use-mmap) +# + +# MERGE tables require MyISAM tables +--let $default=`SELECT @@global.storage_engine` +SET GLOBAL storage_engine = MyISAM; +SET SESSION storage_engine = MyISAM; + +# Clean up resources used in this test case. +--disable_warnings +DROP TABLE IF EXISTS t1, t2, m1, m2; +--enable_warnings + +#################### +## No locked tables. +#################### +# +# INSERT-SELECT with no TEMPORARY table. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +SELECT * FROM t2; +DROP TABLE m2, m1, t2, t1; + +#################### +## With LOCK TABLES. +#################### +# +# INSERT-SELECT with no TEMPORARY table. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +SELECT * FROM t2; +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +--echo End of 6.0 tests + +--disable_result_log +--disable_query_log +eval SET GLOBAL storage_engine = $default; +--enable_result_log +--enable_query_log diff --git a/storage/myisam/mi_statrec.c b/storage/myisam/mi_statrec.c index 7d595916d78..f83afa3c886 100644 --- a/storage/myisam/mi_statrec.c +++ b/storage/myisam/mi_statrec.c @@ -298,8 +298,17 @@ int _mi_read_rnd_static_record(MI_INFO *info, uchar *buf, info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED; DBUG_RETURN(0); } - /* my_errno should be set if rec_cache.error == -1 */ + /* error is TRUE. my_errno should be set if rec_cache.error == -1 */ if (info->rec_cache.error != -1 || my_errno == 0) - my_errno=HA_ERR_WRONG_IN_RECORD; + { + /* + If we could not get a full record, we either have a broken record, + or are at end of file. + */ + if (info->rec_cache.error == 0) + my_errno= HA_ERR_END_OF_FILE; + else + my_errno= HA_ERR_WRONG_IN_RECORD; + } DBUG_RETURN(my_errno); /* Something wrong (EOF?) */ } diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 67b81225b13..1681f062117 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -1322,6 +1322,8 @@ int ha_myisammrg::extra(enum ha_extra_function operation) if (operation == HA_EXTRA_FORCE_REOPEN || operation == HA_EXTRA_PREPARE_FOR_DROP) return 0; + if (operation == HA_EXTRA_MMAP && !opt_myisam_use_mmap) + return 0; return myrg_extra(file,operation,0); }