1
/* Copyright (C) 2000-2006 MySQL AB
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.
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.
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 */
16
/* key handling functions */
21
static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
22
uchar *key, uchar *keypos,
23
uint *return_key_length);
27
int _mi_check_index(MI_INFO *info, int inx)
29
if (inx == -1) /* Use last index */
31
if (inx < 0 || ! mi_is_key_active(info->s->state.key_map, inx))
33
my_errno=HA_ERR_WRONG_INDEX;
36
if (info->lastinx != inx) /* Index changed */
40
info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) |
41
HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND);
43
if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache))
46
} /* mi_check_index */
50
** Search after row by a key
51
** Position to row is stored in info->lastpos
52
** Return: -1 if not found
53
** 1 if one should continue search on higher level
56
int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
57
uchar *key, uint key_len, uint nextflag, register my_off_t pos)
62
uchar *keypos,*maxpos;
63
uchar lastkey[MI_MAX_KEY_BUFF],*buff;
64
DBUG_ENTER("_mi_search");
65
DBUG_PRINT("enter",("pos: %lu nextflag: %u lastpos: %lu",
66
(ulong) pos, nextflag, (ulong) info->lastpos));
67
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_len););
69
if (pos == HA_OFFSET_ERROR)
71
my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
72
info->lastpos= HA_OFFSET_ERROR;
73
if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST)))
74
DBUG_RETURN(-1); /* Not found ; return error */
75
DBUG_RETURN(1); /* Search at upper levels */
78
if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,info->buff,
79
test(!(nextflag & SEARCH_SAVE_BUFF)))))
81
DBUG_DUMP("page",(uchar*) buff,mi_getint(buff));
83
flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag,
84
&keypos,lastkey, &last_key);
85
if (flag == MI_FOUND_WRONG_KEY)
87
nod_flag=mi_test_if_nod(buff);
88
maxpos=buff+mi_getint(buff)-1;
92
if ((error=_mi_search(info,keyinfo,key,key_len,nextflag,
93
_mi_kpos(nod_flag,keypos))) <= 0)
98
if (nextflag & (SEARCH_SMALLER | SEARCH_LAST) &&
99
keypos == buff+2+nod_flag)
100
DBUG_RETURN(1); /* Bigger than key */
102
else if (nextflag & SEARCH_BIGGER && keypos >= maxpos)
103
DBUG_RETURN(1); /* Smaller than key */
107
if ((nextflag & SEARCH_FIND) && nod_flag &&
108
((keyinfo->flag & (HA_NOSAME | HA_NULL_PART)) != HA_NOSAME ||
109
key_len != USE_WHOLE_KEY))
111
if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND,
112
_mi_kpos(nod_flag,keypos))) >= 0 ||
113
my_errno != HA_ERR_KEY_NOT_FOUND)
115
info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in mem */
118
if (pos != info->last_keypage)
120
uchar *old_buff=buff;
121
if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,info->buff,
122
test(!(nextflag & SEARCH_SAVE_BUFF)))))
124
keypos=buff+(keypos-old_buff);
125
maxpos=buff+(maxpos-old_buff);
128
if ((nextflag & (SEARCH_SMALLER | SEARCH_LAST)) && flag != 0)
131
if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos,
132
&info->lastkey_length))
134
if (!(nextflag & SEARCH_SMALLER) &&
135
ha_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
138
my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
144
info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,lastkey);
145
if (!info->lastkey_length)
147
memcpy(info->lastkey,lastkey,info->lastkey_length);
149
info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
150
/* Save position for a possible read next / previous */
151
info->int_keypos=info->buff+ (keypos-buff);
152
info->int_maxpos=info->buff+ (maxpos-buff);
153
info->int_nod_flag=nod_flag;
154
info->int_keytree_version=keyinfo->version;
155
info->last_search_keypage=info->last_keypage;
156
info->page_changed=0;
157
info->buff_used= (info->buff != buff); /* If we have to reread buff */
159
DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos));
163
DBUG_PRINT("exit",("Error: %d",my_errno));
164
info->lastpos= HA_OFFSET_ERROR;
165
info->page_changed=1;
170
/* Search after key in page-block */
171
/* If packed key puts smaller or identical key in buff */
172
/* ret_pos point to where find or bigger key starts */
175
int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
176
uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
177
uchar *buff __attribute__((unused)), my_bool *last_key)
179
register int start,mid,end,save_end;
181
uint totlength,nod_flag,not_used[2];
182
DBUG_ENTER("_mi_bin_search");
184
totlength=keyinfo->keylength+(nod_flag=mi_test_if_nod(page));
186
save_end=end=(int) ((mi_getint(page)-2-nod_flag)/totlength-1);
187
DBUG_PRINT("test",("mi_getint: %d end: %d",mi_getint(page),end));
193
if ((flag=ha_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len,
194
comp_flag, not_used))
201
flag=ha_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len,
202
comp_flag, not_used);
204
start++; /* point at next, bigger key */
205
*ret_pos=page+(uint) start*totlength;
206
*last_key= end == save_end;
207
DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start));
209
} /* _mi_bin_search */
213
Locate a packed key in a key page.
217
info Open table information.
218
keyinfo Key definition information.
219
page Key page (beginning).
221
key_len Length to use from search key or USE_WHOLE_KEY
222
comp_flag Search flags like SEARCH_SAME etc.
223
ret_pos RETURN Position in key page behind this key.
224
buff RETURN Copy of previous or identical unpacked key.
225
last_key RETURN If key is last in page.
228
Used instead of _mi_bin_search() when key is packed.
229
Puts smaller or identical key in buff.
230
Key is searched sequentially.
233
> 0 Key in 'buff' is smaller than search key.
234
0 Key in 'buff' is identical to search key.
238
int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
239
uchar *key, uint key_len, uint comp_flag, uchar **ret_pos,
240
uchar *buff, my_bool *last_key)
243
uint nod_flag,length,not_used[2];
244
uchar t_buff[MI_MAX_KEY_BUFF],*end;
245
DBUG_ENTER("_mi_seq_search");
247
end= page+mi_getint(page);
248
nod_flag=mi_test_if_nod(page);
251
t_buff[0]=0; /* Avoid bugs */
254
length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff);
255
if (length == 0 || page > end)
257
mi_print_error(info->s, HA_ERR_CRASHED);
258
my_errno=HA_ERR_CRASHED;
260
("Found wrong key: length: %u page: 0x%lx end: 0x%lx",
261
length, (long) page, (long) end));
262
DBUG_RETURN(MI_FOUND_WRONG_KEY);
264
if ((flag=ha_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag,
268
DBUG_PRINT("loop",("page: 0x%lx key: '%s' flag: %d", (long) page, t_buff,
271
memcpy(buff,t_buff,length);
275
memcpy(buff,t_buff,length); /* Result is first key */
276
*last_key= page == end;
277
DBUG_PRINT("exit",("flag: %d ret_pos: 0x%lx", flag, (long) *ret_pos));
279
} /* _mi_seq_search */
282
int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page,
283
uchar *key, uint key_len, uint nextflag, uchar **ret_pos,
284
uchar *buff, my_bool *last_key)
287
my_flag is raw comparison result to be changed according to
288
SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags.
289
flag is the value returned by ha_key_cmp and as treated as final
291
int flag=0, my_flag=-1;
292
uint nod_flag, length, len, matched, cmplen, kseg_len;
293
uint prefix_len,suffix_len;
294
int key_len_skip, seg_len_pack, key_len_left;
295
uchar *end, *kseg, *vseg;
296
uchar *sort_order=keyinfo->seg->charset->sort_order;
297
uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2;
298
uchar *saved_from, *saved_to, *saved_vseg;
299
uint saved_length=0, saved_prefix_len=0;
301
DBUG_ENTER("_mi_prefix_search");
303
t_buff[0]=0; /* Avoid bugs */
304
end= page+mi_getint(page);
305
nod_flag=mi_test_if_nod(page);
310
get_key_pack_length(kseg_len,length_pack,kseg);
311
key_len_skip=length_pack+kseg_len;
312
key_len_left=(int) key_len- (int) key_len_skip;
313
/* If key_len is 0, then lenght_pack is 1, then key_len_left is -1. */
314
cmplen=(key_len_left>=0) ? kseg_len : key_len-length_pack;
315
DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg));
318
Keys are compressed the following way:
320
If the max length of first key segment <= 127 bytes the prefix is
321
1 byte else it's 2 byte
323
(prefix) length The high bit is set if this is a prefix for the prev key.
324
[suffix length] Packed length of suffix if the previous was a prefix.
325
(suffix) data Key data bytes (past the common prefix or whole segment).
326
[next-key-seg] Next key segments (([packed length], data), ...)
327
pointer Reference to the data file (last_keyseg->length).
330
matched=0; /* how many char's from prefix were alredy matched */
331
len=0; /* length of previous key unpacked */
335
uint packed= *page & 128;
338
if (keyinfo->seg->length >= 127)
340
suffix_len=mi_uint2korr(vseg) & 32767;
344
suffix_len= *vseg++ & 127;
350
/* == 0x80 or 0x8000, same key, prefix length == old key length. */
355
/* > 0x80 or 0x8000, this is prefix lgt, packed suffix lgt follows. */
356
prefix_len=suffix_len;
357
get_key_length(suffix_len,vseg);
362
/* Not packed. No prefix used from last key. */
366
len=prefix_len+suffix_len;
367
seg_len_pack=get_pack_length(len);
368
t_buff=tt_buff+3-seg_len_pack;
369
store_key_length(t_buff,len);
371
if (prefix_len > saved_prefix_len)
372
memcpy(t_buff+seg_len_pack+saved_prefix_len,saved_vseg,
373
prefix_len-saved_prefix_len);
375
saved_prefix_len=prefix_len;
377
DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,
380
uchar *from=vseg+suffix_len;
384
for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ )
387
if (keyseg->flag & HA_NULL_PART)
392
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
394
get_key_length(l,from);
401
from+=keyseg->length;
408
mi_print_error(info->s, HA_ERR_CRASHED);
409
my_errno=HA_ERR_CRASHED;
411
("Found wrong key: length: %u page: 0x%lx end: %lx",
412
length, (long) page, (long) end));
413
DBUG_RETURN(MI_FOUND_WRONG_KEY);
416
if (matched >= prefix_len)
418
/* We have to compare. But we can still skip part of the key */
420
uchar *k=kseg+prefix_len;
423
If prefix_len > cmplen then we are in the end-space comparison
424
phase. Do not try to acces the key any more ==> left= 0.
426
left= ((len <= cmplen) ? suffix_len :
427
((prefix_len < cmplen) ? cmplen - prefix_len : 0));
429
matched=prefix_len+left;
433
for (my_flag=0;left;left--)
434
if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++]))
439
for (my_flag=0;left;left--)
440
if ((my_flag= (int) *vseg++ - (int) *k++))
444
if (my_flag>0) /* mismatch */
446
if (my_flag==0) /* match */
449
** len cmplen seg_left_len more_segs
450
** < matched=len; continue search
451
** > = prefix ? found : (matched=len; continue search)
459
if ((keyinfo->seg->type != HA_KEYTYPE_TEXT &&
460
keyinfo->seg->type != HA_KEYTYPE_VARTEXT1 &&
461
keyinfo->seg->type != HA_KEYTYPE_VARTEXT2))
465
/* We have to compare k and vseg as if they were space extended */
466
uchar *k_end= k+ (cmplen - len);
467
for ( ; k < k_end && *k == ' '; k++) ;
469
goto cmp_rest; /* should never happen */
470
if (*k < (uchar) ' ')
472
my_flag= 1; /* Compared string is smaller */
475
my_flag= -1; /* Continue searching */
478
else if (len > cmplen)
481
if ((nextflag & SEARCH_PREFIX) && key_len_left == 0)
484
/* We have to compare k and vseg as if they were space extended */
485
for (vseg_end= vseg + (len-cmplen) ;
486
vseg < vseg_end && *vseg == (uchar) ' ';
488
DBUG_ASSERT(vseg < vseg_end);
490
if (*vseg > (uchar) ' ')
492
my_flag= 1; /* Compared string is smaller */
495
my_flag= -1; /* Continue searching */
503
if ((flag = ha_key_cmp(keyinfo->seg+1,vseg,
504
k, key_len_left, nextflag, not_used)) >= 0)
510
at this line flag==-1 if the following lines were already
511
visited and 0 otherwise, i.e. flag <=0 here always !!!
514
DBUG_ASSERT(flag <= 0);
515
if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST))
516
flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
524
/* else (matched < prefix_len) ---> do nothing. */
526
memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
527
saved_to=buff+saved_length;
528
saved_from=saved_vseg;
533
flag=(keyinfo->seg->flag & HA_REVERSE_SORT) ? -my_flag : my_flag;
536
memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len);
537
saved_to=buff+saved_length;
538
saved_from=saved_vseg;
542
memcpy(saved_to,saved_from,saved_length);
544
*last_key= page == end;
546
DBUG_PRINT("exit",("flag: %d ret_pos: 0x%lx", flag, (long) *ret_pos));
548
} /* _mi_prefix_search */
551
/* Get pos to a key_block */
553
my_off_t _mi_kpos(uint nod_flag, uchar *after_key)
559
return mi_uint7korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
561
return mi_uint6korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
563
return mi_uint5korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH;
573
return ((my_off_t) mi_uint4korr(after_key))*MI_MIN_KEY_BLOCK_LENGTH;
575
return ((my_off_t) mi_uint3korr(after_key))*MI_MIN_KEY_BLOCK_LENGTH;
577
return (my_off_t) (mi_uint2korr(after_key)*MI_MIN_KEY_BLOCK_LENGTH);
579
return (uint) (*after_key)*MI_MIN_KEY_BLOCK_LENGTH;
580
case 0: /* At leaf page */
581
default: /* Impossible */
582
return(HA_OFFSET_ERROR);
587
/* Save pos to a key_block */
589
void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos)
591
pos/=MI_MIN_KEY_BLOCK_LENGTH;
592
switch (info->s->base.key_reflength) {
594
case 7: mi_int7store(buff,pos); break;
595
case 6: mi_int6store(buff,pos); break;
596
case 5: mi_int5store(buff,pos); break;
605
case 4: mi_int4store(buff,pos); break;
606
case 3: mi_int3store(buff,pos); break;
607
case 2: mi_int2store(buff,(uint) pos); break;
608
case 1: buff[0]= (uchar) pos; break;
609
default: abort(); /* impossible */
614
/* Calc pos to a data-record from a key */
617
my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key)
620
after_key-=(nod_flag + info->s->rec_reflength);
621
switch (info->s->rec_reflength) {
623
case 8: pos= (my_off_t) mi_uint8korr(after_key); break;
624
case 7: pos= (my_off_t) mi_uint7korr(after_key); break;
625
case 6: pos= (my_off_t) mi_uint6korr(after_key); break;
626
case 5: pos= (my_off_t) mi_uint5korr(after_key); break;
628
case 8: pos= (my_off_t) mi_uint4korr(after_key+4); break;
629
case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break;
630
case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break;
631
case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break;
633
case 4: pos= (my_off_t) mi_uint4korr(after_key); break;
634
case 3: pos= (my_off_t) mi_uint3korr(after_key); break;
635
case 2: pos= (my_off_t) mi_uint2korr(after_key); break;
637
pos=0L; /* Shut compiler up */
639
return (info->s->options &
640
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
641
pos*info->s->base.pack_reclength;
645
/* Calc position from a record pointer ( in delete link chain ) */
647
my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr)
650
switch (s->rec_reflength) {
653
pos= (my_off_t) mi_uint8korr(ptr);
654
if (pos == HA_OFFSET_ERROR)
655
return HA_OFFSET_ERROR; /* end of list */
658
pos= (my_off_t) mi_uint7korr(ptr);
659
if (pos == (((my_off_t) 1) << 56) -1)
660
return HA_OFFSET_ERROR; /* end of list */
663
pos= (my_off_t) mi_uint6korr(ptr);
664
if (pos == (((my_off_t) 1) << 48) -1)
665
return HA_OFFSET_ERROR; /* end of list */
668
pos= (my_off_t) mi_uint5korr(ptr);
669
if (pos == (((my_off_t) 1) << 40) -1)
670
return HA_OFFSET_ERROR; /* end of list */
677
ptr+= (s->rec_reflength-4);
681
pos= (my_off_t) mi_uint4korr(ptr);
682
if (pos == (my_off_t) (uint32) ~0L)
683
return HA_OFFSET_ERROR;
686
pos= (my_off_t) mi_uint3korr(ptr);
687
if (pos == (my_off_t) (1 << 24) -1)
688
return HA_OFFSET_ERROR;
691
pos= (my_off_t) mi_uint2korr(ptr);
692
if (pos == (my_off_t) (1 << 16) -1)
693
return HA_OFFSET_ERROR;
695
default: abort(); /* Impossible */
697
return ((s->options &
698
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos :
699
pos*s->base.pack_reclength);
703
/* save position to record */
705
void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos)
707
if (!(info->s->options &
708
(HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) &&
709
pos != HA_OFFSET_ERROR)
710
pos/=info->s->base.pack_reclength;
712
switch (info->s->rec_reflength) {
714
case 8: mi_int8store(buff,pos); break;
715
case 7: mi_int7store(buff,pos); break;
716
case 6: mi_int6store(buff,pos); break;
717
case 5: mi_int5store(buff,pos); break;
728
case 4: mi_int4store(buff,pos); break;
729
case 3: mi_int3store(buff,pos); break;
730
case 2: mi_int2store(buff,(uint) pos); break;
731
default: abort(); /* Impossible */
736
/* Get key from key-block */
737
/* page points at previous key; its advanced to point at next key */
738
/* key should contain previous key */
739
/* Returns length of found key + pointers */
740
/* nod_flag is a flag if we are on nod */
742
/* same as _mi_get_key but used with fixed length keys */
744
uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag,
745
register uchar **page, register uchar *key)
747
memcpy((uchar*) key,(uchar*) *page,
748
(size_t) (keyinfo->keylength+nod_flag));
749
*page+=keyinfo->keylength+nod_flag;
750
return(keyinfo->keylength);
751
} /* _mi_get_static_key */
755
get key witch is packed against previous key or key with a NULL column.
759
keyinfo key definition information.
760
nod_flag If nod: Length of node pointer, else zero.
761
page_pos RETURN position in key page behind this key.
762
key IN/OUT in: prev key, out: unpacked key.
765
key_length + length of data pointer
768
uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
769
register uchar **page_pos, register uchar *key)
771
register HA_KEYSEG *keyseg;
772
uchar *start_key,*page=*page_pos;
776
for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
778
if (keyseg->flag & HA_PACK_KEY)
780
/* key with length, packed to previous key */
782
uint packed= *page & 128,tot_length,rest_length;
783
if (keyseg->length >= 127)
785
length=mi_uint2korr(page) & 32767;
789
length= *page++ & 127;
793
if (length > (uint) keyseg->length)
795
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
796
my_errno=HA_ERR_CRASHED;
797
return 0; /* Error */
799
if (length == 0) /* Same key */
801
if (keyseg->flag & HA_NULL_PART)
802
*key++=1; /* Can't be NULL */
803
get_key_length(length,key);
804
key+= length; /* Same diff_key as prev */
805
if (length > keyseg->length)
808
("Found too long null packed key: %u of %u at 0x%lx",
809
length, keyseg->length, (long) *page_pos));
810
DBUG_DUMP("key",(uchar*) *page_pos,16);
811
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
812
my_errno=HA_ERR_CRASHED;
817
if (keyseg->flag & HA_NULL_PART)
819
key++; /* Skip null marker*/
823
get_key_length(rest_length,page);
824
tot_length=rest_length+length;
826
/* If the stored length has changed, we must move the key */
827
if (tot_length >= 255 && *start != 255)
829
/* length prefix changed from a length of one to a length of 3 */
830
bmove_upp(key+length+3, key+length+1, length);
832
mi_int2store(key+1,tot_length);
835
else if (tot_length < 255 && *start == 255)
837
bmove(key+1,key+3,length);
843
store_key_length_inc(key,tot_length);
846
memcpy(key,page,rest_length);
853
if (keyseg->flag & HA_NULL_PART)
855
if (!length--) /* Null part */
860
*key++=1; /* Not null */
863
if (length > (uint) keyseg->length)
865
DBUG_PRINT("error",("Found too long packed key: %u of %u at 0x%lx",
866
length, keyseg->length, (long) *page_pos));
867
DBUG_DUMP("key",(uchar*) *page_pos,16);
868
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
869
my_errno=HA_ERR_CRASHED;
870
return 0; /* Error */
872
store_key_length_inc(key,length);
876
if (keyseg->flag & HA_NULL_PART)
878
if (!(*key++ = *page++))
882
(HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
885
get_key_length(length,tmp);
886
length+=(uint) (tmp-page);
889
length=keyseg->length;
891
memcpy((uchar*) key,(uchar*) page,(size_t) length);
895
length=keyseg->length+nod_flag;
896
bmove((uchar*) key,(uchar*) page,length);
897
*page_pos= page+length;
898
return ((uint) (key-start_key)+keyseg->length);
899
} /* _mi_get_pack_key */
903
/* key that is packed relatively to previous */
905
uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag,
906
register uchar **page_pos, register uchar *key)
908
register HA_KEYSEG *keyseg;
909
uchar *start_key,*page,*page_end,*from,*from_end;
911
DBUG_ENTER("_mi_get_binary_pack_key");
914
page_end=page+MI_MAX_KEY_BUFF+1;
918
Keys are compressed the following way:
920
prefix length Packed length of prefix common with prev key (1 or 3 bytes)
921
for each key segment:
922
[is null] Null indicator if can be null (1 byte, zero means null)
923
[length] Packed length if varlength (1 or 3 bytes)
924
key segment 'length' bytes of key segment value
925
pointer Reference to the data file (last_keyseg->length).
927
get_key_length() is a macro. It gets the prefix length from 'page'
928
and puts it into 'length'. It increments 'page' by 1 or 3, depending
929
on the packed length of the prefix length.
931
get_key_length(length,page);
934
if (length > keyinfo->maxlength)
937
("Found too long binary packed key: %u of %u at 0x%lx",
938
length, keyinfo->maxlength, (long) *page_pos));
939
DBUG_DUMP("key",(uchar*) *page_pos,16);
940
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
941
my_errno=HA_ERR_CRASHED;
942
DBUG_RETURN(0); /* Wrong key */
944
/* Key is packed against prev key, take prefix from prev key. */
946
from_end= key + length;
950
/* Key is not packed against prev key, take all from page buffer. */
956
The trouble is that key can be split in two parts:
957
The first part (prefix) is in from .. from_end - 1.
958
The second part starts at page.
959
The split can be at every byte position. So we need to check for
960
the end of the first part before using every byte.
962
for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++)
964
if (keyseg->flag & HA_NULL_PART)
966
/* If prefix is used up, switch to rest. */
967
if (from == from_end) { from=page; from_end=page_end; }
968
if (!(*key++ = *from++))
969
continue; /* Null part */
971
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK))
973
/* If prefix is used up, switch to rest. */
974
if (from == from_end) { from=page; from_end=page_end; }
975
/* Get length of dynamic length key part */
976
if ((length= (*key++ = *from++)) == 255)
978
/* If prefix is used up, switch to rest. */
979
if (from == from_end) { from=page; from_end=page_end; }
980
length= (uint) ((*key++ = *from++)) << 8;
981
/* If prefix is used up, switch to rest. */
982
if (from == from_end) { from=page; from_end=page_end; }
983
length+= (uint) ((*key++ = *from++));
987
length=keyseg->length;
989
if ((tmp=(uint) (from_end-from)) <= length)
991
key+=tmp; /* Use old key */
993
from=page; from_end=page_end;
995
DBUG_PRINT("info",("key: 0x%lx from: 0x%lx length: %u",
996
(long) key, (long) from, length));
997
memmove((uchar*) key, (uchar*) from, (size_t) length);
1002
Last segment (type == 0) contains length of data pointer.
1003
If we have mixed key blocks with data pointer and key block pointer,
1004
we have to copy both.
1006
length=keyseg->length+nod_flag;
1007
if ((tmp=(uint) (from_end-from)) <= length)
1009
/* Remaining length is less or equal max possible length. */
1010
memcpy(key+tmp,page,length-tmp); /* Get last part of key */
1011
*page_pos= page+length-tmp;
1016
Remaining length is greater than max possible length.
1017
This can happen only if we switched to the new key bytes already.
1018
'page_end' is calculated with MI_MAX_KEY_BUFF. So it can be far
1019
behind the real end of the key.
1021
if (from_end != page_end)
1023
DBUG_PRINT("error",("Error when unpacking key"));
1024
mi_print_error(keyinfo->share, HA_ERR_CRASHED);
1025
my_errno=HA_ERR_CRASHED;
1026
DBUG_RETURN(0); /* Error */
1028
/* Copy data pointer and, if appropriate, key block pointer. */
1029
memcpy((uchar*) key,(uchar*) from,(size_t) length);
1030
*page_pos= from+length;
1032
DBUG_RETURN((uint) (key-start_key)+keyseg->length);
1036
/* Get key at position without knowledge of previous key */
1037
/* Returns pointer to next key */
1039
uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
1040
uchar *key, uchar *keypos, uint *return_key_length)
1043
DBUG_ENTER("_mi_get_key");
1045
nod_flag=mi_test_if_nod(page);
1046
if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1048
bmove((uchar*) key,(uchar*) keypos,keyinfo->keylength+nod_flag);
1049
DBUG_RETURN(keypos+keyinfo->keylength+nod_flag);
1054
key[0]=0; /* safety */
1055
while (page <= keypos)
1057
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
1058
if (*return_key_length == 0)
1060
mi_print_error(info->s, HA_ERR_CRASHED);
1061
my_errno=HA_ERR_CRASHED;
1066
DBUG_PRINT("exit",("page: 0x%lx length: %u", (long) page,
1067
*return_key_length));
1072
/* Get key at position without knowledge of previous key */
1073
/* Returns 0 if ok */
1075
static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
1076
uchar *key, uchar *keypos,
1077
uint *return_key_length)
1080
DBUG_ENTER("_mi_get_prev_key");
1082
nod_flag=mi_test_if_nod(page);
1083
if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1085
*return_key_length=keyinfo->keylength;
1086
bmove((uchar*) key,(uchar*) keypos- *return_key_length-nod_flag,
1087
*return_key_length);
1093
key[0]=0; /* safety */
1094
while (page < keypos)
1096
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key);
1097
if (*return_key_length == 0)
1099
mi_print_error(info->s, HA_ERR_CRASHED);
1100
my_errno=HA_ERR_CRASHED;
1110
/* Get last key from key-page */
1111
/* Return pointer to where key starts */
1113
uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page,
1114
uchar *lastkey, uchar *endpos, uint *return_key_length)
1118
DBUG_ENTER("_mi_get_last_key");
1119
DBUG_PRINT("enter",("page: 0x%lx endpos: 0x%lx", (long) page,
1122
nod_flag=mi_test_if_nod(page);
1123
if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1125
lastpos=endpos-keyinfo->keylength-nod_flag;
1126
*return_key_length=keyinfo->keylength;
1128
bmove((uchar*) lastkey,(uchar*) lastpos,keyinfo->keylength+nod_flag);
1132
lastpos=(page+=2+nod_flag);
1134
while (page < endpos)
1137
*return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,lastkey);
1138
if (*return_key_length == 0)
1140
DBUG_PRINT("error",("Couldn't find last key: page: 0x%lx",
1142
mi_print_error(info->s, HA_ERR_CRASHED);
1143
my_errno=HA_ERR_CRASHED;
1148
DBUG_PRINT("exit",("lastpos: 0x%lx length: %u", (long) lastpos,
1149
*return_key_length));
1150
DBUG_RETURN(lastpos);
1151
} /* _mi_get_last_key */
1154
/* Calculate length of key */
1156
uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key)
1158
register HA_KEYSEG *keyseg;
1161
if (! (keyinfo->flag & (HA_VAR_LENGTH_KEY | HA_BINARY_PACK_KEY)))
1162
return (keyinfo->keylength);
1165
for (keyseg=keyinfo->seg ; keyseg->type ; keyseg++)
1167
if (keyseg->flag & HA_NULL_PART)
1170
if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
1173
get_key_length(length,key);
1177
key+= keyseg->length;
1179
return((uint) (key-start)+keyseg->length);
1180
} /* _mi_keylength */
1184
Calculate length of part key.
1186
Used in mi_rkey() to find the key found for the key-part that was used.
1187
This is needed in case of multi-byte character sets where we may search
1188
after '0xDF' but find 'ss'
1191
uint _mi_keylength_part(MI_KEYDEF *keyinfo, register uchar *key,
1194
register HA_KEYSEG *keyseg;
1197
for (keyseg=keyinfo->seg ; keyseg != end ; keyseg++)
1199
if (keyseg->flag & HA_NULL_PART)
1202
if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH_PART))
1205
get_key_length(length,key);
1209
key+= keyseg->length;
1211
return (uint) (key-start);
1216
uchar *_mi_move_key(MI_KEYDEF *keyinfo, uchar *to, uchar *from)
1218
register uint length;
1219
memcpy((uchar*) to, (uchar*) from,
1220
(size_t) (length=_mi_keylength(keyinfo,from)));
1224
/* Find next/previous record with same key */
1225
/* This can't be used when database is touched after last read */
1227
int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo,
1228
uchar *key, uint key_length, uint nextflag, my_off_t pos)
1232
uchar lastkey[MI_MAX_KEY_BUFF];
1233
DBUG_ENTER("_mi_search_next");
1234
DBUG_PRINT("enter",("nextflag: %u lastpos: %lu int_keypos: %lu",
1235
nextflag, (ulong) info->lastpos,
1236
(ulong) info->int_keypos));
1237
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_length););
1239
/* Force full read if we are at last key or if we are not on a leaf
1240
and the key tree has changed since we used it last time
1241
Note that even if the key tree has changed since last read, we can use
1242
the last read data from the leaf if we haven't used the buffer for
1246
if (((nextflag & SEARCH_BIGGER) && info->int_keypos >= info->int_maxpos) ||
1247
info->page_changed ||
1248
(info->int_keytree_version != keyinfo->version &&
1249
(info->int_nod_flag || info->buff_used)))
1250
DBUG_RETURN(_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
1251
nextflag | SEARCH_SAVE_BUFF, pos));
1253
if (info->buff_used)
1255
if (!_mi_fetch_keypage(info,keyinfo,info->last_search_keypage,
1256
DFLT_INIT_HITS,info->buff,0))
1261
/* Last used buffer is in info->buff */
1262
nod_flag=mi_test_if_nod(info->buff);
1264
if (nextflag & SEARCH_BIGGER) /* Next key */
1266
my_off_t tmp_pos=_mi_kpos(nod_flag,info->int_keypos);
1267
if (tmp_pos != HA_OFFSET_ERROR)
1269
if ((error=_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
1270
nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0)
1273
memcpy(lastkey,key,key_length);
1274
if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,
1275
&info->int_keypos,lastkey)))
1278
else /* Previous key */
1281
/* Find start of previous key */
1282
info->int_keypos=_mi_get_last_key(info,keyinfo,info->buff,lastkey,
1283
info->int_keypos, &length);
1284
if (!info->int_keypos)
1286
if (info->int_keypos == info->buff+2)
1287
DBUG_RETURN(_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
1288
nextflag | SEARCH_SAVE_BUFF, pos));
1289
if ((error=_mi_search(info,keyinfo,key, USE_WHOLE_KEY,
1290
nextflag | SEARCH_SAVE_BUFF,
1291
_mi_kpos(nod_flag,info->int_keypos))) <= 0)
1294
/* QQ: We should be able to optimize away the following call */
1295
if (! _mi_get_last_key(info,keyinfo,info->buff,lastkey,
1296
info->int_keypos,&info->lastkey_length))
1299
memcpy(info->lastkey,lastkey,info->lastkey_length);
1300
info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
1301
DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos));
1303
} /* _mi_search_next */
1306
/* Search after position for the first row in an index */
1307
/* This is stored in info->lastpos */
1309
int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo,
1310
register my_off_t pos)
1314
DBUG_ENTER("_mi_search_first");
1316
if (pos == HA_OFFSET_ERROR)
1318
my_errno=HA_ERR_KEY_NOT_FOUND;
1319
info->lastpos= HA_OFFSET_ERROR;
1325
if (!_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,info->buff,0))
1327
info->lastpos= HA_OFFSET_ERROR;
1330
nod_flag=mi_test_if_nod(info->buff);
1331
page=info->buff+2+nod_flag;
1332
} while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
1334
if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,
1336
DBUG_RETURN(-1); /* Crashed */
1338
info->int_keypos=page; info->int_maxpos=info->buff+mi_getint(info->buff)-1;
1339
info->int_nod_flag=nod_flag;
1340
info->int_keytree_version=keyinfo->version;
1341
info->last_search_keypage=info->last_keypage;
1342
info->page_changed=info->buff_used=0;
1343
info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
1345
DBUG_PRINT("exit",("found key at %lu", (ulong) info->lastpos));
1347
} /* _mi_search_first */
1350
/* Search after position for the last row in an index */
1351
/* This is stored in info->lastpos */
1353
int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo,
1354
register my_off_t pos)
1358
DBUG_ENTER("_mi_search_last");
1360
if (pos == HA_OFFSET_ERROR)
1362
my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */
1363
info->lastpos= HA_OFFSET_ERROR;
1370
if (!_mi_fetch_keypage(info,keyinfo,pos,DFLT_INIT_HITS,buff,0))
1372
info->lastpos= HA_OFFSET_ERROR;
1375
page= buff+mi_getint(buff);
1376
nod_flag=mi_test_if_nod(buff);
1377
} while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR);
1379
if (!_mi_get_last_key(info,keyinfo,buff,info->lastkey,page,
1380
&info->lastkey_length))
1382
info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length);
1383
info->int_keypos=info->int_maxpos=page;
1384
info->int_nod_flag=nod_flag;
1385
info->int_keytree_version=keyinfo->version;
1386
info->last_search_keypage=info->last_keypage;
1387
info->page_changed=info->buff_used=0;
1389
DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos));
1391
} /* _mi_search_last */
1395
/****************************************************************************
1397
** Functions to store and pack a key in a page
1399
** mi_calc_xx_key_length takes the following arguments:
1400
** nod_flag If nod: Length of nod-pointer
1401
** next_key Position to pos after the new key in buffer
1402
** org_key Key that was before the next key in buffer
1403
** prev_key Last key before current key
1404
** key Key that will be stored
1405
** s_temp Information how next key will be packed
1406
****************************************************************************/
1408
/* Static length key */
1411
_mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
1412
uchar *next_pos __attribute__((unused)),
1413
uchar *org_key __attribute__((unused)),
1414
uchar *prev_key __attribute__((unused)),
1415
uchar *key, MI_KEY_PARAM *s_temp)
1418
return (int) (s_temp->totlength=keyinfo->keylength+nod_flag);
1421
/* Variable length key */
1424
_mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag,
1425
uchar *next_pos __attribute__((unused)),
1426
uchar *org_key __attribute__((unused)),
1427
uchar *prev_key __attribute__((unused)),
1428
uchar *key, MI_KEY_PARAM *s_temp)
1431
return (int) (s_temp->totlength=_mi_keylength(keyinfo,key)+nod_flag);
1435
length of key with a variable length first segment which is prefix
1436
compressed (myisamchk reports 'packed + stripped')
1438
Keys are compressed the following way:
1440
If the max length of first key segment <= 127 bytes the prefix is
1441
1 byte else it's 2 byte
1443
prefix byte(s) The high bit is set if this is a prefix for the prev key
1444
length Packed length if the previous was a prefix byte
1445
[length] data bytes ('length' bytes)
1446
next-key-seg Next key segments
1448
If the first segment can have NULL:
1449
The length is 0 for NULLS and 1+length for not null columns.
1454
_mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
1455
uchar *org_key, uchar *prev_key, uchar *key,
1456
MI_KEY_PARAM *s_temp)
1458
register HA_KEYSEG *keyseg;
1460
uint key_length,ref_length,org_key_length=0,
1461
length_pack,new_key_length,diff_flag,pack_marker;
1462
uchar *start,*end,*key_end,*sort_order;
1463
my_bool same_length;
1465
length_pack=s_temp->ref_length=s_temp->n_ref_length=s_temp->n_length=0;
1466
same_length=0; keyseg=keyinfo->seg;
1467
key_length=_mi_keylength(keyinfo,key)+nod_flag;
1470
if ((keyinfo->flag & HA_FULLTEXT) &&
1471
((keyseg->type == HA_KEYTYPE_TEXT) ||
1472
(keyseg->type == HA_KEYTYPE_VARTEXT1) ||
1473
(keyseg->type == HA_KEYTYPE_VARTEXT2)) &&
1474
!use_strnxfrm(keyseg->charset))
1475
sort_order=keyseg->charset->sort_order;
1477
/* diff flag contains how many bytes is needed to pack key */
1478
if (keyseg->length >= 127)
1488
s_temp->pack_marker=pack_marker;
1490
/* Handle the case that the first part have NULL values */
1491
if (keyseg->flag & HA_NULL_PART)
1496
s_temp->key_length= 0;
1497
s_temp->totlength=key_length-1+diff_flag;
1498
s_temp->next_key_pos=0; /* No next key */
1499
return (s_temp->totlength);
1501
s_temp->store_not_null=1;
1502
key_length--; /* We don't store NULL */
1503
if (prev_key && !*prev_key++)
1504
org_key=prev_key=0; /* Can't pack against prev */
1506
org_key++; /* Skip NULL */
1509
s_temp->store_not_null=0;
1510
s_temp->prev_key=org_key;
1512
/* The key part will start with a packed length */
1514
get_key_pack_length(new_key_length,length_pack,key);
1515
end=key_end= key+ new_key_length;
1518
/* Calc how many characters are identical between this and the prev. key */
1521
get_key_length(org_key_length,prev_key);
1522
s_temp->prev_key=prev_key; /* Pointer at data */
1523
/* Don't use key-pack if length == 0 */
1524
if (new_key_length && new_key_length == org_key_length)
1526
else if (new_key_length > org_key_length)
1527
end=key + org_key_length;
1529
if (sort_order) /* SerG */
1531
while (key < end && sort_order[*key] == sort_order[*prev_key])
1538
while (key < end && *key == *prev_key)
1546
s_temp->key_length= (uint) (key_end-key);
1548
if (same_length && key == key_end)
1550
/* identical variable length key */
1551
s_temp->ref_length= pack_marker;
1552
length=(int) key_length-(int) (key_end-start)-length_pack;
1555
{ /* Can't combine with next */
1556
s_temp->n_length= *next_key; /* Needed by _mi_store_key */
1563
{ /* Starts as prev key */
1564
ref_length= (uint) (key-start);
1565
s_temp->ref_length= ref_length + pack_marker;
1566
length= (int) (key_length - ref_length);
1568
length-= length_pack;
1570
length+= ((new_key_length-ref_length) >= 255) ? 3 : 1;/* Rest_of_key */
1574
s_temp->key_length+=s_temp->store_not_null; /* If null */
1575
length= key_length - length_pack+ diff_flag;
1578
s_temp->totlength=(uint) length;
1579
s_temp->prev_length=0;
1580
DBUG_PRINT("test",("tot_length: %u length: %d uniq_key_length: %u",
1581
key_length, length, s_temp->key_length));
1583
/* If something after that hasn't length=0, test if we can combine */
1584
if ((s_temp->next_key_pos=next_key))
1586
uint packed,n_length;
1588
packed = *next_key & 128;
1591
n_length= mi_uint2korr(next_key) & 32767; /* Length of next key */
1595
n_length= *next_key++ & 127;
1597
n_length-= s_temp->store_not_null;
1599
if (n_length || packed) /* Don't pack 0 length keys */
1601
uint next_length_pack, new_ref_length=s_temp->ref_length;
1605
/* If first key and next key is packed (only on delete) */
1606
if (!prev_key && org_key)
1608
get_key_length(org_key_length,org_key);
1610
if (sort_order) /* SerG */
1612
while (key < end && sort_order[*key] == sort_order[*org_key])
1619
while (key < end && *key == *org_key)
1624
if ((new_ref_length= (uint) (key - start)))
1625
new_ref_length+=pack_marker;
1631
We put a different key between two identical variable length keys
1632
Extend next key to have same prefix as this key
1634
if (new_ref_length) /* prefix of previus key */
1635
{ /* make next key longer */
1636
s_temp->part_of_prev_key= new_ref_length;
1637
s_temp->prev_length= org_key_length -
1638
(new_ref_length-pack_marker);
1639
s_temp->n_ref_length= s_temp->part_of_prev_key;
1640
s_temp->n_length= s_temp->prev_length;
1641
n_length= get_pack_length(s_temp->prev_length);
1642
s_temp->prev_key+= (new_ref_length - pack_marker);
1643
length+= s_temp->prev_length + n_length;
1646
{ /* Can't use prev key */
1647
s_temp->part_of_prev_key=0;
1648
s_temp->prev_length= org_key_length;
1649
s_temp->n_ref_length=s_temp->n_length= org_key_length;
1650
length+= org_key_length;
1652
return (int) length;
1655
ref_length=n_length;
1656
/* Get information about not packed key suffix */
1657
get_key_pack_length(n_length,next_length_pack,next_key);
1659
/* Test if new keys has fewer characters that match the previous key */
1660
if (!new_ref_length)
1661
{ /* Can't use prev key */
1662
s_temp->part_of_prev_key= 0;
1663
s_temp->prev_length= ref_length;
1664
s_temp->n_ref_length= s_temp->n_length= n_length+ref_length;
1665
return (int) length+ref_length-next_length_pack;
1667
if (ref_length+pack_marker > new_ref_length)
1669
uint new_pack_length=new_ref_length-pack_marker;
1670
/* We must copy characters from the original key to the next key */
1671
s_temp->part_of_prev_key= new_ref_length;
1672
s_temp->prev_length= ref_length - new_pack_length;
1673
s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length;
1674
s_temp->prev_key+= new_pack_length;
1675
length-= (next_length_pack - get_pack_length(s_temp->n_length));
1676
return (int) length + s_temp->prev_length;
1681
/* Next key wasn't a prefix of previous key */
1685
DBUG_PRINT("test",("length: %d next_key: 0x%lx", length,
1690
key=(start+=ref_length);
1691
if (key+n_length < key_end) /* Normalize length based */
1692
key_end=key+n_length;
1693
if (sort_order) /* SerG */
1695
while (key < key_end && sort_order[*key] ==
1696
sort_order[*next_key])
1703
while (key < key_end && *key == *next_key)
1708
if (!(tmp_length=(uint) (key-start)))
1709
{ /* Key can't be re-packed */
1710
s_temp->next_key_pos=0;
1713
ref_length+=tmp_length;
1714
n_length-=tmp_length;
1715
length-=tmp_length+next_length_pack; /* We gained these chars */
1717
if (n_length == 0 && ref_length == new_key_length)
1719
s_temp->n_ref_length=pack_marker; /* Same as prev key */
1723
s_temp->n_ref_length=ref_length | pack_marker;
1724
length+= get_pack_length(n_length);
1725
s_temp->n_length=n_length;
1733
/* Length of key which is prefix compressed */
1736
_mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key,
1737
uchar *org_key, uchar *prev_key, uchar *key,
1738
MI_KEY_PARAM *s_temp)
1740
uint length,key_length,ref_length;
1742
s_temp->totlength=key_length=_mi_keylength(keyinfo,key)+nod_flag;
1744
s_temp->n_length= s_temp->n_ref_length=0; /* For valgrind */
1747
s_temp->prev_key=org_key;
1748
if (prev_key) /* If not first key in block */
1750
/* pack key against previous key */
1752
As keys may be identical when running a sort in myisamchk, we
1753
have to guard against the case where keys may be identical
1757
for ( ; *key == *prev_key && key < end; key++,prev_key++) ;
1758
s_temp->ref_length= ref_length=(uint) (key-s_temp->key);
1759
length=key_length - ref_length + get_pack_length(ref_length);
1763
/* No previous key */
1764
s_temp->ref_length=ref_length=0;
1765
length=key_length+1;
1767
if ((s_temp->next_key_pos=next_key)) /* If another key after */
1769
/* pack key against next key */
1770
uint next_length,next_length_pack;
1771
get_key_pack_length(next_length,next_length_pack,next_key);
1773
/* If first key and next key is packed (only on delete) */
1774
if (!prev_key && org_key && next_length)
1777
for (key= s_temp->key, end=key+next_length ;
1778
*key == *org_key && key < end;
1780
ref_length= (uint) (key - s_temp->key);
1783
if (next_length > ref_length)
1785
/* We put a key with different case between two keys with the same prefix
1786
Extend next key to have same prefix as
1788
s_temp->n_ref_length= ref_length;
1789
s_temp->prev_length= next_length-ref_length;
1790
s_temp->prev_key+= ref_length;
1791
return (int) (length+ s_temp->prev_length - next_length_pack +
1792
get_pack_length(ref_length));
1794
/* Check how many characters are identical to next key */
1795
key= s_temp->key+next_length;
1796
while (*key++ == *next_key++) ;
1797
if ((ref_length= (uint) (key - s_temp->key)-1) == next_length)
1799
s_temp->next_key_pos=0;
1800
return length; /* can't pack next key */
1802
s_temp->prev_length=0;
1803
s_temp->n_ref_length=ref_length;
1804
return (int) (length-(ref_length - next_length) - next_length_pack +
1805
get_pack_length(ref_length));
1807
return (int) length;
1812
** store a key packed with _mi_calc_xxx_key_length in page-buffert
1815
/* store key without compression */
1817
void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)),
1818
register uchar *key_pos,
1819
register MI_KEY_PARAM *s_temp)
1821
memcpy((uchar*) key_pos,(uchar*) s_temp->key,(size_t) s_temp->totlength);
1825
/* store variable length key with prefix compression */
1827
#define store_pack_length(test,pos,length) { \
1828
if (test) { *((pos)++) = (uchar) (length); } else \
1829
{ *((pos)++) = (uchar) ((length) >> 8); *((pos)++) = (uchar) (length); } }
1832
void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
1833
register uchar *key_pos,
1834
register MI_KEY_PARAM *s_temp)
1841
if (s_temp->ref_length)
1843
/* Packed against previous key */
1844
store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->ref_length);
1845
/* If not same key after */
1846
if (s_temp->ref_length != s_temp->pack_marker)
1847
store_key_length_inc(key_pos,s_temp->key_length);
1851
/* Not packed against previous key */
1852
store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->key_length);
1854
bmove((uchar*) key_pos,(uchar*) s_temp->key,
1855
(length=s_temp->totlength-(uint) (key_pos-start)));
1857
if (!s_temp->next_key_pos) /* No following key */
1861
if (s_temp->prev_length)
1863
/* Extend next key because new key didn't have same prefix as prev key */
1864
if (s_temp->part_of_prev_key)
1866
store_pack_length(s_temp->pack_marker == 128,key_pos,
1867
s_temp->part_of_prev_key);
1868
store_key_length_inc(key_pos,s_temp->n_length);
1872
s_temp->n_length+= s_temp->store_not_null;
1873
store_pack_length(s_temp->pack_marker == 128,key_pos,
1876
memcpy(key_pos, s_temp->prev_key, s_temp->prev_length);
1878
else if (s_temp->n_ref_length)
1880
store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_ref_length);
1881
if (s_temp->n_ref_length == s_temp->pack_marker)
1882
return; /* Identical key */
1883
store_key_length(key_pos,s_temp->n_length);
1887
s_temp->n_length+= s_temp->store_not_null;
1888
store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_length);
1893
/* variable length key with prefix compression */
1895
void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)),
1896
register uchar *key_pos,
1897
register MI_KEY_PARAM *s_temp)
1899
store_key_length_inc(key_pos,s_temp->ref_length);
1900
memcpy((char*) key_pos,(char*) s_temp->key+s_temp->ref_length,
1901
(size_t) s_temp->totlength-s_temp->ref_length);
1903
if (s_temp->next_key_pos)
1905
key_pos+=(uint) (s_temp->totlength-s_temp->ref_length);
1906
store_key_length_inc(key_pos,s_temp->n_ref_length);
1907
if (s_temp->prev_length) /* If we must extend key */
1909
memcpy(key_pos,s_temp->prev_key,s_temp->prev_length);