diff --git a/mysql-test/include/index_merge1.inc b/mysql-test/include/index_merge1.inc index 5837df67a75..d137b0957c0 100644 --- a/mysql-test/include/index_merge1.inc +++ b/mysql-test/include/index_merge1.inc @@ -527,4 +527,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/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result index 8a935d87457..c639b20de91 100644 --- a/mysql-test/r/index_merge_myisam.result +++ b/mysql-test/r/index_merge_myisam.result @@ -557,6 +557,30 @@ 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 #---------------- ROR-index_merge tests ----------------------- SET SESSION STORAGE_ENGINE = MyISAM; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 526b926d66d..620af5a9ea7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13490,9 +13490,24 @@ 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->quick_keys.clear_all(); // as far as we cleanup select->quick + table->sort.io_cache= tablesort_result_cache; } tab->select_cond=0; tab->last_inner= 0;