Commit 07c0b1d8 authored by Sergey Petrunya's avatar Sergey Petrunya

MDEV-6434: Wrong result (extra rows) with ORDER BY, multiple-column index, InnoDB

- Filesort has an optmization where it reads only columns that are 
  needed before the sorting is done.
- When ref(_or_null) is picked by the join optimizer, it may remove parts
  of WHERE clause that are guaranteed to be true.
- However, if we use quick select, we must put all of the range columns into the 
  read set. Not doing so will may cause us to fail to detect the end of the range.
parent 71a596b9
drop table if exists t0,t1,t2,t3;
#
# MDEV-6434: Wrong result (extra rows) with ORDER BY, multiple-column index, InnoDB
#
CREATE TABLE t1 (a INT, b INT, c INT, d TEXT, KEY idx(a,b,c)) ENGINE=InnoDB;
INSERT INTO t1 (a,c) VALUES
(8, 9),(8, 10),(13, 15),(16, 17),(16, 18),(16, 19),(20, 21),
(20, 22),(20, 24),(20, 25),(20, 26),(20, 27),(20, 28);
SELECT * FROM t1 WHERE a = 8 AND (b = 1 OR b IS NULL) ORDER BY c;
a b c d
8 NULL 9 NULL
8 NULL 10 NULL
DROP TABLE t1;
#
# ORDER BY handling (e.g. filesort) tests that require innodb
#
-- source include/have_innodb.inc
--disable_warnings
drop table if exists t0,t1,t2,t3;
--enable_warnings
--echo #
--echo # MDEV-6434: Wrong result (extra rows) with ORDER BY, multiple-column index, InnoDB
--echo #
CREATE TABLE t1 (a INT, b INT, c INT, d TEXT, KEY idx(a,b,c)) ENGINE=InnoDB;
INSERT INTO t1 (a,c) VALUES
(8, 9),(8, 10),(13, 15),(16, 17),(16, 18),(16, 19),(20, 21),
(20, 22),(20, 24),(20, 25),(20, 26),(20, 27),(20, 28);
SELECT * FROM t1 WHERE a = 8 AND (b = 1 OR b IS NULL) ORDER BY c;
DROP TABLE t1;
......@@ -642,6 +642,9 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
/* Temporary set for register_used_fields and register_field_in_read_map */
sort_form->read_set= &sort_form->tmp_set;
register_used_fields(param);
if (quick_select)
select->quick->add_used_key_part_to_set(sort_form->read_set);
Item *sort_cond= !select ?
0 : !select->pre_idx_push_select_cond ?
select->cond : select->pre_idx_push_select_cond;
......
......@@ -10538,6 +10538,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
if (quick->init())
goto err;
quick->records= records;
quick->max_used_key_length= ref->key_parts;
if ((cp_buffer_from_ref(thd, table, ref) && thd->is_fatal_error) ||
!(range= new(alloc) QUICK_RANGE()))
......@@ -10547,7 +10548,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
range->min_length= range->max_length= ref->key_length;
range->min_keypart_map= range->max_keypart_map=
make_prev_keypart_map(ref->key_parts);
range->flag= (ref->key_length == key_info->key_length ? EQ_RANGE : 0);
range->flag= EQ_RANGE;
if (!(quick->key_parts=key_part=(KEY_PART *)
alloc_root(&quick->alloc,sizeof(KEY_PART)*ref->key_parts)))
......@@ -11756,6 +11757,60 @@ void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names,
}
void QUICK_RANGE_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
{
for (uint i=0; i < max_used_key_length; i++)
{
bitmap_set_bit(col_set, key_parts[i].field->field_index);
}
}
void QUICK_GROUP_MIN_MAX_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
{
for (uint i=0; i < max_used_key_length; i++)
{
bitmap_set_bit(col_set, index_info->key_part[i].field->field_index);
}
}
void QUICK_ROR_INTERSECT_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
{
List_iterator_fast<QUICK_SELECT_WITH_RECORD> it(quick_selects);
QUICK_SELECT_WITH_RECORD *quick;
while ((quick= it++))
{
quick->quick->add_used_key_part_to_set(col_set);
}
}
void QUICK_INDEX_SORT_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
{
QUICK_RANGE_SELECT *quick;
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
while ((quick= it++))
{
quick->add_used_key_part_to_set(col_set);
}
if (pk_quick_select)
pk_quick_select->add_used_key_part_to_set(col_set);
}
void QUICK_ROR_UNION_SELECT::add_used_key_part_to_set(MY_BITMAP *col_set)
{
QUICK_SELECT_I *quick;
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
while ((quick= it++))
{
quick->add_used_key_part_to_set(col_set);
}
}
/*******************************************************************************
* Implementation of QUICK_GROUP_MIN_MAX_SELECT
*******************************************************************************/
......
......@@ -394,6 +394,13 @@ public:
Returns a QUICK_SELECT with reverse order of to the index.
*/
virtual QUICK_SELECT_I *make_reverse(uint used_key_parts_arg) { return NULL; }
/*
Add the key columns used by the quick select into table's read set.
This is used by an optimization in filesort.
*/
virtual void add_used_key_part_to_set(MY_BITMAP *col_set)=0;
};
......@@ -484,6 +491,9 @@ public:
#endif
virtual void replace_handler(handler *new_file) { file= new_file; }
QUICK_SELECT_I *make_reverse(uint used_key_parts_arg);
virtual void add_used_key_part_to_set(MY_BITMAP *col_set);
private:
/* Default copy ctor used by QUICK_SELECT_DESC */
friend class TRP_ROR_INTERSECT;
......@@ -644,6 +654,8 @@ public:
virtual int read_keys_and_merge()= 0;
/* used to get rows collected in Unique */
READ_RECORD read_record;
virtual void add_used_key_part_to_set(MY_BITMAP *col_set);
};
......@@ -719,6 +731,7 @@ public:
void add_keys_and_lengths(String *key_names, String *used_lengths);
void add_info_string(String *str);
bool is_keys_used(const MY_BITMAP *fields);
void add_used_key_part_to_set(MY_BITMAP *col_set);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
......@@ -798,6 +811,7 @@ public:
void add_keys_and_lengths(String *key_names, String *used_lengths);
void add_info_string(String *str);
bool is_keys_used(const MY_BITMAP *fields);
void add_used_key_part_to_set(MY_BITMAP *col_set);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
......@@ -940,6 +954,7 @@ public:
bool unique_key_range() { return false; }
int get_type() { return QS_TYPE_GROUP_MIN_MAX; }
void add_keys_and_lengths(String *key_names, String *used_lengths);
void add_used_key_part_to_set(MY_BITMAP *col_set);
#ifndef DBUG_OFF
void dbug_dump(int indent, bool verbose);
#endif
......
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