MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
hp_hash.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /* The hash functions used for saveing keys */
17 
18 #include "heapdef.h"
19 #include <m_ctype.h>
20 
21 
22 
23 /*
24  Find out how many rows there is in the given range
25 
26  SYNOPSIS
27  hp_rb_records_in_range()
28  info HEAP handler
29  inx Index to use
30  min_key Min key. Is = 0 if no min range
31  max_key Max key. Is = 0 if no max range
32 
33  NOTES
34  min_key.flag can have one of the following values:
35  HA_READ_KEY_EXACT Include the key in the range
36  HA_READ_AFTER_KEY Don't include key in range
37 
38  max_key.flag can have one of the following values:
39  HA_READ_BEFORE_KEY Don't include key in range
40  HA_READ_AFTER_KEY Include all 'end_key' values in the range
41 
42  RETURN
43  HA_POS_ERROR Something is wrong with the index tree.
44  0 There is no matching keys in the given range
45  number > 0 There is approximately 'number' matching rows in
46  the range.
47 */
48 
49 ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key,
50  key_range *max_key)
51 {
52  ha_rows start_pos, end_pos;
53  HP_KEYDEF *keyinfo= info->s->keydef + inx;
54  TREE *rb_tree = &keyinfo->rb_tree;
55  heap_rb_param custom_arg;
56  DBUG_ENTER("hp_rb_records_in_range");
57 
58  info->lastinx= inx;
59  custom_arg.keyseg= keyinfo->seg;
60  custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME;
61  if (min_key)
62  {
63  custom_arg.key_length= hp_rb_pack_key(keyinfo, (uchar*) info->recbuf,
64  (uchar*) min_key->key,
65  min_key->keypart_map);
66  start_pos= tree_record_pos(rb_tree, info->recbuf, min_key->flag,
67  &custom_arg);
68  }
69  else
70  {
71  start_pos= 0;
72  }
73 
74  if (max_key)
75  {
76  custom_arg.key_length= hp_rb_pack_key(keyinfo, (uchar*) info->recbuf,
77  (uchar*) max_key->key,
78  max_key->keypart_map);
79  end_pos= tree_record_pos(rb_tree, info->recbuf, max_key->flag,
80  &custom_arg);
81  }
82  else
83  {
84  end_pos= rb_tree->elements_in_tree + (ha_rows)1;
85  }
86 
87  DBUG_PRINT("info",("start_pos: %lu end_pos: %lu", (ulong) start_pos,
88  (ulong) end_pos));
89  if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR)
90  DBUG_RETURN(HA_POS_ERROR);
91  DBUG_RETURN(end_pos < start_pos ? (ha_rows) 0 :
92  (end_pos == start_pos ? (ha_rows) 1 : end_pos - start_pos));
93 }
94 
95 
96  /* Search after a record based on a key */
97  /* Sets info->current_ptr to found record */
98  /* next_flag: Search=0, next=1, prev =2, same =3 */
99 
100 uchar *hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *key,
101  uint nextflag)
102 {
103  reg1 HASH_INFO *pos,*prev_ptr;
104  int flag;
105  uint old_nextflag;
106  HP_SHARE *share=info->s;
107  DBUG_ENTER("hp_search");
108  old_nextflag=nextflag;
109  flag=1;
110  prev_ptr=0;
111 
112  if (share->records)
113  {
114  pos=hp_find_hash(&keyinfo->block, hp_mask(hp_hashnr(keyinfo, key),
115  share->blength, share->records));
116  do
117  {
118  if (!hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
119  {
120  switch (nextflag) {
121  case 0: /* Search after key */
122  DBUG_PRINT("exit", ("found key at 0x%lx", (long) pos->ptr_to_rec));
123  info->current_hash_ptr=pos;
124  DBUG_RETURN(info->current_ptr= pos->ptr_to_rec);
125  case 1: /* Search next */
126  if (pos->ptr_to_rec == info->current_ptr)
127  nextflag=0;
128  break;
129  case 2: /* Search previous */
130  if (pos->ptr_to_rec == info->current_ptr)
131  {
132  my_errno=HA_ERR_KEY_NOT_FOUND; /* If gpos == 0 */
133  info->current_hash_ptr=prev_ptr;
134  DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
135  }
136  prev_ptr=pos; /* Prev. record found */
137  break;
138  case 3: /* Search same */
139  if (pos->ptr_to_rec == info->current_ptr)
140  {
141  info->current_hash_ptr=pos;
142  DBUG_RETURN(info->current_ptr);
143  }
144  }
145  }
146  if (flag)
147  {
148  flag=0; /* Reset flag */
149  if (hp_find_hash(&keyinfo->block,
150  hp_mask(hp_rec_hashnr(keyinfo, pos->ptr_to_rec),
151  share->blength, share->records)) != pos)
152  break; /* Wrong link */
153  }
154  }
155  while ((pos=pos->next_key));
156  }
157  my_errno=HA_ERR_KEY_NOT_FOUND;
158  if (nextflag == 2 && ! info->current_ptr)
159  {
160  /* Do a previous from end */
161  info->current_hash_ptr=prev_ptr;
162  DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
163  }
164 
165  if (old_nextflag && nextflag)
166  my_errno=HA_ERR_RECORD_CHANGED; /* Didn't find old record */
167  DBUG_PRINT("exit",("Error: %d",my_errno));
168  info->current_hash_ptr=0;
169  DBUG_RETURN((info->current_ptr= 0));
170 }
171 
172 
173 /*
174  Search next after last read; Assumes that the table hasn't changed
175  since last read !
176 */
177 
178 uchar *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *key,
179  HASH_INFO *pos)
180 {
181  DBUG_ENTER("hp_search_next");
182 
183  while ((pos= pos->next_key))
184  {
185  if (! hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
186  {
187  info->current_hash_ptr=pos;
188  DBUG_RETURN (info->current_ptr= pos->ptr_to_rec);
189  }
190  }
191  my_errno=HA_ERR_KEY_NOT_FOUND;
192  DBUG_PRINT("exit",("Error: %d",my_errno));
193  info->current_hash_ptr=0;
194  DBUG_RETURN ((info->current_ptr= 0));
195 }
196 
197 
198 /*
199  Calculate position number for hash value.
200  SYNOPSIS
201  hp_mask()
202  hashnr Hash value
203  buffmax Value such that
204  2^(n-1) < maxlength <= 2^n = buffmax
205  maxlength
206 
207  RETURN
208  Array index, in [0..maxlength)
209 */
210 
211 ulong hp_mask(ulong hashnr, ulong buffmax, ulong maxlength)
212 {
213  if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
214  return (hashnr & ((buffmax >> 1) -1));
215 }
216 
217 
218 /*
219  Change
220  next_link -> ... -> X -> pos
221  to
222  next_link -> ... -> X -> newlink
223 */
224 
225 void hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink)
226 {
227  HASH_INFO *old_link;
228  do
229  {
230  old_link=next_link;
231  }
232  while ((next_link=next_link->next_key) != pos);
233  old_link->next_key=newlink;
234  return;
235 }
236 
237 #ifndef NEW_HASH_FUNCTION
238 
239  /* Calc hashvalue for a key */
240 
241 ulong hp_hashnr(register HP_KEYDEF *keydef, register const uchar *key)
242 {
243  /*register*/
244  ulong nr=1, nr2=4;
245  HA_KEYSEG *seg,*endseg;
246 
247  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
248  {
249  uchar *pos=(uchar*) key;
250  key+=seg->length;
251  if (seg->null_bit)
252  {
253  key++; /* Skip null byte */
254  if (*pos) /* Found null */
255  {
256  nr^= (nr << 1) | 1;
257  /* Add key pack length (2) to key for VARCHAR segments */
258  if (seg->type == HA_KEYTYPE_VARTEXT1)
259  key+= 2;
260  continue;
261  }
262  pos++;
263  }
264  if (seg->type == HA_KEYTYPE_TEXT)
265  {
266  const CHARSET_INFO *cs= seg->charset;
267  uint length= seg->length;
268  if (cs->mbmaxlen > 1)
269  {
270  uint char_length;
271  char_length= my_charpos(cs, pos, pos + length, length/cs->mbmaxlen);
272  set_if_smaller(length, char_length);
273  }
274  cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
275  }
276  else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
277  {
278  const CHARSET_INFO *cs= seg->charset;
279  uint pack_length= 2; /* Key packing is constant */
280  uint length= uint2korr(pos);
281  if (cs->mbmaxlen > 1)
282  {
283  uint char_length;
284  char_length= my_charpos(cs, pos +pack_length,
285  pos +pack_length + length,
286  seg->length/cs->mbmaxlen);
287  set_if_smaller(length, char_length);
288  }
289  cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
290  key+= pack_length;
291  }
292  else
293  {
294  for (; pos < (uchar*) key ; pos++)
295  {
296  nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos)) + (nr << 8);
297  nr2+=3;
298  }
299  }
300  }
301  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
302  return((ulong) nr);
303 }
304 
305  /* Calc hashvalue for a key in a record */
306 
307 ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const uchar *rec)
308 {
309  ulong nr=1, nr2=4;
310  HA_KEYSEG *seg,*endseg;
311 
312  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
313  {
314  uchar *pos=(uchar*) rec+seg->start,*end=pos+seg->length;
315  if (seg->null_bit)
316  {
317  if (rec[seg->null_pos] & seg->null_bit)
318  {
319  nr^= (nr << 1) | 1;
320  continue;
321  }
322  }
323  if (seg->type == HA_KEYTYPE_TEXT)
324  {
325  const CHARSET_INFO *cs= seg->charset;
326  uint char_length= seg->length;
327  if (cs->mbmaxlen > 1)
328  {
329  char_length= my_charpos(cs, pos, pos + char_length,
330  char_length / cs->mbmaxlen);
331  set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
332  }
333  cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
334  }
335  else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
336  {
337  const CHARSET_INFO *cs= seg->charset;
338  uint pack_length= seg->bit_start;
339  uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
340  if (cs->mbmaxlen > 1)
341  {
342  uint char_length;
343  char_length= my_charpos(cs, pos + pack_length,
344  pos + pack_length + length,
345  seg->length/cs->mbmaxlen);
346  set_if_smaller(length, char_length);
347  }
348  cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
349  }
350  else
351  {
352  for (; pos < end ; pos++)
353  {
354  nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
355  nr2+=3;
356  }
357  }
358  }
359  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
360  return(nr);
361 }
362 
363 #else
364 
365 /*
366  * Fowler/Noll/Vo hash
367  *
368  * The basis of the hash algorithm was taken from an idea sent by email to the
369  * IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
370  * Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com)
371  * later improved on their algorithm.
372  *
373  * The magic is in the interesting relationship between the special prime
374  * 16777619 (2^24 + 403) and 2^32 and 2^8.
375  *
376  * This hash produces the fewest collisions of any function that we've seen so
377  * far, and works well on both numbers and strings.
378  */
379 
380 ulong hp_hashnr(register HP_KEYDEF *keydef, register const uchar *key)
381 {
382  /*
383  Note, if a key consists of a combination of numeric and
384  a text columns, it most likely won't work well.
385  Making text columns work with NEW_HASH_FUNCTION
386  needs also changes in strings/ctype-xxx.c.
387  */
388  ulong nr= 1, nr2= 4;
389  HA_KEYSEG *seg,*endseg;
390 
391  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
392  {
393  uchar *pos=(uchar*) key;
394  key+=seg->length;
395  if (seg->null_bit)
396  {
397  key++;
398  if (*pos)
399  {
400  nr^= (nr << 1) | 1;
401  /* Add key pack length (2) to key for VARCHAR segments */
402  if (seg->type == HA_KEYTYPE_VARTEXT1)
403  key+= 2;
404  continue;
405  }
406  pos++;
407  }
408  if (seg->type == HA_KEYTYPE_TEXT)
409  {
410  seg->charset->coll->hash_sort(seg->charset, pos, ((uchar*)key)-pos,
411  &nr, &nr2);
412  }
413  else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
414  {
415  uint pack_length= 2; /* Key packing is constant */
416  uint length= uint2korr(pos);
417  seg->charset->coll->hash_sort(seg->charset, pos+pack_length, length,
418  &nr, &nr2);
419  key+= pack_length;
420  }
421  else
422  {
423  for ( ; pos < (uchar*) key ; pos++)
424  {
425  nr *=16777619;
426  nr ^=(uint) *pos;
427  }
428  }
429  }
430  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
431  return(nr);
432 }
433 
434  /* Calc hashvalue for a key in a record */
435 
436 ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const uchar *rec)
437 {
438  ulong nr= 1, nr2= 4;
439  HA_KEYSEG *seg,*endseg;
440 
441  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
442  {
443  uchar *pos=(uchar*) rec+seg->start;
444  if (seg->null_bit)
445  {
446  if (rec[seg->null_pos] & seg->null_bit)
447  {
448  nr^= (nr << 1) | 1;
449  continue;
450  }
451  }
452  if (seg->type == HA_KEYTYPE_TEXT)
453  {
454  uint char_length= seg->length; /* TODO: fix to use my_charpos() */
455  seg->charset->coll->hash_sort(seg->charset, pos, char_length,
456  &nr, &nr2);
457  }
458  else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
459  {
460  uint pack_length= seg->bit_start;
461  uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
462  seg->charset->coll->hash_sort(seg->charset, pos+pack_length,
463  length, &nr, &nr2);
464  }
465  else
466  {
467  uchar *end= pos+seg->length;
468  for ( ; pos < end ; pos++)
469  {
470  nr *=16777619;
471  nr ^=(uint) *pos;
472  }
473  }
474  }
475  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
476  return(nr);
477 }
478 
479 #endif
480 
481 
482 /*
483  Compare keys for two records. Returns 0 if they are identical
484 
485  SYNOPSIS
486  hp_rec_key_cmp()
487  keydef Key definition
488  rec1 Record to compare
489  rec2 Other record to compare
490  diff_if_only_endspace_difference
491  Different number of end space is significant
492 
493  NOTES
494  diff_if_only_endspace_difference is used to allow us to insert
495  'a' and 'a ' when there is an an unique key.
496 
497  RETURN
498  0 Key is identical
499  <> 0 Key differes
500 */
501 
502 int hp_rec_key_cmp(HP_KEYDEF *keydef, const uchar *rec1, const uchar *rec2,
503  my_bool diff_if_only_endspace_difference)
504 {
505  HA_KEYSEG *seg,*endseg;
506 
507  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
508  {
509  if (seg->null_bit)
510  {
511  if ((rec1[seg->null_pos] & seg->null_bit) !=
512  (rec2[seg->null_pos] & seg->null_bit))
513  return 1;
514  if (rec1[seg->null_pos] & seg->null_bit)
515  continue;
516  }
517  if (seg->type == HA_KEYTYPE_TEXT)
518  {
519  const CHARSET_INFO *cs= seg->charset;
520  uint char_length1;
521  uint char_length2;
522  uchar *pos1= (uchar*)rec1 + seg->start;
523  uchar *pos2= (uchar*)rec2 + seg->start;
524  if (cs->mbmaxlen > 1)
525  {
526  uint char_length= seg->length / cs->mbmaxlen;
527  char_length1= my_charpos(cs, pos1, pos1 + seg->length, char_length);
528  set_if_smaller(char_length1, seg->length);
529  char_length2= my_charpos(cs, pos2, pos2 + seg->length, char_length);
530  set_if_smaller(char_length2, seg->length);
531  }
532  else
533  {
534  char_length1= char_length2= seg->length;
535  }
536  if (seg->charset->coll->strnncollsp(seg->charset,
537  pos1,char_length1,
538  pos2,char_length2, 0))
539  return 1;
540  }
541  else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
542  {
543  uchar *pos1= (uchar*) rec1 + seg->start;
544  uchar *pos2= (uchar*) rec2 + seg->start;
545  uint char_length1, char_length2;
546  uint pack_length= seg->bit_start;
547  const CHARSET_INFO *cs= seg->charset;
548  if (pack_length == 1)
549  {
550  char_length1= (uint) *(uchar*) pos1++;
551  char_length2= (uint) *(uchar*) pos2++;
552  }
553  else
554  {
555  char_length1= uint2korr(pos1);
556  char_length2= uint2korr(pos2);
557  pos1+= 2;
558  pos2+= 2;
559  }
560  if (cs->mbmaxlen > 1)
561  {
562  uint safe_length1= char_length1;
563  uint safe_length2= char_length2;
564  uint char_length= seg->length / cs->mbmaxlen;
565  char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length);
566  set_if_smaller(char_length1, safe_length1);
567  char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length);
568  set_if_smaller(char_length2, safe_length2);
569  }
570 
571  if (cs->coll->strnncollsp(seg->charset,
572  pos1, char_length1,
573  pos2, char_length2,
574  seg->flag & HA_END_SPACE_ARE_EQUAL ?
575  0 : diff_if_only_endspace_difference))
576  return 1;
577  }
578  else
579  {
580  if (memcmp(rec1+seg->start,rec2+seg->start,seg->length))
581  return 1;
582  }
583  }
584  return 0;
585 }
586 
587  /* Compare a key in a record to a whole key */
588 
589 int hp_key_cmp(HP_KEYDEF *keydef, const uchar *rec, const uchar *key)
590 {
591  HA_KEYSEG *seg,*endseg;
592 
593  for (seg=keydef->seg,endseg=seg+keydef->keysegs ;
594  seg < endseg ;
595  key+= (seg++)->length)
596  {
597  if (seg->null_bit)
598  {
599  int found_null=test(rec[seg->null_pos] & seg->null_bit);
600  if (found_null != (int) *key++)
601  return 1;
602  if (found_null)
603  {
604  /* Add key pack length (2) to key for VARCHAR segments */
605  if (seg->type == HA_KEYTYPE_VARTEXT1)
606  key+= 2;
607  continue;
608  }
609  }
610  if (seg->type == HA_KEYTYPE_TEXT)
611  {
612  const CHARSET_INFO *cs= seg->charset;
613  uint char_length_key;
614  uint char_length_rec;
615  uchar *pos= (uchar*) rec + seg->start;
616  if (cs->mbmaxlen > 1)
617  {
618  uint char_length= seg->length / cs->mbmaxlen;
619  char_length_key= my_charpos(cs, key, key + seg->length, char_length);
620  set_if_smaller(char_length_key, seg->length);
621  char_length_rec= my_charpos(cs, pos, pos + seg->length, char_length);
622  set_if_smaller(char_length_rec, seg->length);
623  }
624  else
625  {
626  char_length_key= seg->length;
627  char_length_rec= seg->length;
628  }
629 
630  if (seg->charset->coll->strnncollsp(seg->charset,
631  (uchar*) pos, char_length_rec,
632  (uchar*) key, char_length_key, 0))
633  return 1;
634  }
635  else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
636  {
637  uchar *pos= (uchar*) rec + seg->start;
638  const CHARSET_INFO *cs= seg->charset;
639  uint pack_length= seg->bit_start;
640  uint char_length_rec= (pack_length == 1 ? (uint) *(uchar*) pos :
641  uint2korr(pos));
642  /* Key segments are always packed with 2 bytes */
643  uint char_length_key= uint2korr(key);
644  pos+= pack_length;
645  key+= 2; /* skip key pack length */
646  if (cs->mbmaxlen > 1)
647  {
648  uint char_length1, char_length2;
649  char_length1= char_length2= seg->length / cs->mbmaxlen;
650  char_length1= my_charpos(cs, key, key + char_length_key, char_length1);
651  set_if_smaller(char_length_key, char_length1);
652  char_length2= my_charpos(cs, pos, pos + char_length_rec, char_length2);
653  set_if_smaller(char_length_rec, char_length2);
654  }
655  else
656  {
657  set_if_smaller(char_length_rec, seg->length);
658  }
659 
660  if (cs->coll->strnncollsp(seg->charset,
661  (uchar*) pos, char_length_rec,
662  (uchar*) key, char_length_key, 0))
663  return 1;
664  }
665  else
666  {
667  if (memcmp(rec+seg->start,key,seg->length))
668  return 1;
669  }
670  }
671  return 0;
672 }
673 
674 
675  /* Copy a key from a record to a keybuffer */
676 
677 void hp_make_key(HP_KEYDEF *keydef, uchar *key, const uchar *rec)
678 {
679  HA_KEYSEG *seg,*endseg;
680 
681  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
682  {
683  const CHARSET_INFO *cs= seg->charset;
684  uint char_length= seg->length;
685  uchar *pos= (uchar*) rec + seg->start;
686  if (seg->null_bit)
687  *key++= test(rec[seg->null_pos] & seg->null_bit);
688  if (cs->mbmaxlen > 1)
689  {
690  char_length= my_charpos(cs, pos, pos + seg->length,
691  char_length / cs->mbmaxlen);
692  set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
693  }
694  if (seg->type == HA_KEYTYPE_VARTEXT1)
695  char_length+= seg->bit_start; /* Copy also length */
696  memcpy(key,rec+seg->start,(size_t) char_length);
697  key+= char_length;
698  }
699 }
700 
701 #define FIX_LENGTH(cs, pos, length, char_length) \
702  do { \
703  if (length > char_length) \
704  char_length= my_charpos(cs, pos, pos+length, char_length); \
705  set_if_smaller(char_length,length); \
706  } while(0)
707 
708 
709 uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key,
710  const uchar *rec, uchar *recpos)
711 {
712  uchar *start_key= key;
713  HA_KEYSEG *seg, *endseg;
714 
715  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
716  {
717  uint char_length;
718  if (seg->null_bit)
719  {
720  if (!(*key++= 1 - test(rec[seg->null_pos] & seg->null_bit)))
721  continue;
722  }
723  if (seg->flag & HA_SWAP_KEY)
724  {
725  uint length= seg->length;
726  uchar *pos= (uchar*) rec + seg->start;
727 
728 #ifdef HAVE_ISNAN
729  if (seg->type == HA_KEYTYPE_FLOAT)
730  {
731  float nr;
732  float4get(nr, pos);
733  if (isnan(nr))
734  {
735  /* Replace NAN with zero */
736  memset(key, 0, length);
737  key+= length;
738  continue;
739  }
740  }
741  else if (seg->type == HA_KEYTYPE_DOUBLE)
742  {
743  double nr;
744  float8get(nr, pos);
745  if (isnan(nr))
746  {
747  memset(key, 0, length);
748  key+= length;
749  continue;
750  }
751  }
752 #endif
753  pos+= length;
754  while (length--)
755  {
756  *key++= *--pos;
757  }
758  continue;
759  }
760 
761  if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
762  {
763  uchar *pos= (uchar*) rec + seg->start;
764  uint length= seg->length;
765  uint pack_length= seg->bit_start;
766  uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
767  uint2korr(pos));
768  const CHARSET_INFO *cs= seg->charset;
769  char_length= length/cs->mbmaxlen;
770 
771  pos+= pack_length; /* Skip VARCHAR length */
772  set_if_smaller(length,tmp_length);
773  FIX_LENGTH(cs, pos, length, char_length);
774  store_key_length_inc(key,char_length);
775  memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
776  key+= char_length;
777  continue;
778  }
779 
780  char_length= seg->length;
781  if (seg->charset->mbmaxlen > 1)
782  {
783  char_length= my_charpos(seg->charset,
784  rec + seg->start, rec + seg->start + char_length,
785  char_length / seg->charset->mbmaxlen);
786  set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
787  if (char_length < seg->length)
788  seg->charset->cset->fill(seg->charset, (char*) key + char_length,
789  seg->length - char_length, ' ');
790  }
791  memcpy(key, rec + seg->start, (size_t) char_length);
792  key+= seg->length;
793  }
794  memcpy(key, &recpos, sizeof(uchar*));
795  return (uint) (key - start_key);
796 }
797 
798 
799 uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
800  key_part_map keypart_map)
801 {
802  HA_KEYSEG *seg, *endseg;
803  uchar *start_key= key;
804 
805  for (seg= keydef->seg, endseg= seg + keydef->keysegs;
806  seg < endseg && keypart_map; old+= seg->length, seg++)
807  {
808  uint char_length;
809  keypart_map>>= 1;
810  if (seg->null_bit)
811  {
812  /* Convert NULL from MySQL representation into HEAP's. */
813  if (!(*key++= (char) 1 - *old++))
814  {
815  /*
816  Skip length part of a variable length field.
817  Length of key-part used with heap_rkey() always 2.
818  See also hp_hashnr().
819  */
820  if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
821  old+= 2;
822  continue;
823  }
824  }
825  if (seg->flag & HA_SWAP_KEY)
826  {
827  uint length= seg->length;
828  uchar *pos= (uchar*) old + length;
829 
830  while (length--)
831  {
832  *key++= *--pos;
833  }
834  continue;
835  }
836  if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
837  {
838  /* Length of key-part used with heap_rkey() always 2 */
839  uint tmp_length=uint2korr(old);
840  uint length= seg->length;
841  const CHARSET_INFO *cs= seg->charset;
842  char_length= length/cs->mbmaxlen;
843 
844  old+= 2;
845  set_if_smaller(length,tmp_length); /* Safety */
846  FIX_LENGTH(cs, old, length, char_length);
847  store_key_length_inc(key,char_length);
848  memcpy((uchar*) key, old,(size_t) char_length);
849  key+= char_length;
850  continue;
851  }
852  char_length= seg->length;
853  if (seg->charset->mbmaxlen > 1)
854  {
855  char_length= my_charpos(seg->charset, old, old+char_length,
856  char_length / seg->charset->mbmaxlen);
857  set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
858  if (char_length < seg->length)
859  seg->charset->cset->fill(seg->charset, (char*) key + char_length,
860  seg->length - char_length, ' ');
861  }
862  memcpy(key, old, (size_t) char_length);
863  key+= seg->length;
864  }
865  return (uint) (key - start_key);
866 }
867 
868 
869 uint hp_rb_key_length(HP_KEYDEF *keydef,
870  const uchar *key __attribute__((unused)))
871 {
872  return keydef->length;
873 }
874 
875 
876 uint hp_rb_null_key_length(HP_KEYDEF *keydef, const uchar *key)
877 {
878  const uchar *start_key= key;
879  HA_KEYSEG *seg, *endseg;
880 
881  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
882  {
883  if (seg->null_bit && !*key++)
884  continue;
885  key+= seg->length;
886  }
887  return (uint) (key - start_key);
888 }
889 
890 
891 uint hp_rb_var_key_length(HP_KEYDEF *keydef, const uchar *key)
892 {
893  const uchar *start_key= key;
894  HA_KEYSEG *seg, *endseg;
895 
896  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
897  {
898  uint length= seg->length;
899  if (seg->null_bit && !*key++)
900  continue;
901  if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
902  {
903  get_key_length(length, key);
904  }
905  key+= length;
906  }
907  return (uint) (key - start_key);
908 }
909 
910 
911 /*
912  Test if any of the key parts are NULL.
913  Return:
914  1 if any of the key parts was NULL
915  0 otherwise
916 */
917 
918 my_bool hp_if_null_in_key(HP_KEYDEF *keydef, const uchar *record)
919 {
920  HA_KEYSEG *seg,*endseg;
921  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
922  {
923  if (seg->null_bit && (record[seg->null_pos] & seg->null_bit))
924  return 1;
925  }
926  return 0;
927 }
928 
929 
930 /*
931  Update auto_increment info
932 
933  SYNOPSIS
934  update_auto_increment()
935  info MyISAM handler
936  record Row to update
937 
938  IMPLEMENTATION
939  Only replace the auto_increment value if it is higher than the previous
940  one. For signed columns we don't update the auto increment value if it's
941  less than zero.
942 */
943 
944 void heap_update_auto_increment(HP_INFO *info, const uchar *record)
945 {
946  ulonglong value= 0; /* Store unsigned values here */
947  longlong s_value= 0; /* Store signed values here */
948 
949  HA_KEYSEG *keyseg= info->s->keydef[info->s->auto_key - 1].seg;
950  const uchar *key= (uchar*) record + keyseg->start;
951 
952  switch (info->s->auto_key_type) {
953  case HA_KEYTYPE_INT8:
954  s_value= (longlong) *(char*)key;
955  break;
956  case HA_KEYTYPE_BINARY:
957  value=(ulonglong) *(uchar*) key;
958  break;
959  case HA_KEYTYPE_SHORT_INT:
960  s_value= (longlong) sint2korr(key);
961  break;
962  case HA_KEYTYPE_USHORT_INT:
963  value=(ulonglong) uint2korr(key);
964  break;
965  case HA_KEYTYPE_LONG_INT:
966  s_value= (longlong) sint4korr(key);
967  break;
968  case HA_KEYTYPE_ULONG_INT:
969  value=(ulonglong) uint4korr(key);
970  break;
971  case HA_KEYTYPE_INT24:
972  s_value= (longlong) sint3korr(key);
973  break;
974  case HA_KEYTYPE_UINT24:
975  value=(ulonglong) uint3korr(key);
976  break;
977  case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
978  {
979  float f_1;
980  float4get(f_1,key);
981  /* Ignore negative values */
982  value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
983  break;
984  }
985  case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
986  {
987  double f_1;
988  float8get(f_1,key);
989  /* Ignore negative values */
990  value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
991  break;
992  }
993  case HA_KEYTYPE_LONGLONG:
994  s_value= sint8korr(key);
995  break;
996  case HA_KEYTYPE_ULONGLONG:
997  value= uint8korr(key);
998  break;
999  default:
1000  DBUG_ASSERT(0);
1001  value=0; /* Error */
1002  break;
1003  }
1004 
1005  /*
1006  The following code works becasue if s_value < 0 then value is 0
1007  and if s_value == 0 then value will contain either s_value or the
1008  correct value.
1009  */
1010  set_if_bigger(info->s->auto_increment,
1011  (s_value > 0) ? (ulonglong) s_value : value);
1012 }