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
/* The hash functions used for saveing keys */
18
#include "heap_priv.h"
20
#include "drizzled/charset_info.h"
21
#include <drizzled/util/test.h>
28
using namespace drizzled;
30
static uint32_t hp_hashnr(register HP_KEYDEF *keydef, register const unsigned char *key);
31
static int hp_key_cmp(HP_KEYDEF *keydef, const unsigned char *rec, const unsigned char *key);
34
Find out how many rows there is in the given range
37
hp_rb_records_in_range()
40
min_key Min key. Is = 0 if no min range
41
max_key Max key. Is = 0 if no max range
44
min_key.flag can have one of the following values:
45
HA_READ_KEY_EXACT Include the key in the range
46
HA_READ_AFTER_KEY Don't include key in range
48
max_key.flag can have one of the following values:
49
HA_READ_BEFORE_KEY Don't include key in range
50
HA_READ_AFTER_KEY Include all 'end_key' values in the range
53
HA_POS_ERROR Something is wrong with the index tree.
54
0 There is no matching keys in the given range
55
number > 0 There is approximately 'number' matching rows in
59
ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key,
62
ha_rows start_pos, end_pos;
63
HP_KEYDEF *keyinfo= info->s->keydef + inx;
64
TREE *rb_tree = &keyinfo->rb_tree;
65
heap_rb_param custom_arg;
68
custom_arg.keyseg= keyinfo->seg;
69
custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME;
72
custom_arg.key_length= hp_rb_pack_key(keyinfo, (unsigned char*) info->recbuf,
73
(unsigned char*) min_key->key,
74
min_key->keypart_map);
75
start_pos= tree_record_pos(rb_tree, info->recbuf, min_key->flag,
85
custom_arg.key_length= hp_rb_pack_key(keyinfo, (unsigned char*) info->recbuf,
86
(unsigned char*) max_key->key,
87
max_key->keypart_map);
88
end_pos= tree_record_pos(rb_tree, info->recbuf, max_key->flag,
93
end_pos= rb_tree->elements_in_tree + (ha_rows)1;
96
if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR)
98
return(end_pos < start_pos ? (ha_rows) 0 :
99
(end_pos == start_pos ? (ha_rows) 1 : end_pos - start_pos));
103
/* Search after a record based on a key */
104
/* Sets info->current_ptr to found record */
105
/* next_flag: Search=0, next=1, prev =2, same =3 */
107
unsigned char *hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const unsigned char *key,
110
register HASH_INFO *pos,*prev_ptr;
112
uint32_t old_nextflag;
113
HP_SHARE *share=info->s;
114
old_nextflag=nextflag;
120
pos=hp_find_hash(&keyinfo->block, hp_mask(hp_hashnr(keyinfo, key),
121
share->blength, share->records));
124
if (!hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
127
case 0: /* Search after key */
128
info->current_hash_ptr=pos;
129
return(info->current_ptr= pos->ptr_to_rec);
130
case 1: /* Search next */
131
if (pos->ptr_to_rec == info->current_ptr)
134
case 2: /* Search previous */
135
if (pos->ptr_to_rec == info->current_ptr)
137
errno=HA_ERR_KEY_NOT_FOUND; /* If gpos == 0 */
138
info->current_hash_ptr=prev_ptr;
139
return(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
141
prev_ptr=pos; /* Prev. record found */
143
case 3: /* Search same */
144
if (pos->ptr_to_rec == info->current_ptr)
146
info->current_hash_ptr=pos;
147
return(info->current_ptr);
153
flag=0; /* Reset flag */
154
if (hp_find_hash(&keyinfo->block,
155
hp_mask(hp_rec_hashnr(keyinfo, pos->ptr_to_rec),
156
share->blength, share->records)) != pos)
157
break; /* Wrong link */
160
while ((pos=pos->next_key));
162
errno=HA_ERR_KEY_NOT_FOUND;
163
if (nextflag == 2 && ! info->current_ptr)
165
/* Do a previous from end */
166
info->current_hash_ptr=prev_ptr;
167
return(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
170
if (old_nextflag && nextflag)
171
errno=HA_ERR_RECORD_CHANGED; /* Didn't find old record */
172
info->current_hash_ptr=0;
173
return((info->current_ptr= 0));
178
Search next after last read; Assumes that the table hasn't changed
182
unsigned char *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const unsigned char *key,
185
while ((pos= pos->next_key))
187
if (! hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
189
info->current_hash_ptr=pos;
190
return (info->current_ptr= pos->ptr_to_rec);
193
errno=HA_ERR_KEY_NOT_FOUND;
194
info->current_hash_ptr=0;
195
return ((info->current_ptr= 0));
200
Calculate position number for hash value.
204
buffmax Value such that
205
2^(n-1) < maxlength <= 2^n = buffmax
209
Array index, in [0..maxlength)
212
uint32_t hp_mask(uint32_t hashnr, uint32_t buffmax, uint32_t maxlength)
214
if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
215
return (hashnr & ((buffmax >> 1) -1));
221
next_link -> ... -> X -> pos
223
next_link -> ... -> X -> newlink
226
void hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink)
233
while ((next_link=next_link->next_key) != pos);
234
old_link->next_key=newlink;
238
/* Calc hashvalue for a key */
240
static uint32_t hp_hashnr(register HP_KEYDEF *keydef, register const unsigned char *key)
243
uint32_t nr=1, nr2=4;
244
HA_KEYSEG *seg,*endseg;
246
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
248
unsigned char *pos=(unsigned char*) key;
252
key++; /* Skip null byte */
253
if (*pos) /* Found null */
256
/* Add key pack length (2) to key for VARCHAR segments */
257
if (seg->type == HA_KEYTYPE_VARTEXT1)
263
if (seg->type == HA_KEYTYPE_TEXT)
265
const CHARSET_INFO * const cs= seg->charset;
266
uint32_t length= seg->length;
267
if (cs->mbmaxlen > 1)
269
uint32_t char_length;
270
char_length= my_charpos(cs, pos, pos + length, length/cs->mbmaxlen);
271
set_if_smaller(length, char_length);
273
cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
275
else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
277
const CHARSET_INFO * const cs= seg->charset;
278
uint32_t pack_length= 2; /* Key packing is constant */
279
uint32_t length= uint2korr(pos);
280
if (cs->mbmaxlen > 1)
282
uint32_t char_length;
283
char_length= my_charpos(cs, pos +pack_length,
284
pos +pack_length + length,
285
seg->length/cs->mbmaxlen);
286
set_if_smaller(length, char_length);
288
cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
293
for (; pos < (unsigned char*) key ; pos++)
295
nr^=(uint32_t) ((((uint) nr & 63)+nr2)*((uint) *pos)) + (nr << 8);
300
return((uint32_t) nr);
303
/* Calc hashvalue for a key in a record */
305
uint32_t hp_rec_hashnr(register HP_KEYDEF *keydef, register const unsigned char *rec)
307
uint32_t nr=1, nr2=4;
308
HA_KEYSEG *seg,*endseg;
310
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
312
unsigned char *pos=(unsigned char*) rec+seg->start,*end=pos+seg->length;
315
if (rec[seg->null_pos] & seg->null_bit)
321
if (seg->type == HA_KEYTYPE_TEXT)
323
const CHARSET_INFO * const cs= seg->charset;
324
uint32_t char_length= seg->length;
325
if (cs->mbmaxlen > 1)
327
char_length= my_charpos(cs, pos, pos + char_length,
328
char_length / cs->mbmaxlen);
329
set_if_smaller(char_length, (uint32_t)seg->length); /* QQ: ok to remove? */
331
cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
333
else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
335
const CHARSET_INFO * const cs= seg->charset;
336
uint32_t pack_length= seg->bit_start;
337
uint32_t length= (pack_length == 1 ? (uint) *(unsigned char*) pos : uint2korr(pos));
338
if (cs->mbmaxlen > 1)
340
uint32_t char_length;
341
char_length= my_charpos(cs, pos + pack_length,
342
pos + pack_length + length,
343
seg->length/cs->mbmaxlen);
344
set_if_smaller(length, char_length);
346
cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
350
for (; pos < end ; pos++)
352
nr^=(uint32_t) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
361
Compare keys for two records. Returns 0 if they are identical
365
keydef Key definition
366
rec1 Record to compare
367
rec2 Other record to compare
368
diff_if_only_endspace_difference
369
Different number of end space is significant
372
diff_if_only_endspace_difference is used to allow us to insert
373
'a' and 'a ' when there is an an unique key.
380
int hp_rec_key_cmp(HP_KEYDEF *keydef, const unsigned char *rec1, const unsigned char *rec2,
381
bool diff_if_only_endspace_difference)
383
HA_KEYSEG *seg,*endseg;
385
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
389
if ((rec1[seg->null_pos] & seg->null_bit) !=
390
(rec2[seg->null_pos] & seg->null_bit))
392
if (rec1[seg->null_pos] & seg->null_bit)
395
if (seg->type == HA_KEYTYPE_TEXT)
397
const CHARSET_INFO * const cs= seg->charset;
398
uint32_t char_length1;
399
uint32_t char_length2;
400
unsigned char *pos1= (unsigned char*)rec1 + seg->start;
401
unsigned char *pos2= (unsigned char*)rec2 + seg->start;
402
if (cs->mbmaxlen > 1)
404
uint32_t char_length= seg->length / cs->mbmaxlen;
405
char_length1= my_charpos(cs, pos1, pos1 + seg->length, char_length);
406
set_if_smaller(char_length1, (uint32_t)seg->length);
407
char_length2= my_charpos(cs, pos2, pos2 + seg->length, char_length);
408
set_if_smaller(char_length2, (uint32_t)seg->length);
412
char_length1= char_length2= seg->length;
414
if (seg->charset->coll->strnncollsp(seg->charset,
416
pos2,char_length2, 0))
419
else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
421
unsigned char *pos1= (unsigned char*) rec1 + seg->start;
422
unsigned char *pos2= (unsigned char*) rec2 + seg->start;
423
uint32_t char_length1, char_length2;
424
uint32_t pack_length= seg->bit_start;
425
const CHARSET_INFO * const cs= seg->charset;
426
if (pack_length == 1)
428
char_length1= (uint) *(unsigned char*) pos1++;
429
char_length2= (uint) *(unsigned char*) pos2++;
433
char_length1= uint2korr(pos1);
434
char_length2= uint2korr(pos2);
438
if (cs->mbmaxlen > 1)
440
uint32_t safe_length1= char_length1;
441
uint32_t safe_length2= char_length2;
442
uint32_t char_length= seg->length / cs->mbmaxlen;
443
char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length);
444
set_if_smaller(char_length1, safe_length1);
445
char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length);
446
set_if_smaller(char_length2, safe_length2);
449
if (cs->coll->strnncollsp(seg->charset,
452
seg->flag & HA_END_SPACE_ARE_EQUAL ?
453
0 : diff_if_only_endspace_difference))
458
if (memcmp(rec1+seg->start,rec2+seg->start,seg->length))
465
/* Compare a key in a record to a whole key */
467
static int hp_key_cmp(HP_KEYDEF *keydef, const unsigned char *rec, const unsigned char *key)
469
HA_KEYSEG *seg,*endseg;
471
for (seg=keydef->seg,endseg=seg+keydef->keysegs ;
473
key+= (seg++)->length)
477
int found_null=test(rec[seg->null_pos] & seg->null_bit);
478
if (found_null != (int) *key++)
482
/* Add key pack length (2) to key for VARCHAR segments */
483
if (seg->type == HA_KEYTYPE_VARTEXT1)
488
if (seg->type == HA_KEYTYPE_TEXT)
490
const CHARSET_INFO * const cs= seg->charset;
491
uint32_t char_length_key;
492
uint32_t char_length_rec;
493
unsigned char *pos= (unsigned char*) rec + seg->start;
494
if (cs->mbmaxlen > 1)
496
uint32_t char_length= seg->length / cs->mbmaxlen;
497
char_length_key= my_charpos(cs, key, key + seg->length, char_length);
498
set_if_smaller(char_length_key, (uint32_t)seg->length);
499
char_length_rec= my_charpos(cs, pos, pos + seg->length, char_length);
500
set_if_smaller(char_length_rec, (uint32_t)seg->length);
504
char_length_key= seg->length;
505
char_length_rec= seg->length;
508
if (seg->charset->coll->strnncollsp(seg->charset,
509
(unsigned char*) pos, char_length_rec,
510
(unsigned char*) key, char_length_key, 0))
513
else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
515
unsigned char *pos= (unsigned char*) rec + seg->start;
516
const CHARSET_INFO * const cs= seg->charset;
517
uint32_t pack_length= seg->bit_start;
518
uint32_t char_length_rec= (pack_length == 1 ? (uint) *(unsigned char*) pos :
520
/* Key segments are always packed with 2 bytes */
521
uint32_t char_length_key= uint2korr(key);
523
key+= 2; /* skip key pack length */
524
if (cs->mbmaxlen > 1)
526
uint32_t char_length1, char_length2;
527
char_length1= char_length2= seg->length / cs->mbmaxlen;
528
char_length1= my_charpos(cs, key, key + char_length_key, char_length1);
529
set_if_smaller(char_length_key, char_length1);
530
char_length2= my_charpos(cs, pos, pos + char_length_rec, char_length2);
531
set_if_smaller(char_length_rec, char_length2);
534
if (cs->coll->strnncollsp(seg->charset,
535
(unsigned char*) pos, char_length_rec,
536
(unsigned char*) key, char_length_key, 0))
541
if (memcmp(rec+seg->start,key,seg->length))
549
/* Copy a key from a record to a keybuffer */
551
void hp_make_key(HP_KEYDEF *keydef, unsigned char *key, const unsigned char *rec)
553
HA_KEYSEG *seg,*endseg;
555
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
557
const CHARSET_INFO * const cs= seg->charset;
558
uint32_t char_length= seg->length;
559
unsigned char *pos= (unsigned char*) rec + seg->start;
561
*key++= test(rec[seg->null_pos] & seg->null_bit);
562
if (cs->mbmaxlen > 1)
564
char_length= my_charpos(cs, pos, pos + seg->length,
565
char_length / cs->mbmaxlen);
566
set_if_smaller(char_length, (uint32_t)seg->length); /* QQ: ok to remove? */
568
if (seg->type == HA_KEYTYPE_VARTEXT1)
569
char_length+= seg->bit_start; /* Copy also length */
570
memcpy(key,rec+seg->start,(size_t) char_length);
575
#define FIX_LENGTH(cs, pos, length, char_length) \
577
if (length > char_length) \
578
char_length= my_charpos(cs, pos, pos+length, char_length); \
579
set_if_smaller(char_length,length); \
583
uint32_t hp_rb_make_key(HP_KEYDEF *keydef, unsigned char *key,
584
const unsigned char *rec, unsigned char *recpos)
586
unsigned char *start_key= key;
587
HA_KEYSEG *seg, *endseg;
589
for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
591
uint32_t char_length;
594
if (!(*key++= 1 - test(rec[seg->null_pos] & seg->null_bit)))
597
if (seg->flag & HA_SWAP_KEY)
599
uint32_t length= seg->length;
600
unsigned char *pos= (unsigned char*) rec + seg->start;
602
if (seg->type == HA_KEYTYPE_DOUBLE)
608
memset(key, 0, length);
621
if (seg->flag & HA_VAR_LENGTH_PART)
623
unsigned char *pos= (unsigned char*) rec + seg->start;
624
uint32_t length= seg->length;
625
uint32_t pack_length= seg->bit_start;
626
uint32_t tmp_length= (pack_length == 1 ? (uint) *(unsigned char*) pos :
628
const CHARSET_INFO * const cs= seg->charset;
629
char_length= length/cs->mbmaxlen;
631
pos+= pack_length; /* Skip VARCHAR length */
632
set_if_smaller(length,tmp_length);
633
FIX_LENGTH(cs, pos, length, char_length);
634
store_key_length_inc(key,char_length);
635
memcpy(key,pos,(size_t) char_length);
640
char_length= seg->length;
641
if (seg->charset->mbmaxlen > 1)
643
char_length= my_charpos(seg->charset,
644
rec + seg->start, rec + seg->start + char_length,
645
char_length / seg->charset->mbmaxlen);
646
set_if_smaller(char_length, (uint32_t)seg->length); /* QQ: ok to remove? */
647
if (char_length < seg->length)
648
seg->charset->cset->fill(seg->charset, (char*) key + char_length,
649
seg->length - char_length, ' ');
651
memcpy(key, rec + seg->start, (size_t) char_length);
654
memcpy(key, &recpos, sizeof(unsigned char*));
655
return (uint32_t) (key - start_key);
659
uint32_t hp_rb_pack_key(HP_KEYDEF *keydef, unsigned char *key, const unsigned char *old,
660
key_part_map keypart_map)
662
HA_KEYSEG *seg, *endseg;
663
unsigned char *start_key= key;
665
for (seg= keydef->seg, endseg= seg + keydef->keysegs;
666
seg < endseg && keypart_map; old+= seg->length, seg++)
668
uint32_t char_length;
672
if (!(*key++= (char) 1 - *old++))
675
if (seg->flag & HA_SWAP_KEY)
677
uint32_t length= seg->length;
678
unsigned char *pos= (unsigned char*) old + length;
686
if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
688
/* Length of key-part used with heap_rkey() always 2 */
689
uint32_t tmp_length=uint2korr(old);
690
uint32_t length= seg->length;
691
const CHARSET_INFO * const cs= seg->charset;
692
char_length= length/cs->mbmaxlen;
695
set_if_smaller(length,tmp_length); /* Safety */
696
FIX_LENGTH(cs, old, length, char_length);
697
store_key_length_inc(key,char_length);
698
memcpy(key, old,(size_t) char_length);
702
char_length= seg->length;
703
if (seg->charset->mbmaxlen > 1)
705
char_length= my_charpos(seg->charset, old, old+char_length,
706
char_length / seg->charset->mbmaxlen);
707
set_if_smaller(char_length, (uint32_t)seg->length); /* QQ: ok to remove? */
708
if (char_length < seg->length)
709
seg->charset->cset->fill(seg->charset, (char*) key + char_length,
710
seg->length - char_length, ' ');
712
memcpy(key, old, (size_t) char_length);
715
return (uint) (key - start_key);
719
uint32_t hp_rb_key_length(HP_KEYDEF *keydef, const unsigned char *not_used)
722
return keydef->length;
726
uint32_t hp_rb_null_key_length(HP_KEYDEF *keydef, const unsigned char *key)
728
const unsigned char *start_key= key;
729
HA_KEYSEG *seg, *endseg;
731
for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
733
if (seg->null_bit && !*key++)
737
return (uint) (key - start_key);
741
uint32_t hp_rb_var_key_length(HP_KEYDEF *keydef, const unsigned char *key)
743
const unsigned char *start_key= key;
744
HA_KEYSEG *seg, *endseg;
746
for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
748
uint32_t length= seg->length;
749
if (seg->null_bit && !*key++)
751
if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
753
get_key_length(length, key);
757
return (uint) (key - start_key);
762
Test if any of the key parts are NULL.
764
1 if any of the key parts was NULL
768
bool hp_if_null_in_key(HP_KEYDEF *keydef, const unsigned char *record)
770
HA_KEYSEG *seg,*endseg;
771
for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
773
if (seg->null_bit && (record[seg->null_pos] & seg->null_bit))
781
Update auto_increment info
784
update_auto_increment()
789
Only replace the auto_increment value if it is higher than the previous
790
one. For signed columns we don't update the auto increment value if it's
794
void heap_update_auto_increment(HP_INFO *info, const unsigned char *record)
796
uint64_t value= 0; /* Store unsigned values here */
797
int64_t s_value= 0; /* Store signed values here */
799
HA_KEYSEG *keyseg= info->s->keydef[info->s->auto_key - 1].seg;
800
const unsigned char *key= (unsigned char*) record + keyseg->start;
802
switch (info->s->auto_key_type) {
803
case HA_KEYTYPE_BINARY:
804
value=(uint64_t) *(unsigned char*) key;
806
case HA_KEYTYPE_LONG_INT:
807
s_value= (int64_t) sint4korr(key);
809
case HA_KEYTYPE_ULONG_INT:
810
value=(uint64_t) uint4korr(key);
812
case HA_KEYTYPE_UINT24:
813
value=(uint64_t) uint3korr(key);
815
case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
819
/* Ignore negative values */
820
value = (f_1 < 0.0) ? 0 : (uint64_t) f_1;
823
case HA_KEYTYPE_LONGLONG:
824
s_value= sint8korr(key);
826
case HA_KEYTYPE_ULONGLONG:
827
value= uint8korr(key);
836
The following code works becasue if s_value < 0 then value is 0
837
and if s_value == 0 then value will contain either s_value or the
840
set_if_bigger(info->s->auto_increment,
841
(s_value > 0) ? (uint64_t) s_value : value);