mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
fix for the bug #2419: order by ignores rows.
null_ref_key moved to TABLE_REF. new null range created if necessary.
This commit is contained in:
@ -590,3 +590,24 @@ SELECT id FROM t1 WHERE id <11984 AND menu =2 ORDER BY id DESC LIMIT 1 ;
|
|||||||
id
|
id
|
||||||
11392
|
11392
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
create table t1(a int, b int, index(b));
|
||||||
|
insert into t1 values (2, 1), (1, 1), (4, NULL), (3, NULL), (6, 2), (5, 2);
|
||||||
|
explain select * from t1 where b=1 or b is null order by a;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref_or_null b b 5 const 3 Using where; Using filesort
|
||||||
|
select * from t1 where b=1 or b is null order by a;
|
||||||
|
a b
|
||||||
|
1 1
|
||||||
|
2 1
|
||||||
|
3 NULL
|
||||||
|
4 NULL
|
||||||
|
explain select * from t1 where b=2 or b is null order by a;
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE t1 ref_or_null b b 5 const 4 Using where; Using filesort
|
||||||
|
select * from t1 where b=2 or b is null order by a;
|
||||||
|
a b
|
||||||
|
3 NULL
|
||||||
|
4 NULL
|
||||||
|
5 2
|
||||||
|
6 2
|
||||||
|
drop table t1;
|
||||||
|
@ -381,3 +381,15 @@ CREATE TABLE t1 ( id smallint(6) unsigned NOT NULL default '0', menu tinyint(4
|
|||||||
INSERT INTO t1 VALUES (11384, 2),(11392, 2);
|
INSERT INTO t1 VALUES (11384, 2),(11392, 2);
|
||||||
SELECT id FROM t1 WHERE id <11984 AND menu =2 ORDER BY id DESC LIMIT 1 ;
|
SELECT id FROM t1 WHERE id <11984 AND menu =2 ORDER BY id DESC LIMIT 1 ;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# REF_OR_NULL optimization + filesort (bug #2419)
|
||||||
|
#
|
||||||
|
|
||||||
|
create table t1(a int, b int, index(b));
|
||||||
|
insert into t1 values (2, 1), (1, 1), (4, NULL), (3, NULL), (6, 2), (5, 2);
|
||||||
|
explain select * from t1 where b=1 or b is null order by a;
|
||||||
|
select * from t1 where b=1 or b is null order by a;
|
||||||
|
explain select * from t1 where b=2 or b is null order by a;
|
||||||
|
select * from t1 where b=2 or b is null order by a;
|
||||||
|
drop table t1;
|
||||||
|
@ -1110,7 +1110,7 @@ int subselect_indexsubquery_engine::exec()
|
|||||||
if (check_null)
|
if (check_null)
|
||||||
{
|
{
|
||||||
/* We need to check for NULL if there wasn't a matching value */
|
/* We need to check for NULL if there wasn't a matching value */
|
||||||
*tab->null_ref_key= 0; // Search first for not null
|
*tab->ref.null_ref_key= 0; // Search first for not null
|
||||||
((Item_in_subselect *) item)->was_null= 0;
|
((Item_in_subselect *) item)->was_null= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1155,7 +1155,7 @@ int subselect_indexsubquery_engine::exec()
|
|||||||
{
|
{
|
||||||
if (!check_null || null_finding)
|
if (!check_null || null_finding)
|
||||||
break; /* We don't need to check nulls */
|
break; /* We don't need to check nulls */
|
||||||
*tab->null_ref_key= 1;
|
*tab->ref.null_ref_key= 1;
|
||||||
null_finding= 1;
|
null_finding= 1;
|
||||||
/* Check if there exists a row with a null value in the index */
|
/* Check if there exists a row with a null value in the index */
|
||||||
if ((error= (safe_index_read(tab) == 1)))
|
if ((error= (safe_index_read(tab) == 1)))
|
||||||
|
@ -2513,8 +2513,25 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref)
|
|||||||
key_part->part_length+=HA_KEY_BLOB_LENGTH;
|
key_part->part_length+=HA_KEY_BLOB_LENGTH;
|
||||||
key_part->null_bit= key_info->key_part[part].null_bit;
|
key_part->null_bit= key_info->key_part[part].null_bit;
|
||||||
}
|
}
|
||||||
if (!quick->ranges.push_back(range))
|
if (quick->ranges.push_back(range))
|
||||||
return quick;
|
goto err;
|
||||||
|
|
||||||
|
if (ref->null_ref_key)
|
||||||
|
{
|
||||||
|
QUICK_RANGE *null_range;
|
||||||
|
|
||||||
|
*ref->null_ref_key= 1; // Set null byte then create a range
|
||||||
|
if (!(null_range= new QUICK_RANGE(ref->key_buff, ref->key_length,
|
||||||
|
ref->key_buff, ref->key_length,
|
||||||
|
EQ_RANGE)))
|
||||||
|
goto err;
|
||||||
|
*ref->null_ref_key= 0; // Clear null byte
|
||||||
|
/* Do we need to do something with key_parts here? Looks like we don't */
|
||||||
|
if (quick->ranges.push_back(null_range))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return quick;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
delete quick;
|
delete quick;
|
||||||
|
@ -860,8 +860,10 @@ JOIN::optimize()
|
|||||||
as in other cases the join is done before the sort.
|
as in other cases the join is done before the sort.
|
||||||
*/
|
*/
|
||||||
if (const_tables != tables &&
|
if (const_tables != tables &&
|
||||||
(order || group_list) && join_tab[const_tables].type != JT_ALL &&
|
(order || group_list) &&
|
||||||
|
join_tab[const_tables].type != JT_ALL &&
|
||||||
join_tab[const_tables].type != JT_FT &&
|
join_tab[const_tables].type != JT_FT &&
|
||||||
|
join_tab[const_tables].type != JT_REF_OR_NULL &&
|
||||||
(order && simple_order || group_list && simple_group))
|
(order && simple_order || group_list && simple_group))
|
||||||
{
|
{
|
||||||
if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
|
if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
|
||||||
@ -3257,7 +3259,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
|
|||||||
{
|
{
|
||||||
/* Must read with repeat */
|
/* Must read with repeat */
|
||||||
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
|
j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF;
|
||||||
j->null_ref_key= null_ref_key;
|
j->ref.null_ref_key= null_ref_key;
|
||||||
}
|
}
|
||||||
else if (ref_key == j->ref.key_copy)
|
else if (ref_key == j->ref.key_copy)
|
||||||
{
|
{
|
||||||
@ -6208,12 +6210,12 @@ join_read_always_key_or_null(JOIN_TAB *tab)
|
|||||||
int res;
|
int res;
|
||||||
|
|
||||||
/* First read according to key which is NOT NULL */
|
/* First read according to key which is NOT NULL */
|
||||||
*tab->null_ref_key=0;
|
*tab->ref.null_ref_key= 0; // Clear null byte
|
||||||
if ((res= join_read_always_key(tab)) >= 0)
|
if ((res= join_read_always_key(tab)) >= 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/* Then read key with null value */
|
/* Then read key with null value */
|
||||||
*tab->null_ref_key= 1;
|
*tab->ref.null_ref_key= 1; // Set null byte
|
||||||
return safe_index_read(tab);
|
return safe_index_read(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6227,10 +6229,10 @@ join_read_next_same_or_null(READ_RECORD *info)
|
|||||||
JOIN_TAB *tab= info->table->reginfo.join_tab;
|
JOIN_TAB *tab= info->table->reginfo.join_tab;
|
||||||
|
|
||||||
/* Test if we have already done a read after null key */
|
/* Test if we have already done a read after null key */
|
||||||
if (*tab->null_ref_key)
|
if (*tab->ref.null_ref_key)
|
||||||
return -1; // All keys read
|
return -1; // All keys read
|
||||||
*tab->null_ref_key= 1; // Read null key
|
*tab->ref.null_ref_key= 1; // Set null byte
|
||||||
return safe_index_read(tab);
|
return safe_index_read(tab); // then read null keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,6 +46,8 @@ typedef struct st_table_ref
|
|||||||
store_key **key_copy; //
|
store_key **key_copy; //
|
||||||
Item **items; // val()'s for each keypart
|
Item **items; // val()'s for each keypart
|
||||||
table_map depend_map; // Table depends on these tables.
|
table_map depend_map; // Table depends on these tables.
|
||||||
|
byte *null_ref_key; // null byte position in the key_buf.
|
||||||
|
// used for REF_OR_NULL optimization.
|
||||||
} TABLE_REF;
|
} TABLE_REF;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -88,7 +90,6 @@ typedef struct st_join_table {
|
|||||||
QUICK_SELECT *quick;
|
QUICK_SELECT *quick;
|
||||||
Item *on_expr;
|
Item *on_expr;
|
||||||
const char *info;
|
const char *info;
|
||||||
byte *null_ref_key;
|
|
||||||
int (*read_first_record)(struct st_join_table *tab);
|
int (*read_first_record)(struct st_join_table *tab);
|
||||||
int (*next_select)(JOIN *,struct st_join_table *,bool);
|
int (*next_select)(JOIN *,struct st_join_table *,bool);
|
||||||
READ_RECORD read_record;
|
READ_RECORD read_record;
|
||||||
|
Reference in New Issue
Block a user