From 6fab168a63ae63604318186885389e630bedfdbc Mon Sep 17 00:00:00 2001 From: "ram@gw.mysql.r18.ru" <> Date: Sat, 31 Jan 2004 10:04:16 +0400 Subject: [PATCH] fix for the bug #2419: order by ignores rows. null_ref_key moved to TABLE_REF. new null range created if necessary. --- mysql-test/r/order_by.result | 21 +++++++++++++++++++++ mysql-test/t/order_by.test | 12 ++++++++++++ sql/item_subselect.cc | 4 ++-- sql/opt_range.cc | 21 +++++++++++++++++++-- sql/sql_select.cc | 16 +++++++++------- sql/sql_select.h | 3 ++- 6 files changed, 65 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 4d166a961f3..c1053087603 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -590,3 +590,24 @@ SELECT id FROM t1 WHERE id <11984 AND menu =2 ORDER BY id DESC LIMIT 1 ; id 11392 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; diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 1db783c212b..bbb0046b47f 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -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); SELECT id FROM t1 WHERE id <11984 AND menu =2 ORDER BY id DESC LIMIT 1 ; 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; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 518b712ad18..5b3cc326679 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1110,7 +1110,7 @@ int subselect_indexsubquery_engine::exec() if (check_null) { /* 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; } @@ -1155,7 +1155,7 @@ int subselect_indexsubquery_engine::exec() { if (!check_null || null_finding) break; /* We don't need to check nulls */ - *tab->null_ref_key= 1; + *tab->ref.null_ref_key= 1; null_finding= 1; /* Check if there exists a row with a null value in the index */ if ((error= (safe_index_read(tab) == 1))) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index acc23924f75..9f56064cfb1 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -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->null_bit= key_info->key_part[part].null_bit; } - if (!quick->ranges.push_back(range)) - return quick; + if (quick->ranges.push_back(range)) + 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: delete quick; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 874a3b16312..5e2445be845 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -860,8 +860,10 @@ JOIN::optimize() as in other cases the join is done before the sort. */ 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_REF_OR_NULL && (order && simple_order || group_list && simple_group)) { 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 */ 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) { @@ -6208,12 +6210,12 @@ join_read_always_key_or_null(JOIN_TAB *tab) int res; /* 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) return res; /* 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); } @@ -6227,10 +6229,10 @@ join_read_next_same_or_null(READ_RECORD *info) JOIN_TAB *tab= info->table->reginfo.join_tab; /* 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 - *tab->null_ref_key= 1; // Read null key - return safe_index_read(tab); + *tab->ref.null_ref_key= 1; // Set null byte + return safe_index_read(tab); // then read null keys } diff --git a/sql/sql_select.h b/sql/sql_select.h index 7cc71117914..ed650c450c0 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -46,6 +46,8 @@ typedef struct st_table_ref store_key **key_copy; // Item **items; // val()'s for each keypart 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; /* @@ -88,7 +90,6 @@ typedef struct st_join_table { QUICK_SELECT *quick; Item *on_expr; const char *info; - byte *null_ref_key; int (*read_first_record)(struct st_join_table *tab); int (*next_select)(JOIN *,struct st_join_table *,bool); READ_RECORD read_record;