List:Commits« Previous MessageNext Message »
From:Georgi Kodinov Date:June 3 2009 12:37pm
Subject:bzr commit into mysql-5.0-bugteam branch (joro:2759) Bug#44810
View as plain text  
#At file:///home/kgeorge/mysql/work/B44810-5.0-bugteam/ based on revid:sergey.glukhov@stripped

 2759 Georgi Kodinov	2009-06-03
      Bug #44810: index merge and order by with low sort_buffer_size
      crashes server!
      
      The problem affects the scenario when index merge is followed by a filesort
      and the sort buffer is not big enough for all the sort keys.
      In this case the filesort function will read the data to the end through the 
      index merge quick access method (and thus closing the cursor etc), 
      but will leave the pointer to the quick select method in place.
      It will then create a temporary file to hold the results of the filesort and
      will add it as a sort output file (in sort.io_cache).
      Note that filesort will copy the original 'sort' structure in an automatic
      variable and restore it after it's done.
      As a result at exiting filesort() we have a sort.io_cache filled in and 
      nothing else (as a result of close of the cursors at end of reading data 
      through index merge).
      Now create_sort_index() will note that there is a select and will clean it up
      (as it's been used already by filesort() reading the data in). While doing that
      a special case in the index merge destructor will clean up the sort.io_cache,
      assuming it's an output of the index merge method and is not needed anymore.
      As a result the code that tries to read the data back from the filesort output 
      will get no data in both memory and disk and will crash.
      
      Fixed similarly to how filesort() does it : by copying the sort.io_cache structure
      to a local variable, removing the pointer to the io_cache (so that it's not freed 
      by the index merge destructor) and restoring the original structure (together with
      the valid pointer) after the cleanup is done.
      This is a safe thing to do because all the structures are already cleaned up by
      hitting the end of the index merge's read method (get_next()) and the cleanup 
      code being written in a way that tolerates consecutive cleanups.
     @ mysql-test/r/index_merge.result
        Bug #44810: test case
     @ mysql-test/t/index_merge.test
        Bug #44810: test case
     @ sql/sql_select.cc
        Bug #44810: preserve the io_cache produced by filesort while cleaning up
        the index merge quick access method.

    modified:
      mysql-test/r/index_merge.result
      mysql-test/t/index_merge.test
      sql/sql_select.cc
=== modified file 'mysql-test/r/index_merge.result'
--- a/mysql-test/r/index_merge.result	2008-12-19 13:38:39 +0000
+++ b/mysql-test/r/index_merge.result	2009-06-03 12:37:54 +0000
@@ -555,4 +555,28 @@ a
 1
 2
 drop table t0, t1, t2, t3;
+#
+# BUG#44810: index merge and order by with low sort_buffer_size 
+# crashes server!
+#
+CREATE TABLE t1(a VARCHAR(128),b VARCHAR(128),KEY(A),KEY(B));
+INSERT INTO t1 VALUES (REPEAT('a',128),REPEAT('b',128));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+SET SESSION sort_buffer_size=1;
+Warnings:
+Warning	1292	Truncated incorrect sort_buffer_size value: '1'
+EXPLAIN 
+SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' 
+ORDER BY a,b;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	index_merge	a,b	a,b	131,131	NULL	64	Using sort_union(a,b); Using where; Using filesort
+SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' 
+ORDER BY a,b;
+SET SESSION sort_buffer_size=DEFAULT;
+DROP TABLE t1;
 End of 5.0 tests

=== modified file 'mysql-test/t/index_merge.test'
--- a/mysql-test/t/index_merge.test	2008-12-19 13:38:39 +0000
+++ b/mysql-test/t/index_merge.test	2009-06-03 12:37:54 +0000
@@ -503,4 +503,29 @@ where exists (select 1 from t2, t3 
 
 drop table t0, t1, t2, t3;
 
+--echo #
+--echo # BUG#44810: index merge and order by with low sort_buffer_size 
+--echo # crashes server!
+--echo #
+CREATE TABLE t1(a VARCHAR(128),b VARCHAR(128),KEY(A),KEY(B));
+INSERT INTO t1 VALUES (REPEAT('a',128),REPEAT('b',128));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+SET SESSION sort_buffer_size=1;
+EXPLAIN 
+SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' 
+  ORDER BY a,b;
+# we don't actually care about the result : we're checking if it crashes
+--disable_result_log
+SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%' 
+  ORDER BY a,b;
+--enable_result_log
+
+SET SESSION sort_buffer_size=DEFAULT;
+DROP TABLE t1;
+
 --echo End of 5.0 tests

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2009-05-15 09:29:41 +0000
+++ b/sql/sql_select.cc	2009-06-03 12:37:54 +0000
@@ -12865,8 +12865,19 @@ create_sort_index(THD *thd, JOIN *join, 
   tab->records= table->sort.found_records;	// For SQL_CALC_ROWS
   if (select)
   {
+    FILESORT_INFO table_sort;
+    /* 
+      Don't use table->sort in filesort as it is also used by 
+      QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end 
+      when index_merge select has finished with it.
+    */
+    memcpy(&table_sort, &table->sort, sizeof(FILESORT_INFO));
+    table->sort.io_cache= NULL;
+
     select->cleanup();				// filesort did select
     tab->select= 0;
+
+    memcpy(&table->sort, &table_sort, sizeof(FILESORT_INFO));
   }
   tab->select_cond=0;
   tab->last_inner= 0;


Attachment: [text/bzr-bundle] bzr/joro@sun.com-20090603123754-a5w10jl61nnz5hps.bundle
Thread
bzr commit into mysql-5.0-bugteam branch (joro:2759) Bug#44810Georgi Kodinov3 Jun
  • Re: bzr commit into mysql-5.0-bugteam branch (joro:2759) Bug#44810Timour Katchaounov15 Jun