Commit b586bed7 authored by Sergey Vojtovich's avatar Sergey Vojtovich

BUG#49902 - SELECT returns incorrect results

Queries optimized with GROUP_MIN_MAX didn't cleanup KEYREAD
optimization properly. As a result subsequent queries may
return incomplete rows (fields are initialized to default
values).

mysql-test/r/group_min_max.result:
  A test case for BUG#49902.
mysql-test/t/group_min_max.test:
  A test case for BUG#49902.
sql/opt_range.cc:
  Refactor of KEYREAD optimization switch so that KEYREAD
  handler state is in sync with st_table::key_read flag.
  
  All SQL code is supposed to switch KEYREAD optimization
  via st_table::set_keyread().
sql/opt_sum.cc:
  Refactor of KEYREAD optimization switch so that KEYREAD
  handler state is in sync with st_table::key_read flag.
  
  All SQL code is supposed to switch KEYREAD optimization
  via st_table::set_keyread().
sql/sql_select.cc:
  Refactor of KEYREAD optimization switch so that KEYREAD
  handler state is in sync with st_table::key_read flag.
  
  All SQL code is supposed to switch KEYREAD optimization
  via st_table::set_keyread().
sql/sql_update.cc:
  Refactor of KEYREAD optimization switch so that KEYREAD
  handler state is in sync with st_table::key_read flag.
  
  All SQL code is supposed to switch KEYREAD optimization
  via st_table::set_keyread().
sql/table.cc:
  Refactor of KEYREAD optimization switch so that KEYREAD
  handler state is in sync with st_table::key_read flag.
  
  All SQL code is supposed to switch KEYREAD optimization
  via st_table::set_keyread().
sql/table.h:
  Refactor of KEYREAD optimization switch so that KEYREAD
  handler state is in sync with st_table::key_read flag.
  
  All SQL code is supposed to switch KEYREAD optimization
  via st_table::set_keyread().
parent e29fdb2c
...@@ -2524,4 +2524,17 @@ SELECT a, MAX(b) FROM t WHERE b GROUP BY a; ...@@ -2524,4 +2524,17 @@ SELECT a, MAX(b) FROM t WHERE b GROUP BY a;
a MAX(b) a MAX(b)
2 1 2 1
DROP TABLE t; DROP TABLE t;
CREATE TABLE t1(a INT NOT NULL, b INT NOT NULL, KEY (b));
INSERT INTO t1 VALUES(1,1),(2,1);
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status OK
SELECT 1 AS c, b FROM t1 WHERE b IN (1,2) GROUP BY c, b;
c b
1 1
SELECT a FROM t1 WHERE b=1;
a
1
2
DROP TABLE t1;
End of 5.1 tests End of 5.1 tests
...@@ -1044,4 +1044,14 @@ SELECT a, MAX(b) FROM t WHERE b GROUP BY a; ...@@ -1044,4 +1044,14 @@ SELECT a, MAX(b) FROM t WHERE b GROUP BY a;
DROP TABLE t; DROP TABLE t;
#
# BUG#49902 - SELECT returns incorrect results
#
CREATE TABLE t1(a INT NOT NULL, b INT NOT NULL, KEY (b));
INSERT INTO t1 VALUES(1,1),(2,1);
ANALYZE TABLE t1;
SELECT 1 AS c, b FROM t1 WHERE b IN (1,2) GROUP BY c, b;
SELECT a FROM t1 WHERE b=1;
DROP TABLE t1;
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -1171,11 +1171,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() ...@@ -1171,11 +1171,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
if (file) if (file)
{ {
range_end(); range_end();
if (head->key_read) head->set_keyread(FALSE);
{
head->key_read= 0;
file->extra(HA_EXTRA_NO_KEYREAD);
}
if (free_file) if (free_file)
{ {
DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file, DBUG_PRINT("info", ("Freeing separate handler 0x%lx (free: %d)", (long) file,
...@@ -1377,10 +1373,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) ...@@ -1377,10 +1373,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
head->file= file; head->file= file;
/* We don't have to set 'head->keyread' here as the 'file' is unique */ /* We don't have to set 'head->keyread' here as the 'file' is unique */
if (!head->no_keyread) if (!head->no_keyread)
{
head->key_read= 1;
head->mark_columns_used_by_index(index); head->mark_columns_used_by_index(index);
}
head->prepare_for_position(); head->prepare_for_position();
head->file= org_file; head->file= org_file;
bitmap_copy(&column_bitmap, head->read_set); bitmap_copy(&column_bitmap, head->read_set);
...@@ -8165,7 +8158,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() ...@@ -8165,7 +8158,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge"); DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge");
/* We're going to just read rowids. */ /* We're going to just read rowids. */
file->extra(HA_EXTRA_KEYREAD); head->set_keyread(TRUE);
head->prepare_for_position(); head->prepare_for_position();
cur_quick_it.rewind(); cur_quick_it.rewind();
...@@ -8241,7 +8234,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() ...@@ -8241,7 +8234,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
delete unique; delete unique;
doing_pk_scan= FALSE; doing_pk_scan= FALSE;
/* index_merge currently doesn't support "using index" at all */ /* index_merge currently doesn't support "using index" at all */
file->extra(HA_EXTRA_NO_KEYREAD); head->set_keyread(FALSE);
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE); init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE);
DBUG_RETURN(result); DBUG_RETURN(result);
} }
...@@ -10628,7 +10621,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void) ...@@ -10628,7 +10621,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::reset(void)
int result; int result;
DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset"); DBUG_ENTER("QUICK_GROUP_MIN_MAX_SELECT::reset");
file->extra(HA_EXTRA_KEYREAD); /* We need only the key attributes */ head->set_keyread(TRUE); /* We need only the key attributes */
if ((result= file->ha_index_init(index,1))) if ((result= file->ha_index_init(index,1)))
DBUG_RETURN(result); DBUG_RETURN(result);
if (quick_prefix_select && quick_prefix_select->reset()) if (quick_prefix_select && quick_prefix_select->reset())
......
...@@ -326,11 +326,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -326,11 +326,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (!error && reckey_in_range(0, &ref, item_field->field, if (!error && reckey_in_range(0, &ref, item_field->field,
conds, range_fl, prefix_len)) conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND; error= HA_ERR_KEY_NOT_FOUND;
if (table->key_read) table->set_keyread(FALSE);
{
table->key_read= 0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
table->file->ha_index_end(); table->file->ha_index_end();
if (error) if (error)
{ {
...@@ -413,11 +409,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) ...@@ -413,11 +409,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (!error && reckey_in_range(1, &ref, item_field->field, if (!error && reckey_in_range(1, &ref, item_field->field,
conds, range_fl, prefix_len)) conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND; error= HA_ERR_KEY_NOT_FOUND;
if (table->key_read) table->set_keyread(FALSE);
{
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
table->file->ha_index_end(); table->file->ha_index_end();
if (error) if (error)
{ {
...@@ -876,10 +868,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, ...@@ -876,10 +868,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
converted (for example to upper case) converted (for example to upper case)
*/ */
if (field->part_of_key.is_set(idx)) if (field->part_of_key.is_set(idx))
{ table->set_keyread(TRUE);
table->key_read= 1;
table->file->extra(HA_EXTRA_KEYREAD);
}
return 1; return 1;
} }
} }
......
...@@ -6594,10 +6594,7 @@ make_join_readinfo(JOIN *join, ulonglong options) ...@@ -6594,10 +6594,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
case JT_CONST: // Only happens with left join case JT_CONST: // Only happens with left join
if (table->covering_keys.is_set(tab->ref.key) && if (table->covering_keys.is_set(tab->ref.key) &&
!table->no_keyread) !table->no_keyread)
{ table->set_keyread(TRUE);
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
break; break;
case JT_ALL: case JT_ALL:
/* /*
...@@ -6658,10 +6655,7 @@ make_join_readinfo(JOIN *join, ulonglong options) ...@@ -6658,10 +6655,7 @@ make_join_readinfo(JOIN *join, ulonglong options)
if (tab->select && tab->select->quick && if (tab->select && tab->select->quick &&
tab->select->quick->index != MAX_KEY && //not index_merge tab->select->quick->index != MAX_KEY && //not index_merge
table->covering_keys.is_set(tab->select->quick->index)) table->covering_keys.is_set(tab->select->quick->index))
{ table->set_keyread(TRUE);
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
else if (!table->covering_keys.is_clear_all() && else if (!table->covering_keys.is_clear_all() &&
!(tab->select && tab->select->quick)) !(tab->select && tab->select->quick))
{ // Only read index tree { // Only read index tree
...@@ -6745,11 +6739,7 @@ void JOIN_TAB::cleanup() ...@@ -6745,11 +6739,7 @@ void JOIN_TAB::cleanup()
limit= 0; limit= 0;
if (table) if (table)
{ {
if (table->key_read) table->set_keyread(FALSE);
{
table->key_read= 0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
table->file->ha_index_or_rnd_end(); table->file->ha_index_or_rnd_end();
/* /*
We need to reset this for next select We need to reset this for next select
...@@ -11595,16 +11585,11 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos) ...@@ -11595,16 +11585,11 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
!table->no_keyread && !table->no_keyread &&
(int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY) (int) table->reginfo.lock_type <= (int) TL_READ_HIGH_PRIORITY)
{ {
table->key_read=1; table->set_keyread(TRUE);
table->file->extra(HA_EXTRA_KEYREAD);
tab->index= tab->ref.key; tab->index= tab->ref.key;
} }
error=join_read_const(tab); error=join_read_const(tab);
if (table->key_read) table->set_keyread(FALSE);
{
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
if (error) if (error)
{ {
tab->info="unique row not found"; tab->info="unique row not found";
...@@ -11959,12 +11944,8 @@ join_read_first(JOIN_TAB *tab) ...@@ -11959,12 +11944,8 @@ join_read_first(JOIN_TAB *tab)
{ {
int error; int error;
TABLE *table=tab->table; TABLE *table=tab->table;
if (!table->key_read && table->covering_keys.is_set(tab->index) && if (table->covering_keys.is_set(tab->index) && !table->no_keyread)
!table->no_keyread) table->set_keyread(TRUE);
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
tab->table->status=0; tab->table->status=0;
tab->read_record.read_record=join_read_next; tab->read_record.read_record=join_read_next;
tab->read_record.table=table; tab->read_record.table=table;
...@@ -11998,12 +11979,8 @@ join_read_last(JOIN_TAB *tab) ...@@ -11998,12 +11979,8 @@ join_read_last(JOIN_TAB *tab)
{ {
TABLE *table=tab->table; TABLE *table=tab->table;
int error; int error;
if (!table->key_read && table->covering_keys.is_set(tab->index) && if (table->covering_keys.is_set(tab->index) && !table->no_keyread)
!table->no_keyread) table->set_keyread(TRUE);
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
tab->table->status=0; tab->table->status=0;
tab->read_record.read_record=join_read_prev; tab->read_record.read_record=join_read_prev;
tab->read_record.table=table; tab->read_record.table=table;
...@@ -13413,11 +13390,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, ...@@ -13413,11 +13390,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If ref_key used index tree reading only ('Using index' in EXPLAIN), If ref_key used index tree reading only ('Using index' in EXPLAIN),
and best_key doesn't, then revert the decision. and best_key doesn't, then revert the decision.
*/ */
if (!table->covering_keys.is_set(best_key) && table->key_read) if (!table->covering_keys.is_set(best_key))
{ table->set_keyread(FALSE);
table->key_read= 0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
if (!quick_created) if (!quick_created)
{ {
tab->index= best_key; tab->index= best_key;
...@@ -13430,10 +13404,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, ...@@ -13430,10 +13404,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
select->quick= 0; select->quick= 0;
} }
if (table->covering_keys.is_set(best_key)) if (table->covering_keys.is_set(best_key))
{ table->set_keyread(TRUE);
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
table->file->ha_index_or_rnd_end(); table->file->ha_index_or_rnd_end();
if (join->select_options & SELECT_DESCRIBE) if (join->select_options & SELECT_DESCRIBE)
{ {
...@@ -13607,11 +13578,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -13607,11 +13578,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
We can only use 'Only index' if quick key is same as ref_key We can only use 'Only index' if quick key is same as ref_key
and in index_merge 'Only index' cannot be used and in index_merge 'Only index' cannot be used
*/ */
if (table->key_read && ((uint) tab->ref.key != select->quick->index)) if (((uint) tab->ref.key != select->quick->index))
{ table->set_keyread(FALSE);
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
} }
else else
{ {
...@@ -13667,11 +13635,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, ...@@ -13667,11 +13635,7 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
tab->type=JT_ALL; // Read with normal read_record tab->type=JT_ALL; // Read with normal read_record
tab->read_first_record= join_init_read_record; tab->read_first_record= join_init_read_record;
tab->join->examined_rows+=examined_rows; tab->join->examined_rows+=examined_rows;
if (table->key_read) // Restore if we used indexes table->set_keyread(FALSE); // Restore if we used indexes
{
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
DBUG_RETURN(table->sort.found_records == HA_POS_ERROR); DBUG_RETURN(table->sort.found_records == HA_POS_ERROR);
err: err:
DBUG_RETURN(-1); DBUG_RETURN(-1);
......
...@@ -397,10 +397,7 @@ int mysql_update(THD *thd, ...@@ -397,10 +397,7 @@ int mysql_update(THD *thd,
matching rows before updating the table! matching rows before updating the table!
*/ */
if (used_index < MAX_KEY && old_covering_keys.is_set(used_index)) if (used_index < MAX_KEY && old_covering_keys.is_set(used_index))
{
table->key_read=1;
table->mark_columns_used_by_index(used_index); table->mark_columns_used_by_index(used_index);
}
else else
{ {
table->use_all_columns(); table->use_all_columns();
...@@ -844,11 +841,7 @@ int mysql_update(THD *thd, ...@@ -844,11 +841,7 @@ int mysql_update(THD *thd,
err: err:
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
if (table->key_read) table->set_keyread(FALSE);
{
table->key_read=0;
table->file->extra(HA_EXTRA_NO_KEYREAD);
}
thd->abort_on_warning= 0; thd->abort_on_warning= 0;
DBUG_RETURN(1); DBUG_RETURN(1);
} }
......
...@@ -4374,7 +4374,7 @@ void st_table::mark_columns_used_by_index(uint index) ...@@ -4374,7 +4374,7 @@ void st_table::mark_columns_used_by_index(uint index)
MY_BITMAP *bitmap= &tmp_set; MY_BITMAP *bitmap= &tmp_set;
DBUG_ENTER("st_table::mark_columns_used_by_index"); DBUG_ENTER("st_table::mark_columns_used_by_index");
(void) file->extra(HA_EXTRA_KEYREAD); set_keyread(TRUE);
bitmap_clear_all(bitmap); bitmap_clear_all(bitmap);
mark_columns_used_by_index_no_reset(index, bitmap); mark_columns_used_by_index_no_reset(index, bitmap);
column_bitmaps_set(bitmap, bitmap); column_bitmaps_set(bitmap, bitmap);
...@@ -4397,8 +4397,7 @@ void st_table::restore_column_maps_after_mark_index() ...@@ -4397,8 +4397,7 @@ void st_table::restore_column_maps_after_mark_index()
{ {
DBUG_ENTER("st_table::restore_column_maps_after_mark_index"); DBUG_ENTER("st_table::restore_column_maps_after_mark_index");
key_read= 0; set_keyread(FALSE);
(void) file->extra(HA_EXTRA_NO_KEYREAD);
default_column_bitmaps(); default_column_bitmaps();
file->column_bitmaps_signal(); file->column_bitmaps_signal();
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
......
...@@ -902,6 +902,20 @@ struct st_table { ...@@ -902,6 +902,20 @@ struct st_table {
inline bool needs_reopen_or_name_lock() inline bool needs_reopen_or_name_lock()
{ return s->version != refresh_version; } { return s->version != refresh_version; }
bool is_children_attached(void); bool is_children_attached(void);
inline void set_keyread(bool flag)
{
DBUG_ASSERT(file);
if (flag && !key_read)
{
key_read= 1;
file->extra(HA_EXTRA_KEYREAD);
}
else if (!flag && key_read)
{
key_read= 0;
file->extra(HA_EXTRA_NO_KEYREAD);
}
}
}; };
enum enum_schema_table_state enum enum_schema_table_state
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment