1 /* Copyright (c) 2000, 2019, 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, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 /* The hash functions used for saveing keys */
24 
25 #include <inttypes.h>
26 #include <sys/types.h>
27 
28 #include <algorithm>
29 #include <cmath>
30 
31 #include "m_ctype.h"
32 #include "my_byteorder.h"
33 #include "my_compiler.h"
34 #include "my_dbug.h"
35 #include "my_inttypes.h"
36 #include "my_macros.h"
37 #include "storage/heap/heapdef.h"
38 
39 /*
40   Find out how many rows there is in the given range
41 
42   SYNOPSIS
43     hp_rb_records_in_range()
44     info		HEAP handler
45     inx			Index to use
46     min_key		Min key. Is = 0 if no min range
47     max_key		Max key. Is = 0 if no max range
48 
49   NOTES
50     min_key.flag can have one of the following values:
51       HA_READ_KEY_EXACT		Include the key in the range
52       HA_READ_AFTER_KEY		Don't include key in range
53 
54     max_key.flag can have one of the following values:
55       HA_READ_BEFORE_KEY	Don't include key in range
56       HA_READ_AFTER_KEY		Include all 'end_key' values in the range
57 
58   RETURN
59    HA_POS_ERROR		Something is wrong with the index tree.
60    0			There is no matching keys in the given range
61    number > 0		There is approximately 'number' matching rows in
62                         the range.
63 */
64 
hp_rb_records_in_range(HP_INFO * info,int inx,key_range * min_key,key_range * max_key)65 ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key,
66                                key_range *max_key) {
67   ha_rows start_pos, end_pos;
68   HP_KEYDEF *keyinfo = info->s->keydef + inx;
69   TREE *rb_tree = &keyinfo->rb_tree;
70   heap_rb_param custom_arg;
71   DBUG_TRACE;
72 
73   info->lastinx = inx;
74   custom_arg.keyseg = keyinfo->seg;
75   custom_arg.search_flag = SEARCH_FIND | SEARCH_SAME;
76   if (min_key) {
77     custom_arg.key_length = hp_rb_pack_key(keyinfo, info->recbuf, min_key->key,
78                                            min_key->keypart_map);
79     start_pos =
80         tree_record_pos(rb_tree, info->recbuf, min_key->flag, &custom_arg);
81   } else {
82     start_pos = 0;
83   }
84 
85   if (max_key) {
86     custom_arg.key_length = hp_rb_pack_key(keyinfo, info->recbuf, max_key->key,
87                                            max_key->keypart_map);
88     end_pos =
89         tree_record_pos(rb_tree, info->recbuf, max_key->flag, &custom_arg);
90   } else {
91     end_pos = rb_tree->elements_in_tree + (ha_rows)1;
92   }
93 
94   DBUG_PRINT("info", ("start_pos: %lu  end_pos: %lu", (ulong)start_pos,
95                       (ulong)end_pos));
96   if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR) return HA_POS_ERROR;
97   return end_pos < start_pos
98              ? (ha_rows)0
99              : (end_pos == start_pos ? (ha_rows)1 : end_pos - start_pos);
100 }
101 
102 /* Search after a record based on a key */
103 /* Sets info->current_ptr to found record */
104 /* next_flag:  Search=0, next=1, prev =2, same =3 */
105 
hp_search(HP_INFO * info,HP_KEYDEF * keyinfo,const uchar * key,uint nextflag)106 uchar *hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *key,
107                  uint nextflag) {
108   HASH_INFO *pos, *prev_ptr;
109   int flag;
110   uint old_nextflag;
111   HP_SHARE *share = info->s;
112   DBUG_TRACE;
113   old_nextflag = nextflag;
114   flag = 1;
115   prev_ptr = nullptr;
116 
117   if (share->records) {
118     pos = hp_find_hash(
119         &keyinfo->block,
120         hp_mask(hp_hashnr(keyinfo, key), share->blength, share->records));
121     do {
122       if (!hp_key_cmp(keyinfo, pos->ptr_to_rec, key)) {
123         switch (nextflag) {
124           case 0: /* Search after key */
125             DBUG_PRINT("exit", ("found key at %p", pos->ptr_to_rec));
126             info->current_hash_ptr = pos;
127             return info->current_ptr = pos->ptr_to_rec;
128           case 1: /* Search next */
129             if (pos->ptr_to_rec == info->current_ptr) nextflag = 0;
130             break;
131           case 2: /* Search previous */
132             if (pos->ptr_to_rec == info->current_ptr) {
133               set_my_errno(HA_ERR_KEY_NOT_FOUND); /* If gpos == 0 */
134               info->current_hash_ptr = prev_ptr;
135               return info->current_ptr =
136                          prev_ptr ? prev_ptr->ptr_to_rec : nullptr;
137             }
138             prev_ptr = pos; /* Prev. record found */
139             break;
140           case 3: /* Search same */
141             if (pos->ptr_to_rec == info->current_ptr) {
142               info->current_hash_ptr = pos;
143               return info->current_ptr;
144             }
145         }
146       }
147       if (flag) {
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     } while ((pos = pos->next_key));
155   }
156   set_my_errno(HA_ERR_KEY_NOT_FOUND);
157   if (nextflag == 2 && !info->current_ptr) {
158     /* Do a previous from end */
159     info->current_hash_ptr = prev_ptr;
160     return info->current_ptr = prev_ptr ? prev_ptr->ptr_to_rec : nullptr;
161   }
162 
163   if (old_nextflag && nextflag)
164     set_my_errno(HA_ERR_RECORD_CHANGED); /* Didn't find old record */
165   DBUG_PRINT("exit", ("Error: %d", my_errno()));
166   info->current_hash_ptr = nullptr;
167   return (info->current_ptr = nullptr);
168 }
169 
170 /*
171   Search next after last read;  Assumes that the table hasn't changed
172   since last read !
173 */
174 
hp_search_next(HP_INFO * info,HP_KEYDEF * keyinfo,const uchar * key,HASH_INFO * pos)175 uchar *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *key,
176                       HASH_INFO *pos) {
177   DBUG_TRACE;
178 
179   while ((pos = pos->next_key)) {
180     if (!hp_key_cmp(keyinfo, pos->ptr_to_rec, key)) {
181       info->current_hash_ptr = pos;
182       return info->current_ptr = pos->ptr_to_rec;
183     }
184   }
185   set_my_errno(HA_ERR_KEY_NOT_FOUND);
186   DBUG_PRINT("exit", ("Error: %d", my_errno()));
187   info->current_hash_ptr = nullptr;
188   return (info->current_ptr = nullptr);
189 }
190 
191 /*
192   Calculate position number for hash value.
193   SYNOPSIS
194     hp_mask()
195       hashnr     Hash value
196       buffmax    Value such that
197                  2^(n-1) < maxlength <= 2^n = buffmax
198       maxlength
199 
200   RETURN
201     Array index, in [0..maxlength)
202 */
203 
hp_mask(uint64 hashnr,uint64 buffmax,uint64 maxlength)204 uint64 hp_mask(uint64 hashnr, uint64 buffmax, uint64 maxlength) {
205   if ((hashnr & (buffmax - 1)) < maxlength) return (hashnr & (buffmax - 1));
206   return (hashnr & ((buffmax >> 1) - 1));
207 }
208 
209 /*
210   Change
211     next_link -> ... -> X -> pos
212   to
213     next_link -> ... -> X -> newlink
214 */
215 
hp_movelink(HASH_INFO * pos,HASH_INFO * next_link,HASH_INFO * newlink)216 void hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink) {
217   HASH_INFO *old_link;
218   do {
219     old_link = next_link;
220   } while ((next_link = next_link->next_key) != pos);
221   old_link->next_key = newlink;
222   return;
223 }
224 
225 /* Calc hashvalue for a key */
226 
hp_hashnr(HP_KEYDEF * keydef,const uchar * key)227 uint64 hp_hashnr(HP_KEYDEF *keydef, const uchar *key) {
228   /*register*/
229   uint64 nr = 1, nr2 = 4;
230   HA_KEYSEG *seg, *endseg;
231 
232   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg; seg++) {
233     const uchar *pos = key;
234     key += seg->length;
235     if (seg->null_bit) {
236       key++;    /* Skip null byte */
237       if (*pos) /* Found null */
238       {
239         nr ^= (nr << 1) | 1;
240         /* Add key pack length (2) to key for VARCHAR segments */
241         if (seg->type == HA_KEYTYPE_VARTEXT1) key += 2;
242         continue;
243       }
244       pos++;
245     }
246     if (seg->type == HA_KEYTYPE_TEXT) {
247       const CHARSET_INFO *cs = seg->charset;
248       size_t length = seg->length;
249       if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
250         size_t char_length;
251         char_length = my_charpos(cs, pos, pos + length, length / cs->mbmaxlen);
252         length = std::min(length, char_length);
253       }
254       if (cs->pad_attribute == NO_PAD) {
255         /*
256           MySQL specifies that CHAR fields are stripped of
257           trailing spaces before being returned from the database.
258           Normally this is done in Field_string::val_str(),
259           but since we don't involve the Field classes for
260           hashing, we need to do the same thing here
261           for NO PAD collations. (If not, hash_sort will ignore
262           the spaces for us, so we don't need to do it here.)
263         */
264         length = cs->cset->lengthsp(cs, (const char *)pos, length);
265       }
266       cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
267     } else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
268     {
269       const CHARSET_INFO *cs = seg->charset;
270       uint pack_length = 2; /* Key packing is constant */
271       size_t length = uint2korr(pos);
272       if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
273         size_t char_length;
274         char_length =
275             my_charpos(cs, pos + pack_length, pos + pack_length + length,
276                        seg->length / cs->mbmaxlen);
277         length = std::min(length, char_length);
278       }
279       cs->coll->hash_sort(cs, pos + pack_length, length, &nr, &nr2);
280       key += pack_length;
281     } else {
282       for (; pos < key; pos++) {
283         nr ^= (uint64)((((uint)nr & 63) + nr2) * ((uint)*pos)) + (nr << 8);
284         nr2 += 3;
285       }
286     }
287   }
288   DBUG_PRINT("exit", ("hash: 0x%" PRIx64, nr));
289   return nr;
290 }
291 
292 /* Calc hashvalue for a key in a record */
293 
hp_rec_hashnr(HP_KEYDEF * keydef,const uchar * rec)294 uint64 hp_rec_hashnr(HP_KEYDEF *keydef, const uchar *rec) {
295   uint64 nr = 1, nr2 = 4;
296   HA_KEYSEG *seg, *endseg;
297 
298   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg; seg++) {
299     const uchar *pos = rec + seg->start, *end = pos + seg->length;
300     if (seg->null_bit) {
301       if (rec[seg->null_pos] & seg->null_bit) {
302         nr ^= (nr << 1) | 1;
303         continue;
304       }
305     }
306     if (seg->type == HA_KEYTYPE_TEXT) {
307       const CHARSET_INFO *cs = seg->charset;
308       size_t char_length = seg->length;
309       if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
310         char_length =
311             my_charpos(cs, pos, pos + char_length, char_length / cs->mbmaxlen);
312         char_length =
313             std::min(char_length, size_t(seg->length)); /* QQ: ok to remove? */
314       }
315       if (cs->pad_attribute == NO_PAD) {
316         /*
317           MySQL specifies that CHAR fields are stripped of
318           trailing spaces before being returned from the database.
319           Normally this is done in Field_string::val_str(),
320           but since we don't involve the Field classes for
321           hashing, we need to do the same thing here
322           for NO PAD collations. (If not, hash_sort will ignore
323           the spaces for us, so we don't need to do it here.)
324         */
325         char_length = cs->cset->lengthsp(cs, (const char *)pos, char_length);
326       }
327       cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
328     } else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
329     {
330       const CHARSET_INFO *cs = seg->charset;
331       uint pack_length = seg->bit_start;
332       size_t length = (pack_length == 1 ? (uint)*pos : uint2korr(pos));
333       if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
334         size_t char_length;
335         char_length =
336             my_charpos(cs, pos + pack_length, pos + pack_length + length,
337                        seg->length / cs->mbmaxlen);
338         length = std::min(length, char_length);
339       }
340       cs->coll->hash_sort(cs, pos + pack_length, length, &nr, &nr2);
341     } else {
342       for (; pos < end; pos++) {
343         nr ^= (uint64)((((uint)nr & 63) + nr2) * ((uint)*pos)) + (nr << 8);
344         nr2 += 3;
345       }
346     }
347   }
348   DBUG_PRINT("exit", ("hash: 0x%" PRIx64, nr));
349   return (nr);
350 }
351 
352 /*
353   Compare keys for two records. Returns 0 if they are identical
354 
355   SYNOPSIS
356     hp_rec_key_cmp()
357     keydef		Key definition
358     rec1		Record to compare
359     rec2		Other record to compare
360 
361   RETURN
362     0		Key is identical
363     <> 0 	Key differes
364 */
365 
hp_rec_key_cmp(HP_KEYDEF * keydef,const uchar * rec1,const uchar * rec2)366 int hp_rec_key_cmp(HP_KEYDEF *keydef, const uchar *rec1, const uchar *rec2) {
367   HA_KEYSEG *seg, *endseg;
368 
369   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg; seg++) {
370     if (seg->null_bit) {
371       if ((rec1[seg->null_pos] & seg->null_bit) !=
372           (rec2[seg->null_pos] & seg->null_bit))
373         return 1;
374       if (rec1[seg->null_pos] & seg->null_bit) continue;
375     }
376     if (seg->type == HA_KEYTYPE_TEXT) {
377       const CHARSET_INFO *cs = seg->charset;
378       size_t char_length1;
379       size_t char_length2;
380       const uchar *pos1 = rec1 + seg->start;
381       const uchar *pos2 = rec2 + seg->start;
382       if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
383         size_t char_length = seg->length / cs->mbmaxlen;
384         char_length1 = my_charpos(cs, pos1, pos1 + seg->length, char_length);
385         char_length1 = std::min(char_length1, size_t(seg->length));
386         char_length2 = my_charpos(cs, pos2, pos2 + seg->length, char_length);
387         char_length2 = std::min(char_length2, size_t(seg->length));
388       } else {
389         char_length1 = char_length2 = seg->length;
390       }
391       if (cs->pad_attribute == NO_PAD) {
392         /*
393           MySQL specifies that CHAR fields are stripped of
394           trailing spaces before being returned from the database.
395           Normally this is done in Field_string::val_str(),
396           but since we don't involve the Field classes for
397           internal comparisons, we need to do the same thing here
398           for NO PAD collations. (If not, strnncollsp will ignore
399           the spaces for us, so we don't need to do it here.)
400         */
401         char_length1 = cs->cset->lengthsp(cs, (const char *)pos1, char_length1);
402         char_length2 = cs->cset->lengthsp(cs, (const char *)pos2, char_length2);
403       }
404       if (cs->coll->strnncollsp(cs, pos1, char_length1, pos2, char_length2))
405         return 1;
406     } else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
407     {
408       const uchar *pos1 = rec1 + seg->start;
409       const uchar *pos2 = rec2 + seg->start;
410       uint char_length1, char_length2;
411       uint pack_length = seg->bit_start;
412       const CHARSET_INFO *cs = seg->charset;
413       if (pack_length == 1) {
414         char_length1 = (uint) * (pos1++);
415         char_length2 = (uint) * (pos2++);
416       } else {
417         char_length1 = uint2korr(pos1);
418         char_length2 = uint2korr(pos2);
419         pos1 += 2;
420         pos2 += 2;
421       }
422       if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
423         uint safe_length1 = char_length1;
424         uint safe_length2 = char_length2;
425         uint char_length = seg->length / cs->mbmaxlen;
426         char_length1 = my_charpos(cs, pos1, pos1 + char_length1, char_length);
427         char_length1 = std::min(char_length1, safe_length1);
428         char_length2 = my_charpos(cs, pos2, pos2 + char_length2, char_length);
429         char_length2 = std::min(char_length2, safe_length2);
430       }
431 
432       if (cs->coll->strnncollsp(seg->charset, pos1, char_length1, pos2,
433                                 char_length2))
434         return 1;
435     } else {
436       if (memcmp(rec1 + seg->start, rec2 + seg->start, seg->length)) return 1;
437     }
438   }
439   return 0;
440 }
441 
442 /* Compare a key in a record to a whole key */
443 
hp_key_cmp(HP_KEYDEF * keydef,const uchar * rec,const uchar * key)444 int hp_key_cmp(HP_KEYDEF *keydef, const uchar *rec, const uchar *key) {
445   HA_KEYSEG *seg, *endseg;
446 
447   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg;
448        key += (seg++)->length) {
449     if (seg->null_bit) {
450       bool found_null = (rec[seg->null_pos] & seg->null_bit);
451       if (found_null != (int)*key++) return 1;
452       if (found_null) {
453         /* Add key pack length (2) to key for VARCHAR segments */
454         if (seg->type == HA_KEYTYPE_VARTEXT1) key += 2;
455         continue;
456       }
457     }
458     if (seg->type == HA_KEYTYPE_TEXT) {
459       const CHARSET_INFO *cs = seg->charset;
460       uint char_length_key;
461       uint char_length_rec;
462       const uchar *pos = rec + seg->start;
463       if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
464         uint char_length = seg->length / cs->mbmaxlen;
465         char_length_key = my_charpos(cs, key, key + seg->length, char_length);
466         char_length_key = std::min(char_length_key, uint(seg->length));
467         char_length_rec = my_charpos(cs, pos, pos + seg->length, char_length);
468         char_length_rec = std::min(char_length_rec, uint(seg->length));
469       } else {
470         char_length_key = seg->length;
471         char_length_rec = seg->length;
472       }
473 
474       if (cs->pad_attribute == NO_PAD) {
475         /*
476           MySQL specifies that CHAR fields are stripped of
477           trailing spaces before being returned from the database.
478           Normally this is done in Field_string::val_str(),
479           but since we don't involve the Field classes for
480           internal comparisons, we need to do the same thing here
481           for NO PAD collations. (If not, strnncollsp will ignore
482           the spaces for us, so we don't need to do it here.)
483         */
484         char_length_rec =
485             cs->cset->lengthsp(cs, (const char *)pos, char_length_rec);
486         char_length_key =
487             cs->cset->lengthsp(cs, (const char *)key, char_length_key);
488       }
489 
490       if (cs->coll->strnncollsp(cs, pos, char_length_rec, key, char_length_key))
491         return 1;
492     } else if (seg->type == HA_KEYTYPE_VARTEXT1) /* Any VARCHAR segments */
493     {
494       const uchar *pos = rec + seg->start;
495       const CHARSET_INFO *cs = seg->charset;
496       uint pack_length = seg->bit_start;
497       uint char_length_rec = (pack_length == 1 ? (uint)*pos : uint2korr(pos));
498       /* Key segments are always packed with 2 bytes */
499       uint char_length_key = uint2korr(key);
500       pos += pack_length;
501       key += 2; /* skip key pack length */
502       if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
503         uint char_length1, char_length2;
504         char_length1 = char_length2 = seg->length / cs->mbmaxlen;
505         char_length1 = my_charpos(cs, key, key + char_length_key, char_length1);
506         char_length_key = std::min(char_length_key, char_length1);
507         char_length2 = my_charpos(cs, pos, pos + char_length_rec, char_length2);
508         char_length_rec = std::min(char_length_rec, char_length2);
509       } else {
510         char_length_rec = std::min(char_length_rec, uint(seg->length));
511       }
512 
513       if (cs->coll->strnncollsp(seg->charset, pos, char_length_rec, key,
514                                 char_length_key))
515         return 1;
516     } else {
517       if (memcmp(rec + seg->start, key, seg->length)) return 1;
518     }
519   }
520   return 0;
521 }
522 
523 /* Copy a key from a record to a keybuffer */
524 
hp_make_key(HP_KEYDEF * keydef,uchar * key,const uchar * rec)525 void hp_make_key(HP_KEYDEF *keydef, uchar *key, const uchar *rec) {
526   HA_KEYSEG *seg, *endseg;
527 
528   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg; seg++) {
529     const CHARSET_INFO *cs = seg->charset;
530     uint char_length = seg->length;
531     const uchar *pos = rec + seg->start;
532     if (seg->null_bit) {
533       bool rec_is_null = rec[seg->null_pos] & seg->null_bit;
534       *key++ = (rec_is_null ? 1 : 0);
535     }
536     if (cs->mbmaxlen > 1 && (seg->flag & HA_PART_KEY_SEG)) {
537       char_length =
538           my_charpos(cs, pos, pos + seg->length, char_length / cs->mbmaxlen);
539       char_length =
540           std::min(char_length, uint(seg->length)); /* QQ: ok to remove? */
541     }
542     if (seg->type == HA_KEYTYPE_VARTEXT1)
543       char_length += seg->bit_start; /* Copy also length */
544     memcpy(key, rec + seg->start, (size_t)char_length);
545     key += char_length;
546   }
547 }
548 
549 #define FIX_LENGTH(cs, pos, length, char_length)                    \
550   do {                                                              \
551     if (length > char_length)                                       \
552       char_length = my_charpos(cs, pos, pos + length, char_length); \
553     char_length = std::min(char_length, size_t(length));            \
554   } while (0)
555 
hp_rb_make_key(HP_KEYDEF * keydef,uchar * key,const uchar * rec,uchar * recpos)556 uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key, const uchar *rec,
557                     uchar *recpos) {
558   uchar *start_key = key;
559   HA_KEYSEG *seg, *endseg;
560 
561   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg; seg++) {
562     size_t char_length;
563     if (seg->null_bit) {
564       bool rec_is_null = rec[seg->null_pos] & seg->null_bit;
565       if (!(*key++ = 1 - (rec_is_null ? 1 : 0))) continue;
566     }
567     if (seg->flag & HA_SWAP_KEY) {
568       uint length = seg->length;
569       const uchar *pos = rec + seg->start;
570       if (seg->type == HA_KEYTYPE_FLOAT) {
571         float nr = float4get(pos);
572         if (std::isnan(nr)) {
573           /* Replace NAN with zero */
574           memset(key, 0, length);
575           key += length;
576           continue;
577         }
578       } else if (seg->type == HA_KEYTYPE_DOUBLE) {
579         double nr = float8get(pos);
580         if (std::isnan(nr)) {
581           memset(key, 0, length);
582           key += length;
583           continue;
584         }
585       }
586       pos += length;
587       while (length--) {
588         *key++ = *--pos;
589       }
590       continue;
591     }
592 
593     if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) {
594       const uchar *pos = rec + seg->start;
595       uint length = seg->length;
596       uint pack_length = seg->bit_start;
597       uint tmp_length = (pack_length == 1 ? (uint)*pos : uint2korr(pos));
598       const CHARSET_INFO *cs = seg->charset;
599       char_length = length / cs->mbmaxlen;
600 
601       pos += pack_length; /* Skip VARCHAR length */
602       length = std::min(length, tmp_length);
603       FIX_LENGTH(cs, pos, length, char_length);
604       store_key_length_inc(key, char_length);
605       memcpy(key, pos, char_length);
606       key += char_length;
607       continue;
608     }
609 
610     char_length = seg->length;
611     if (seg->charset->mbmaxlen > 1) {
612       char_length = my_charpos(seg->charset, rec + seg->start,
613                                rec + seg->start + char_length,
614                                char_length / seg->charset->mbmaxlen);
615       char_length =
616           std::min(char_length, size_t(seg->length)); /* QQ: ok to remove? */
617       if (char_length < seg->length)
618         seg->charset->cset->fill(seg->charset, (char *)key + char_length,
619                                  seg->length - char_length, ' ');
620     }
621     memcpy(key, rec + seg->start, (size_t)char_length);
622     key += seg->length;
623   }
624   memcpy(key, &recpos, sizeof(uchar *));
625   return (uint)(key - start_key);
626 }
627 
hp_rb_pack_key(const HP_KEYDEF * keydef,uchar * key,const uchar * old,key_part_map keypart_map)628 uint hp_rb_pack_key(const HP_KEYDEF *keydef, uchar *key, const uchar *old,
629                     key_part_map keypart_map) {
630   HA_KEYSEG *seg, *endseg;
631   uchar *start_key = key;
632 
633   for (seg = keydef->seg, endseg = seg + keydef->keysegs;
634        seg < endseg && keypart_map; old += seg->length, seg++) {
635     size_t char_length;
636     keypart_map >>= 1;
637     if (seg->null_bit) {
638       /* Convert NULL from MySQL representation into HEAP's. */
639       if (!(*key++ = (char)1 - *old++)) {
640         /*
641           Skip length part of a variable length field.
642           Length of key-part used with heap_rkey() always 2.
643           See also hp_hashnr().
644         */
645         if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) old += 2;
646         continue;
647       }
648     }
649     if (seg->flag & HA_SWAP_KEY) {
650       uint length = seg->length;
651       const uchar *pos = old + length;
652 
653       while (length--) {
654         *key++ = *--pos;
655       }
656       continue;
657     }
658     if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) {
659       /* Length of key-part used with heap_rkey() always 2 */
660       uint tmp_length = uint2korr(old);
661       uint length = seg->length;
662       const CHARSET_INFO *cs = seg->charset;
663       char_length = length / cs->mbmaxlen;
664 
665       old += 2;
666       length = std::min(length, tmp_length); /* Safety */
667       FIX_LENGTH(cs, old, length, char_length);
668       store_key_length_inc(key, char_length);
669       memcpy((uchar *)key, old, (size_t)char_length);
670       key += char_length;
671       continue;
672     }
673     char_length = seg->length;
674     if (seg->charset->mbmaxlen > 1) {
675       char_length = my_charpos(seg->charset, old, old + char_length,
676                                char_length / seg->charset->mbmaxlen);
677       char_length =
678           std::min(char_length, size_t(seg->length)); /* QQ: ok to remove? */
679       if (char_length < seg->length)
680         seg->charset->cset->fill(seg->charset, (char *)key + char_length,
681                                  seg->length - char_length, ' ');
682     }
683     memcpy(key, old, (size_t)char_length);
684     key += seg->length;
685   }
686   return (uint)(key - start_key);
687 }
688 
hp_rb_key_length(HP_KEYDEF * keydef,const uchar * key MY_ATTRIBUTE ((unused)))689 uint hp_rb_key_length(HP_KEYDEF *keydef,
690                       const uchar *key MY_ATTRIBUTE((unused))) {
691   return keydef->length;
692 }
693 
hp_rb_null_key_length(HP_KEYDEF * keydef,const uchar * key)694 uint hp_rb_null_key_length(HP_KEYDEF *keydef, const uchar *key) {
695   const uchar *start_key = key;
696   HA_KEYSEG *seg, *endseg;
697 
698   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg; seg++) {
699     if (seg->null_bit && !*key++) continue;
700     key += seg->length;
701   }
702   return (uint)(key - start_key);
703 }
704 
hp_rb_var_key_length(HP_KEYDEF * keydef,const uchar * key)705 uint hp_rb_var_key_length(HP_KEYDEF *keydef, const uchar *key) {
706   const uchar *start_key = key;
707   HA_KEYSEG *seg, *endseg;
708 
709   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg; seg++) {
710     uint length = seg->length;
711     if (seg->null_bit && !*key++) continue;
712     if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) {
713       length = get_key_length(&key);
714     }
715     key += length;
716   }
717   return (uint)(key - start_key);
718 }
719 
720 /*
721   Test if any of the key parts are NULL.
722   Return:
723     1 if any of the key parts was NULL
724     0 otherwise
725 */
726 
hp_if_null_in_key(HP_KEYDEF * keydef,const uchar * record)727 bool hp_if_null_in_key(HP_KEYDEF *keydef, const uchar *record) {
728   HA_KEYSEG *seg, *endseg;
729   for (seg = keydef->seg, endseg = seg + keydef->keysegs; seg < endseg; seg++) {
730     if (seg->null_bit && (record[seg->null_pos] & seg->null_bit)) return true;
731   }
732   return false;
733 }
734 
735 /*
736   Update auto_increment info
737 
738   SYNOPSIS
739     update_auto_increment()
740     info			MyISAM handler
741     record			Row to update
742 
743   IMPLEMENTATION
744     Only replace the auto_increment value if it is higher than the previous
745     one. For signed columns we don't update the auto increment value if it's
746     less than zero.
747 */
748 
heap_update_auto_increment(HP_INFO * info,const uchar * record)749 void heap_update_auto_increment(HP_INFO *info, const uchar *record) {
750   ulonglong value = 0;  /* Store unsigned values here */
751   longlong s_value = 0; /* Store signed values here */
752 
753   HA_KEYSEG *keyseg = info->s->keydef[info->s->auto_key - 1].seg;
754   const uchar *key = record + keyseg->start;
755 
756   switch (info->s->auto_key_type) {
757     case HA_KEYTYPE_INT8:
758       s_value = (longlong) static_cast<char>(*key);
759       break;
760     case HA_KEYTYPE_BINARY:
761       value = (ulonglong)*key;
762       break;
763     case HA_KEYTYPE_SHORT_INT:
764       s_value = (longlong)sint2korr(key);
765       break;
766     case HA_KEYTYPE_USHORT_INT:
767       value = (ulonglong)uint2korr(key);
768       break;
769     case HA_KEYTYPE_LONG_INT:
770       s_value = (longlong)sint4korr(key);
771       break;
772     case HA_KEYTYPE_ULONG_INT:
773       value = (ulonglong)uint4korr(key);
774       break;
775     case HA_KEYTYPE_INT24:
776       s_value = (longlong)sint3korr(key);
777       break;
778     case HA_KEYTYPE_UINT24:
779       value = (ulonglong)uint3korr(key);
780       break;
781     case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
782     {
783       float f_1 = float4get(key);
784       /* Ignore negative values */
785       value = (f_1 < (float)0.0) ? 0 : (ulonglong)f_1;
786       break;
787     }
788     case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
789     {
790       double f_1 = float8get(key);
791       /* Ignore negative values */
792       value = (f_1 < 0.0) ? 0 : (ulonglong)f_1;
793       break;
794     }
795     case HA_KEYTYPE_LONGLONG:
796       s_value = sint8korr(key);
797       break;
798     case HA_KEYTYPE_ULONGLONG:
799       value = uint8korr(key);
800       break;
801     default:
802       DBUG_ASSERT(0);
803       value = 0; /* Error */
804       break;
805   }
806 
807   /*
808     The following code works becasue if s_value < 0 then value is 0
809     and if s_value == 0 then value will contain either s_value or the
810     correct value.
811   */
812   info->s->auto_increment = std::max(
813       info->s->auto_increment, (s_value > 0) ? ulonglong(s_value) : value);
814 }
815