From 015c320a75e830deafcd51fdda00504c4d642b60 Mon Sep 17 00:00:00 2001 From: Jorgen Loland Date: Wed, 20 Mar 2013 11:20:12 +0100 Subject: [PATCH] Bug#16394084: LOOSE INDEX SCAN WITH QUOTED INT PREDICATE RETURNS RANDOM DATA MySQL 5.5 specific version of bugfix. When Loose Index Scan Range access is used, MySQL execution needs to copy non-aggregated fields. end_send() checked if this was necessary by checking if join_tab->select->quick had type QS_TYPE_GROUP_MIN_MAX. In this bug, however, MySQL created a sort index to sort the rows read from this range access method. create_sort_index() deletes join_tab->select->quick which makes it impossible to inquire the join_tab if LIS has been used. The fix for MySQL 5.5 is to introduce a variable in JOIN_TAB that stores whether or not LIS has been used. There is no need for this variable in later MySQL versions because the relevant code has been refactored. --- sql/sql_select.cc | 15 +++++++++++++++ sql/sql_select.h | 34 +++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d40c7cb7c81..2f20d7aad17 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2713,6 +2713,8 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, s->const_keys.init(); s->checked_keys.init(); s->needed_reg.init(); + s->filesort_used_loose_index_scan= false; + s->filesort_used_loose_index_scan_agg_distinct= false; table_vector[i]=s->table=table=tables->table; table->pos_in_table_list= tables; error= table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -6163,6 +6165,8 @@ JOIN::make_simple_join(JOIN *parent, TABLE *temp_table) join_tab->read_first_record= join_init_read_record; join_tab->join= this; join_tab->ref.key_parts= 0; + join_tab->filesort_used_loose_index_scan= false; + join_tab->filesort_used_loose_index_scan_agg_distinct= false; bzero((char*) &join_tab->read_record,sizeof(join_tab->read_record)); temp_table->status=0; temp_table->null_row=0; @@ -14240,6 +14244,17 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, tablesort_result_cache= table->sort.io_cache; table->sort.io_cache= NULL; + if (select->quick && + select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) + { + tab->filesort_used_loose_index_scan= true; + + QUICK_GROUP_MIN_MAX_SELECT *minmax_quick= + static_cast(select->quick); + if (minmax_quick->is_agg_distinct()) + tab->filesort_used_loose_index_scan_agg_distinct= true; + } + /* If a quick object was created outside of create_sort_index() that might be reused, then do not call select->cleanup() since diff --git a/sql/sql_select.h b/sql/sql_select.h index 6732eb354d6..fc39eb30984 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -243,16 +243,40 @@ typedef struct st_join_table { nested_join_map embedding_map; void cleanup(); + /* + In cases where filesort reads rows from a table using Loose Index + Scan, the fact that LIS was used is lost because + create_sort_index() deletes join_tab->select->quick. MySQL needs + this information during JOIN::exec(). + + This variable is a hack for MySQL 5.5 only. A value of true means + that filesort used LIS to read from the table. In MySQL 5.6 and + later, join_tab->filesort is a separate structure with it's own + select that can be inquired to get the same information. There is + no need for this variable in MySQL 5.6 and later. + */ + bool filesort_used_loose_index_scan; + /* + Similar hack as for filesort_used_loose_index_scan. Not needed for + MySQL 5.6 and later. + */ + bool filesort_used_loose_index_scan_agg_distinct; inline bool is_using_loose_index_scan() { - return (select && select->quick && - (select->quick->get_type() == - QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)); + return (filesort_used_loose_index_scan || + (select && select->quick && + (select->quick->get_type() == + QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)) + ); } bool is_using_agg_loose_index_scan () { - return (is_using_loose_index_scan() && - ((QUICK_GROUP_MIN_MAX_SELECT *)select->quick)->is_agg_distinct()); + return (filesort_used_loose_index_scan_agg_distinct || + (select && select->quick && + (select->quick->get_type() == + QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) && + ((QUICK_GROUP_MIN_MAX_SELECT *)select->quick)->is_agg_distinct()) + ); } } JOIN_TAB;