Bug #42760: Select doesn't return desired results when we have null

values
 
 We should re-set the access method functions when changing the access
 method when switching to another index to avoid sorting.
 
 Fixed by doing a little re-engineering : encapsulating all the function
 assignment into a special function and calling it when flipping the 
 indexes.
This commit is contained in:
Georgi Kodinov 2009-11-10 10:21:41 +02:00
parent 5d725601a8
commit 154c348031
3 changed files with 108 additions and 50 deletions

View file

@ -1092,3 +1092,24 @@ FROM t3;
2 2
NULL NULL
DROP TABLE t1, t2, t3; 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

View file

@ -756,3 +756,29 @@ SELECT
FROM t3; FROM t3;
DROP TABLE t1, t2, 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

View file

@ -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 static void
make_join_readinfo(JOIN *join, ulonglong options) 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))) (join->sort_by_table == (TABLE *) 1 && i != join->const_tables)))
ordered_set= 1; ordered_set= 1;
table->status=STATUS_NO_RECORD;
pick_table_access_method (tab);
switch (tab->type) { 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: 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.unlock_row= join_read_key_unlock_row;
tab->read_record.read_record= join_no_more_records; /* fall through */
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_REF_OR_NULL: case JT_REF_OR_NULL:
case JT_REF: case JT_REF:
table->status=STATUS_NO_RECORD;
if (tab->select) if (tab->select)
{ {
delete tab->select->quick; delete tab->select->quick;
@ -6280,34 +6300,20 @@ make_join_readinfo(JOIN *join, ulonglong options)
} }
delete tab->quick; delete tab->quick;
tab->quick=0; tab->quick=0;
/* fall through */
case JT_CONST: // Only happens with left join
if (table->used_keys.is_set(tab->ref.key) && if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread) !table->no_keyread)
{ {
table->key_read=1; table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD); 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; break;
case JT_ALL: case JT_ALL:
/* /*
If previous table use cache If previous table use cache
If the incoming data set is already sorted don't 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) && if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE) &&
tab->use_quick != 2 && !tab->first_inner && !ordered_set) tab->use_quick != 2 && !tab->first_inner && !ordered_set)
{ {
@ -6381,6 +6387,9 @@ make_join_readinfo(JOIN *join, ulonglong options)
} }
} }
break; break;
case JT_FT:
case JT_SYSTEM:
break;
default: default:
DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */ DBUG_PRINT("error",("Table type %d found",tab->type)); /* purecov: deadcode */
break; /* 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, if (create_ref_for_key(tab->join, tab, keyuse,
tab->join->const_table_map)) tab->join->const_table_map))
DBUG_RETURN(0); DBUG_RETURN(0);
pick_table_access_method(tab);
} }
else else
{ {