diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index f64bbc79cbd..f0e5b5fde3d 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1092,3 +1092,24 @@ FROM t3; 2 NULL DROP TABLE t1, t2, t3; +# +# Bug #42760: Select doesn't return desired results when we have null +# values +# +CREATE TABLE t1 ( +a INT, +c INT, +UNIQUE KEY a_c (a,c), +KEY (a)); +INSERT INTO t1 VALUES (1, 10), (2, NULL); +# Must use ref-or-null on the a_c index +EXPLAIN +SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a_c,a a_c 10 const,const 1 Using where +# Must return 1 row +SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c; +col +1 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 6d7ee1c1ca7..d9a6c0f844d 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -756,3 +756,29 @@ SELECT FROM t3; DROP TABLE t1, t2, t3; + + + +--echo # +--echo # Bug #42760: Select doesn't return desired results when we have null +--echo # values +--echo # + +CREATE TABLE t1 ( + a INT, + c INT, + UNIQUE KEY a_c (a,c), + KEY (a)); + +INSERT INTO t1 VALUES (1, 10), (2, NULL); + +--echo # Must use ref-or-null on the a_c index +EXPLAIN +SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c; +--echo # Must return 1 row +SELECT 1 AS col FROM t1 WHERE a=2 AND (c=10 OR c IS NULL) ORDER BY c; + +DROP TABLE t1; + + +--echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1ee31c788ff..f7c1fcec2a4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6202,6 +6202,56 @@ void rr_unlock_row(st_join_table *tab) +/** + Pick the appropriate access method functions + + Sets the functions for the selected table access method + + @param tab Table reference to put access method +*/ + +static void +pick_table_access_method(JOIN_TAB *tab) +{ + switch (tab->type) + { + case JT_REF: + tab->read_first_record= join_read_always_key; + tab->read_record.read_record= join_read_next_same; + break; + + case JT_REF_OR_NULL: + tab->read_first_record= join_read_always_key_or_null; + tab->read_record.read_record= join_read_next_same_or_null; + break; + + case JT_CONST: + tab->read_first_record= join_read_const; + tab->read_record.read_record= join_no_more_records; + break; + + case JT_EQ_REF: + tab->read_first_record= join_read_key; + tab->read_record.read_record= join_no_more_records; + break; + + case JT_FT: + tab->read_first_record= join_ft_read_first; + tab->read_record.read_record= join_ft_read_next; + break; + + case JT_SYSTEM: + tab->read_first_record= join_read_system; + tab->read_record.read_record= join_no_more_records; + break; + + /* keep gcc happy */ + default: + break; + } +} + + static void make_join_readinfo(JOIN *join, ulonglong options) { @@ -6234,45 +6284,15 @@ make_join_readinfo(JOIN *join, ulonglong options) (join->sort_by_table == (TABLE *) 1 && i != join->const_tables))) ordered_set= 1; + table->status=STATUS_NO_RECORD; + pick_table_access_method (tab); + switch (tab->type) { - case JT_SYSTEM: // Only happens with left join - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_read_system; - tab->read_record.read_record= join_no_more_records; - break; - case JT_CONST: // Only happens with left join - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_read_const; - tab->read_record.read_record= join_no_more_records; - if (table->used_keys.is_set(tab->ref.key) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } - break; case JT_EQ_REF: - table->status=STATUS_NO_RECORD; - if (tab->select) - { - delete tab->select->quick; - tab->select->quick=0; - } - delete tab->quick; - tab->quick=0; - tab->read_first_record= join_read_key; tab->read_record.unlock_row= join_read_key_unlock_row; - tab->read_record.read_record= join_no_more_records; - if (table->used_keys.is_set(tab->ref.key) && - !table->no_keyread) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } - break; + /* fall through */ case JT_REF_OR_NULL: case JT_REF: - table->status=STATUS_NO_RECORD; if (tab->select) { delete tab->select->quick; @@ -6280,34 +6300,20 @@ make_join_readinfo(JOIN *join, ulonglong options) } delete tab->quick; tab->quick=0; + /* fall through */ + case JT_CONST: // Only happens with left join if (table->used_keys.is_set(tab->ref.key) && !table->no_keyread) { table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); } - if (tab->type == JT_REF) - { - tab->read_first_record= join_read_always_key; - tab->read_record.read_record= join_read_next_same; - } - else - { - tab->read_first_record= join_read_always_key_or_null; - tab->read_record.read_record= join_read_next_same_or_null; - } - break; - case JT_FT: - table->status=STATUS_NO_RECORD; - tab->read_first_record= join_ft_read_first; - tab->read_record.read_record= join_ft_read_next; break; case JT_ALL: /* If previous table use cache If the incoming data set is already sorted don't use cache. */ - table->status=STATUS_NO_RECORD; if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) && tab->use_quick != 2 && !tab->first_inner && !ordered_set) { @@ -6381,6 +6387,9 @@ make_join_readinfo(JOIN *join, ulonglong options) } } break; + case JT_FT: + case JT_SYSTEM: + break; default: DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */ break; /* purecov: deadcode */ @@ -12753,6 +12762,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, if (create_ref_for_key(tab->join, tab, keyuse, tab->join->const_table_map)) DBUG_RETURN(0); + + pick_table_access_method(tab); } else {