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