MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mi_search.c
1 /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /* key handling functions */
17 
18 #include "fulltext.h"
19 #include "m_ctype.h"
20 
21 static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
22  uchar *key, uchar *keypos,
23  uint *return_key_length);
24 
25  /* Check index */
26 
27 int _mi_check_index(MI_INFO *info, int inx)
28 {
29  if (inx == -1) /* Use last index */
30  inx=info->lastinx;
31  if (inx < 0)
32  {
33  my_errno= HA_ERR_WRONG_INDEX;
34  return -1;
35  }
36  if (!mi_is_key_active(info->s->state.key_map, inx))
37  {
38  my_errno= info->s->state.state.records ? HA_ERR_WRONG_INDEX :
39  HA_ERR_END_OF_FILE;
40  return -1;
41  }
42  if (info->lastinx != inx) /* Index changed */
43  {
44  info->lastinx = inx;
45  info->page_changed=1;
46  info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
47  HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
48  }
49  if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
50  return(-1);
51  return(inx);
52 } /* mi_check_index */
53 
54 
55  /*
56  ** Search after row by a key
57  ** Position to row is stored in info->lastpos
58  ** Return: -1 if not found
59  ** 1 if one should continue search on higher level
60  */
61 
62 int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
63  uchar *key, uint key_len, uint nextflag, register my_off_t pos)
64 {
65  my_bool last_key;
66  int error,flag;
67  uint nod_flag;
68  uchar *keypos,*maxpos;
69  uchar lastkey[MI_MAX_KEY_BUFF],*buff;
70  DBUG_ENTER("_mi_search");
71  DBUG_PRINT("enter",("pos: %lu nextflag: %u lastpos: %lu",
72  (ulong) pos, nextflag, (ulong) info->lastpos));
73  DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_len););
74 
75  if (pos == HA_OFFSET_ERROR)
76  {
77  my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
78  info->lastpos= HA_OFFSET_ERROR;
79  if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
80  DBUG_RETURN(-1); /* Not found ; return error */
81  DBUG_RETURN(1); /* Search at upper levels */
82  }
83 
84  if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,info->buff,
85  test(!(nextflag & SEARCH_SAVE_BUFF)))))
86  goto err;
87  DBUG_DUMP("page", buff, mi_getint(buff));
88 
89  flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
90  &keypos,lastkey, &last_key);
91  if (flag == MI_FOUND_WRONG_KEY)
92  DBUG_RETURN(-1);
93  nod_flag=mi_test_if_nod(buff);
94  maxpos=buff+mi_getint(buff)-1;
95 
96  if (flag)
97  {
98  if ((error=_mi_search(info,keyinfo,key,key_len,nextflag,
99  _mi_kpos(nod_flag,keypos))) <= 0)
100  DBUG_RETURN(error);
101 
102  if (flag >0)
103  {
104  if (nextflag & (SEARCH_SMALLER | SEARCH_LAST) &&
105  keypos == buff+2+nod_flag)
106  DBUG_RETURN(1); /* Bigger than key */
107  }
108  else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
109  DBUG_RETURN(1); /* Smaller than key */
110  }
111  else
112  {
113  if ((nextflag & SEARCH_FIND) && nod_flag &&
114  ((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
115  key_len != USE_WHOLE_KEY))
116  {
117  if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND,
118  _mi_kpos(nod_flag,keypos))) >= 0 ||
119  my_errno != HA_ERR_KEY_NOT_FOUND)
120  DBUG_RETURN(error);
121  info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in mem */
122  }
123  }
124  if (pos != info->last_keypage)
125  {
126  uchar *old_buff=buff;
127  if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,info->buff,
128  test(!(nextflag & SEARCH_SAVE_BUFF)))))
129  goto err;
130  keypos=buff+(keypos-old_buff);
131  maxpos=buff+(maxpos-old_buff);
132  }
133 
134  if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
135  {
136  uint not_used[2];
137  if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos,
138  &info->lastkey_length))
139  goto err;
140  if (!(nextflag & SEARCH_SMALLER) &&
141  ha_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
142  not_used))
143  {
144  my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
145  goto err;
146  }
147  }
148  else
149  {
150  info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey);
151  if (!info->lastkey_length)
152  goto err;
153  memcpy(info->lastkey,lastkey,info->lastkey_length);
154  }
155  info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
156  /* Save position for a possible read next / previous */
157  info->int_keypos=info->buff+ (keypos-buff);
158  info->int_maxpos=info->buff+ (maxpos-buff);
159  info->int_nod_flag=nod_flag;
160  info->int_keytree_version=keyinfo->version;
161  info->last_search_keypage=info->last_keypage;
162  info->page_changed=0;
163  info->buff_used= (info->buff != buff); /* If we have to reread buff */
164 
165  DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos));
166  DBUG_RETURN(0);
167 
168 err:
169  DBUG_PRINT("exit",("Error: %d",my_errno));
170  info->lastpos= HA_OFFSET_ERROR;
171  info->page_changed=1;
172  DBUG_RETURN (-1);
173 } /* _mi_search */
174 
175 
176  /* Search after key in page-block */
177  /* If packed key puts smaller or identical key in buff */
178  /* ret_pos point to where find or bigger key starts */
179  /* ARGSUSED */
180 
181 int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
182  uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
183  uchar *buff __attribute__((unused)), my_bool *last_key)
184 {
185  reg4 int start,mid,end,save_end;
186  int flag;
187  uint totlength,nod_flag,not_used[2];
188  DBUG_ENTER("_mi_bin_search");
189 
190  LINT_INIT(flag);
191  totlength=keyinfo->keylength+(nod_flag=mi_test_if_nod(page));
192  start=0; mid=1;
193  save_end=end=(int) ((mi_getint(page)-2-nod_flag)/totlength-1);
194  DBUG_PRINT("test",("mi_getint: %d end: %d",mi_getint(page),end));
195  page+=2+nod_flag;
196 
197  while (start != end)
198  {
199  mid= (start+end)/2;
200  if ((flag=ha_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
201  comp_flag, not_used))
202  >= 0)
203  end=mid;
204  else
205  start=mid+1;
206  }
207  if (mid != start)
208  flag=ha_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
209  comp_flag, not_used);
210  if (flag < 0)
211  start++; /* point at next, bigger key */
212  *ret_pos=page+(uint) start*totlength;
213  *last_key= end == save_end;
214  DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start));
215  DBUG_RETURN(flag);
216 } /* _mi_bin_search */
217 
218 
219 /*
220  Locate a packed key in a key page.
221 
222  SYNOPSIS
223  _mi_seq_search()
224  info Open table information.
225  keyinfo Key definition information.
226  page Key page (beginning).
227  key Search key.
228  key_len Length to use from search key or USE_WHOLE_KEY
229  comp_flag Search flags like SEARCH_SAME etc.
230  ret_pos RETURN Position in key page behind this key.
231  buff RETURN Copy of previous or identical unpacked key.
232  last_key RETURN If key is last in page.
233 
234  DESCRIPTION
235  Used instead of _mi_bin_search() when key is packed.
236  Puts smaller or identical key in buff.
237  Key is searched sequentially.
238 
239  RETURN
240  > 0 Key in 'buff' is smaller than search key.
241  0 Key in 'buff' is identical to search key.
242  < 0 Not found.
243 */
244 
245 int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
246  uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
247  uchar *buff, my_bool *last_key)
248 {
249  int UNINIT_VAR(flag);
250  uint nod_flag,UNINIT_VAR(length),not_used[2];
251  uchar t_buff[MI_MAX_KEY_BUFF],*end;
252  DBUG_ENTER("_mi_seq_search");
253 
254  end= page+mi_getint(page);
255  nod_flag=mi_test_if_nod(page);
256  page+=2+nod_flag;
257  *ret_pos=page;
258  t_buff[0]=0; /* Avoid bugs */
259  while (page < end)
260  {
261  length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
262  if (length == 0 || page > end)
263  {
264  mi_print_error(info->s, HA_ERR_CRASHED);
265  my_errno=HA_ERR_CRASHED;
266  DBUG_PRINT("error",
267  ("Found wrong key: length: %u page: 0x%lx end: 0x%lx",
268  length, (long) page, (long) end));
269  DBUG_RETURN(MI_FOUND_WRONG_KEY);
270  }
271  if ((flag=ha_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
272  not_used)) >= 0)
273  break;
274 #ifdef EXTRA_DEBUG
275  DBUG_PRINT("loop",("page: 0x%lx key: '%s' flag: %d", (long) page, t_buff,
276  flag));
277 #endif
278  memcpy(buff,t_buff,length);
279  *ret_pos=page;
280  }
281  if (flag == 0)
282  memcpy(buff,t_buff,length); /* Result is first key */
283  *last_key= page == end;
284  DBUG_PRINT("exit",("flag: %d ret_pos: 0x%lx", flag, (long) *ret_pos));
285  DBUG_RETURN(flag);
286 } /* _mi_seq_search */
287 
288 
289 int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
290  uchar *key, uint key_len, uint nextflag, uchar **ret_pos,
291  uchar *buff, my_bool *last_key)
292 {
293  /*
294  my_flag is raw comparison result to be changed according to
295  SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
296  flag is the value returned by ha_key_cmp and as treated as final
297  */
298  int flag=0, my_flag=-1;
299  uint nod_flag, UNINIT_VAR(length), len, matched, cmplen, kseg_len;
300  uint UNINIT_VAR(prefix_len), suffix_len;
301  int key_len_skip, UNINIT_VAR(seg_len_pack), key_len_left;
302  uchar *end, *kseg, *vseg;
303  uchar *sort_order=keyinfo->seg->charset->sort_order;
304  uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
305  uchar *UNINIT_VAR(saved_from), *UNINIT_VAR(saved_to);
306  uchar *UNINIT_VAR(saved_vseg);
307  uint saved_length=0, saved_prefix_len=0;
308  uint length_pack;
309  DBUG_ENTER("_mi_prefix_search");
310 
311  t_buff[0]=0; /* Avoid bugs */
312  end= page+mi_getint(page);
313  nod_flag=mi_test_if_nod(page);
314  page+=2+nod_flag;
315  *ret_pos=page;
316  kseg=key;
317 
318  get_key_pack_length(kseg_len,length_pack,kseg);
319  key_len_skip=length_pack+kseg_len;
320  key_len_left=(int) key_len- (int) key_len_skip;
321  /* If key_len is 0, then lenght_pack is 1, then key_len_left is -1. */
322  cmplen=(key_len_left>=0) ? kseg_len : key_len-length_pack;
323  DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg));
324 
325  /*
326  Keys are compressed the following way:
327 
328  If the max length of first key segment <= 127 bytes the prefix is
329  1 byte else it's 2 byte
330 
331  (prefix) length The high bit is set if this is a prefix for the prev key.
332  [suffix length] Packed length of suffix if the previous was a prefix.
333  (suffix) data Key data bytes (past the common prefix or whole segment).
334  [next-key-seg] Next key segments (([packed length], data), ...)
335  pointer Reference to the data file (last_keyseg->length).
336  */
337 
338  matched=0; /* how many char's from prefix were alredy matched */
339  len=0; /* length of previous key unpacked */
340 
341  while (page < end)
342  {
343  uint packed= *page & 128;
344 
345  vseg=page;
346  if (keyinfo->seg->length >= 127)
347  {
348  suffix_len=mi_uint2korr(vseg) & 32767;
349  vseg+=2;
350  }
351  else
352  suffix_len= *vseg++ & 127;
353 
354  if (packed)
355  {
356  if (suffix_len == 0)
357  {
358  /* == 0x80 or 0x8000, same key, prefix length == old key length. */
359  prefix_len=len;
360  }
361  else
362  {
363  /* > 0x80 or 0x8000, this is prefix lgt, packed suffix lgt follows. */
364  prefix_len=suffix_len;
365  get_key_length(suffix_len,vseg);
366  }
367  }
368  else
369  {
370  /* Not packed. No prefix used from last key. */
371  prefix_len=0;
372  }
373 
374  len=prefix_len+suffix_len;
375  seg_len_pack=get_pack_length(len);
376  t_buff=tt_buff+3-seg_len_pack;
377  store_key_length(t_buff,len);
378 
379  if (prefix_len > saved_prefix_len)
380  memcpy(t_buff+seg_len_pack+saved_prefix_len,saved_vseg,
381  prefix_len-saved_prefix_len);
382  saved_vseg=vseg;
383  saved_prefix_len=prefix_len;
384 
385  DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,
386  suffix_len,vseg));
387  {
388  uchar *from=vseg+suffix_len;
389  HA_KEYSEG *keyseg;
390  uint l;
391 
392  for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ )
393  {
394 
395  if (keyseg->flag & HA_NULL_PART)
396  {
397  if (!(*from++))
398  continue;
399  }
400  if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
401  {
402  get_key_length(l,from);
403  }
404  else
405  l=keyseg->length;
406 
407  from+=l;
408  }
409  from+=keyseg->length;
410  page=from+nod_flag;
411  length= (uint) (from - vseg);
412  }
413 
414  if (page > end)
415  {
416  mi_print_error(info->s, HA_ERR_CRASHED);
417  my_errno=HA_ERR_CRASHED;
418  DBUG_PRINT("error",
419  ("Found wrong key: length: %u page: 0x%lx end: %lx",
420  length, (long) page, (long) end));
421  DBUG_RETURN(MI_FOUND_WRONG_KEY);
422  }
423 
424  if (matched >= prefix_len)
425  {
426  /* We have to compare. But we can still skip part of the key */
427  uint left;
428  uchar *k=kseg+prefix_len;
429 
430  /*
431  If prefix_len > cmplen then we are in the end-space comparison
432  phase. Do not try to acces the key any more ==> left= 0.
433  */
434  left= ((len <= cmplen) ? suffix_len :
435  ((prefix_len < cmplen) ? cmplen - prefix_len : 0));
436 
437  matched=prefix_len+left;
438 
439  if (sort_order)
440  {
441  for (my_flag=0;left;left--)
442  if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++]))
443  break;
444  }
445  else
446  {
447  for (my_flag=0;left;left--)
448  if ((my_flag= (int) *vseg++ - (int) *k++))
449  break;
450  }
451 
452  if (my_flag>0) /* mismatch */
453  break;
454  if (my_flag==0) /* match */
455  {
456  /*
457  ** len cmplen seg_left_len more_segs
458  ** < matched=len; continue search
459  ** > = prefix ? found : (matched=len; continue search)
460  ** > < - ok, found
461  ** = < - ok, found
462  ** = = - ok, found
463  ** = = + next seg
464  */
465  if (len < cmplen)
466  {
467  if ((keyinfo->seg->type != HA_KEYTYPE_TEXT &&
468  keyinfo->seg->type != HA_KEYTYPE_VARTEXT1 &&
469  keyinfo->seg->type != HA_KEYTYPE_VARTEXT2))
470  my_flag= -1;
471  else
472  {
473  /* We have to compare k and vseg as if they were space extended */
474  uchar *k_end= k+ (cmplen - len);
475  for ( ; k < k_end && *k == ' '; k++) ;
476  if (k == k_end)
477  goto cmp_rest; /* should never happen */
478  if (*k < (uchar) ' ')
479  {
480  my_flag= 1; /* Compared string is smaller */
481  break;
482  }
483  my_flag= -1; /* Continue searching */
484  }
485  }
486  else if (len > cmplen)
487  {
488  uchar *vseg_end;
489  if ((nextflag & SEARCH_PREFIX) && key_len_left == 0)
490  goto fix_flag;
491 
492  /* We have to compare k and vseg as if they were space extended */
493  for (vseg_end= vseg + (len-cmplen) ;
494  vseg < vseg_end && *vseg == (uchar) ' ';
495  vseg++, matched++) ;
496  DBUG_ASSERT(vseg < vseg_end);
497 
498  if (*vseg > (uchar) ' ')
499  {
500  my_flag= 1; /* Compared string is smaller */
501  break;
502  }
503  my_flag= -1; /* Continue searching */
504  }
505  else
506  {
507  cmp_rest:
508  if (key_len_left>0)
509  {
510  uint not_used[2];
511  if ((flag = ha_key_cmp(keyinfo->seg+1,vseg,
512  k, key_len_left, nextflag, not_used)) >= 0)
513  break;
514  }
515  else
516  {
517  /*
518  at this line flag==-1 if the following lines were already
519  visited and 0 otherwise, i.e. flag <=0 here always !!!
520  */
521  fix_flag:
522  DBUG_ASSERT(flag <= 0);
523  if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST))
524  flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
525  if (flag>=0)
526  break;
527  }
528  }
529  }
530  matched-=left;
531  }
532  /* else (matched < prefix_len) ---> do nothing. */
533 
534  memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
535  saved_to=buff+saved_length;
536  saved_from=saved_vseg;
537  saved_length=length;
538  *ret_pos=page;
539  }
540  if (my_flag)
541  flag=(keyinfo->seg->flag & HA_REVERSE_SORT) ? -my_flag : my_flag;
542  if (flag == 0)
543  {
544  memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
545  saved_to=buff+saved_length;
546  saved_from=saved_vseg;
547  saved_length=length;
548  }
549  if (saved_length)
550  memcpy(saved_to,saved_from,saved_length);
551 
552  *last_key= page == end;
553 
554  DBUG_PRINT("exit",("flag: %d ret_pos: 0x%lx", flag, (long) *ret_pos));
555  DBUG_RETURN(flag);
556 } /* _mi_prefix_search */
557 
558 
559  /* Get pos to a key_block */
560 
561 my_off_t _mi_kpos(uint nod_flag, uchar *after_key)
562 {
563  after_key-=nod_flag;
564  switch (nod_flag) {
565 #if SIZEOF_OFF_T > 4
566  case 7:
567  return mi_uint7korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
568  case 6:
569  return mi_uint6korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
570  case 5:
571  return mi_uint5korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
572 #else
573  case 7:
574  after_key++;
575  case 6:
576  after_key++;
577  case 5:
578  after_key++;
579 #endif
580  case 4:
581  return ((my_off_t) mi_uint4korr(after_key))*MI_MIN_KEY_BLOCK_LENGTH;
582  case 3:
583  return ((my_off_t) mi_uint3korr(after_key))*MI_MIN_KEY_BLOCK_LENGTH;
584  case 2:
585  return (my_off_t) (mi_uint2korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH);
586  case 1:
587  return (uint) (*after_key)*MI_MIN_KEY_BLOCK_LENGTH;
588  case 0: /* At leaf page */
589  default: /* Impossible */
590  return(HA_OFFSET_ERROR);
591  }
592 } /* _kpos */
593 
594 
595  /* Save pos to a key_block */
596 
597 void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos)
598 {
599  pos/=MI_MIN_KEY_BLOCK_LENGTH;
600  switch (info->s->base.key_reflength) {
601 #if SIZEOF_OFF_T > 4
602  case 7: mi_int7store(buff,pos); break;
603  case 6: mi_int6store(buff,pos); break;
604  case 5: mi_int5store(buff,pos); break;
605 #else
606  case 7: *buff++=0;
607  /* fall trough */
608  case 6: *buff++=0;
609  /* fall trough */
610  case 5: *buff++=0;
611  /* fall trough */
612 #endif
613  case 4: mi_int4store(buff,pos); break;
614  case 3: mi_int3store(buff,pos); break;
615  case 2: mi_int2store(buff,(uint) pos); break;
616  case 1: buff[0]= (uchar) pos; break;
617  default: abort(); /* impossible */
618  }
619 } /* _mi_kpointer */
620 
621 
622  /* Calc pos to a data-record from a key */
623 
624 
625 my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key)
626 {
627  my_off_t pos;
628  after_key-=(nod_flag + info->s->rec_reflength);
629  switch (info->s->rec_reflength) {
630 #if SIZEOF_OFF_T > 4
631  case 8: pos= (my_off_t) mi_uint8korr(after_key); break;
632  case 7: pos= (my_off_t) mi_uint7korr(after_key); break;
633  case 6: pos= (my_off_t) mi_uint6korr(after_key); break;
634  case 5: pos= (my_off_t) mi_uint5korr(after_key); break;
635 #else
636  case 8: pos= (my_off_t) mi_uint4korr(after_key+4); break;
637  case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break;
638  case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break;
639  case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break;
640 #endif
641  case 4: pos= (my_off_t) mi_uint4korr(after_key); break;
642  case 3: pos= (my_off_t) mi_uint3korr(after_key); break;
643  case 2: pos= (my_off_t) mi_uint2korr(after_key); break;
644  default:
645  pos=0L; /* Shut compiler up */
646  }
647  return (info->s->options &
648  (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
649  pos*info->s->base.pack_reclength;
650 }
651 
652 
653 /* Calc position from a record pointer ( in delete link chain ) */
654 
655 my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr)
656 {
657  my_off_t pos;
658  switch (s->rec_reflength) {
659 #if SIZEOF_OFF_T > 4
660  case 8:
661  pos= (my_off_t) mi_uint8korr(ptr);
662  if (pos == HA_OFFSET_ERROR)
663  return HA_OFFSET_ERROR; /* end of list */
664  break;
665  case 7:
666  pos= (my_off_t) mi_uint7korr(ptr);
667  if (pos == (((my_off_t) 1) << 56) -1)
668  return HA_OFFSET_ERROR; /* end of list */
669  break;
670  case 6:
671  pos= (my_off_t) mi_uint6korr(ptr);
672  if (pos == (((my_off_t) 1) << 48) -1)
673  return HA_OFFSET_ERROR; /* end of list */
674  break;
675  case 5:
676  pos= (my_off_t) mi_uint5korr(ptr);
677  if (pos == (((my_off_t) 1) << 40) -1)
678  return HA_OFFSET_ERROR; /* end of list */
679  break;
680 #else
681  case 8:
682  case 7:
683  case 6:
684  case 5:
685  ptr+= (s->rec_reflength-4);
686  /* fall through */
687 #endif
688  case 4:
689  pos= (my_off_t) mi_uint4korr(ptr);
690  if (pos == (my_off_t) (uint32) ~0L)
691  return HA_OFFSET_ERROR;
692  break;
693  case 3:
694  pos= (my_off_t) mi_uint3korr(ptr);
695  if (pos == (my_off_t) (1 << 24) -1)
696  return HA_OFFSET_ERROR;
697  break;
698  case 2:
699  pos= (my_off_t) mi_uint2korr(ptr);
700  if (pos == (my_off_t) (1 << 16) -1)
701  return HA_OFFSET_ERROR;
702  break;
703  default: abort(); /* Impossible */
704  }
705  return ((s->options &
706  (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
707  pos*s->base.pack_reclength);
708 }
709 
710 
711  /* save position to record */
712 
713 void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos)
714 {
715  if (!(info->s->options &
716  (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) &&
717  pos != HA_OFFSET_ERROR)
718  pos/=info->s->base.pack_reclength;
719 
720  switch (info->s->rec_reflength) {
721 #if SIZEOF_OFF_T > 4
722  case 8: mi_int8store(buff,pos); break;
723  case 7: mi_int7store(buff,pos); break;
724  case 6: mi_int6store(buff,pos); break;
725  case 5: mi_int5store(buff,pos); break;
726 #else
727  case 8: *buff++=0;
728  /* fall trough */
729  case 7: *buff++=0;
730  /* fall trough */
731  case 6: *buff++=0;
732  /* fall trough */
733  case 5: *buff++=0;
734  /* fall trough */
735 #endif
736  case 4: mi_int4store(buff,pos); break;
737  case 3: mi_int3store(buff,pos); break;
738  case 2: mi_int2store(buff,(uint) pos); break;
739  default: abort(); /* Impossible */
740  }
741 } /* _mi_dpointer */
742 
743 
744  /* Get key from key-block */
745  /* page points at previous key; its advanced to point at next key */
746  /* key should contain previous key */
747  /* Returns length of found key + pointers */
748  /* nod_flag is a flag if we are on nod */
749 
750  /* same as _mi_get_key but used with fixed length keys */
751 
752 uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag,
753  register uchar **page, register uchar *key)
754 {
755  memcpy((uchar*) key,(uchar*) *page,
756  (size_t) (keyinfo->keylength+nod_flag));
757  *page+=keyinfo->keylength+nod_flag;
758  return(keyinfo->keylength);
759 } /* _mi_get_static_key */
760 
761 
762 /*
763  get key witch is packed against previous key or key with a NULL column.
764 
765  SYNOPSIS
766  _mi_get_pack_key()
767  keyinfo key definition information.
768  nod_flag If nod: Length of node pointer, else zero.
769  page_pos RETURN position in key page behind this key.
770  key IN/OUT in: prev key, out: unpacked key.
771 
772  RETURN
773  key_length + length of data pointer
774 */
775 
776 uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
777  register uchar **page_pos, register uchar *key)
778 {
779  reg1 HA_KEYSEG *keyseg;
780  uchar *start_key,*page=*page_pos;
781  uint length;
782 
783  start_key=key;
784  for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
785  {
786  if (keyseg->flag & HA_PACK_KEY)
787  {
788  /* key with length, packed to previous key */
789  uchar *start=key;
790  uint packed= *page & 128,tot_length,rest_length;
791  if (keyseg->length >= 127)
792  {
793  length=mi_uint2korr(page) & 32767;
794  page+=2;
795  }
796  else
797  length= *page++ & 127;
798 
799  if (packed)
800  {
801  if (length > (uint) keyseg->length)
802  {
803  mi_print_error(keyinfo->share, HA_ERR_CRASHED);
804  my_errno=HA_ERR_CRASHED;
805  return 0; /* Error */
806  }
807  if (length == 0) /* Same key */
808  {
809  if (keyseg->flag & HA_NULL_PART)
810  *key++=1; /* Can't be NULL */
811  get_key_length(length,key);
812  key+= length; /* Same diff_key as prev */
813  if (length > keyseg->length)
814  {
815  DBUG_PRINT("error",
816  ("Found too long null packed key: %u of %u at 0x%lx",
817  length, keyseg->length, (long) *page_pos));
818  DBUG_DUMP("key", *page_pos, 16);
819  mi_print_error(keyinfo->share, HA_ERR_CRASHED);
820  my_errno=HA_ERR_CRASHED;
821  return 0;
822  }
823  continue;
824  }
825  if (keyseg->flag & HA_NULL_PART)
826  {
827  key++; /* Skip null marker*/
828  start++;
829  }
830 
831  get_key_length(rest_length,page);
832  tot_length=rest_length+length;
833 
834  /* If the stored length has changed, we must move the key */
835  if (tot_length >= 255 && *start != 255)
836  {
837  /* length prefix changed from a length of one to a length of 3 */
838  bmove_upp(key+length+3, key+length+1, length);
839  *key=255;
840  mi_int2store(key+1,tot_length);
841  key+=3+length;
842  }
843  else if (tot_length < 255 && *start == 255)
844  {
845  bmove(key+1,key+3,length);
846  *key=tot_length;
847  key+=1+length;
848  }
849  else
850  {
851  store_key_length_inc(key,tot_length);
852  key+=length;
853  }
854  memcpy(key,page,rest_length);
855  page+=rest_length;
856  key+=rest_length;
857  continue;
858  }
859  else
860  {
861  if (keyseg->flag & HA_NULL_PART)
862  {
863  if (!length--) /* Null part */
864  {
865  *key++=0;
866  continue;
867  }
868  *key++=1; /* Not null */
869  }
870  }
871  if (length > (uint) keyseg->length)
872  {
873  DBUG_PRINT("error",("Found too long packed key: %u of %u at 0x%lx",
874  length, keyseg->length, (long) *page_pos));
875  DBUG_DUMP("key", *page_pos, 16);
876  mi_print_error(keyinfo->share, HA_ERR_CRASHED);
877  my_errno=HA_ERR_CRASHED;
878  return 0; /* Error */
879  }
880  store_key_length_inc(key,length);
881  }
882  else
883  {
884  if (keyseg->flag & HA_NULL_PART)
885  {
886  if (!(*key++ = *page++))
887  continue;
888  }
889  if (keyseg->flag &
890  (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
891  {
892  uchar *tmp=page;
893  get_key_length(length,tmp);
894  length+=(uint) (tmp-page);
895  }
896  else
897  length=keyseg->length;
898  }
899  memcpy((uchar*) key,(uchar*) page,(size_t) length);
900  key+=length;
901  page+=length;
902  }
903  length=keyseg->length+nod_flag;
904  bmove((uchar*) key,(uchar*) page,length);
905  *page_pos= page+length;
906  return ((uint) (key-start_key)+keyseg->length);
907 } /* _mi_get_pack_key */
908 
909 
910 
911 /* key that is packed relatively to previous */
912 
913 uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
914  register uchar **page_pos, register uchar *key)
915 {
916  reg1 HA_KEYSEG *keyseg;
917  uchar *start_key,*page,*page_end,*from,*from_end;
918  uint length,tmp;
919  DBUG_ENTER("_mi_get_binary_pack_key");
920 
921  page= *page_pos;
922  page_end=page+MI_MAX_KEY_BUFF+1;
923  start_key=key;
924 
925  /*
926  Keys are compressed the following way:
927 
928  prefix length Packed length of prefix common with prev key (1 or 3 bytes)
929  for each key segment:
930  [is null] Null indicator if can be null (1 byte, zero means null)
931  [length] Packed length if varlength (1 or 3 bytes)
932  key segment 'length' bytes of key segment value
933  pointer Reference to the data file (last_keyseg->length).
934 
935  get_key_length() is a macro. It gets the prefix length from 'page'
936  and puts it into 'length'. It increments 'page' by 1 or 3, depending
937  on the packed length of the prefix length.
938  */
939  get_key_length(length,page);
940  if (length)
941  {
942  if (length > keyinfo->maxlength)
943  {
944  DBUG_PRINT("error",
945  ("Found too long binary packed key: %u of %u at 0x%lx",
946  length, keyinfo->maxlength, (long) *page_pos));
947  DBUG_DUMP("key", *page_pos, 16);
948  goto crashed; /* Wrong key */
949  }
950  /* Key is packed against prev key, take prefix from prev key. */
951  from= key;
952  from_end= key + length;
953  }
954  else
955  {
956  /* Key is not packed against prev key, take all from page buffer. */
957  from= page;
958  from_end= page_end;
959  }
960 
961  /*
962  The trouble is that key can be split in two parts:
963  The first part (prefix) is in from .. from_end - 1.
964  The second part starts at page.
965  The split can be at every byte position. So we need to check for
966  the end of the first part before using every byte.
967  */
968  for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
969  {
970  if (keyseg->flag & HA_NULL_PART)
971  {
972  /* If prefix is used up, switch to rest. */
973  if (from == from_end) { from=page; from_end=page_end; }
974  if (!(*key++ = *from++))
975  continue; /* Null part */
976  }
977  if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
978  {
979  /* If prefix is used up, switch to rest. */
980  if (from == from_end) { from=page; from_end=page_end; }
981  /* Get length of dynamic length key part */
982  if ((length= (*key++ = *from++)) == 255)
983  {
984  /* If prefix is used up, switch to rest. */
985  if (from == from_end) { from=page; from_end=page_end; }
986  length= (uint) ((*key++ = *from++)) << 8;
987  /* If prefix is used up, switch to rest. */
988  if (from == from_end) { from=page; from_end=page_end; }
989  length+= (uint) ((*key++ = *from++));
990  }
991  if (length > keyseg->length)
992  goto crashed;
993  }
994  else
995  length=keyseg->length;
996 
997  if ((tmp=(uint) (from_end-from)) <= length)
998  {
999  key+=tmp; /* Use old key */
1000  length-=tmp;
1001  from=page; from_end=page_end;
1002  }
1003  DBUG_PRINT("info",("key: 0x%lx from: 0x%lx length: %u",
1004  (long) key, (long) from, length));
1005  memmove((uchar*) key, (uchar*) from, (size_t) length);
1006  key+=length;
1007  from+=length;
1008  }
1009  /*
1010  Last segment (type == 0) contains length of data pointer.
1011  If we have mixed key blocks with data pointer and key block pointer,
1012  we have to copy both.
1013  */
1014  length=keyseg->length+nod_flag;
1015  if ((tmp=(uint) (from_end-from)) <= length)
1016  {
1017  /* Remaining length is less or equal max possible length. */
1018  memcpy(key+tmp,page,length-tmp); /* Get last part of key */
1019  *page_pos= page+length-tmp;
1020  }
1021  else
1022  {
1023  /*
1024  Remaining length is greater than max possible length.
1025  This can happen only if we switched to the new key bytes already.
1026  'page_end' is calculated with MI_MAX_KEY_BUFF. So it can be far
1027  behind the real end of the key.
1028  */
1029  if (from_end != page_end)
1030  {
1031  DBUG_PRINT("error",("Error when unpacking key"));
1032  goto crashed; /* Error */
1033  }
1034  /* Copy data pointer and, if appropriate, key block pointer. */
1035  memcpy((uchar*) key,(uchar*) from,(size_t) length);
1036  *page_pos= from+length;
1037  }
1038  DBUG_RETURN((uint) (key-start_key)+keyseg->length);
1039 
1040  crashed:
1041  mi_print_error(keyinfo->share, HA_ERR_CRASHED);
1042  my_errno= HA_ERR_CRASHED;
1043  DBUG_RETURN(0);
1044 }
1045 
1046 
1047  /* Get key at position without knowledge of previous key */
1048  /* Returns pointer to next key */
1049 
1050 uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
1051  uchar *key, uchar *keypos, uint *return_key_length)
1052 {
1053  uint nod_flag;
1054  DBUG_ENTER("_mi_get_key");
1055 
1056  nod_flag=mi_test_if_nod(page);
1057  if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1058  {
1059  bmove((uchar*) key,(uchar*) keypos,keyinfo->keylength+nod_flag);
1060  DBUG_RETURN(keypos+keyinfo->keylength+nod_flag);
1061  }
1062  else
1063  {
1064  page+=2+nod_flag;
1065  key[0]=0; /* safety */
1066  while (page <= keypos)
1067  {
1068  *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
1069  if (*return_key_length == 0)
1070  {
1071  mi_print_error(info->s, HA_ERR_CRASHED);
1072  my_errno=HA_ERR_CRASHED;
1073  DBUG_RETURN(0);
1074  }
1075  }
1076  }
1077  DBUG_PRINT("exit",("page: 0x%lx length: %u", (long) page,
1078  *return_key_length));
1079  DBUG_RETURN(page);
1080 } /* _mi_get_key */
1081 
1082 
1083  /* Get key at position without knowledge of previous key */
1084  /* Returns 0 if ok */
1085 
1086 static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
1087  uchar *key, uchar *keypos,
1088  uint *return_key_length)
1089 {
1090  uint nod_flag;
1091  DBUG_ENTER("_mi_get_prev_key");
1092 
1093  nod_flag=mi_test_if_nod(page);
1094  if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1095  {
1096  *return_key_length=keyinfo->keylength;
1097  bmove((uchar*) key,(uchar*) keypos- *return_key_length-nod_flag,
1098  *return_key_length);
1099  DBUG_RETURN(0);
1100  }
1101  else
1102  {
1103  page+=2+nod_flag;
1104  key[0]=0; /* safety */
1105  while (page < keypos)
1106  {
1107  *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
1108  if (*return_key_length == 0)
1109  {
1110  mi_print_error(info->s, HA_ERR_CRASHED);
1111  my_errno=HA_ERR_CRASHED;
1112  DBUG_RETURN(1);
1113  }
1114  }
1115  }
1116  DBUG_RETURN(0);
1117 } /* _mi_get_key */
1118 
1119 
1120 
1121  /* Get last key from key-page */
1122  /* Return pointer to where key starts */
1123 
1124 uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
1125  uchar *lastkey, uchar *endpos, uint *return_key_length)
1126 {
1127  uint nod_flag;
1128  uchar *lastpos;
1129  DBUG_ENTER("_mi_get_last_key");
1130  DBUG_PRINT("enter",("page: 0x%lx endpos: 0x%lx", (long) page,
1131  (long) endpos));
1132 
1133  nod_flag=mi_test_if_nod(page);
1134  if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1135  {
1136  lastpos=endpos-keyinfo->keylength-nod_flag;
1137  *return_key_length=keyinfo->keylength;
1138  if (lastpos > page)
1139  bmove((uchar*) lastkey,(uchar*) lastpos,keyinfo->keylength+nod_flag);
1140  }
1141  else
1142  {
1143  lastpos=(page+=2+nod_flag);
1144  lastkey[0]=0;
1145  while (page < endpos)
1146  {
1147  lastpos=page;
1148  *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,lastkey);
1149  if (*return_key_length == 0)
1150  {
1151  DBUG_PRINT("error",("Couldn't find last key: page: 0x%lx",
1152  (long) page));
1153  mi_print_error(info->s, HA_ERR_CRASHED);
1154  my_errno=HA_ERR_CRASHED;
1155  DBUG_RETURN(0);
1156  }
1157  }
1158  }
1159  DBUG_PRINT("exit",("lastpos: 0x%lx length: %u", (long) lastpos,
1160  *return_key_length));
1161  DBUG_RETURN(lastpos);
1162 } /* _mi_get_last_key */
1163 
1164 
1165  /* Calculate length of key */
1166 
1167 uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
1168 {
1169  reg1 HA_KEYSEG *keyseg;
1170  uchar *start;
1171 
1172  if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1173  return (keyinfo->keylength);
1174 
1175  start=key;
1176  for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++)
1177  {
1178  if (keyseg->flag & HA_NULL_PART)
1179  if (!*key++)
1180  continue;
1181  if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
1182  {
1183  uint length;
1184  get_key_length(length,key);
1185  key+=length;
1186  }
1187  else
1188  key+= keyseg->length;
1189  }
1190  return((uint) (key-start)+keyseg->length);
1191 } /* _mi_keylength */
1192 
1193 
1194 /*
1195  Calculate length of part key.
1196 
1197  Used in mi_rkey() to find the key found for the key-part that was used.
1198  This is needed in case of multi-byte character sets where we may search
1199  after '0xDF' but find 'ss'
1200 */
1201 
1202 uint _mi_keylength_part(MI_KEYDEF *keyinfo, register uchar *key,
1203  HA_KEYSEG *end)
1204 {
1205  reg1 HA_KEYSEG *keyseg;
1206  uchar *start= key;
1207 
1208  for (keyseg=keyinfo->seg ; keyseg != end ; keyseg++)
1209  {
1210  if (keyseg->flag & HA_NULL_PART)
1211  if (!*key++)
1212  continue;
1213  if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
1214  {
1215  uint length;
1216  get_key_length(length,key);
1217  key+=length;
1218  }
1219  else
1220  key+= keyseg->length;
1221  }
1222  return (uint) (key-start);
1223 }
1224 
1225  /* Move a key */
1226 
1227 uchar *_mi_move_key(MI_KEYDEF *keyinfo, uchar *to, uchar *from)
1228 {
1229  reg1 uint length;
1230  memcpy((uchar*) to, (uchar*) from,
1231  (size_t) (length=_mi_keylength(keyinfo,from)));
1232  return to+length;
1233 }
1234 
1235  /* Find next/previous record with same key */
1236  /* This can't be used when database is touched after last read */
1237 
1238 int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
1239  uchar *key, uint key_length, uint nextflag, my_off_t pos)
1240 {
1241  int error;
1242  uint nod_flag;
1243  uchar lastkey[MI_MAX_KEY_BUFF];
1244  DBUG_ENTER("_mi_search_next");
1245  DBUG_PRINT("enter",("nextflag: %u lastpos: %lu int_keypos: %lu",
1246  nextflag, (ulong) info->lastpos,
1247  (ulong) info->int_keypos));
1248  DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_length););
1249 
1250  /* Force full read if we are at last key or if we are not on a leaf
1251  and the key tree has changed since we used it last time
1252  Note that even if the key tree has changed since last read, we can use
1253  the last read data from the leaf if we haven't used the buffer for
1254  something else.
1255  */
1256 
1257  if (((nextflag & SEARCH_BIGGER) && info->int_keypos >= info->int_maxpos) ||
1258  info->page_changed ||
1259  (info->int_keytree_version != keyinfo->version &&
1260  (info->int_nod_flag || info->buff_used)))
1261  DBUG_RETURN(_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
1262  nextflag | SEARCH_SAVE_BUFF, pos));
1263 
1264  if (info->buff_used)
1265  {
1266  if (!_mi_fetch_keypage(info,keyinfo,info->last_search_keypage,
1267  DFLT_INIT_HITS,info->buff,0))
1268  DBUG_RETURN(-1);
1269  info->buff_used=0;
1270  }
1271 
1272  /* Last used buffer is in info->buff */
1273  nod_flag=mi_test_if_nod(info->buff);
1274 
1275  if (nextflag & SEARCH_BIGGER) /* Next key */
1276  {
1277  my_off_t tmp_pos=_mi_kpos(nod_flag,info->int_keypos);
1278  if (tmp_pos != HA_OFFSET_ERROR)
1279  {
1280  if ((error=_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
1281  nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0)
1282  DBUG_RETURN(error);
1283  }
1284  memcpy(lastkey,key,key_length);
1285  if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,
1286  &info->int_keypos,lastkey)))
1287  DBUG_RETURN(-1);
1288  }
1289  else /* Previous key */
1290  {
1291  uint length;
1292  /* Find start of previous key */
1293  info->int_keypos=_mi_get_last_key(info,keyinfo,info->buff,lastkey,
1294  info->int_keypos, &length);
1295  if (!info->int_keypos)
1296  DBUG_RETURN(-1);
1297  if (info->int_keypos == info->buff+2)
1298  DBUG_RETURN(_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
1299  nextflag | SEARCH_SAVE_BUFF, pos));
1300  if ((error=_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
1301  nextflag | SEARCH_SAVE_BUFF,
1302  _mi_kpos(nod_flag,info->int_keypos))) <= 0)
1303  DBUG_RETURN(error);
1304 
1305  /* QQ: We should be able to optimize away the following call */
1306  if (! _mi_get_last_key(info,keyinfo,info->buff,lastkey,
1307  info->int_keypos,&info->lastkey_length))
1308  DBUG_RETURN(-1);
1309  }
1310  memcpy(info->lastkey,lastkey,info->lastkey_length);
1311  info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
1312  DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos));
1313  DBUG_RETURN(0);
1314 } /* _mi_search_next */
1315 
1316 
1317  /* Search after position for the first row in an index */
1318  /* This is stored in info->lastpos */
1319 
1320 int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
1321  register my_off_t pos)
1322 {
1323  uint nod_flag;
1324  uchar *page;
1325  DBUG_ENTER("_mi_search_first");
1326 
1327  if (pos == HA_OFFSET_ERROR)
1328  {
1329  my_errno=HA_ERR_KEY_NOT_FOUND;
1330  info->lastpos= HA_OFFSET_ERROR;
1331  DBUG_RETURN(-1);
1332  }
1333 
1334  do
1335  {
1336  if (!_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,info->buff,0))
1337  {
1338  info->lastpos= HA_OFFSET_ERROR;
1339  DBUG_RETURN(-1);
1340  }
1341  nod_flag=mi_test_if_nod(info->buff);
1342  page=info->buff+2+nod_flag;
1343  } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
1344 
1345  if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,
1346  info->lastkey)))
1347  DBUG_RETURN(-1); /* Crashed */
1348 
1349  info->int_keypos=page; info->int_maxpos=info->buff+mi_getint(info->buff)-1;
1350  info->int_nod_flag=nod_flag;
1351  info->int_keytree_version=keyinfo->version;
1352  info->last_search_keypage=info->last_keypage;
1353  info->page_changed=info->buff_used=0;
1354  info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
1355 
1356  DBUG_PRINT("exit",("found key at %lu", (ulong) info->lastpos));
1357  DBUG_RETURN(0);
1358 } /* _mi_search_first */
1359 
1360 
1361  /* Search after position for the last row in an index */
1362  /* This is stored in info->lastpos */
1363 
1364 int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
1365  register my_off_t pos)
1366 {
1367  uint nod_flag;
1368  uchar *buff,*page;
1369  DBUG_ENTER("_mi_search_last");
1370 
1371  if (pos == HA_OFFSET_ERROR)
1372  {
1373  my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
1374  info->lastpos= HA_OFFSET_ERROR;
1375  DBUG_RETURN(-1);
1376  }
1377 
1378  buff=info->buff;
1379  do
1380  {
1381  if (!_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,buff,0))
1382  {
1383  info->lastpos= HA_OFFSET_ERROR;
1384  DBUG_RETURN(-1);
1385  }
1386  page= buff+mi_getint(buff);
1387  nod_flag=mi_test_if_nod(buff);
1388  } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
1389 
1390  if (!_mi_get_last_key(info,keyinfo,buff,info->lastkey,page,
1391  &info->lastkey_length))
1392  DBUG_RETURN(-1);
1393  info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
1394  info->int_keypos=info->int_maxpos=page;
1395  info->int_nod_flag=nod_flag;
1396  info->int_keytree_version=keyinfo->version;
1397  info->last_search_keypage=info->last_keypage;
1398  info->page_changed=info->buff_used=0;
1399 
1400  DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos));
1401  DBUG_RETURN(0);
1402 } /* _mi_search_last */
1403 
1404 
1405 
1406 /****************************************************************************
1407 **
1408 ** Functions to store and pack a key in a page
1409 **
1410 ** mi_calc_xx_key_length takes the following arguments:
1411 ** nod_flag If nod: Length of nod-pointer
1412 ** next_key Position to pos after the new key in buffer
1413 ** org_key Key that was before the next key in buffer
1414 ** prev_key Last key before current key
1415 ** key Key that will be stored
1416 ** s_temp Information how next key will be packed
1417 ****************************************************************************/
1418 
1419 /* Static length key */
1420 
1421 int
1422 _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
1423  uchar *next_pos __attribute__((unused)),
1424  uchar *org_key __attribute__((unused)),
1425  uchar *prev_key __attribute__((unused)),
1426  uchar *key, MI_KEY_PARAM *s_temp)
1427 {
1428  s_temp->key=key;
1429  return (int) (s_temp->totlength=keyinfo->keylength+nod_flag);
1430 }
1431 
1432 /* Variable length key */
1433 
1434 int
1435 _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
1436  uchar *next_pos __attribute__((unused)),
1437  uchar *org_key __attribute__((unused)),
1438  uchar *prev_key __attribute__((unused)),
1439  uchar *key, MI_KEY_PARAM *s_temp)
1440 {
1441  s_temp->key=key;
1442  return (int) (s_temp->totlength=_mi_keylength(keyinfo,key)+nod_flag);
1443 }
1444 
1445 /*
1446  length of key with a variable length first segment which is prefix
1447  compressed (myisamchk reports 'packed + stripped')
1448 
1449  Keys are compressed the following way:
1450 
1451  If the max length of first key segment <= 127 bytes the prefix is
1452  1 byte else it's 2 byte
1453 
1454  prefix byte(s) The high bit is set if this is a prefix for the prev key
1455  length Packed length if the previous was a prefix byte
1456  [length] data bytes ('length' bytes)
1457  next-key-seg Next key segments
1458 
1459  If the first segment can have NULL:
1460  The length is 0 for NULLS and 1+length for not null columns.
1461 
1462 */
1463 
1464 int
1465 _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
1466  uchar *org_key, uchar *prev_key, uchar *key,
1467  MI_KEY_PARAM *s_temp)
1468 {
1469  reg1 HA_KEYSEG *keyseg;
1470  int length;
1471  uint key_length,ref_length,org_key_length=0,
1472  length_pack,new_key_length,diff_flag,pack_marker;
1473  uchar *start,*end,*key_end,*sort_order;
1474  my_bool same_length;
1475 
1476  length_pack=s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
1477  same_length=0; keyseg=keyinfo->seg;
1478  key_length=_mi_keylength(keyinfo,key)+nod_flag;
1479 
1480  sort_order=0;
1481  if ((keyinfo->flag & HA_FULLTEXT) &&
1482  ((keyseg->type == HA_KEYTYPE_TEXT) ||
1483  (keyseg->type == HA_KEYTYPE_VARTEXT1) ||
1484  (keyseg->type == HA_KEYTYPE_VARTEXT2)) &&
1485  !use_strnxfrm(keyseg->charset))
1486  sort_order=keyseg->charset->sort_order;
1487 
1488  /* diff flag contains how many bytes is needed to pack key */
1489  if (keyseg->length >= 127)
1490  {
1491  diff_flag=2;
1492  pack_marker=32768;
1493  }
1494  else
1495  {
1496  diff_flag= 1;
1497  pack_marker=128;
1498  }
1499  s_temp->pack_marker=pack_marker;
1500 
1501  /* Handle the case that the first part have NULL values */
1502  if (keyseg->flag & HA_NULL_PART)
1503  {
1504  if (!*key++)
1505  {
1506  s_temp->key=key;
1507  s_temp->key_length= 0;
1508  s_temp->totlength=key_length-1+diff_flag;
1509  s_temp->next_key_pos=0; /* No next key */
1510  return (s_temp->totlength);
1511  }
1512  s_temp->store_not_null=1;
1513  key_length--; /* We don't store NULL */
1514  if (prev_key && !*prev_key++)
1515  org_key=prev_key=0; /* Can't pack against prev */
1516  else if (org_key)
1517  org_key++; /* Skip NULL */
1518  }
1519  else
1520  s_temp->store_not_null=0;
1521  s_temp->prev_key=org_key;
1522 
1523  /* The key part will start with a packed length */
1524 
1525  get_key_pack_length(new_key_length,length_pack,key);
1526  end=key_end= key+ new_key_length;
1527  start=key;
1528 
1529  /* Calc how many characters are identical between this and the prev. key */
1530  if (prev_key)
1531  {
1532  get_key_length(org_key_length,prev_key);
1533  s_temp->prev_key=prev_key; /* Pointer at data */
1534  /* Don't use key-pack if length == 0 */
1535  if (new_key_length && new_key_length == org_key_length)
1536  same_length=1;
1537  else if (new_key_length > org_key_length)
1538  end=key + org_key_length;
1539 
1540  if (sort_order) /* SerG */
1541  {
1542  while (key < end && sort_order[*key] == sort_order[*prev_key])
1543  {
1544  key++; prev_key++;
1545  }
1546  }
1547  else
1548  {
1549  while (key < end && *key == *prev_key)
1550  {
1551  key++; prev_key++;
1552  }
1553  }
1554  }
1555 
1556  s_temp->key=key;
1557  s_temp->key_length= (uint) (key_end-key);
1558 
1559  if (same_length && key == key_end)
1560  {
1561  /* identical variable length key */
1562  s_temp->ref_length= pack_marker;
1563  length=(int) key_length-(int) (key_end-start)-length_pack;
1564  length+= diff_flag;
1565  if (next_key)
1566  { /* Can't combine with next */
1567  s_temp->n_length= *next_key; /* Needed by _mi_store_key */
1568  next_key=0;
1569  }
1570  }
1571  else
1572  {
1573  if (start != key)
1574  { /* Starts as prev key */
1575  ref_length= (uint) (key-start);
1576  s_temp->ref_length= ref_length + pack_marker;
1577  length= (int) (key_length - ref_length);
1578 
1579  length-= length_pack;
1580  length+= diff_flag;
1581  length+= ((new_key_length-ref_length) >= 255) ? 3 : 1;/* Rest_of_key */
1582  }
1583  else
1584  {
1585  s_temp->key_length+=s_temp->store_not_null; /* If null */
1586  length= key_length - length_pack+ diff_flag;
1587  }
1588  }
1589  s_temp->totlength=(uint) length;
1590  s_temp->prev_length=0;
1591  DBUG_PRINT("test",("tot_length: %u length: %d uniq_key_length: %u",
1592  key_length, length, s_temp->key_length));
1593 
1594  /* If something after that hasn't length=0, test if we can combine */
1595  if ((s_temp->next_key_pos=next_key))
1596  {
1597  uint packed,n_length;
1598 
1599  packed = *next_key & 128;
1600  if (diff_flag == 2)
1601  {
1602  n_length= mi_uint2korr(next_key) & 32767; /* Length of next key */
1603  next_key+=2;
1604  }
1605  else
1606  n_length= *next_key++ & 127;
1607  if (!packed)
1608  n_length-= s_temp->store_not_null;
1609 
1610  if (n_length || packed) /* Don't pack 0 length keys */
1611  {
1612  uint next_length_pack, new_ref_length=s_temp->ref_length;
1613 
1614  if (packed)
1615  {
1616  /* If first key and next key is packed (only on delete) */
1617  if (!prev_key && org_key)
1618  {
1619  get_key_length(org_key_length,org_key);
1620  key=start;
1621  if (sort_order) /* SerG */
1622  {
1623  while (key < end && sort_order[*key] == sort_order[*org_key])
1624  {
1625  key++; org_key++;
1626  }
1627  }
1628  else
1629  {
1630  while (key < end && *key == *org_key)
1631  {
1632  key++; org_key++;
1633  }
1634  }
1635  if ((new_ref_length= (uint) (key - start)))
1636  new_ref_length+=pack_marker;
1637  }
1638 
1639  if (!n_length)
1640  {
1641  /*
1642  We put a different key between two identical variable length keys
1643  Extend next key to have same prefix as this key
1644  */
1645  if (new_ref_length) /* prefix of previus key */
1646  { /* make next key longer */
1647  s_temp->part_of_prev_key= new_ref_length;
1648  s_temp->prev_length= org_key_length -
1649  (new_ref_length-pack_marker);
1650  s_temp->n_ref_length= s_temp->part_of_prev_key;
1651  s_temp->n_length= s_temp->prev_length;
1652  n_length= get_pack_length(s_temp->prev_length);
1653  s_temp->prev_key+= (new_ref_length - pack_marker);
1654  length+= s_temp->prev_length + n_length;
1655  }
1656  else
1657  { /* Can't use prev key */
1658  s_temp->part_of_prev_key=0;
1659  s_temp->prev_length= org_key_length;
1660  s_temp->n_ref_length=s_temp->n_length= org_key_length;
1661  length+= org_key_length;
1662  }
1663  return (int) length;
1664  }
1665 
1666  ref_length=n_length;
1667  /* Get information about not packed key suffix */
1668  get_key_pack_length(n_length,next_length_pack,next_key);
1669 
1670  /* Test if new keys has fewer characters that match the previous key */
1671  if (!new_ref_length)
1672  { /* Can't use prev key */
1673  s_temp->part_of_prev_key= 0;
1674  s_temp->prev_length= ref_length;
1675  s_temp->n_ref_length= s_temp->n_length= n_length+ref_length;
1676  return (int) length+ref_length-next_length_pack;
1677  }
1678  if (ref_length+pack_marker > new_ref_length)
1679  {
1680  uint new_pack_length=new_ref_length-pack_marker;
1681  /* We must copy characters from the original key to the next key */
1682  s_temp->part_of_prev_key= new_ref_length;
1683  s_temp->prev_length= ref_length - new_pack_length;
1684  s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length;
1685  s_temp->prev_key+= new_pack_length;
1686  length-= (next_length_pack - get_pack_length(s_temp->n_length));
1687  return (int) length + s_temp->prev_length;
1688  }
1689  }
1690  else
1691  {
1692  /* Next key wasn't a prefix of previous key */
1693  ref_length=0;
1694  next_length_pack=0;
1695  }
1696  DBUG_PRINT("test",("length: %d next_key: 0x%lx", length,
1697  (long) next_key));
1698 
1699  {
1700  uint tmp_length;
1701  key=(start+=ref_length);
1702  if (key+n_length < key_end) /* Normalize length based */
1703  key_end=key+n_length;
1704  if (sort_order) /* SerG */
1705  {
1706  while (key < key_end && sort_order[*key] ==
1707  sort_order[*next_key])
1708  {
1709  key++; next_key++;
1710  }
1711  }
1712  else
1713  {
1714  while (key < key_end && *key == *next_key)
1715  {
1716  key++; next_key++;
1717  }
1718  }
1719  if (!(tmp_length=(uint) (key-start)))
1720  { /* Key can't be re-packed */
1721  s_temp->next_key_pos=0;
1722  return length;
1723  }
1724  ref_length+=tmp_length;
1725  n_length-=tmp_length;
1726  length-=tmp_length+next_length_pack; /* We gained these chars */
1727  }
1728  if (n_length == 0 && ref_length == new_key_length)
1729  {
1730  s_temp->n_ref_length=pack_marker; /* Same as prev key */
1731  }
1732  else
1733  {
1734  s_temp->n_ref_length=ref_length | pack_marker;
1735  length+= get_pack_length(n_length);
1736  s_temp->n_length=n_length;
1737  }
1738  }
1739  }
1740  return length;
1741 }
1742 
1743 
1744 /* Length of key which is prefix compressed */
1745 
1746 int
1747 _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
1748  uchar *org_key, uchar *prev_key, uchar *key,
1749  MI_KEY_PARAM *s_temp)
1750 {
1751  uint length,key_length,ref_length;
1752 
1753  s_temp->totlength=key_length=_mi_keylength(keyinfo,key)+nod_flag;
1754 #ifdef HAVE_purify
1755  s_temp->n_length= s_temp->n_ref_length=0; /* For valgrind */
1756 #endif
1757  s_temp->key=key;
1758  s_temp->prev_key=org_key;
1759  if (prev_key) /* If not first key in block */
1760  {
1761  /* pack key against previous key */
1762  /*
1763  As keys may be identical when running a sort in myisamchk, we
1764  have to guard against the case where keys may be identical
1765  */
1766  uchar *end;
1767  end=key+key_length;
1768  for ( ; *key == *prev_key && key < end; key++,prev_key++) ;
1769  s_temp->ref_length= ref_length=(uint) (key-s_temp->key);
1770  length=key_length - ref_length + get_pack_length(ref_length);
1771  }
1772  else
1773  {
1774  /* No previous key */
1775  s_temp->ref_length=ref_length=0;
1776  length=key_length+1;
1777  }
1778  if ((s_temp->next_key_pos=next_key)) /* If another key after */
1779  {
1780  /* pack key against next key */
1781  uint next_length,next_length_pack;
1782  get_key_pack_length(next_length,next_length_pack,next_key);
1783 
1784  /* If first key and next key is packed (only on delete) */
1785  if (!prev_key && org_key && next_length)
1786  {
1787  uchar *end;
1788  for (key= s_temp->key, end=key+next_length ;
1789  *key == *org_key && key < end;
1790  key++,org_key++) ;
1791  ref_length= (uint) (key - s_temp->key);
1792  }
1793 
1794  if (next_length > ref_length)
1795  {
1796  /* We put a key with different case between two keys with the same prefix
1797  Extend next key to have same prefix as
1798  this key */
1799  s_temp->n_ref_length= ref_length;
1800  s_temp->prev_length= next_length-ref_length;
1801  s_temp->prev_key+= ref_length;
1802  return (int) (length+ s_temp->prev_length - next_length_pack +
1803  get_pack_length(ref_length));
1804  }
1805  /* Check how many characters are identical to next key */
1806  key= s_temp->key+next_length;
1807  while (*key++ == *next_key++) ;
1808  if ((ref_length= (uint) (key - s_temp->key)-1) == next_length)
1809  {
1810  s_temp->next_key_pos=0;
1811  return length; /* can't pack next key */
1812  }
1813  s_temp->prev_length=0;
1814  s_temp->n_ref_length=ref_length;
1815  return (int) (length-(ref_length - next_length) - next_length_pack +
1816  get_pack_length(ref_length));
1817  }
1818  return (int) length;
1819 }
1820 
1821 
1822 /*
1823 ** store a key packed with _mi_calc_xxx_key_length in page-buffert
1824 */
1825 
1826 /* store key without compression */
1827 
1828 void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)),
1829  register uchar *key_pos,
1830  register MI_KEY_PARAM *s_temp)
1831 {
1832  memcpy((uchar*) key_pos,(uchar*) s_temp->key,(size_t) s_temp->totlength);
1833 }
1834 
1835 
1836 /* store variable length key with prefix compression */
1837 
1838 #define store_pack_length(test,pos,length) { \
1839  if (test) { *((pos)++) = (uchar) (length); } else \
1840  { *((pos)++) = (uchar) ((length) >> 8); *((pos)++) = (uchar) (length); } }
1841 
1842 
1843 void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
1844  register uchar *key_pos,
1845  register MI_KEY_PARAM *s_temp)
1846 {
1847  uint length;
1848  uchar *start;
1849 
1850  start=key_pos;
1851 
1852  if (s_temp->ref_length)
1853  {
1854  /* Packed against previous key */
1855  store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->ref_length);
1856  /* If not same key after */
1857  if (s_temp->ref_length != s_temp->pack_marker)
1858  store_key_length_inc(key_pos,s_temp->key_length);
1859  }
1860  else
1861  {
1862  /* Not packed against previous key */
1863  store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->key_length);
1864  }
1865  bmove((uchar*) key_pos,(uchar*) s_temp->key,
1866  (length=s_temp->totlength-(uint) (key_pos-start)));
1867 
1868  if (!s_temp->next_key_pos) /* No following key */
1869  return;
1870  key_pos+=length;
1871 
1872  if (s_temp->prev_length)
1873  {
1874  /* Extend next key because new key didn't have same prefix as prev key */
1875  if (s_temp->part_of_prev_key)
1876  {
1877  store_pack_length(s_temp->pack_marker == 128,key_pos,
1878  s_temp->part_of_prev_key);
1879  store_key_length_inc(key_pos,s_temp->n_length);
1880  }
1881  else
1882  {
1883  s_temp->n_length+= s_temp->store_not_null;
1884  store_pack_length(s_temp->pack_marker == 128,key_pos,
1885  s_temp->n_length);
1886  }
1887  memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
1888  }
1889  else if (s_temp->n_ref_length)
1890  {
1891  store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_ref_length);
1892  if (s_temp->n_ref_length == s_temp->pack_marker)
1893  return; /* Identical key */
1894  store_key_length(key_pos,s_temp->n_length);
1895  }
1896  else
1897  {
1898  s_temp->n_length+= s_temp->store_not_null;
1899  store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_length);
1900  }
1901 }
1902 
1903 
1904 /* variable length key with prefix compression */
1905 
1906 void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
1907  register uchar *key_pos,
1908  register MI_KEY_PARAM *s_temp)
1909 {
1910  store_key_length_inc(key_pos,s_temp->ref_length);
1911  memcpy((char*) key_pos,(char*) s_temp->key+s_temp->ref_length,
1912  (size_t) s_temp->totlength-s_temp->ref_length);
1913 
1914  if (s_temp->next_key_pos)
1915  {
1916  key_pos+=(uint) (s_temp->totlength-s_temp->ref_length);
1917  store_key_length_inc(key_pos,s_temp->n_ref_length);
1918  if (s_temp->prev_length) /* If we must extend key */
1919  {
1920  memcpy(key_pos,s_temp->prev_key,s_temp->prev_length);
1921  }
1922  }
1923 }