diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result index f3fce29c910..4b3b0fb54fc 100644 --- a/mysql-test/r/index_merge.result +++ b/mysql-test/r/index_merge.result @@ -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 diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test index 7f176a4cd11..ebe0fa42fcd 100644 --- a/mysql-test/t/index_merge.test +++ b/mysql-test/t/index_merge.test @@ -503,4 +503,30 @@ 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 diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 437aca866c6..0417460fe4f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12872,8 +12872,23 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tab->records= table->sort.found_records; // For SQL_CALC_ROWS if (select) { + /* + We need to preserve tablesort's output resultset here, because + QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT (called by + SQL_SELECT::cleanup()) may free it assuming it's the result of the quick + select operation that we no longer need. Note that all the other parts of + this data structure are cleaned up when + QUICK_INDEX_MERGE_SELECT::get_next encounters end of data, so the next + SQL_SELECT::cleanup() call changes sort.io_cache alone. + */ + IO_CACHE *tablesort_result_cache; + + tablesort_result_cache= table->sort.io_cache; + table->sort.io_cache= NULL; + select->cleanup(); // filesort did select tab->select= 0; + table->sort.io_cache= tablesort_result_cache; } tab->select_cond=0; tab->last_inner= 0;