~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/heap/hp_hash.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
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 */
 
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
15
 
16
16
/* The hash functions used for saveing keys */
17
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
 
using namespace std;
30
 
 
31
 
static uint32_t hp_hashnr(register HP_KEYDEF *keydef, register const unsigned char *key);
32
 
static int hp_key_cmp(HP_KEYDEF *keydef, const unsigned char *rec, const unsigned char *key);
 
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
}
33
94
 
34
95
 
35
96
        /* Search after a record based on a key */
36
97
        /* Sets info->current_ptr to found record */
37
98
        /* next_flag:  Search=0, next=1, prev =2, same =3 */
38
99
 
39
 
unsigned char *hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const unsigned char *key,
40
 
                uint32_t nextflag)
 
100
uchar *hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *key,
 
101
                uint nextflag)
41
102
{
42
103
  register HASH_INFO *pos,*prev_ptr;
43
104
  int flag;
44
 
  uint32_t old_nextflag;
45
 
  HP_SHARE *share=info->getShare();
 
105
  uint old_nextflag;
 
106
  HP_SHARE *share=info->s;
 
107
  DBUG_ENTER("hp_search");
46
108
  old_nextflag=nextflag;
47
109
  flag=1;
48
110
  prev_ptr=0;
57
119
      {
58
120
        switch (nextflag) {
59
121
        case 0:                                 /* Search after key */
 
122
          DBUG_PRINT("exit", ("found key at 0x%lx", (long) pos->ptr_to_rec));
60
123
          info->current_hash_ptr=pos;
61
 
          return(info->current_ptr= pos->ptr_to_rec);
 
124
          DBUG_RETURN(info->current_ptr= pos->ptr_to_rec);
62
125
        case 1:                                 /* Search next */
63
126
          if (pos->ptr_to_rec == info->current_ptr)
64
127
            nextflag=0;
66
129
        case 2:                                 /* Search previous */
67
130
          if (pos->ptr_to_rec == info->current_ptr)
68
131
          {
69
 
            errno=HA_ERR_KEY_NOT_FOUND; /* If gpos == 0 */
 
132
            my_errno=HA_ERR_KEY_NOT_FOUND;      /* If gpos == 0 */
70
133
            info->current_hash_ptr=prev_ptr;
71
 
            return(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
 
134
            DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
72
135
          }
73
136
          prev_ptr=pos;                         /* Prev. record found */
74
137
          break;
76
139
          if (pos->ptr_to_rec == info->current_ptr)
77
140
          {
78
141
            info->current_hash_ptr=pos;
79
 
            return(info->current_ptr);
 
142
            DBUG_RETURN(info->current_ptr);
80
143
          }
81
144
        }
82
145
      }
91
154
    }
92
155
    while ((pos=pos->next_key));
93
156
  }
94
 
  errno=HA_ERR_KEY_NOT_FOUND;
 
157
  my_errno=HA_ERR_KEY_NOT_FOUND;
95
158
  if (nextflag == 2 && ! info->current_ptr)
96
159
  {
97
160
    /* Do a previous from end */
98
161
    info->current_hash_ptr=prev_ptr;
99
 
    return(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
 
162
    DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
100
163
  }
101
164
 
102
165
  if (old_nextflag && nextflag)
103
 
    errno=HA_ERR_RECORD_CHANGED;                /* Didn't find old record */
104
 
  info->current_hash_ptr=0;
105
 
  return((info->current_ptr= 0));
 
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));
106
170
}
107
171
 
108
172
 
111
175
  since last read !
112
176
*/
113
177
 
114
 
unsigned char *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const unsigned char *key,
 
178
uchar *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *key,
115
179
                      HASH_INFO *pos)
116
180
{
 
181
  DBUG_ENTER("hp_search_next");
 
182
 
117
183
  while ((pos= pos->next_key))
118
184
  {
119
185
    if (! hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
120
186
    {
121
187
      info->current_hash_ptr=pos;
122
 
      return (info->current_ptr= pos->ptr_to_rec);
 
188
      DBUG_RETURN (info->current_ptr= pos->ptr_to_rec);
123
189
    }
124
190
  }
125
 
  errno=HA_ERR_KEY_NOT_FOUND;
 
191
  my_errno=HA_ERR_KEY_NOT_FOUND;
 
192
  DBUG_PRINT("exit",("Error: %d",my_errno));
126
193
  info->current_hash_ptr=0;
127
 
  return ((info->current_ptr= 0));
 
194
  DBUG_RETURN ((info->current_ptr= 0));
128
195
}
129
196
 
130
197
 
135
202
      hashnr     Hash value
136
203
      buffmax    Value such that
137
204
                 2^(n-1) < maxlength <= 2^n = buffmax
138
 
      maxlength
139
 
 
 
205
      maxlength  
 
206
  
140
207
  RETURN
141
208
    Array index, in [0..maxlength)
142
209
*/
143
210
 
144
 
uint32_t hp_mask(uint32_t hashnr, uint32_t buffmax, uint32_t maxlength)
 
211
ulong hp_mask(ulong hashnr, ulong buffmax, ulong maxlength)
145
212
{
146
213
  if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
147
214
  return (hashnr & ((buffmax >> 1) -1));
167
234
  return;
168
235
}
169
236
 
 
237
#ifndef NEW_HASH_FUNCTION
 
238
 
170
239
        /* Calc hashvalue for a key */
171
240
 
172
 
static uint32_t hp_hashnr(register HP_KEYDEF *keydef, register const unsigned char *key)
 
241
ulong hp_hashnr(register HP_KEYDEF *keydef, register const uchar *key)
173
242
{
174
 
  /*register*/
175
 
  uint32_t nr=1, nr2=4;
 
243
  /*register*/ 
 
244
  ulong nr=1, nr2=4;
176
245
  HA_KEYSEG *seg,*endseg;
177
246
 
178
247
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
179
248
  {
180
 
    unsigned char *pos=(unsigned char*) key;
 
249
    uchar *pos=(uchar*) key;
181
250
    key+=seg->length;
182
251
    if (seg->null_bit)
183
252
    {
194
263
    }
195
264
    if (seg->type == HA_KEYTYPE_TEXT)
196
265
    {
197
 
       const CHARSET_INFO * const cs= seg->charset;
198
 
       uint32_t length= seg->length;
 
266
       CHARSET_INFO *cs= seg->charset;
 
267
       uint length= seg->length;
199
268
       if (cs->mbmaxlen > 1)
200
269
       {
201
 
         uint32_t char_length;
 
270
         uint char_length;
202
271
         char_length= my_charpos(cs, pos, pos + length, length/cs->mbmaxlen);
203
272
         set_if_smaller(length, char_length);
204
273
       }
206
275
    }
207
276
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
208
277
    {
209
 
       const CHARSET_INFO * const cs= seg->charset;
210
 
       uint32_t pack_length= 2;                     /* Key packing is constant */
211
 
       uint32_t length= uint2korr(pos);
 
278
       CHARSET_INFO *cs= seg->charset;
 
279
       uint pack_length= 2;                     /* Key packing is constant */
 
280
       uint length= uint2korr(pos);
212
281
       if (cs->mbmaxlen > 1)
213
282
       {
214
 
         uint32_t char_length;
 
283
         uint char_length;
215
284
         char_length= my_charpos(cs, pos +pack_length,
216
285
                                 pos +pack_length + length,
217
286
                                 seg->length/cs->mbmaxlen);
222
291
    }
223
292
    else
224
293
    {
225
 
      for (; pos < (unsigned char*) key ; pos++)
 
294
      for (; pos < (uchar*) key ; pos++)
226
295
      {
227
 
        nr^=(uint32_t) ((((uint) nr & 63)+nr2)*((uint) *pos)) + (nr << 8);
 
296
        nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos)) + (nr << 8);
228
297
        nr2+=3;
229
298
      }
230
299
    }
231
300
  }
232
 
  return((uint32_t) nr);
 
301
  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
 
302
  return((ulong) nr);
233
303
}
234
304
 
235
305
        /* Calc hashvalue for a key in a record */
236
306
 
237
 
uint32_t hp_rec_hashnr(register HP_KEYDEF *keydef, register const unsigned char *rec)
 
307
ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const uchar *rec)
238
308
{
239
 
  uint32_t nr=1, nr2=4;
 
309
  ulong nr=1, nr2=4;
240
310
  HA_KEYSEG *seg,*endseg;
241
311
 
242
312
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
243
313
  {
244
 
    unsigned char *pos=(unsigned char*) rec+seg->start,*end=pos+seg->length;
 
314
    uchar *pos=(uchar*) rec+seg->start,*end=pos+seg->length;
245
315
    if (seg->null_bit)
246
316
    {
247
317
      if (rec[seg->null_pos] & seg->null_bit)
252
322
    }
253
323
    if (seg->type == HA_KEYTYPE_TEXT)
254
324
    {
255
 
      const CHARSET_INFO * const cs= seg->charset;
256
 
      uint32_t char_length= seg->length;
 
325
      CHARSET_INFO *cs= seg->charset;
 
326
      uint char_length= seg->length;
257
327
      if (cs->mbmaxlen > 1)
258
328
      {
259
329
        char_length= my_charpos(cs, pos, pos + char_length,
260
330
                                char_length / cs->mbmaxlen);
261
 
        set_if_smaller(char_length, (uint32_t)seg->length); /* QQ: ok to remove? */
 
331
        set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
262
332
      }
263
333
      cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
264
334
    }
265
335
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
266
336
    {
267
 
      const CHARSET_INFO * const cs= seg->charset;
268
 
      uint32_t pack_length= seg->bit_start;
269
 
      uint32_t length= (pack_length == 1 ? (uint) *(unsigned char*) pos : uint2korr(pos));
 
337
      CHARSET_INFO *cs= seg->charset;
 
338
      uint pack_length= seg->bit_start;
 
339
      uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
270
340
      if (cs->mbmaxlen > 1)
271
341
      {
272
 
        uint32_t char_length;
 
342
        uint char_length;
273
343
        char_length= my_charpos(cs, pos + pack_length,
274
344
                                pos + pack_length + length,
275
345
                                seg->length/cs->mbmaxlen);
281
351
    {
282
352
      for (; pos < end ; pos++)
283
353
      {
284
 
        nr^=(uint32_t) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
 
354
        nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
285
355
        nr2+=3;
286
356
      }
287
357
    }
288
358
  }
289
 
  return(nr);
290
 
}
 
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
 
291
481
 
292
482
/*
293
483
  Compare keys for two records. Returns 0 if they are identical
298
488
    rec1                Record to compare
299
489
    rec2                Other record to compare
300
490
    diff_if_only_endspace_difference
301
 
                        Different number of end space is significant
 
491
                        Different number of end space is significant    
302
492
 
303
493
  NOTES
304
494
    diff_if_only_endspace_difference is used to allow us to insert
309
499
    <> 0        Key differes
310
500
*/
311
501
 
312
 
int hp_rec_key_cmp(HP_KEYDEF *keydef, const unsigned char *rec1, const unsigned char *rec2,
313
 
                   bool diff_if_only_endspace_difference)
 
502
int hp_rec_key_cmp(HP_KEYDEF *keydef, const uchar *rec1, const uchar *rec2,
 
503
                   my_bool diff_if_only_endspace_difference)
314
504
{
315
505
  HA_KEYSEG *seg,*endseg;
316
506
 
326
516
    }
327
517
    if (seg->type == HA_KEYTYPE_TEXT)
328
518
    {
329
 
      const CHARSET_INFO * const cs= seg->charset;
330
 
      uint32_t char_length1;
331
 
      uint32_t char_length2;
332
 
      unsigned char *pos1= (unsigned char*)rec1 + seg->start;
333
 
      unsigned char *pos2= (unsigned char*)rec2 + seg->start;
 
519
      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;
334
524
      if (cs->mbmaxlen > 1)
335
525
      {
336
 
        uint32_t char_length= seg->length / cs->mbmaxlen;
 
526
        uint char_length= seg->length / cs->mbmaxlen;
337
527
        char_length1= my_charpos(cs, pos1, pos1 + seg->length, char_length);
338
 
        set_if_smaller(char_length1, (uint32_t)seg->length);
 
528
        set_if_smaller(char_length1, seg->length);
339
529
        char_length2= my_charpos(cs, pos2, pos2 + seg->length, char_length);
340
 
        set_if_smaller(char_length2, (uint32_t)seg->length);
 
530
        set_if_smaller(char_length2, seg->length);
341
531
      }
342
532
      else
343
533
      {
350
540
    }
351
541
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
352
542
    {
353
 
      unsigned char *pos1= (unsigned char*) rec1 + seg->start;
354
 
      unsigned char *pos2= (unsigned char*) rec2 + seg->start;
355
 
      uint32_t char_length1, char_length2;
356
 
      uint32_t pack_length= seg->bit_start;
357
 
      const CHARSET_INFO * const cs= seg->charset;
 
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
      CHARSET_INFO *cs= seg->charset;
358
548
      if (pack_length == 1)
359
549
      {
360
 
        char_length1= (uint) *(unsigned char*) pos1++;
361
 
        char_length2= (uint) *(unsigned char*) pos2++;
 
550
        char_length1= (uint) *(uchar*) pos1++;
 
551
        char_length2= (uint) *(uchar*) pos2++;
362
552
      }
363
553
      else
364
554
      {
369
559
      }
370
560
      if (cs->mbmaxlen > 1)
371
561
      {
372
 
        uint32_t safe_length1= char_length1;
373
 
        uint32_t safe_length2= char_length2;
374
 
        uint32_t char_length= seg->length / cs->mbmaxlen;
 
562
        uint safe_length1= char_length1;
 
563
        uint safe_length2= char_length2;
 
564
        uint char_length= seg->length / cs->mbmaxlen;
375
565
        char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length);
376
566
        set_if_smaller(char_length1, safe_length1);
377
567
        char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length);
387
577
    }
388
578
    else
389
579
    {
390
 
      if (memcmp(rec1+seg->start,rec2+seg->start,seg->length))
 
580
      if (bcmp(rec1+seg->start,rec2+seg->start,seg->length))
391
581
        return 1;
392
582
    }
393
583
  }
396
586
 
397
587
        /* Compare a key in a record to a whole key */
398
588
 
399
 
static int hp_key_cmp(HP_KEYDEF *keydef, const unsigned char *rec, const unsigned char *key)
 
589
int hp_key_cmp(HP_KEYDEF *keydef, const uchar *rec, const uchar *key)
400
590
{
401
591
  HA_KEYSEG *seg,*endseg;
402
592
 
419
609
    }
420
610
    if (seg->type == HA_KEYTYPE_TEXT)
421
611
    {
422
 
      const CHARSET_INFO * const cs= seg->charset;
423
 
      uint32_t char_length_key;
424
 
      uint32_t char_length_rec;
425
 
      unsigned char *pos= (unsigned char*) rec + seg->start;
 
612
      CHARSET_INFO *cs= seg->charset;
 
613
      uint char_length_key;
 
614
      uint char_length_rec;
 
615
      uchar *pos= (uchar*) rec + seg->start;
426
616
      if (cs->mbmaxlen > 1)
427
617
      {
428
 
        uint32_t char_length= seg->length / cs->mbmaxlen;
 
618
        uint char_length= seg->length / cs->mbmaxlen;
429
619
        char_length_key= my_charpos(cs, key, key + seg->length, char_length);
430
 
        set_if_smaller(char_length_key, (uint32_t)seg->length);
 
620
        set_if_smaller(char_length_key, seg->length);
431
621
        char_length_rec= my_charpos(cs, pos, pos + seg->length, char_length);
432
 
        set_if_smaller(char_length_rec, (uint32_t)seg->length);
 
622
        set_if_smaller(char_length_rec, seg->length);
433
623
      }
434
624
      else
435
625
      {
436
626
        char_length_key= seg->length;
437
627
        char_length_rec= seg->length;
438
628
      }
439
 
 
 
629
      
440
630
      if (seg->charset->coll->strnncollsp(seg->charset,
441
 
                                          (unsigned char*) pos, char_length_rec,
442
 
                                          (unsigned char*) key, char_length_key, 0))
 
631
                                          (uchar*) pos, char_length_rec,
 
632
                                          (uchar*) key, char_length_key, 0))
443
633
        return 1;
444
634
    }
445
635
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
446
636
    {
447
 
      unsigned char *pos= (unsigned char*) rec + seg->start;
448
 
      const CHARSET_INFO * const cs= seg->charset;
449
 
      uint32_t pack_length= seg->bit_start;
450
 
      uint32_t char_length_rec= (pack_length == 1 ? (uint) *(unsigned char*) pos :
 
637
      uchar *pos= (uchar*) rec + seg->start;
 
638
      CHARSET_INFO *cs= seg->charset;
 
639
      uint pack_length= seg->bit_start;
 
640
      uint char_length_rec= (pack_length == 1 ? (uint) *(uchar*) pos :
451
641
                             uint2korr(pos));
452
642
      /* Key segments are always packed with 2 bytes */
453
 
      uint32_t char_length_key= uint2korr(key);
 
643
      uint char_length_key= uint2korr(key);
454
644
      pos+= pack_length;
455
645
      key+= 2;                                  /* skip key pack length */
456
646
      if (cs->mbmaxlen > 1)
457
647
      {
458
 
        uint32_t char_length1, char_length2;
459
 
        char_length1= char_length2= seg->length / cs->mbmaxlen;
 
648
        uint char_length1, char_length2;
 
649
        char_length1= char_length2= seg->length / cs->mbmaxlen; 
460
650
        char_length1= my_charpos(cs, key, key + char_length_key, char_length1);
461
651
        set_if_smaller(char_length_key, char_length1);
462
652
        char_length2= my_charpos(cs, pos, pos + char_length_rec, char_length2);
464
654
      }
465
655
 
466
656
      if (cs->coll->strnncollsp(seg->charset,
467
 
                                (unsigned char*) pos, char_length_rec,
468
 
                                (unsigned char*) key, char_length_key, 0))
 
657
                                (uchar*) pos, char_length_rec,
 
658
                                (uchar*) key, char_length_key, 0))
469
659
        return 1;
470
660
    }
471
661
    else
472
662
    {
473
 
      if (memcmp(rec+seg->start,key,seg->length))
 
663
      if (bcmp(rec+seg->start,key,seg->length))
474
664
        return 1;
475
665
    }
476
666
  }
480
670
 
481
671
        /* Copy a key from a record to a keybuffer */
482
672
 
483
 
void hp_make_key(HP_KEYDEF *keydef, unsigned char *key, const unsigned char *rec)
 
673
void hp_make_key(HP_KEYDEF *keydef, uchar *key, const uchar *rec)
484
674
{
485
675
  HA_KEYSEG *seg,*endseg;
486
676
 
487
677
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
488
678
  {
489
 
    const CHARSET_INFO * const cs= seg->charset;
490
 
    uint32_t char_length= seg->length;
491
 
    unsigned char *pos= (unsigned char*) rec + seg->start;
 
679
    CHARSET_INFO *cs= seg->charset;
 
680
    uint char_length= seg->length;
 
681
    uchar *pos= (uchar*) rec + seg->start;
492
682
    if (seg->null_bit)
493
683
      *key++= test(rec[seg->null_pos] & seg->null_bit);
494
684
    if (cs->mbmaxlen > 1)
495
685
    {
496
686
      char_length= my_charpos(cs, pos, pos + seg->length,
497
687
                              char_length / cs->mbmaxlen);
498
 
      set_if_smaller(char_length, (uint32_t)seg->length); /* QQ: ok to remove? */
 
688
      set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
499
689
    }
500
690
    if (seg->type == HA_KEYTYPE_VARTEXT1)
501
691
      char_length+= seg->bit_start;             /* Copy also length */
511
701
    set_if_smaller(char_length,length);                                 \
512
702
  } while(0)
513
703
 
 
704
 
 
705
uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key, 
 
706
                    const uchar *rec, uchar *recpos)
 
707
{
 
708
  uchar *start_key= key;
 
709
  HA_KEYSEG *seg, *endseg;
 
710
 
 
711
  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
 
712
  {
 
713
    uint char_length;
 
714
    if (seg->null_bit)
 
715
    {
 
716
      if (!(*key++= 1 - test(rec[seg->null_pos] & seg->null_bit)))
 
717
        continue;
 
718
    }
 
719
    if (seg->flag & HA_SWAP_KEY)
 
720
    {
 
721
      uint length= seg->length;
 
722
      uchar *pos= (uchar*) rec + seg->start;
 
723
      
 
724
#ifdef HAVE_ISNAN
 
725
      if (seg->type == HA_KEYTYPE_FLOAT)
 
726
      {
 
727
        float nr;
 
728
        float4get(nr, pos);
 
729
        if (isnan(nr))
 
730
        {
 
731
          /* Replace NAN with zero */
 
732
          bzero(key, length);
 
733
          key+= length;
 
734
          continue;
 
735
        }
 
736
      }
 
737
      else if (seg->type == HA_KEYTYPE_DOUBLE)
 
738
      {
 
739
        double nr;
 
740
        float8get(nr, pos);
 
741
        if (isnan(nr))
 
742
        {
 
743
          bzero(key, length);
 
744
          key+= length;
 
745
          continue;
 
746
        }
 
747
      }
 
748
#endif
 
749
      pos+= length;
 
750
      while (length--)
 
751
      {
 
752
        *key++= *--pos;
 
753
      }
 
754
      continue;
 
755
    }
 
756
 
 
757
    if (seg->flag & HA_VAR_LENGTH_PART)
 
758
    {
 
759
      uchar *pos=      (uchar*) rec + seg->start;
 
760
      uint length=     seg->length;
 
761
      uint pack_length= seg->bit_start;
 
762
      uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
 
763
                        uint2korr(pos));
 
764
      CHARSET_INFO *cs= seg->charset;
 
765
      char_length= length/cs->mbmaxlen;
 
766
 
 
767
      pos+= pack_length;                        /* Skip VARCHAR length */
 
768
      set_if_smaller(length,tmp_length);
 
769
      FIX_LENGTH(cs, pos, length, char_length);
 
770
      store_key_length_inc(key,char_length);
 
771
      memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
 
772
      key+= char_length;
 
773
      continue;
 
774
    }
 
775
 
 
776
    char_length= seg->length;
 
777
    if (seg->charset->mbmaxlen > 1)
 
778
    {
 
779
      char_length= my_charpos(seg->charset, 
 
780
                              rec + seg->start, rec + seg->start + char_length,
 
781
                              char_length / seg->charset->mbmaxlen);
 
782
      set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
 
783
      if (char_length < seg->length)
 
784
        seg->charset->cset->fill(seg->charset, (char*) key + char_length,
 
785
                                 seg->length - char_length, ' ');
 
786
    }
 
787
    memcpy(key, rec + seg->start, (size_t) char_length);
 
788
    key+= seg->length;
 
789
  }
 
790
  memcpy(key, &recpos, sizeof(uchar*));
 
791
  return (uint) (key - start_key);
 
792
}
 
793
 
 
794
 
 
795
uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
 
796
                    key_part_map keypart_map)
 
797
{
 
798
  HA_KEYSEG *seg, *endseg;
 
799
  uchar *start_key= key;
 
800
 
 
801
  for (seg= keydef->seg, endseg= seg + keydef->keysegs;
 
802
       seg < endseg && keypart_map; old+= seg->length, seg++)
 
803
  {
 
804
    uint char_length;
 
805
    keypart_map>>= 1;
 
806
    if (seg->null_bit)
 
807
    {
 
808
      if (!(*key++= (char) 1 - *old++))
 
809
        continue;
 
810
      }
 
811
    if (seg->flag & HA_SWAP_KEY)
 
812
    {
 
813
      uint length= seg->length;
 
814
      uchar *pos= (uchar*) old + length;
 
815
      
 
816
      while (length--)
 
817
      {
 
818
        *key++= *--pos;
 
819
      }
 
820
      continue;
 
821
    }
 
822
    if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
 
823
    {
 
824
      /* Length of key-part used with heap_rkey() always 2 */
 
825
      uint tmp_length=uint2korr(old);
 
826
      uint length= seg->length;
 
827
      CHARSET_INFO *cs= seg->charset;
 
828
      char_length= length/cs->mbmaxlen;
 
829
 
 
830
      old+= 2;
 
831
      set_if_smaller(length,tmp_length);        /* Safety */
 
832
      FIX_LENGTH(cs, old, length, char_length);
 
833
      store_key_length_inc(key,char_length);
 
834
      memcpy((uchar*) key, old,(size_t) char_length);
 
835
      key+= char_length;
 
836
      continue;
 
837
    }
 
838
    char_length= seg->length;
 
839
    if (seg->charset->mbmaxlen > 1)
 
840
    {
 
841
      char_length= my_charpos(seg->charset, old, old+char_length,
 
842
                              char_length / seg->charset->mbmaxlen);
 
843
      set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
 
844
      if (char_length < seg->length)
 
845
        seg->charset->cset->fill(seg->charset, (char*) key + char_length, 
 
846
                                 seg->length - char_length, ' ');
 
847
    }
 
848
    memcpy(key, old, (size_t) char_length);
 
849
    key+= seg->length;
 
850
  }
 
851
  return (uint) (key - start_key);
 
852
}
 
853
 
 
854
 
 
855
uint hp_rb_key_length(HP_KEYDEF *keydef, 
 
856
                      const uchar *key __attribute__((unused)))
 
857
{
 
858
  return keydef->length;
 
859
}
 
860
 
 
861
 
 
862
uint hp_rb_null_key_length(HP_KEYDEF *keydef, const uchar *key)
 
863
{
 
864
  const uchar *start_key= key;
 
865
  HA_KEYSEG *seg, *endseg;
 
866
  
 
867
  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
 
868
  {
 
869
    if (seg->null_bit && !*key++)
 
870
      continue;
 
871
    key+= seg->length;
 
872
  }
 
873
  return (uint) (key - start_key);
 
874
}
 
875
                  
 
876
 
 
877
uint hp_rb_var_key_length(HP_KEYDEF *keydef, const uchar *key)
 
878
{
 
879
  const uchar *start_key= key;
 
880
  HA_KEYSEG *seg, *endseg;
 
881
  
 
882
  for (seg= keydef->seg, endseg= seg + keydef->keysegs; seg < endseg; seg++)
 
883
  {
 
884
    uint length= seg->length;
 
885
    if (seg->null_bit && !*key++)
 
886
      continue;
 
887
    if (seg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
 
888
    {
 
889
      get_key_length(length, key);
 
890
    }
 
891
    key+= length;
 
892
  }
 
893
  return (uint) (key - start_key);
 
894
}
 
895
 
 
896
 
514
897
/*
515
898
  Test if any of the key parts are NULL.
516
899
  Return:
518
901
    0 otherwise
519
902
*/
520
903
 
521
 
bool hp_if_null_in_key(HP_KEYDEF *keydef, const unsigned char *record)
 
904
my_bool hp_if_null_in_key(HP_KEYDEF *keydef, const uchar *record)
522
905
{
523
906
  HA_KEYSEG *seg,*endseg;
524
907
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
544
927
    less than zero.
545
928
*/
546
929
 
547
 
void heap_update_auto_increment(HP_INFO *info, const unsigned char *record)
 
930
void heap_update_auto_increment(HP_INFO *info, const uchar *record)
548
931
{
549
 
  uint64_t value= 0;                    /* Store unsigned values here */
550
 
  int64_t s_value= 0;                   /* Store signed values here */
551
 
 
552
 
  HA_KEYSEG *keyseg= info->getShare()->keydef[info->getShare()->auto_key - 1].seg;
553
 
  const unsigned char *key=  (unsigned char*) record + keyseg->start;
554
 
 
555
 
  switch (info->getShare()->auto_key_type) {
 
932
  ulonglong value= 0;                   /* Store unsigned values here */
 
933
  longlong s_value= 0;                  /* Store signed values here */
 
934
 
 
935
  HA_KEYSEG *keyseg= info->s->keydef[info->s->auto_key - 1].seg;
 
936
  const uchar *key=  (uchar*) record + keyseg->start;
 
937
 
 
938
  switch (info->s->auto_key_type) {
 
939
  case HA_KEYTYPE_INT8:
 
940
    s_value= (longlong) *(char*)key;
 
941
    break;
556
942
  case HA_KEYTYPE_BINARY:
557
 
    value=(uint64_t)  *(unsigned char*) key;
 
943
    value=(ulonglong)  *(uchar*) key;
 
944
    break;
 
945
  case HA_KEYTYPE_SHORT_INT:
 
946
    s_value= (longlong) sint2korr(key);
 
947
    break;
 
948
  case HA_KEYTYPE_USHORT_INT:
 
949
    value=(ulonglong) uint2korr(key);
558
950
    break;
559
951
  case HA_KEYTYPE_LONG_INT:
560
 
    s_value= (int64_t) sint4korr(key);
 
952
    s_value= (longlong) sint4korr(key);
561
953
    break;
562
954
  case HA_KEYTYPE_ULONG_INT:
563
 
    value=(uint64_t) uint4korr(key);
564
 
    break;
 
955
    value=(ulonglong) uint4korr(key);
 
956
    break;
 
957
  case HA_KEYTYPE_INT24:
 
958
    s_value= (longlong) sint3korr(key);
 
959
    break;
 
960
  case HA_KEYTYPE_UINT24:
 
961
    value=(ulonglong) uint3korr(key);
 
962
    break;
 
963
  case HA_KEYTYPE_FLOAT:                        /* This shouldn't be used */
 
964
  {
 
965
    float f_1;
 
966
    float4get(f_1,key);
 
967
    /* Ignore negative values */
 
968
    value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
 
969
    break;
 
970
  }
565
971
  case HA_KEYTYPE_DOUBLE:                       /* This shouldn't be used */
566
972
  {
567
973
    double f_1;
568
974
    float8get(f_1,key);
569
975
    /* Ignore negative values */
570
 
    value = (f_1 < 0.0) ? 0 : (uint64_t) f_1;
 
976
    value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
571
977
    break;
572
978
  }
573
979
  case HA_KEYTYPE_LONGLONG:
577
983
    value= uint8korr(key);
578
984
    break;
579
985
  default:
580
 
    assert(0);
 
986
    DBUG_ASSERT(0);
581
987
    value=0;                                    /* Error */
582
988
    break;
583
989
  }
587
993
    and if s_value == 0 then value will contain either s_value or the
588
994
    correct value.
589
995
  */
590
 
  set_if_bigger(info->getShare()->auto_increment,
591
 
                (s_value > 0) ? (uint64_t) s_value : value);
 
996
  set_if_bigger(info->s->auto_increment,
 
997
                (s_value > 0) ? (ulonglong) s_value : value);
592
998
}