~drizzle-trunk/drizzle/development

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