~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/heap/hp_hash.cc

Split out warnings - start using the pandora build system.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
 
 
16
 
/* The hash functions used for saveing keys */
17
 
 
18
 
#include "heap_priv.h"
19
 
 
20
 
#include "drizzled/charset_info.h"
21
 
#include <drizzled/util/test.h>
22
 
 
23
 
#include <math.h>
24
 
#include <string.h>
25
 
 
26
 
#include <cassert>
27
 
 
28
 
using namespace drizzled;
29
 
 
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);
32
 
 
33
 
/*
34
 
  Find out how many rows there is in the given range
35
 
 
36
 
  SYNOPSIS
37
 
    hp_rb_records_in_range()
38
 
    info                HEAP handler
39
 
    inx                 Index to use
40
 
    min_key             Min key. Is = 0 if no min range
41
 
    max_key             Max key. Is = 0 if no max range
42
 
 
43
 
  NOTES
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
47
 
 
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
51
 
 
52
 
  RETURN
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
56
 
                        the range.
57
 
*/
58
 
 
59
 
ha_rows hp_rb_records_in_range(HP_INFO *info, int inx,  key_range *min_key,
60
 
                               key_range *max_key)
61
 
{
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;
66
 
 
67
 
  info->lastinx= inx;
68
 
  custom_arg.keyseg= keyinfo->seg;
69
 
  custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME;
70
 
  if (min_key)
71
 
  {
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,
76
 
                               &custom_arg);
77
 
  }
78
 
  else
79
 
  {
80
 
    start_pos= 0;
81
 
  }
82
 
 
83
 
  if (max_key)
84
 
  {
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,
89
 
                             &custom_arg);
90
 
  }
91
 
  else
92
 
  {
93
 
    end_pos= rb_tree->elements_in_tree + (ha_rows)1;
94
 
  }
95
 
 
96
 
  if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR)
97
 
    return(HA_POS_ERROR);
98
 
  return(end_pos < start_pos ? (ha_rows) 0 :
99
 
              (end_pos == start_pos ? (ha_rows) 1 : end_pos - start_pos));
100
 
}
101
 
 
102
 
 
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 */
106
 
 
107
 
unsigned char *hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const unsigned char *key,
108
 
                uint32_t nextflag)
109
 
{
110
 
  register HASH_INFO *pos,*prev_ptr;
111
 
  int flag;
112
 
  uint32_t old_nextflag;
113
 
  HP_SHARE *share=info->s;
114
 
  old_nextflag=nextflag;
115
 
  flag=1;
116
 
  prev_ptr=0;
117
 
 
118
 
  if (share->records)
119
 
  {
120
 
    pos=hp_find_hash(&keyinfo->block, hp_mask(hp_hashnr(keyinfo, key),
121
 
                                              share->blength, share->records));
122
 
    do
123
 
    {
124
 
      if (!hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
125
 
      {
126
 
        switch (nextflag) {
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)
132
 
            nextflag=0;
133
 
          break;
134
 
        case 2:                                 /* Search previous */
135
 
          if (pos->ptr_to_rec == info->current_ptr)
136
 
          {
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);
140
 
          }
141
 
          prev_ptr=pos;                         /* Prev. record found */
142
 
          break;
143
 
        case 3:                                 /* Search same */
144
 
          if (pos->ptr_to_rec == info->current_ptr)
145
 
          {
146
 
            info->current_hash_ptr=pos;
147
 
            return(info->current_ptr);
148
 
          }
149
 
        }
150
 
      }
151
 
      if (flag)
152
 
      {
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 */
158
 
      }
159
 
    }
160
 
    while ((pos=pos->next_key));
161
 
  }
162
 
  errno=HA_ERR_KEY_NOT_FOUND;
163
 
  if (nextflag == 2 && ! info->current_ptr)
164
 
  {
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);
168
 
  }
169
 
 
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));
174
 
}
175
 
 
176
 
 
177
 
/*
178
 
  Search next after last read;  Assumes that the table hasn't changed
179
 
  since last read !
180
 
*/
181
 
 
182
 
unsigned char *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const unsigned char *key,
183
 
                      HASH_INFO *pos)
184
 
{
185
 
  while ((pos= pos->next_key))
186
 
  {
187
 
    if (! hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
188
 
    {
189
 
      info->current_hash_ptr=pos;
190
 
      return (info->current_ptr= pos->ptr_to_rec);
191
 
    }
192
 
  }
193
 
  errno=HA_ERR_KEY_NOT_FOUND;
194
 
  info->current_hash_ptr=0;
195
 
  return ((info->current_ptr= 0));
196
 
}
197
 
 
198
 
 
199
 
/*
200
 
  Calculate position number for hash value.
201
 
  SYNOPSIS
202
 
    hp_mask()
203
 
      hashnr     Hash value
204
 
      buffmax    Value such that
205
 
                 2^(n-1) < maxlength <= 2^n = buffmax
206
 
      maxlength
207
 
 
208
 
  RETURN
209
 
    Array index, in [0..maxlength)
210
 
*/
211
 
 
212
 
uint32_t hp_mask(uint32_t hashnr, uint32_t buffmax, uint32_t maxlength)
213
 
{
214
 
  if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
215
 
  return (hashnr & ((buffmax >> 1) -1));
216
 
}
217
 
 
218
 
 
219
 
/*
220
 
  Change
221
 
    next_link -> ... -> X -> pos
222
 
  to
223
 
    next_link -> ... -> X -> newlink
224
 
*/
225
 
 
226
 
void hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink)
227
 
{
228
 
  HASH_INFO *old_link;
229
 
  do
230
 
  {
231
 
    old_link=next_link;
232
 
  }
233
 
  while ((next_link=next_link->next_key) != pos);
234
 
  old_link->next_key=newlink;
235
 
  return;
236
 
}
237
 
 
238
 
        /* Calc hashvalue for a key */
239
 
 
240
 
static uint32_t hp_hashnr(register HP_KEYDEF *keydef, register const unsigned char *key)
241
 
{
242
 
  /*register*/
243
 
  uint32_t nr=1, nr2=4;
244
 
  HA_KEYSEG *seg,*endseg;
245
 
 
246
 
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
247
 
  {
248
 
    unsigned char *pos=(unsigned char*) key;
249
 
    key+=seg->length;
250
 
    if (seg->null_bit)
251
 
    {
252
 
      key++;                                    /* Skip null byte */
253
 
      if (*pos)                                 /* Found null */
254
 
      {
255
 
        nr^= (nr << 1) | 1;
256
 
        /* Add key pack length (2) to key for VARCHAR segments */
257
 
        if (seg->type == HA_KEYTYPE_VARTEXT1)
258
 
          key+= 2;
259
 
        continue;
260
 
      }
261
 
      pos++;
262
 
    }
263
 
    if (seg->type == HA_KEYTYPE_TEXT)
264
 
    {
265
 
       const CHARSET_INFO * const cs= seg->charset;
266
 
       uint32_t length= seg->length;
267
 
       if (cs->mbmaxlen > 1)
268
 
       {
269
 
         uint32_t char_length;
270
 
         char_length= my_charpos(cs, pos, pos + length, length/cs->mbmaxlen);
271
 
         set_if_smaller(length, char_length);
272
 
       }
273
 
       cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
274
 
    }
275
 
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
276
 
    {
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)
281
 
       {
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);
287
 
       }
288
 
       cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
289
 
       key+= pack_length;
290
 
    }
291
 
    else
292
 
    {
293
 
      for (; pos < (unsigned char*) key ; pos++)
294
 
      {
295
 
        nr^=(uint32_t) ((((uint) nr & 63)+nr2)*((uint) *pos)) + (nr << 8);
296
 
        nr2+=3;
297
 
      }
298
 
    }
299
 
  }
300
 
  return((uint32_t) nr);
301
 
}
302
 
 
303
 
        /* Calc hashvalue for a key in a record */
304
 
 
305
 
uint32_t hp_rec_hashnr(register HP_KEYDEF *keydef, register const unsigned char *rec)
306
 
{
307
 
  uint32_t nr=1, nr2=4;
308
 
  HA_KEYSEG *seg,*endseg;
309
 
 
310
 
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
311
 
  {
312
 
    unsigned char *pos=(unsigned char*) rec+seg->start,*end=pos+seg->length;
313
 
    if (seg->null_bit)
314
 
    {
315
 
      if (rec[seg->null_pos] & seg->null_bit)
316
 
      {
317
 
        nr^= (nr << 1) | 1;
318
 
        continue;
319
 
      }
320
 
    }
321
 
    if (seg->type == HA_KEYTYPE_TEXT)
322
 
    {
323
 
      const CHARSET_INFO * const cs= seg->charset;
324
 
      uint32_t char_length= seg->length;
325
 
      if (cs->mbmaxlen > 1)
326
 
      {
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? */
330
 
      }
331
 
      cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
332
 
    }
333
 
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
334
 
    {
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)
339
 
      {
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);
345
 
      }
346
 
      cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
347
 
    }
348
 
    else
349
 
    {
350
 
      for (; pos < end ; pos++)
351
 
      {
352
 
        nr^=(uint32_t) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
353
 
        nr2+=3;
354
 
      }
355
 
    }
356
 
  }
357
 
  return(nr);
358
 
}
359
 
 
360
 
/*
361
 
  Compare keys for two records. Returns 0 if they are identical
362
 
 
363
 
  SYNOPSIS
364
 
    hp_rec_key_cmp()
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
370
 
 
371
 
  NOTES
372
 
    diff_if_only_endspace_difference is used to allow us to insert
373
 
    'a' and 'a ' when there is an an unique key.
374
 
 
375
 
  RETURN
376
 
    0           Key is identical
377
 
    <> 0        Key differes
378
 
*/
379
 
 
380
 
int hp_rec_key_cmp(HP_KEYDEF *keydef, const unsigned char *rec1, const unsigned char *rec2,
381
 
                   bool diff_if_only_endspace_difference)
382
 
{
383
 
  HA_KEYSEG *seg,*endseg;
384
 
 
385
 
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
386
 
  {
387
 
    if (seg->null_bit)
388
 
    {
389
 
      if ((rec1[seg->null_pos] & seg->null_bit) !=
390
 
          (rec2[seg->null_pos] & seg->null_bit))
391
 
        return 1;
392
 
      if (rec1[seg->null_pos] & seg->null_bit)
393
 
        continue;
394
 
    }
395
 
    if (seg->type == HA_KEYTYPE_TEXT)
396
 
    {
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)
403
 
      {
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);
409
 
      }
410
 
      else
411
 
      {
412
 
        char_length1= char_length2= seg->length;
413
 
      }
414
 
      if (seg->charset->coll->strnncollsp(seg->charset,
415
 
                                          pos1,char_length1,
416
 
                                          pos2,char_length2, 0))
417
 
        return 1;
418
 
    }
419
 
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
420
 
    {
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)
427
 
      {
428
 
        char_length1= (uint) *(unsigned char*) pos1++;
429
 
        char_length2= (uint) *(unsigned char*) pos2++;
430
 
      }
431
 
      else
432
 
      {
433
 
        char_length1= uint2korr(pos1);
434
 
        char_length2= uint2korr(pos2);
435
 
        pos1+= 2;
436
 
        pos2+= 2;
437
 
      }
438
 
      if (cs->mbmaxlen > 1)
439
 
      {
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);
447
 
      }
448
 
 
449
 
      if (cs->coll->strnncollsp(seg->charset,
450
 
                                pos1, char_length1,
451
 
                                pos2, char_length2,
452
 
                                seg->flag & HA_END_SPACE_ARE_EQUAL ?
453
 
                                0 : diff_if_only_endspace_difference))
454
 
        return 1;
455
 
    }
456
 
    else
457
 
    {
458
 
      if (memcmp(rec1+seg->start,rec2+seg->start,seg->length))
459
 
        return 1;
460
 
    }
461
 
  }
462
 
  return 0;
463
 
}
464
 
 
465
 
        /* Compare a key in a record to a whole key */
466
 
 
467
 
static int hp_key_cmp(HP_KEYDEF *keydef, const unsigned char *rec, const unsigned char *key)
468
 
{
469
 
  HA_KEYSEG *seg,*endseg;
470
 
 
471
 
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ;
472
 
       seg < endseg ;
473
 
       key+= (seg++)->length)
474
 
  {
475
 
    if (seg->null_bit)
476
 
    {
477
 
      int found_null=test(rec[seg->null_pos] & seg->null_bit);
478
 
      if (found_null != (int) *key++)
479
 
        return 1;
480
 
      if (found_null)
481
 
      {
482
 
        /* Add key pack length (2) to key for VARCHAR segments */
483
 
        if (seg->type == HA_KEYTYPE_VARTEXT1)
484
 
          key+= 2;
485
 
        continue;
486
 
      }
487
 
    }
488
 
    if (seg->type == HA_KEYTYPE_TEXT)
489
 
    {
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)
495
 
      {
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);
501
 
      }
502
 
      else
503
 
      {
504
 
        char_length_key= seg->length;
505
 
        char_length_rec= seg->length;
506
 
      }
507
 
 
508
 
      if (seg->charset->coll->strnncollsp(seg->charset,
509
 
                                          (unsigned char*) pos, char_length_rec,
510
 
                                          (unsigned char*) key, char_length_key, 0))
511
 
        return 1;
512
 
    }
513
 
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
514
 
    {
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 :
519
 
                             uint2korr(pos));
520
 
      /* Key segments are always packed with 2 bytes */
521
 
      uint32_t char_length_key= uint2korr(key);
522
 
      pos+= pack_length;
523
 
      key+= 2;                                  /* skip key pack length */
524
 
      if (cs->mbmaxlen > 1)
525
 
      {
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);
532
 
      }
533
 
 
534
 
      if (cs->coll->strnncollsp(seg->charset,
535
 
                                (unsigned char*) pos, char_length_rec,
536
 
                                (unsigned char*) key, char_length_key, 0))
537
 
        return 1;
538
 
    }
539
 
    else
540
 
    {
541
 
      if (memcmp(rec+seg->start,key,seg->length))
542
 
        return 1;
543
 
    }
544
 
  }
545
 
  return 0;
546
 
}
547
 
 
548
 
 
549
 
        /* Copy a key from a record to a keybuffer */
550
 
 
551
 
void hp_make_key(HP_KEYDEF *keydef, unsigned char *key, const unsigned char *rec)
552
 
{
553
 
  HA_KEYSEG *seg,*endseg;
554
 
 
555
 
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
556
 
  {
557
 
    const CHARSET_INFO * const cs= seg->charset;
558
 
    uint32_t char_length= seg->length;
559
 
    unsigned char *pos= (unsigned char*) rec + seg->start;
560
 
    if (seg->null_bit)
561
 
      *key++= test(rec[seg->null_pos] & seg->null_bit);
562
 
    if (cs->mbmaxlen > 1)
563
 
    {
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? */
567
 
    }
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);
571
 
    key+= char_length;
572
 
  }
573
 
}
574
 
 
575
 
#define FIX_LENGTH(cs, pos, length, char_length)                        \
576
 
  do {                                                                  \
577
 
    if (length > char_length)                                           \
578
 
      char_length= my_charpos(cs, pos, pos+length, char_length);        \
579
 
    set_if_smaller(char_length,length);                                 \
580
 
  } while(0)
581
 
 
582
 
 
583
 
uint32_t hp_rb_make_key(HP_KEYDEF *keydef, unsigned char *key,
584
 
                    const unsigned char *rec, unsigned char *recpos)
585
 
{
586
 
  unsigned char *start_key= key;
587
 
  HA_KEYSEG *seg, *endseg;
588
 
 
589
 
  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
590
 
  {
591
 
    uint32_t char_length;
592
 
    if (seg->null_bit)
593
 
    {
594
 
      if (!(*key++= 1 - test(rec[seg->null_pos] & seg->null_bit)))
595
 
        continue;
596
 
    }
597
 
    if (seg->flag & HA_SWAP_KEY)
598
 
    {
599
 
      uint32_t length= seg->length;
600
 
      unsigned char *pos= (unsigned char*) rec + seg->start;
601
 
 
602
 
      if (seg->type == HA_KEYTYPE_DOUBLE)
603
 
      {
604
 
        double nr;
605
 
        float8get(nr, pos);
606
 
        if (isnan(nr))
607
 
        {
608
 
          memset(key, 0, length);
609
 
          key+= length;
610
 
          continue;
611
 
        }
612
 
      }
613
 
      pos+= length;
614
 
      while (length--)
615
 
      {
616
 
        *key++= *--pos;
617
 
      }
618
 
      continue;
619
 
    }
620
 
 
621
 
    if (seg->flag & HA_VAR_LENGTH_PART)
622
 
    {
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 :
627
 
                        uint2korr(pos));
628
 
      const CHARSET_INFO * const cs= seg->charset;
629
 
      char_length= length/cs->mbmaxlen;
630
 
 
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);
636
 
      key+= char_length;
637
 
      continue;
638
 
    }
639
 
 
640
 
    char_length= seg->length;
641
 
    if (seg->charset->mbmaxlen > 1)
642
 
    {
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, ' ');
650
 
    }
651
 
    memcpy(key, rec + seg->start, (size_t) char_length);
652
 
    key+= seg->length;
653
 
  }
654
 
  memcpy(key, &recpos, sizeof(unsigned char*));
655
 
  return (uint32_t) (key - start_key);
656
 
}
657
 
 
658
 
 
659
 
uint32_t hp_rb_pack_key(HP_KEYDEF *keydef, unsigned char *key, const unsigned char *old,
660
 
                    key_part_map keypart_map)
661
 
{
662
 
  HA_KEYSEG *seg, *endseg;
663
 
  unsigned char *start_key= key;
664
 
 
665
 
  for (seg= keydef->seg, endseg= seg + keydef->keysegs;
666
 
       seg < endseg && keypart_map; old+= seg->length, seg++)
667
 
  {
668
 
    uint32_t char_length;
669
 
    keypart_map>>= 1;
670
 
    if (seg->null_bit)
671
 
    {
672
 
      if (!(*key++= (char) 1 - *old++))
673
 
        continue;
674
 
      }
675
 
    if (seg->flag & HA_SWAP_KEY)
676
 
    {
677
 
      uint32_t length= seg->length;
678
 
      unsigned char *pos= (unsigned char*) old + length;
679
 
 
680
 
      while (length--)
681
 
      {
682
 
        *key++= *--pos;
683
 
      }
684
 
      continue;
685
 
    }
686
 
    if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
687
 
    {
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;
693
 
 
694
 
      old+= 2;
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);
699
 
      key+= char_length;
700
 
      continue;
701
 
    }
702
 
    char_length= seg->length;
703
 
    if (seg->charset->mbmaxlen > 1)
704
 
    {
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, ' ');
711
 
    }
712
 
    memcpy(key, old, (size_t) char_length);
713
 
    key+= seg->length;
714
 
  }
715
 
  return (uint) (key - start_key);
716
 
}
717
 
 
718
 
 
719
 
uint32_t hp_rb_key_length(HP_KEYDEF *keydef, const unsigned char *not_used)
720
 
{
721
 
  (void)not_used;
722
 
  return keydef->length;
723
 
}
724
 
 
725
 
 
726
 
uint32_t hp_rb_null_key_length(HP_KEYDEF *keydef, const unsigned char *key)
727
 
{
728
 
  const unsigned char *start_key= key;
729
 
  HA_KEYSEG *seg, *endseg;
730
 
 
731
 
  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
732
 
  {
733
 
    if (seg->null_bit && !*key++)
734
 
      continue;
735
 
    key+= seg->length;
736
 
  }
737
 
  return (uint) (key - start_key);
738
 
}
739
 
 
740
 
 
741
 
uint32_t hp_rb_var_key_length(HP_KEYDEF *keydef, const unsigned char *key)
742
 
{
743
 
  const unsigned char *start_key= key;
744
 
  HA_KEYSEG *seg, *endseg;
745
 
 
746
 
  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
747
 
  {
748
 
    uint32_t length= seg->length;
749
 
    if (seg->null_bit && !*key++)
750
 
      continue;
751
 
    if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
752
 
    {
753
 
      get_key_length(length, key);
754
 
    }
755
 
    key+= length;
756
 
  }
757
 
  return (uint) (key - start_key);
758
 
}
759
 
 
760
 
 
761
 
/*
762
 
  Test if any of the key parts are NULL.
763
 
  Return:
764
 
    1 if any of the key parts was NULL
765
 
    0 otherwise
766
 
*/
767
 
 
768
 
bool hp_if_null_in_key(HP_KEYDEF *keydef, const unsigned char *record)
769
 
{
770
 
  HA_KEYSEG *seg,*endseg;
771
 
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
772
 
  {
773
 
    if (seg->null_bit && (record[seg->null_pos] & seg->null_bit))
774
 
      return 1;
775
 
  }
776
 
  return 0;
777
 
}
778
 
 
779
 
 
780
 
/*
781
 
  Update auto_increment info
782
 
 
783
 
  SYNOPSIS
784
 
    update_auto_increment()
785
 
    info                        MyISAM handler
786
 
    record                      Row to update
787
 
 
788
 
  IMPLEMENTATION
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
791
 
    less than zero.
792
 
*/
793
 
 
794
 
void heap_update_auto_increment(HP_INFO *info, const unsigned char *record)
795
 
{
796
 
  uint64_t value= 0;                    /* Store unsigned values here */
797
 
  int64_t s_value= 0;                   /* Store signed values here */
798
 
 
799
 
  HA_KEYSEG *keyseg= info->s->keydef[info->s->auto_key - 1].seg;
800
 
  const unsigned char *key=  (unsigned char*) record + keyseg->start;
801
 
 
802
 
  switch (info->s->auto_key_type) {
803
 
  case HA_KEYTYPE_BINARY:
804
 
    value=(uint64_t)  *(unsigned char*) key;
805
 
    break;
806
 
  case HA_KEYTYPE_LONG_INT:
807
 
    s_value= (int64_t) sint4korr(key);
808
 
    break;
809
 
  case HA_KEYTYPE_ULONG_INT:
810
 
    value=(uint64_t) uint4korr(key);
811
 
    break;
812
 
  case HA_KEYTYPE_UINT24:
813
 
    value=(uint64_t) uint3korr(key);
814
 
    break;
815
 
  case HA_KEYTYPE_DOUBLE:                       /* This shouldn't be used */
816
 
  {
817
 
    double f_1;
818
 
    float8get(f_1,key);
819
 
    /* Ignore negative values */
820
 
    value = (f_1 < 0.0) ? 0 : (uint64_t) f_1;
821
 
    break;
822
 
  }
823
 
  case HA_KEYTYPE_LONGLONG:
824
 
    s_value= sint8korr(key);
825
 
    break;
826
 
  case HA_KEYTYPE_ULONGLONG:
827
 
    value= uint8korr(key);
828
 
    break;
829
 
  default:
830
 
    assert(0);
831
 
    value=0;                                    /* Error */
832
 
    break;
833
 
  }
834
 
 
835
 
  /*
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
838
 
    correct value.
839
 
  */
840
 
  set_if_bigger(info->s->auto_increment,
841
 
                (s_value > 0) ? (uint64_t) s_value : value);
842
 
}