summaryrefslogtreecommitdiff
path: root/myisam/mi_search.c
diff options
context:
space:
mode:
Diffstat (limited to 'myisam/mi_search.c')
-rw-r--r--myisam/mi_search.c124
1 files changed, 82 insertions, 42 deletions
diff --git a/myisam/mi_search.c b/myisam/mi_search.c
index 2871633102d..1c4342ff39a 100644
--- a/myisam/mi_search.c
+++ b/myisam/mi_search.c
@@ -18,6 +18,7 @@
#include "fulltext.h"
#include "m_ctype.h"
+#include <assert.h>
static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
uchar *key, uchar *keypos,
@@ -273,7 +274,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
uchar *sort_order=keyinfo->seg->charset->sort_order;
uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
uchar *saved_from, *saved_to, *saved_vseg;
- uint saved_length=0, saved_prefix_len=0;
+ uint saved_length=0, saved_prefix_len=0;
+ uint length_pack;
DBUG_ENTER("_mi_prefix_search");
LINT_INIT(length);
@@ -289,26 +291,24 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
page+=2+nod_flag;
*ret_pos=page;
kseg=key;
- {
- uint lenght_pack;
- get_key_pack_length(kseg_len,lenght_pack,kseg);
- key_len_skip=lenght_pack+kseg_len;
- key_len_left=(int) key_len- (int) key_len_skip;
- cmplen=(key_len_left>=0) ? kseg_len : key_len-lenght_pack;
- DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg));
- }
-/*
- Keys are compressed the following way:
+ get_key_pack_length(kseg_len,length_pack,kseg);
+ key_len_skip=length_pack+kseg_len;
+ key_len_left=(int) key_len- (int) key_len_skip;
+ cmplen=(key_len_left>=0) ? kseg_len : key_len-length_pack;
+ DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg));
- If the max length of first key segment <= 127 characters the prefix is
- 1 byte else it's 2 byte
+ /*
+ Keys are compressed the following way:
- prefix The high bit is set if this is a prefix for the prev key
- length Packed length if the previous was a prefix byte
- [length] Length character of data
- next-key-seg Next key segments
-*/
+ If the max length of first key segment <= 127 characters the prefix is
+ 1 byte else it's 2 byte
+
+ prefix The high bit is set if this is a prefix for the prev key
+ length Packed length if the previous was a prefix byte
+ [length] Length character of data
+ next-key-seg Next key segments
+ */
matched=0; /* how many char's from prefix were alredy matched */
len=0; /* length of previous key unpacked */
@@ -350,7 +350,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
saved_vseg=vseg;
saved_prefix_len=prefix_len;
- DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,suffix_len,vseg));
+ DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,
+ suffix_len,vseg));
{
uchar *from=vseg+suffix_len;
HA_KEYSEG *keyseg;
@@ -396,14 +397,15 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
matched=prefix_len+left;
- for(my_flag=0;left;left--)
+ for (my_flag=0;left;left--)
if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++]))
break;
if (my_flag>0) /* mismatch */
break;
- else if (my_flag==0) /* match */
- { /*
+ if (my_flag==0) /* match */
+ {
+ /*
** len cmplen seg_left_len more_segs
** < matched=len; continue search
** > = prefix ? found : (matched=len; continue search)
@@ -414,30 +416,68 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
*/
if (len < cmplen)
{
- my_flag= -1;
+ if ((keyinfo->seg->type != HA_KEYTYPE_TEXT &&
+ keyinfo->seg->type != HA_KEYTYPE_VARTEXT))
+ my_flag= -1;
+ else
+ {
+ /* We have to compare k and vseg as if they where space extended */
+ uchar *end= k+ (cmplen - len);
+ for ( ; k < end && *k == ' '; k++) ;
+ if (k == end)
+ goto cmp_rest; /* should never happen */
+ if (*k < (uchar) ' ')
+ {
+ my_flag= 1; /* Compared string is smaller */
+ break;
+ }
+ my_flag= -1; /* Continue searching */
+ }
}
else if (len > cmplen)
{
- if ((my_flag= (!(nextflag & SEARCH_PREFIX) || key_len_left>0)))
- break;
- goto fix_flag;
- }
- else if (key_len_left>0)
- {
- uint not_used;
- if ((flag = ha_key_cmp(keyinfo->seg+1,vseg,
- k,key_len_left,nextflag,&not_used)) >= 0)
- break;
+ uchar *end;
+ if ((nextflag & SEARCH_PREFIX) && key_len_left == 0)
+ goto fix_flag;
+
+ /* We have to compare k and vseg as if they where space extended */
+ for (end=vseg + (len-cmplen) ;
+ vseg < end && *vseg == (uchar) ' ';
+ vseg++) ;
+ if (vseg == end)
+ goto cmp_rest; /* should never happen */
+
+ if (*vseg > (uchar) ' ')
+ {
+ my_flag= 1; /* Compared string is smaller */
+ break;
+ }
+ my_flag= -1; /* Continue searching */
}
else
- {
- /* at this line flag==-1 if the following lines were already
- visited and 0 otherwise, i.e. flag <=0 here always !!! */
- fix_flag:
- if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST))
- flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
- if (flag>=0) break;
- }
+ {
+ cmp_rest:
+ if (key_len_left>0)
+ {
+ uint not_used;
+ if ((flag = ha_key_cmp(keyinfo->seg+1,vseg,
+ k,key_len_left,nextflag,&not_used)) >= 0)
+ break;
+ }
+ else
+ {
+ /*
+ at this line flag==-1 if the following lines were already
+ visited and 0 otherwise, i.e. flag <=0 here always !!!
+ */
+ fix_flag:
+ DBUG_ASSERT(flag <= 0);
+ if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST))
+ flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
+ if (flag>=0)
+ break;
+ }
+ }
}
matched-=left;
}
@@ -1567,7 +1607,7 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
n_length-=tmp_length;
length-=tmp_length+next_length_pack; /* We gained these chars */
}
- if (n_length == 0)
+ if (n_length == 0 && ref_length == new_key_length)
{
s_temp->n_ref_length=pack_marker; /* Same as prev key */
}