summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/order_by_innodb.result13
-rw-r--r--mysql-test/t/order_by_innodb.test23
-rw-r--r--sql/filesort.cc3
-rw-r--r--sql/opt_range.cc57
-rw-r--r--sql/opt_range.h15
5 files changed, 110 insertions, 1 deletions
diff --git a/mysql-test/r/order_by_innodb.result b/mysql-test/r/order_by_innodb.result
new file mode 100644
index 00000000000..3c6c4053741
--- /dev/null
+++ b/mysql-test/r/order_by_innodb.result
@@ -0,0 +1,13 @@
+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;
diff --git a/mysql-test/t/order_by_innodb.test b/mysql-test/t/order_by_innodb.test
new file mode 100644
index 00000000000..c20eaceb053
--- /dev/null
+++ b/mysql-test/t/order_by_innodb.test
@@ -0,0 +1,23 @@
+#
+# 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;
+
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 34cd11cbcf3..d6cb22ebe2c 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -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;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 5db080394eb..80807c01fd0 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -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
*******************************************************************************/
diff --git a/sql/opt_range.h b/sql/opt_range.h
index fff6e414ad9..b8b46ae5ab1 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -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