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