~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>
612.2.13 by Monty Taylor
Work on removing global.h from headers that should be installed.
20
#include <mystrings/m_string.h>
492.1.7 by Monty Taylor
Moved test() to its own file.
21
#include <drizzled/util/test.h>
1 by brian
clean slate
22
481 by Brian Aker
Remove all of uchar.
23
static bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, unsigned char *page,
24
                                unsigned char *key, unsigned char *keypos,
482 by Brian Aker
Remove uint.
25
                                uint32_t *return_key_length);
1 by brian
clean slate
26
27
        /* Check index */
28
29
int _mi_check_index(MI_INFO *info, int inx)
30
{
31
  if (inx == -1)                        /* Use last index */
32
    inx=info->lastinx;
33
  if (inx < 0 || ! mi_is_key_active(info->s->state.key_map, inx))
34
  {
35
    my_errno=HA_ERR_WRONG_INDEX;
36
    return -1;
37
  }
38
  if (info->lastinx != inx)             /* Index changed */
39
  {
40
    info->lastinx = inx;
41
    info->page_changed=1;
42
    info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
43
                   HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
44
  }
45
  if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
46
    return(-1);
47
  return(inx);
48
} /* mi_check_index */
49
50
51
        /*
52
        ** Search after row by a key
53
        ** Position to row is stored in info->lastpos
54
        ** Return: -1 if not found
55
        **          1 if one should continue search on higher level
56
        */
57
58
int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
482 by Brian Aker
Remove uint.
59
               unsigned char *key, uint32_t key_len, uint32_t nextflag, register my_off_t pos)
1 by brian
clean slate
60
{
281 by Brian Aker
Converted myisam away from my_bool
61
  bool last_key;
1 by brian
clean slate
62
  int error,flag;
482 by Brian Aker
Remove uint.
63
  uint32_t nod_flag;
481 by Brian Aker
Remove all of uchar.
64
  unsigned char *keypos,*maxpos;
65
  unsigned char lastkey[MI_MAX_KEY_BUFF],*buff;
1 by brian
clean slate
66
67
  if (pos == HA_OFFSET_ERROR)
68
  {
69
    my_errno=HA_ERR_KEY_NOT_FOUND;                      /* Didn't find key */
70
    info->lastpos= HA_OFFSET_ERROR;
71
    if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
51.1.111 by Jay Pipes
Removed DBUG symbols
72
      return(-1);                          /* Not found ; return error */
73
    return(1);                             /* Search at upper levels */
1 by brian
clean slate
74
  }
75
76
  if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,info->buff,
77
                               test(!(nextflag & SEARCH_SAVE_BUFF)))))
78
    goto err;
79
80
  flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
81
                              &keypos,lastkey, &last_key);
82
  if (flag == MI_FOUND_WRONG_KEY)
51.1.111 by Jay Pipes
Removed DBUG symbols
83
    return(-1);
1 by brian
clean slate
84
  nod_flag=mi_test_if_nod(buff);
85
  maxpos=buff+mi_getint(buff)-1;
86
87
  if (flag)
88
  {
89
    if ((error=_mi_search(info,keyinfo,key,key_len,nextflag,
90
                          _mi_kpos(nod_flag,keypos))) <= 0)
51.1.111 by Jay Pipes
Removed DBUG symbols
91
      return(error);
1 by brian
clean slate
92
93
    if (flag >0)
94
    {
95
      if (nextflag & (SEARCH_SMALLER | SEARCH_LAST) &&
96
          keypos == buff+2+nod_flag)
51.1.111 by Jay Pipes
Removed DBUG symbols
97
        return(1);                                 /* Bigger than key */
1 by brian
clean slate
98
    }
99
    else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
51.1.111 by Jay Pipes
Removed DBUG symbols
100
      return(1);                                   /* Smaller than key */
1 by brian
clean slate
101
  }
102
  else
103
  {
104
    if ((nextflag & SEARCH_FIND) && nod_flag &&
105
	((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
106
	 key_len != USE_WHOLE_KEY))
107
    {
108
      if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND,
109
                            _mi_kpos(nod_flag,keypos))) >= 0 ||
110
          my_errno != HA_ERR_KEY_NOT_FOUND)
51.1.111 by Jay Pipes
Removed DBUG symbols
111
        return(error);
1 by brian
clean slate
112
      info->last_keypage= HA_OFFSET_ERROR;              /* Buffer not in mem */
113
    }
114
  }
115
  if (pos != info->last_keypage)
116
  {
481 by Brian Aker
Remove all of uchar.
117
    unsigned char *old_buff=buff;
1 by brian
clean slate
118
    if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,info->buff,
119
                                 test(!(nextflag & SEARCH_SAVE_BUFF)))))
120
      goto err;
121
    keypos=buff+(keypos-old_buff);
122
    maxpos=buff+(maxpos-old_buff);
123
  }
124
125
  if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
126
  {
482 by Brian Aker
Remove uint.
127
    uint32_t not_used[2];
1 by brian
clean slate
128
    if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos,
129
                         &info->lastkey_length))
130
      goto err;
131
    if (!(nextflag & SEARCH_SMALLER) &&
132
        ha_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
133
                   not_used))
134
    {
135
      my_errno=HA_ERR_KEY_NOT_FOUND;                    /* Didn't find key */
136
      goto err;
137
    }
138
  }
139
  else
140
  {
141
    info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey);
142
    if (!info->lastkey_length)
143
      goto err;
144
    memcpy(info->lastkey,lastkey,info->lastkey_length);
145
  }
146
  info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
147
  /* Save position for a possible read next / previous */
148
  info->int_keypos=info->buff+ (keypos-buff);
149
  info->int_maxpos=info->buff+ (maxpos-buff);
150
  info->int_nod_flag=nod_flag;
151
  info->int_keytree_version=keyinfo->version;
152
  info->last_search_keypage=info->last_keypage;
153
  info->page_changed=0;
154
  info->buff_used= (info->buff != buff);        /* If we have to reread buff */
155
51.1.111 by Jay Pipes
Removed DBUG symbols
156
  return(0);
1 by brian
clean slate
157
158
err:
159
  info->lastpos= HA_OFFSET_ERROR;
160
  info->page_changed=1;
51.1.111 by Jay Pipes
Removed DBUG symbols
161
  return (-1);
1 by brian
clean slate
162
} /* _mi_search */
163
164
165
        /* Search after key in page-block */
166
        /* If packed key puts smaller or identical key in buff */
167
        /* ret_pos point to where find or bigger key starts */
168
        /* ARGSUSED */
169
481 by Brian Aker
Remove all of uchar.
170
int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
171
                   unsigned char *key, uint32_t key_len, uint32_t comp_flag, unsigned char **ret_pos,
481 by Brian Aker
Remove all of uchar.
172
                   unsigned char *buff __attribute__((unused)), bool *last_key)
1 by brian
clean slate
173
{
174
  register int start,mid,end,save_end;
175
  int flag;
482 by Brian Aker
Remove uint.
176
  uint32_t totlength,nod_flag,not_used[2];
1 by brian
clean slate
177
178
  totlength=keyinfo->keylength+(nod_flag=mi_test_if_nod(page));
179
  start=0; mid=1;
180
  save_end=end=(int) ((mi_getint(page)-2-nod_flag)/totlength-1);
181
  page+=2+nod_flag;
182
183
  while (start != end)
184
  {
185
    mid= (start+end)/2;
186
    if ((flag=ha_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
187
                         comp_flag, not_used))
188
        >= 0)
189
      end=mid;
190
    else
191
      start=mid+1;
192
  }
193
  if (mid != start)
194
    flag=ha_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
195
                     comp_flag, not_used);
196
  if (flag < 0)
197
    start++;                    /* point at next, bigger key */
198
  *ret_pos=page+(uint) start*totlength;
199
  *last_key= end == save_end;
51.1.111 by Jay Pipes
Removed DBUG symbols
200
  return(flag);
1 by brian
clean slate
201
} /* _mi_bin_search */
202
203
204
/*
205
  Locate a packed key in a key page.
206
207
  SYNOPSIS
208
    _mi_seq_search()
209
    info                        Open table information.
210
    keyinfo                     Key definition information.
211
    page                        Key page (beginning).
212
    key                         Search key.
213
    key_len                     Length to use from search key or USE_WHOLE_KEY
214
    comp_flag                   Search flags like SEARCH_SAME etc.
215
    ret_pos             RETURN  Position in key page behind this key.
216
    buff                RETURN  Copy of previous or identical unpacked key.
217
    last_key            RETURN  If key is last in page.
218
219
  DESCRIPTION
220
    Used instead of _mi_bin_search() when key is packed.
221
    Puts smaller or identical key in buff.
222
    Key is searched sequentially.
223
224
  RETURN
225
    > 0         Key in 'buff' is smaller than search key.
226
    0           Key in 'buff' is identical to search key.
227
    < 0         Not found.
228
*/
229
481 by Brian Aker
Remove all of uchar.
230
int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
231
                   unsigned char *key, uint32_t key_len, uint32_t comp_flag, unsigned char **ret_pos,
481 by Brian Aker
Remove all of uchar.
232
                   unsigned char *buff, bool *last_key)
1 by brian
clean slate
233
{
77.1.77 by Monty Taylor
A crapton more warning cleanups (I turned on more warnings)
234
  int flag=0;
482 by Brian Aker
Remove uint.
235
  uint32_t nod_flag,length=0,not_used[2];
481 by Brian Aker
Remove all of uchar.
236
  unsigned char t_buff[MI_MAX_KEY_BUFF],*end;
1 by brian
clean slate
237
238
  end= page+mi_getint(page);
239
  nod_flag=mi_test_if_nod(page);
240
  page+=2+nod_flag;
241
  *ret_pos=page;
242
  t_buff[0]=0;                                  /* Avoid bugs */
243
  while (page < end)
244
  {
245
    length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
246
    if (length == 0 || page > end)
247
    {
248
      mi_print_error(info->s, HA_ERR_CRASHED);
249
      my_errno=HA_ERR_CRASHED;
51.1.111 by Jay Pipes
Removed DBUG symbols
250
      return(MI_FOUND_WRONG_KEY);
1 by brian
clean slate
251
    }
252
    if ((flag=ha_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
253
                         not_used)) >= 0)
254
      break;
255
    memcpy(buff,t_buff,length);
256
    *ret_pos=page;
257
  }
258
  if (flag == 0)
259
    memcpy(buff,t_buff,length);                 /* Result is first key */
260
  *last_key= page == end;
51.1.111 by Jay Pipes
Removed DBUG symbols
261
  return(flag);
1 by brian
clean slate
262
} /* _mi_seq_search */
263
264
481 by Brian Aker
Remove all of uchar.
265
int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
266
                      unsigned char *key, uint32_t key_len, uint32_t nextflag, unsigned char **ret_pos,
481 by Brian Aker
Remove all of uchar.
267
                      unsigned char *buff, bool *last_key)
1 by brian
clean slate
268
{
269
  /*
270
    my_flag is raw comparison result to be changed according to
271
    SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
272
    flag is the value returned by ha_key_cmp and as treated as final
273
  */
274
  int flag=0, my_flag=-1;
482 by Brian Aker
Remove uint.
275
  uint32_t nod_flag, length=0, len, matched, cmplen, kseg_len;
276
  uint32_t prefix_len=0,suffix_len;
171.1.1 by Patrick Galbraith
Dar, I forgot to commit this earlier.
277
  int key_len_skip, seg_len_pack=0, key_len_left;
481 by Brian Aker
Remove all of uchar.
278
  unsigned char *end, *kseg, *vseg;
279
  unsigned char *sort_order=keyinfo->seg->charset->sort_order;
280
  unsigned char tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
281
  unsigned char *saved_from=NULL, *saved_to=NULL, *saved_vseg=NULL;
482 by Brian Aker
Remove uint.
282
  uint32_t  saved_length=0, saved_prefix_len=0;
283
  uint32_t  length_pack;
1 by brian
clean slate
284
171.1.1 by Patrick Galbraith
Dar, I forgot to commit this earlier.
285
1 by brian
clean slate
286
  t_buff[0]=0;                                  /* Avoid bugs */
287
  end= page+mi_getint(page);
288
  nod_flag=mi_test_if_nod(page);
289
  page+=2+nod_flag;
290
  *ret_pos=page;
291
  kseg=key;
292
293
  get_key_pack_length(kseg_len,length_pack,kseg);
294
  key_len_skip=length_pack+kseg_len;
295
  key_len_left=(int) key_len- (int) key_len_skip;
296
  /* If key_len is 0, then lenght_pack is 1, then key_len_left is -1. */
297
  cmplen=(key_len_left>=0) ? kseg_len : key_len-length_pack;
298
299
  /*
300
    Keys are compressed the following way:
301
302
    If the max length of first key segment <= 127 bytes the prefix is
303
    1 byte else it's 2 byte
304
305
    (prefix) length  The high bit is set if this is a prefix for the prev key.
306
    [suffix length]  Packed length of suffix if the previous was a prefix.
307
    (suffix) data    Key data bytes (past the common prefix or whole segment).
308
    [next-key-seg]   Next key segments (([packed length], data), ...)
309
    pointer          Reference to the data file (last_keyseg->length).
310
  */
311
312
  matched=0;  /* how many char's from prefix were alredy matched */
313
  len=0;      /* length of previous key unpacked */
314
315
  while (page < end)
316
  {
482 by Brian Aker
Remove uint.
317
    uint32_t packed= *page & 128;
1 by brian
clean slate
318
319
    vseg=page;
320
    if (keyinfo->seg->length >= 127)
321
    {
322
      suffix_len=mi_uint2korr(vseg) & 32767;
323
      vseg+=2;
324
    }
325
    else
326
      suffix_len= *vseg++ & 127;
327
328
    if (packed)
329
    {
330
      if (suffix_len == 0)
331
      {
332
        /* == 0x80 or 0x8000, same key, prefix length == old key length. */
333
        prefix_len=len;
334
      }
335
      else
336
      {
337
        /* > 0x80 or 0x8000, this is prefix lgt, packed suffix lgt follows. */
338
        prefix_len=suffix_len;
339
        get_key_length(suffix_len,vseg);
340
      }
341
    }
342
    else
343
    {
344
      /* Not packed. No prefix used from last key. */
345
      prefix_len=0;
346
    }
347
348
    len=prefix_len+suffix_len;
349
    seg_len_pack=get_pack_length(len);
350
    t_buff=tt_buff+3-seg_len_pack;
351
    store_key_length(t_buff,len);
352
353
    if (prefix_len > saved_prefix_len)
354
      memcpy(t_buff+seg_len_pack+saved_prefix_len,saved_vseg,
355
             prefix_len-saved_prefix_len);
356
    saved_vseg=vseg;
357
    saved_prefix_len=prefix_len;
358
359
    {
481 by Brian Aker
Remove all of uchar.
360
      unsigned char *from=vseg+suffix_len;
1 by brian
clean slate
361
      HA_KEYSEG *keyseg;
482 by Brian Aker
Remove uint.
362
      uint32_t l;
1 by brian
clean slate
363
364
      for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ )
365
      {
366
367
        if (keyseg->flag & HA_NULL_PART)
368
        {
369
          if (!(*from++))
370
            continue;
371
        }
372
        if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
373
        {
374
          get_key_length(l,from);
375
        }
376
        else
377
          l=keyseg->length;
378
379
        from+=l;
380
      }
381
      from+=keyseg->length;
382
      page=from+nod_flag;
383
      length=from-vseg;
384
    }
385
386
    if (page > end)
387
    {
388
      mi_print_error(info->s, HA_ERR_CRASHED);
389
      my_errno=HA_ERR_CRASHED;
51.1.111 by Jay Pipes
Removed DBUG symbols
390
      return(MI_FOUND_WRONG_KEY);
1 by brian
clean slate
391
    }
392
393
    if (matched >= prefix_len)
394
    {
395
      /* We have to compare. But we can still skip part of the key */
482 by Brian Aker
Remove uint.
396
      uint32_t  left;
481 by Brian Aker
Remove all of uchar.
397
      unsigned char *k=kseg+prefix_len;
1 by brian
clean slate
398
399
      /*
400
        If prefix_len > cmplen then we are in the end-space comparison
401
        phase. Do not try to acces the key any more ==> left= 0.
402
      */
403
      left= ((len <= cmplen) ? suffix_len :
404
             ((prefix_len < cmplen) ? cmplen - prefix_len : 0));
405
406
      matched=prefix_len+left;
407
408
      if (sort_order)
409
      {
410
        for (my_flag=0;left;left--)
411
          if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++]))
412
            break;
413
      }
414
      else
415
      {
416
        for (my_flag=0;left;left--)
417
          if ((my_flag= (int) *vseg++ - (int) *k++))
418
            break;
419
      }
420
421
      if (my_flag>0)      /* mismatch */
422
        break;
423
      if (my_flag==0) /* match */
424
      {
425
	/*
426
        **  len cmplen seg_left_len more_segs
427
        **     <                               matched=len; continue search
428
        **     >      =                        prefix ? found : (matched=len; continue search)
429
        **     >      <                 -      ok, found
430
        **     =      <                 -      ok, found
431
        **     =      =                 -      ok, found
432
        **     =      =                 +      next seg
433
        */
434
        if (len < cmplen)
435
        {
436
	  if ((keyinfo->seg->type != HA_KEYTYPE_TEXT &&
437
	       keyinfo->seg->type != HA_KEYTYPE_VARTEXT1 &&
438
               keyinfo->seg->type != HA_KEYTYPE_VARTEXT2))
439
	    my_flag= -1;
440
	  else
441
	  {
442
	    /* We have to compare k and vseg as if they were space extended */
481 by Brian Aker
Remove all of uchar.
443
	    unsigned char *k_end= k+ (cmplen - len);
1 by brian
clean slate
444
	    for ( ; k < k_end && *k == ' '; k++) ;
445
	    if (k == k_end)
446
	      goto cmp_rest;		/* should never happen */
481 by Brian Aker
Remove all of uchar.
447
	    if (*k < (unsigned char) ' ')
1 by brian
clean slate
448
	    {
449
	      my_flag= 1;		/* Compared string is smaller */
450
	      break;
451
	    }
452
	    my_flag= -1;		/* Continue searching */
453
	  }
454
        }
455
        else if (len > cmplen)
456
        {
481 by Brian Aker
Remove all of uchar.
457
	  unsigned char *vseg_end;
1 by brian
clean slate
458
	  if ((nextflag & SEARCH_PREFIX) && key_len_left == 0)
459
	    goto fix_flag;
460
461
	  /* We have to compare k and vseg as if they were space extended */
462
	  for (vseg_end= vseg + (len-cmplen) ;
481 by Brian Aker
Remove all of uchar.
463
	       vseg < vseg_end && *vseg == (unsigned char) ' ';
1 by brian
clean slate
464
	       vseg++, matched++) ;
51.1.111 by Jay Pipes
Removed DBUG symbols
465
	  assert(vseg < vseg_end);
1 by brian
clean slate
466
481 by Brian Aker
Remove all of uchar.
467
	  if (*vseg > (unsigned char) ' ')
1 by brian
clean slate
468
	  {
469
	    my_flag= 1;			/* Compared string is smaller */
470
	    break;
471
	  }
472
	  my_flag= -1;			/* Continue searching */
473
        }
474
        else
475
	{
476
      cmp_rest:
477
	  if (key_len_left>0)
478
	  {
482 by Brian Aker
Remove uint.
479
	    uint32_t not_used[2];
1 by brian
clean slate
480
	    if ((flag = ha_key_cmp(keyinfo->seg+1,vseg,
481
				   k, key_len_left, nextflag, not_used)) >= 0)
482
	      break;
483
	  }
484
	  else
485
	  {
486
	    /*
487
	      at this line flag==-1 if the following lines were already
488
	      visited and 0 otherwise,  i.e. flag <=0 here always !!!
489
	    */
490
	fix_flag:
51.1.111 by Jay Pipes
Removed DBUG symbols
491
	    assert(flag <= 0);
1 by brian
clean slate
492
	    if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST))
493
	      flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
494
	    if (flag>=0)
495
	      break;
496
	  }
497
	}
498
      }
499
      matched-=left;
500
    }
501
    /* else (matched < prefix_len) ---> do nothing. */
502
503
    memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
504
    saved_to=buff+saved_length;
505
    saved_from=saved_vseg;
506
    saved_length=length;
507
    *ret_pos=page;
508
  }
509
  if (my_flag)
510
    flag=(keyinfo->seg->flag & HA_REVERSE_SORT) ? -my_flag : my_flag;
511
  if (flag == 0)
512
  {
513
    memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
514
    saved_to=buff+saved_length;
515
    saved_from=saved_vseg;
516
    saved_length=length;
517
  }
518
  if (saved_length)
519
    memcpy(saved_to,saved_from,saved_length);
520
521
  *last_key= page == end;
522
51.1.111 by Jay Pipes
Removed DBUG symbols
523
  return(flag);
1 by brian
clean slate
524
} /* _mi_prefix_search */
525
526
527
        /* Get pos to a key_block */
528
482 by Brian Aker
Remove uint.
529
my_off_t _mi_kpos(uint32_t nod_flag, unsigned char *after_key)
1 by brian
clean slate
530
{
531
  after_key-=nod_flag;
532
  switch (nod_flag) {
533
#if SIZEOF_OFF_T > 4
534
  case 7:
535
    return mi_uint7korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
536
  case 6:
537
    return mi_uint6korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
538
  case 5:
539
    return mi_uint5korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
540
#else
541
  case 7:
542
    after_key++;
543
  case 6:
544
    after_key++;
545
  case 5:
546
    after_key++;
547
#endif
548
  case 4:
549
    return ((my_off_t) mi_uint4korr(after_key))*MI_MIN_KEY_BLOCK_LENGTH;
550
  case 3:
551
    return ((my_off_t) mi_uint3korr(after_key))*MI_MIN_KEY_BLOCK_LENGTH;
552
  case 2:
553
    return (my_off_t) (mi_uint2korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH);
554
  case 1:
555
    return (uint) (*after_key)*MI_MIN_KEY_BLOCK_LENGTH;
556
  case 0:                                       /* At leaf page */
557
  default:                                      /* Impossible */
558
    return(HA_OFFSET_ERROR);
559
  }
560
} /* _kpos */
561
562
563
        /* Save pos to a key_block */
564
481 by Brian Aker
Remove all of uchar.
565
void _mi_kpointer(register MI_INFO *info, register unsigned char *buff, my_off_t pos)
1 by brian
clean slate
566
{
567
  pos/=MI_MIN_KEY_BLOCK_LENGTH;
568
  switch (info->s->base.key_reflength) {
569
#if SIZEOF_OFF_T > 4
570
  case 7: mi_int7store(buff,pos); break;
571
  case 6: mi_int6store(buff,pos); break;
572
  case 5: mi_int5store(buff,pos); break;
573
#else
574
  case 7: *buff++=0;
575
    /* fall trough */
576
  case 6: *buff++=0;
577
    /* fall trough */
578
  case 5: *buff++=0;
579
    /* fall trough */
580
#endif
581
  case 4: mi_int4store(buff,pos); break;
582
  case 3: mi_int3store(buff,pos); break;
583
  case 2: mi_int2store(buff,(uint) pos); break;
481 by Brian Aker
Remove all of uchar.
584
  case 1: buff[0]= (unsigned char) pos; break;
1 by brian
clean slate
585
  default: abort();                             /* impossible */
586
  }
587
} /* _mi_kpointer */
588
589
590
        /* Calc pos to a data-record from a key */
591
592
482 by Brian Aker
Remove uint.
593
my_off_t _mi_dpos(MI_INFO *info, uint32_t nod_flag, unsigned char *after_key)
1 by brian
clean slate
594
{
595
  my_off_t pos;
596
  after_key-=(nod_flag + info->s->rec_reflength);
597
  switch (info->s->rec_reflength) {
598
#if SIZEOF_OFF_T > 4
599
  case 8:  pos= (my_off_t) mi_uint8korr(after_key);  break;
600
  case 7:  pos= (my_off_t) mi_uint7korr(after_key);  break;
601
  case 6:  pos= (my_off_t) mi_uint6korr(after_key);  break;
602
  case 5:  pos= (my_off_t) mi_uint5korr(after_key);  break;
603
#else
604
  case 8:  pos= (my_off_t) mi_uint4korr(after_key+4);   break;
605
  case 7:  pos= (my_off_t) mi_uint4korr(after_key+3);   break;
606
  case 6:  pos= (my_off_t) mi_uint4korr(after_key+2);   break;
607
  case 5:  pos= (my_off_t) mi_uint4korr(after_key+1);   break;
608
#endif
609
  case 4:  pos= (my_off_t) mi_uint4korr(after_key);  break;
610
  case 3:  pos= (my_off_t) mi_uint3korr(after_key);  break;
611
  case 2:  pos= (my_off_t) mi_uint2korr(after_key);  break;
612
  default:
613
    pos=0L;                                     /* Shut compiler up */
614
  }
615
  return (info->s->options &
616
          (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
617
            pos*info->s->base.pack_reclength;
618
}
619
620
621
/* Calc position from a record pointer ( in delete link chain ) */
622
481 by Brian Aker
Remove all of uchar.
623
my_off_t _mi_rec_pos(MYISAM_SHARE *s, unsigned char *ptr)
1 by brian
clean slate
624
{
625
  my_off_t pos;
626
  switch (s->rec_reflength) {
627
#if SIZEOF_OFF_T > 4
628
  case 8:
629
    pos= (my_off_t) mi_uint8korr(ptr);
630
    if (pos == HA_OFFSET_ERROR)
631
      return HA_OFFSET_ERROR;                   /* end of list */
632
    break;
633
  case 7:
634
    pos= (my_off_t) mi_uint7korr(ptr);
635
    if (pos == (((my_off_t) 1) << 56) -1)
636
      return HA_OFFSET_ERROR;                   /* end of list */
637
    break;
638
  case 6:
639
    pos= (my_off_t) mi_uint6korr(ptr);
640
    if (pos == (((my_off_t) 1) << 48) -1)
641
      return HA_OFFSET_ERROR;                   /* end of list */
642
    break;
643
  case 5:
644
    pos= (my_off_t) mi_uint5korr(ptr);
645
    if (pos == (((my_off_t) 1) << 40) -1)
646
      return HA_OFFSET_ERROR;                   /* end of list */
647
    break;
648
#else
649
  case 8:
650
  case 7:
651
  case 6:
652
  case 5:
653
    ptr+= (s->rec_reflength-4);
654
    /* fall through */
655
#endif
656
  case 4:
657
    pos= (my_off_t) mi_uint4korr(ptr);
365.2.8 by Monty Taylor
More MAX macros.
658
    if (pos == (my_off_t) UINT32_MAX)
1 by brian
clean slate
659
      return  HA_OFFSET_ERROR;
660
    break;
661
  case 3:
662
    pos= (my_off_t) mi_uint3korr(ptr);
663
    if (pos == (my_off_t) (1 << 24) -1)
664
      return HA_OFFSET_ERROR;
665
    break;
666
  case 2:
667
    pos= (my_off_t) mi_uint2korr(ptr);
668
    if (pos == (my_off_t) (1 << 16) -1)
669
      return HA_OFFSET_ERROR;
670
    break;
671
  default: abort();                             /* Impossible */
672
  }
673
  return ((s->options &
674
          (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
675
          pos*s->base.pack_reclength);
676
}
677
678
679
        /* save position to record */
680
481 by Brian Aker
Remove all of uchar.
681
void _mi_dpointer(MI_INFO *info, unsigned char *buff, my_off_t pos)
1 by brian
clean slate
682
{
683
  if (!(info->s->options &
684
        (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) &&
685
      pos != HA_OFFSET_ERROR)
686
    pos/=info->s->base.pack_reclength;
687
688
  switch (info->s->rec_reflength) {
689
#if SIZEOF_OFF_T > 4
690
  case 8: mi_int8store(buff,pos); break;
691
  case 7: mi_int7store(buff,pos); break;
692
  case 6: mi_int6store(buff,pos); break;
693
  case 5: mi_int5store(buff,pos); break;
694
#else
695
  case 8: *buff++=0;
696
    /* fall trough */
697
  case 7: *buff++=0;
698
    /* fall trough */
699
  case 6: *buff++=0;
700
    /* fall trough */
701
  case 5: *buff++=0;
702
    /* fall trough */
703
#endif
704
  case 4: mi_int4store(buff,pos); break;
705
  case 3: mi_int3store(buff,pos); break;
706
  case 2: mi_int2store(buff,(uint) pos); break;
707
  default: abort();                             /* Impossible */
708
  }
709
} /* _mi_dpointer */
710
711
712
        /* Get key from key-block */
713
        /* page points at previous key; its advanced to point at next key */
714
        /* key should contain previous key */
715
        /* Returns length of found key + pointers */
716
        /* nod_flag is a flag if we are on nod */
717
718
        /* same as _mi_get_key but used with fixed length keys */
719
482 by Brian Aker
Remove uint.
720
uint32_t _mi_get_static_key(register MI_KEYDEF *keyinfo, uint32_t nod_flag,
481 by Brian Aker
Remove all of uchar.
721
                       register unsigned char **page, register unsigned char *key)
1 by brian
clean slate
722
{
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
723
  memcpy(key, *page, keyinfo->keylength+nod_flag);
1 by brian
clean slate
724
  *page+=keyinfo->keylength+nod_flag;
725
  return(keyinfo->keylength);
726
} /* _mi_get_static_key */
727
728
729
/*
730
  get key witch is packed against previous key or key with a NULL column.
731
732
  SYNOPSIS
733
    _mi_get_pack_key()
734
    keyinfo                     key definition information.
735
    nod_flag                    If nod: Length of node pointer, else zero.
736
    page_pos            RETURN  position in key page behind this key.
737
    key                 IN/OUT  in: prev key, out: unpacked key.
738
739
  RETURN
740
    key_length + length of data pointer
741
*/
742
482 by Brian Aker
Remove uint.
743
uint32_t _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint32_t nod_flag,
481 by Brian Aker
Remove all of uchar.
744
                      register unsigned char **page_pos, register unsigned char *key)
1 by brian
clean slate
745
{
746
  register HA_KEYSEG *keyseg;
481 by Brian Aker
Remove all of uchar.
747
  unsigned char *start_key,*page=*page_pos;
482 by Brian Aker
Remove uint.
748
  uint32_t length;
1 by brian
clean slate
749
750
  start_key=key;
751
  for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
752
  {
753
    if (keyseg->flag & HA_PACK_KEY)
754
    {
755
      /* key with length, packed to previous key */
481 by Brian Aker
Remove all of uchar.
756
      unsigned char *start=key;
482 by Brian Aker
Remove uint.
757
      uint32_t packed= *page & 128,tot_length,rest_length;
1 by brian
clean slate
758
      if (keyseg->length >= 127)
759
      {
760
        length=mi_uint2korr(page) & 32767;
761
        page+=2;
762
      }
763
      else
764
        length= *page++ & 127;
765
766
      if (packed)
767
      {
768
	if (length > (uint) keyseg->length)
769
	{
770
          mi_print_error(keyinfo->share, HA_ERR_CRASHED);
771
	  my_errno=HA_ERR_CRASHED;
772
	  return 0;				/* Error */
773
	}
774
	if (length == 0)			/* Same key */
775
	{
776
	  if (keyseg->flag & HA_NULL_PART)
777
	    *key++=1;				/* Can't be NULL */
778
	  get_key_length(length,key);
779
	  key+= length;				/* Same diff_key as prev */
780
	  if (length > keyseg->length)
781
	  {
782
            mi_print_error(keyinfo->share, HA_ERR_CRASHED);
783
	    my_errno=HA_ERR_CRASHED;
784
	    return 0;
785
	  }
786
	  continue;
787
	}
788
	if (keyseg->flag & HA_NULL_PART)
789
	{
790
	  key++;				/* Skip null marker*/
791
	  start++;
792
	}
793
794
	get_key_length(rest_length,page);
795
	tot_length=rest_length+length;
796
797
	/* If the stored length has changed, we must move the key */
798
	if (tot_length >= 255 && *start != 255)
799
	{
800
	  /* length prefix changed from a length of one to a length of 3 */
801
	  bmove_upp(key+length+3, key+length+1, length);
802
	  *key=255;
803
	  mi_int2store(key+1,tot_length);
804
	  key+=3+length;
805
	}
806
	else if (tot_length < 255 && *start == 255)
807
	{
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
808
          memmove(key+1,key+3,length);
1 by brian
clean slate
809
	  *key=tot_length;
810
	  key+=1+length;
811
	}
812
	else
813
	{
814
	  store_key_length_inc(key,tot_length);
815
	  key+=length;
816
	}
817
	memcpy(key,page,rest_length);
818
	page+=rest_length;
819
	key+=rest_length;
820
	continue;
821
      }
822
      else
823
      {
824
        if (keyseg->flag & HA_NULL_PART)
825
        {
826
          if (!length--)                        /* Null part */
827
          {
828
            *key++=0;
829
            continue;
830
          }
831
          *key++=1;                             /* Not null */
832
        }
833
      }
834
      if (length > (uint) keyseg->length)
835
      {
836
        mi_print_error(keyinfo->share, HA_ERR_CRASHED);
837
        my_errno=HA_ERR_CRASHED;
838
        return 0;                               /* Error */
839
      }
840
      store_key_length_inc(key,length);
841
    }
842
    else
843
    {
844
      if (keyseg->flag & HA_NULL_PART)
845
      {
846
        if (!(*key++ = *page++))
847
          continue;
848
      }
849
      if (keyseg->flag &
850
          (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
851
      {
481 by Brian Aker
Remove all of uchar.
852
        unsigned char *tmp=page;
1 by brian
clean slate
853
        get_key_length(length,tmp);
854
        length+=(uint) (tmp-page);
855
      }
856
      else
857
        length=keyseg->length;
858
    }
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
859
    memcpy(key, page, length);
1 by brian
clean slate
860
    key+=length;
861
    page+=length;
862
  }
863
  length=keyseg->length+nod_flag;
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
864
  memmove(key,page,length);
1 by brian
clean slate
865
  *page_pos= page+length;
866
  return ((uint) (key-start_key)+keyseg->length);
867
} /* _mi_get_pack_key */
868
869
870
871
/* key that is packed relatively to previous */
872
482 by Brian Aker
Remove uint.
873
uint32_t _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint32_t nod_flag,
481 by Brian Aker
Remove all of uchar.
874
                             register unsigned char **page_pos, register unsigned char *key)
1 by brian
clean slate
875
{
876
  register HA_KEYSEG *keyseg;
481 by Brian Aker
Remove all of uchar.
877
  unsigned char *start_key,*page,*page_end,*from,*from_end;
482 by Brian Aker
Remove uint.
878
  uint32_t length,tmp;
1 by brian
clean slate
879
880
  page= *page_pos;
881
  page_end=page+MI_MAX_KEY_BUFF+1;
882
  start_key=key;
883
884
  /*
885
    Keys are compressed the following way:
886
887
    prefix length    Packed length of prefix common with prev key (1 or 3 bytes)
888
    for each key segment:
889
      [is null]        Null indicator if can be null (1 byte, zero means null)
890
      [length]         Packed length if varlength (1 or 3 bytes)
891
      key segment      'length' bytes of key segment value
892
    pointer          Reference to the data file (last_keyseg->length).
893
894
    get_key_length() is a macro. It gets the prefix length from 'page'
895
    and puts it into 'length'. It increments 'page' by 1 or 3, depending
896
    on the packed length of the prefix length.
897
  */
898
  get_key_length(length,page);
899
  if (length)
900
  {
901
    if (length > keyinfo->maxlength)
902
    {
903
      mi_print_error(keyinfo->share, HA_ERR_CRASHED);
904
      my_errno=HA_ERR_CRASHED;
51.1.111 by Jay Pipes
Removed DBUG symbols
905
      return(0);                                 /* Wrong key */
1 by brian
clean slate
906
    }
907
    /* Key is packed against prev key, take prefix from prev key. */
908
    from= key;
909
    from_end= key + length;
910
  }
911
  else
912
  {
913
    /* Key is not packed against prev key, take all from page buffer. */
914
    from= page;
915
    from_end= page_end;
916
  }
917
918
  /*
919
    The trouble is that key can be split in two parts:
920
      The first part (prefix) is in from .. from_end - 1.
921
      The second part starts at page.
922
    The split can be at every byte position. So we need to check for
923
    the end of the first part before using every byte.
924
  */
925
  for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
926
  {
927
    if (keyseg->flag & HA_NULL_PART)
928
    {
929
      /* If prefix is used up, switch to rest. */
930
      if (from == from_end) { from=page;  from_end=page_end; }
931
      if (!(*key++ = *from++))
932
        continue;                               /* Null part */
933
    }
934
    if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
935
    {
936
      /* If prefix is used up, switch to rest. */
937
      if (from == from_end) { from=page;  from_end=page_end; }
938
      /* Get length of dynamic length key part */
939
      if ((length= (*key++ = *from++)) == 255)
940
      {
941
        /* If prefix is used up, switch to rest. */
942
        if (from == from_end) { from=page;  from_end=page_end; }
943
        length= (uint) ((*key++ = *from++)) << 8;
944
        /* If prefix is used up, switch to rest. */
945
        if (from == from_end) { from=page;  from_end=page_end; }
946
        length+= (uint) ((*key++ = *from++));
947
      }
948
    }
949
    else
950
      length=keyseg->length;
951
952
    if ((tmp=(uint) (from_end-from)) <= length)
953
    {
954
      key+=tmp;                                 /* Use old key */
955
      length-=tmp;
956
      from=page; from_end=page_end;
957
    }
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
958
    memmove(key, from, length);
1 by brian
clean slate
959
    key+=length;
960
    from+=length;
961
  }
962
  /*
963
    Last segment (type == 0) contains length of data pointer.
964
    If we have mixed key blocks with data pointer and key block pointer,
965
    we have to copy both.
966
  */
967
  length=keyseg->length+nod_flag;
968
  if ((tmp=(uint) (from_end-from)) <= length)
969
  {
970
    /* Remaining length is less or equal max possible length. */
971
    memcpy(key+tmp,page,length-tmp);            /* Get last part of key */
972
    *page_pos= page+length-tmp;
973
  }
974
  else
975
  {
976
    /*
977
      Remaining length is greater than max possible length.
978
      This can happen only if we switched to the new key bytes already.
979
      'page_end' is calculated with MI_MAX_KEY_BUFF. So it can be far
980
      behind the real end of the key.
981
    */
982
    if (from_end != page_end)
983
    {
984
      mi_print_error(keyinfo->share, HA_ERR_CRASHED);
985
      my_errno=HA_ERR_CRASHED;
51.1.111 by Jay Pipes
Removed DBUG symbols
986
      return(0);                                 /* Error */
1 by brian
clean slate
987
    }
988
    /* Copy data pointer and, if appropriate, key block pointer. */
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
989
    memcpy(key, from, length);
1 by brian
clean slate
990
    *page_pos= from+length;
991
  }
51.1.111 by Jay Pipes
Removed DBUG symbols
992
  return((uint) (key-start_key)+keyseg->length);
1 by brian
clean slate
993
}
994
995
996
        /* Get key at position without knowledge of previous key */
997
        /* Returns pointer to next key */
998
481 by Brian Aker
Remove all of uchar.
999
unsigned char *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
1000
                   unsigned char *key, unsigned char *keypos, uint32_t *return_key_length)
1 by brian
clean slate
1001
{
482 by Brian Aker
Remove uint.
1002
  uint32_t nod_flag;
1 by brian
clean slate
1003
1004
  nod_flag=mi_test_if_nod(page);
1005
  if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1006
  {
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
1007
    memmove(key,keypos,keyinfo->keylength+nod_flag);
51.1.111 by Jay Pipes
Removed DBUG symbols
1008
    return(keypos+keyinfo->keylength+nod_flag);
1 by brian
clean slate
1009
  }
1010
  else
1011
  {
1012
    page+=2+nod_flag;
1013
    key[0]=0;                                   /* safety */
1014
    while (page <= keypos)
1015
    {
1016
      *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
1017
      if (*return_key_length == 0)
1018
      {
1019
        mi_print_error(info->s, HA_ERR_CRASHED);
1020
        my_errno=HA_ERR_CRASHED;
51.1.111 by Jay Pipes
Removed DBUG symbols
1021
        return(0);
1 by brian
clean slate
1022
      }
1023
    }
1024
  }
51.1.111 by Jay Pipes
Removed DBUG symbols
1025
  return(page);
1 by brian
clean slate
1026
} /* _mi_get_key */
1027
1028
1029
        /* Get key at position without knowledge of previous key */
1030
        /* Returns 0 if ok */
1031
481 by Brian Aker
Remove all of uchar.
1032
static bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, unsigned char *page,
1033
                                unsigned char *key, unsigned char *keypos,
482 by Brian Aker
Remove uint.
1034
                                uint32_t *return_key_length)
1 by brian
clean slate
1035
{
482 by Brian Aker
Remove uint.
1036
  uint32_t nod_flag;
1 by brian
clean slate
1037
1038
  nod_flag=mi_test_if_nod(page);
1039
  if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1040
  {
1041
    *return_key_length=keyinfo->keylength;
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
1042
    memmove(key, keypos - *return_key_length-nod_flag, *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
481 by Brian Aker
Remove all of uchar.
1068
unsigned char *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, unsigned char *page,
482 by Brian Aker
Remove uint.
1069
                        unsigned char *lastkey, unsigned char *endpos, uint32_t *return_key_length)
1 by brian
clean slate
1070
{
482 by Brian Aker
Remove uint.
1071
  uint32_t nod_flag;
481 by Brian Aker
Remove all of uchar.
1072
  unsigned char *lastpos;
1 by brian
clean slate
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)
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
1080
      memmove(lastkey,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
482 by Brian Aker
Remove uint.
1104
uint32_t _mi_keylength(MI_KEYDEF *keyinfo, register unsigned char *key)
1 by brian
clean slate
1105
{
1106
  register HA_KEYSEG *keyseg;
481 by Brian Aker
Remove all of uchar.
1107
  unsigned char *start;
1 by brian
clean slate
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
    {
482 by Brian Aker
Remove uint.
1120
      uint32_t length;
1 by brian
clean slate
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
482 by Brian Aker
Remove uint.
1139
uint32_t _mi_keylength_part(MI_KEYDEF *keyinfo, register unsigned char *key,
1 by brian
clean slate
1140
			HA_KEYSEG *end)
1141
{
1142
  register HA_KEYSEG *keyseg;
481 by Brian Aker
Remove all of uchar.
1143
  unsigned char *start= key;
1 by brian
clean slate
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
    {
482 by Brian Aker
Remove uint.
1152
      uint32_t length;
1 by brian
clean slate
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
481 by Brian Aker
Remove all of uchar.
1164
unsigned char *_mi_move_key(MI_KEYDEF *keyinfo, unsigned char *to, unsigned char *from)
1 by brian
clean slate
1165
{
482 by Brian Aker
Remove uint.
1166
  register uint32_t length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
1167
  length= _mi_keylength(keyinfo, from);
1168
  memcpy(to, from, length);
1 by brian
clean slate
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,
482 by Brian Aker
Remove uint.
1176
                    unsigned char *key, uint32_t key_length, uint32_t nextflag, my_off_t pos)
1 by brian
clean slate
1177
{
1178
  int error;
482 by Brian Aker
Remove uint.
1179
  uint32_t nod_flag;
481 by Brian Aker
Remove all of uchar.
1180
  unsigned char lastkey[MI_MAX_KEY_BUFF];
1 by brian
clean slate
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
  {
482 by Brian Aker
Remove uint.
1223
    uint32_t length;
1 by brian
clean slate
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
{
482 by Brian Aker
Remove uint.
1254
  uint32_t nod_flag;
481 by Brian Aker
Remove all of uchar.
1255
  unsigned char *page;
1 by brian
clean slate
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
{
482 by Brian Aker
Remove uint.
1296
  uint32_t nod_flag;
481 by Brian Aker
Remove all of uchar.
1297
  unsigned char *buff,*page;
1 by brian
clean slate
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
482 by Brian Aker
Remove uint.
1349
_mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint32_t nod_flag,
481 by Brian Aker
Remove all of uchar.
1350
                           unsigned char *next_pos  __attribute__((unused)),
1351
                           unsigned char *org_key  __attribute__((unused)),
1352
                           unsigned char *prev_key __attribute__((unused)),
1353
                           unsigned char *key, MI_KEY_PARAM *s_temp)
1 by brian
clean slate
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
482 by Brian Aker
Remove uint.
1362
_mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint32_t nod_flag,
481 by Brian Aker
Remove all of uchar.
1363
                        unsigned char *next_pos  __attribute__((unused)),
1364
                        unsigned char *org_key  __attribute__((unused)),
1365
                        unsigned char *prev_key __attribute__((unused)),
1366
                        unsigned char *key, MI_KEY_PARAM *s_temp)
1 by brian
clean slate
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
482 by Brian Aker
Remove uint.
1392
_mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint32_t nod_flag,unsigned char *next_key,
481 by Brian Aker
Remove all of uchar.
1393
                             unsigned char *org_key, unsigned char *prev_key, unsigned char *key,
1 by brian
clean slate
1394
                             MI_KEY_PARAM *s_temp)
1395
{
1396
  register HA_KEYSEG *keyseg;
1397
  int length;
482 by Brian Aker
Remove uint.
1398
  uint32_t key_length,ref_length,org_key_length=0,
1 by brian
clean slate
1399
       length_pack,new_key_length,diff_flag,pack_marker;
481 by Brian Aker
Remove all of uchar.
1400
  unsigned char *start,*end,*key_end,*sort_order;
281 by Brian Aker
Converted myisam away from my_bool
1401
  bool same_length;
1 by brian
clean slate
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
  {
482 by Brian Aker
Remove uint.
1516
    uint32_t packed,n_length;
1 by brian
clean slate
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
    {
482 by Brian Aker
Remove uint.
1531
      uint32_t next_length_pack, new_ref_length=s_temp->ref_length;
1 by brian
clean slate
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
        {
482 by Brian Aker
Remove uint.
1599
          uint32_t new_pack_length=new_ref_length-pack_marker;
1 by brian
clean slate
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
      {
482 by Brian Aker
Remove uint.
1617
        uint32_t tmp_length;
1 by brian
clean slate
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
482 by Brian Aker
Remove uint.
1664
_mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint32_t nod_flag,unsigned char *next_key,
481 by Brian Aker
Remove all of uchar.
1665
                             unsigned char *org_key, unsigned char *prev_key, unsigned char *key,
1 by brian
clean slate
1666
                             MI_KEY_PARAM *s_temp)
1667
{
482 by Brian Aker
Remove uint.
1668
  uint32_t length,key_length,ref_length;
1 by brian
clean slate
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
    */
481 by Brian Aker
Remove all of uchar.
1683
    unsigned char *end;
1 by brian
clean slate
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 */
482 by Brian Aker
Remove uint.
1698
    uint32_t next_length,next_length_pack;
1 by brian
clean slate
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
    {
481 by Brian Aker
Remove all of uchar.
1704
      unsigned char *end;
1 by brian
clean slate
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)),
481 by Brian Aker
Remove all of uchar.
1746
                          register unsigned char *key_pos,
1 by brian
clean slate
1747
                          register MI_KEY_PARAM *s_temp)
1748
{
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
1749
  memcpy(key_pos, s_temp->key, s_temp->totlength);
1 by brian
clean slate
1750
}
1751
1752
1753
/* store variable length key with prefix compression */
1754
1755
#define store_pack_length(test,pos,length) { \
481 by Brian Aker
Remove all of uchar.
1756
  if (test) { *((pos)++) = (unsigned char) (length); } else \
1757
  { *((pos)++) = (unsigned char) ((length) >> 8); *((pos)++) = (unsigned char) (length);  } }
1 by brian
clean slate
1758
1759
1760
void _mi_store_var_pack_key(MI_KEYDEF *keyinfo  __attribute__((unused)),
481 by Brian Aker
Remove all of uchar.
1761
                            register unsigned char *key_pos,
1 by brian
clean slate
1762
                            register MI_KEY_PARAM *s_temp)
1763
{
482 by Brian Aker
Remove uint.
1764
  uint32_t length;
481 by Brian Aker
Remove all of uchar.
1765
  unsigned char *start;
1 by brian
clean slate
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.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
1782
  assert(key_pos >= start);
1783
  length= s_temp->totlength - (key_pos - start);
629.3.4 by Kristian Nielsen
Take Mats'es changes from bmove()->memcpy(), and fix all of them to be
1784
  memmove(key_pos, s_temp->key, length);
1 by brian
clean slate
1785
1786
  if (!s_temp->next_key_pos)                    /* No following key */
1787
    return;
1788
  key_pos+=length;
1789
1790
  if (s_temp->prev_length)
1791
  {
1792
    /* Extend next key because new key didn't have same prefix as prev key */
1793
    if (s_temp->part_of_prev_key)
1794
    {
1795
      store_pack_length(s_temp->pack_marker == 128,key_pos,
1796
                        s_temp->part_of_prev_key);
1797
      store_key_length_inc(key_pos,s_temp->n_length);
1798
    }
1799
    else
1800
    {
1801
      s_temp->n_length+= s_temp->store_not_null;
1802
      store_pack_length(s_temp->pack_marker == 128,key_pos,
1803
                        s_temp->n_length);
1804
    }
1805
    memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
1806
  }
1807
  else if (s_temp->n_ref_length)
1808
  {
1809
    store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_ref_length);
1810
    if (s_temp->n_ref_length == s_temp->pack_marker)
1811
      return;                                   /* Identical key */
1812
    store_key_length(key_pos,s_temp->n_length);
1813
  }
1814
  else
1815
  {
1816
    s_temp->n_length+= s_temp->store_not_null;
1817
    store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_length);
1818
  }
1819
}
1820
1821
1822
/* variable length key with prefix compression */
1823
1824
void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo  __attribute__((unused)),
481 by Brian Aker
Remove all of uchar.
1825
                            register unsigned char *key_pos,
1 by brian
clean slate
1826
                            register MI_KEY_PARAM *s_temp)
1827
{
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
1828
  assert(s_temp->totlength >= s_temp->ref_length);
1 by brian
clean slate
1829
  store_key_length_inc(key_pos,s_temp->ref_length);
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
1830
  memcpy(key_pos,s_temp->key+s_temp->ref_length,
1831
         s_temp->totlength - s_temp->ref_length);
1 by brian
clean slate
1832
1833
  if (s_temp->next_key_pos)
1834
  {
1835
    key_pos+=(uint) (s_temp->totlength-s_temp->ref_length);
1836
    store_key_length_inc(key_pos,s_temp->n_ref_length);
1837
    if (s_temp->prev_length)                    /* If we must extend key */
1838
    {
1839
      memcpy(key_pos,s_temp->prev_key,s_temp->prev_length);
1840
    }
1841
  }
1842
}