~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to storage/heap/hp_hash.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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 "heapdef.h"
 
19
#include <m_ctype.h>
 
20
 
 
21
 
 
22
 
 
23
/*
 
24
  Find out how many rows there is in the given range
 
25
 
 
26
  SYNOPSIS
 
27
    hp_rb_records_in_range()
 
28
    info                HEAP handler
 
29
    inx                 Index to use
 
30
    min_key             Min key. Is = 0 if no min range
 
31
    max_key             Max key. Is = 0 if no max range
 
32
 
 
33
  NOTES
 
34
    min_key.flag can have one of the following values:
 
35
      HA_READ_KEY_EXACT         Include the key in the range
 
36
      HA_READ_AFTER_KEY         Don't include key in range
 
37
 
 
38
    max_key.flag can have one of the following values:
 
39
      HA_READ_BEFORE_KEY        Don't include key in range
 
40
      HA_READ_AFTER_KEY         Include all 'end_key' values in the range
 
41
 
 
42
  RETURN
 
43
   HA_POS_ERROR         Something is wrong with the index tree.
 
44
   0                    There is no matching keys in the given range
 
45
   number > 0           There is approximately 'number' matching rows in
 
46
                        the range.
 
47
*/
 
48
 
 
49
ha_rows hp_rb_records_in_range(HP_INFO *info, int inx,  key_range *min_key,
 
50
                               key_range *max_key)
 
51
{
 
52
  ha_rows start_pos, end_pos;
 
53
  HP_KEYDEF *keyinfo= info->s->keydef + inx;
 
54
  TREE *rb_tree = &keyinfo->rb_tree;
 
55
  heap_rb_param custom_arg;
 
56
  DBUG_ENTER("hp_rb_records_in_range");
 
57
 
 
58
  info->lastinx= inx;
 
59
  custom_arg.keyseg= keyinfo->seg;
 
60
  custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME;
 
61
  if (min_key)
 
62
  {
 
63
    custom_arg.key_length= hp_rb_pack_key(keyinfo, (uchar*) info->recbuf,
 
64
                                          (uchar*) min_key->key,
 
65
                                          min_key->keypart_map);
 
66
    start_pos= tree_record_pos(rb_tree, info->recbuf, min_key->flag,
 
67
                               &custom_arg);
 
68
  }
 
69
  else
 
70
  {
 
71
    start_pos= 0;
 
72
  }
 
73
 
 
74
  if (max_key)
 
75
  {
 
76
    custom_arg.key_length= hp_rb_pack_key(keyinfo, (uchar*) info->recbuf,
 
77
                                          (uchar*) max_key->key,
 
78
                                          max_key->keypart_map);
 
79
    end_pos= tree_record_pos(rb_tree, info->recbuf, max_key->flag,
 
80
                             &custom_arg);
 
81
  }
 
82
  else
 
83
  {
 
84
    end_pos= rb_tree->elements_in_tree + (ha_rows)1;
 
85
  }
 
86
 
 
87
  DBUG_PRINT("info",("start_pos: %lu  end_pos: %lu", (ulong) start_pos,
 
88
                     (ulong) end_pos));
 
89
  if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR)
 
90
    DBUG_RETURN(HA_POS_ERROR);
 
91
  DBUG_RETURN(end_pos < start_pos ? (ha_rows) 0 :
 
92
              (end_pos == start_pos ? (ha_rows) 1 : end_pos - start_pos));
 
93
}
 
94
 
 
95
 
 
96
        /* Search after a record based on a key */
 
97
        /* Sets info->current_ptr to found record */
 
98
        /* next_flag:  Search=0, next=1, prev =2, same =3 */
 
99
 
 
100
uchar *hp_search(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *key,
 
101
                uint nextflag)
 
102
{
 
103
  reg1 HASH_INFO *pos,*prev_ptr;
 
104
  int flag;
 
105
  uint old_nextflag;
 
106
  HP_SHARE *share=info->s;
 
107
  DBUG_ENTER("hp_search");
 
108
  old_nextflag=nextflag;
 
109
  flag=1;
 
110
  prev_ptr=0;
 
111
 
 
112
  if (share->records)
 
113
  {
 
114
    pos=hp_find_hash(&keyinfo->block, hp_mask(hp_hashnr(keyinfo, key),
 
115
                                              share->blength, share->records));
 
116
    do
 
117
    {
 
118
      if (!hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
 
119
      {
 
120
        switch (nextflag) {
 
121
        case 0:                                 /* Search after key */
 
122
          DBUG_PRINT("exit", ("found key at 0x%lx", (long) pos->ptr_to_rec));
 
123
          info->current_hash_ptr=pos;
 
124
          DBUG_RETURN(info->current_ptr= pos->ptr_to_rec);
 
125
        case 1:                                 /* Search next */
 
126
          if (pos->ptr_to_rec == info->current_ptr)
 
127
            nextflag=0;
 
128
          break;
 
129
        case 2:                                 /* Search previous */
 
130
          if (pos->ptr_to_rec == info->current_ptr)
 
131
          {
 
132
            my_errno=HA_ERR_KEY_NOT_FOUND;      /* If gpos == 0 */
 
133
            info->current_hash_ptr=prev_ptr;
 
134
            DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
 
135
          }
 
136
          prev_ptr=pos;                         /* Prev. record found */
 
137
          break;
 
138
        case 3:                                 /* Search same */
 
139
          if (pos->ptr_to_rec == info->current_ptr)
 
140
          {
 
141
            info->current_hash_ptr=pos;
 
142
            DBUG_RETURN(info->current_ptr);
 
143
          }
 
144
        }
 
145
      }
 
146
      if (flag)
 
147
      {
 
148
        flag=0;                                 /* Reset flag */
 
149
        if (hp_find_hash(&keyinfo->block,
 
150
                         hp_mask(hp_rec_hashnr(keyinfo, pos->ptr_to_rec),
 
151
                                  share->blength, share->records)) != pos)
 
152
          break;                                /* Wrong link */
 
153
      }
 
154
    }
 
155
    while ((pos=pos->next_key));
 
156
  }
 
157
  my_errno=HA_ERR_KEY_NOT_FOUND;
 
158
  if (nextflag == 2 && ! info->current_ptr)
 
159
  {
 
160
    /* Do a previous from end */
 
161
    info->current_hash_ptr=prev_ptr;
 
162
    DBUG_RETURN(info->current_ptr=prev_ptr ? prev_ptr->ptr_to_rec : 0);
 
163
  }
 
164
 
 
165
  if (old_nextflag && nextflag)
 
166
    my_errno=HA_ERR_RECORD_CHANGED;             /* Didn't find old record */
 
167
  DBUG_PRINT("exit",("Error: %d",my_errno));
 
168
  info->current_hash_ptr=0;  
 
169
  DBUG_RETURN((info->current_ptr= 0));
 
170
}
 
171
 
 
172
 
 
173
/*
 
174
  Search next after last read;  Assumes that the table hasn't changed
 
175
  since last read !
 
176
*/
 
177
 
 
178
uchar *hp_search_next(HP_INFO *info, HP_KEYDEF *keyinfo, const uchar *key,
 
179
                      HASH_INFO *pos)
 
180
{
 
181
  DBUG_ENTER("hp_search_next");
 
182
 
 
183
  while ((pos= pos->next_key))
 
184
  {
 
185
    if (! hp_key_cmp(keyinfo, pos->ptr_to_rec, key))
 
186
    {
 
187
      info->current_hash_ptr=pos;
 
188
      DBUG_RETURN (info->current_ptr= pos->ptr_to_rec);
 
189
    }
 
190
  }
 
191
  my_errno=HA_ERR_KEY_NOT_FOUND;
 
192
  DBUG_PRINT("exit",("Error: %d",my_errno));
 
193
  info->current_hash_ptr=0;
 
194
  DBUG_RETURN ((info->current_ptr= 0));
 
195
}
 
196
 
 
197
 
 
198
/*
 
199
  Calculate position number for hash value.
 
200
  SYNOPSIS
 
201
    hp_mask()
 
202
      hashnr     Hash value
 
203
      buffmax    Value such that
 
204
                 2^(n-1) < maxlength <= 2^n = buffmax
 
205
      maxlength  
 
206
  
 
207
  RETURN
 
208
    Array index, in [0..maxlength)
 
209
*/
 
210
 
 
211
ulong hp_mask(ulong hashnr, ulong buffmax, ulong maxlength)
 
212
{
 
213
  if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
 
214
  return (hashnr & ((buffmax >> 1) -1));
 
215
}
 
216
 
 
217
 
 
218
/*
 
219
  Change
 
220
    next_link -> ... -> X -> pos
 
221
  to
 
222
    next_link -> ... -> X -> newlink
 
223
*/
 
224
 
 
225
void hp_movelink(HASH_INFO *pos, HASH_INFO *next_link, HASH_INFO *newlink)
 
226
{
 
227
  HASH_INFO *old_link;
 
228
  do
 
229
  {
 
230
    old_link=next_link;
 
231
  }
 
232
  while ((next_link=next_link->next_key) != pos);
 
233
  old_link->next_key=newlink;
 
234
  return;
 
235
}
 
236
 
 
237
#ifndef NEW_HASH_FUNCTION
 
238
 
 
239
        /* Calc hashvalue for a key */
 
240
 
 
241
ulong hp_hashnr(register HP_KEYDEF *keydef, register const uchar *key)
 
242
{
 
243
  /*register*/ 
 
244
  ulong nr=1, nr2=4;
 
245
  HA_KEYSEG *seg,*endseg;
 
246
 
 
247
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
 
248
  {
 
249
    uchar *pos=(uchar*) key;
 
250
    key+=seg->length;
 
251
    if (seg->null_bit)
 
252
    {
 
253
      key++;                                    /* Skip null byte */
 
254
      if (*pos)                                 /* Found null */
 
255
      {
 
256
        nr^= (nr << 1) | 1;
 
257
        /* Add key pack length (2) to key for VARCHAR segments */
 
258
        if (seg->type == HA_KEYTYPE_VARTEXT1)
 
259
          key+= 2;
 
260
        continue;
 
261
      }
 
262
      pos++;
 
263
    }
 
264
    if (seg->type == HA_KEYTYPE_TEXT)
 
265
    {
 
266
       CHARSET_INFO *cs= seg->charset;
 
267
       uint length= seg->length;
 
268
       if (cs->mbmaxlen > 1)
 
269
       {
 
270
         uint char_length;
 
271
         char_length= my_charpos(cs, pos, pos + length, length/cs->mbmaxlen);
 
272
         set_if_smaller(length, char_length);
 
273
       }
 
274
       cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
 
275
    }
 
276
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
 
277
    {
 
278
       CHARSET_INFO *cs= seg->charset;
 
279
       uint pack_length= 2;                     /* Key packing is constant */
 
280
       uint length= uint2korr(pos);
 
281
       if (cs->mbmaxlen > 1)
 
282
       {
 
283
         uint char_length;
 
284
         char_length= my_charpos(cs, pos +pack_length,
 
285
                                 pos +pack_length + length,
 
286
                                 seg->length/cs->mbmaxlen);
 
287
         set_if_smaller(length, char_length);
 
288
       }
 
289
       cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
 
290
       key+= pack_length;
 
291
    }
 
292
    else
 
293
    {
 
294
      for (; pos < (uchar*) key ; pos++)
 
295
      {
 
296
        nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos)) + (nr << 8);
 
297
        nr2+=3;
 
298
      }
 
299
    }
 
300
  }
 
301
  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
 
302
  return((ulong) nr);
 
303
}
 
304
 
 
305
        /* Calc hashvalue for a key in a record */
 
306
 
 
307
ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const uchar *rec)
 
308
{
 
309
  ulong nr=1, nr2=4;
 
310
  HA_KEYSEG *seg,*endseg;
 
311
 
 
312
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
 
313
  {
 
314
    uchar *pos=(uchar*) rec+seg->start,*end=pos+seg->length;
 
315
    if (seg->null_bit)
 
316
    {
 
317
      if (rec[seg->null_pos] & seg->null_bit)
 
318
      {
 
319
        nr^= (nr << 1) | 1;
 
320
        continue;
 
321
      }
 
322
    }
 
323
    if (seg->type == HA_KEYTYPE_TEXT)
 
324
    {
 
325
      CHARSET_INFO *cs= seg->charset;
 
326
      uint char_length= seg->length;
 
327
      if (cs->mbmaxlen > 1)
 
328
      {
 
329
        char_length= my_charpos(cs, pos, pos + char_length,
 
330
                                char_length / cs->mbmaxlen);
 
331
        set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
 
332
      }
 
333
      cs->coll->hash_sort(cs, pos, char_length, &nr, &nr2);
 
334
    }
 
335
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
 
336
    {
 
337
      CHARSET_INFO *cs= seg->charset;
 
338
      uint pack_length= seg->bit_start;
 
339
      uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
 
340
      if (cs->mbmaxlen > 1)
 
341
      {
 
342
        uint char_length;
 
343
        char_length= my_charpos(cs, pos + pack_length,
 
344
                                pos + pack_length + length,
 
345
                                seg->length/cs->mbmaxlen);
 
346
        set_if_smaller(length, char_length);
 
347
      }
 
348
      cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
 
349
    }
 
350
    else
 
351
    {
 
352
      for (; pos < end ; pos++)
 
353
      {
 
354
        nr^=(ulong) ((((uint) nr & 63)+nr2)*((uint) *pos))+ (nr << 8);
 
355
        nr2+=3;
 
356
      }
 
357
    }
 
358
  }
 
359
  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
 
360
  return(nr);
 
361
}
 
362
 
 
363
#else
 
364
 
 
365
/*
 
366
 * Fowler/Noll/Vo hash
 
367
 *
 
368
 * The basis of the hash algorithm was taken from an idea sent by email to the
 
369
 * IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and
 
370
 * Glenn Fowler (gsf@research.att.com).  Landon Curt Noll (chongo@toad.com)
 
371
 * later improved on their algorithm.
 
372
 *
 
373
 * The magic is in the interesting relationship between the special prime
 
374
 * 16777619 (2^24 + 403) and 2^32 and 2^8.
 
375
 *
 
376
 * This hash produces the fewest collisions of any function that we've seen so
 
377
 * far, and works well on both numbers and strings.
 
378
 */
 
379
 
 
380
ulong hp_hashnr(register HP_KEYDEF *keydef, register const uchar *key)
 
381
{
 
382
  /*
 
383
    Note, if a key consists of a combination of numeric and
 
384
    a text columns, it most likely won't work well.
 
385
    Making text columns work with NEW_HASH_FUNCTION
 
386
    needs also changes in strings/ctype-xxx.c.
 
387
  */
 
388
  ulong nr= 1, nr2= 4;
 
389
  HA_KEYSEG *seg,*endseg;
 
390
 
 
391
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
 
392
  {
 
393
    uchar *pos=(uchar*) key;
 
394
    key+=seg->length;
 
395
    if (seg->null_bit)
 
396
    {
 
397
      key++;
 
398
      if (*pos)
 
399
      {
 
400
        nr^= (nr << 1) | 1;
 
401
        /* Add key pack length (2) to key for VARCHAR segments */
 
402
        if (seg->type == HA_KEYTYPE_VARTEXT1)
 
403
          key+= 2;
 
404
        continue;
 
405
      }
 
406
      pos++;
 
407
    }
 
408
    if (seg->type == HA_KEYTYPE_TEXT)
 
409
    {
 
410
      seg->charset->coll->hash_sort(seg->charset, pos, ((uchar*)key)-pos,
 
411
                                    &nr, &nr2);
 
412
    }
 
413
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
 
414
    {
 
415
      uint pack_length= 2;                      /* Key packing is constant */
 
416
      uint length= uint2korr(pos);
 
417
      seg->charset->coll->hash_sort(seg->charset, pos+pack_length, length,
 
418
                                    &nr, &nr2);
 
419
      key+= pack_length;
 
420
    }
 
421
    else
 
422
    {
 
423
      for ( ; pos < (uchar*) key ; pos++)
 
424
      {
 
425
        nr *=16777619; 
 
426
        nr ^=(uint) *pos;
 
427
      }
 
428
    }
 
429
  }
 
430
  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
 
431
  return(nr);
 
432
}
 
433
 
 
434
        /* Calc hashvalue for a key in a record */
 
435
 
 
436
ulong hp_rec_hashnr(register HP_KEYDEF *keydef, register const uchar *rec)
 
437
{
 
438
  ulong nr= 1, nr2= 4;
 
439
  HA_KEYSEG *seg,*endseg;
 
440
 
 
441
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
 
442
  {
 
443
    uchar *pos=(uchar*) rec+seg->start;
 
444
    if (seg->null_bit)
 
445
    {
 
446
      if (rec[seg->null_pos] & seg->null_bit)
 
447
      {
 
448
        nr^= (nr << 1) | 1;
 
449
        continue;
 
450
      }
 
451
    }
 
452
    if (seg->type == HA_KEYTYPE_TEXT)
 
453
    {
 
454
      uint char_length= seg->length; /* TODO: fix to use my_charpos() */
 
455
      seg->charset->coll->hash_sort(seg->charset, pos, char_length,
 
456
                                    &nr, &nr2);
 
457
    }
 
458
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
 
459
    {
 
460
      uint pack_length= seg->bit_start;
 
461
      uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
 
462
      seg->charset->coll->hash_sort(seg->charset, pos+pack_length,
 
463
                                    length, &nr, &nr2);
 
464
    }
 
465
    else
 
466
    {
 
467
      uchar *end= pos+seg->length;
 
468
      for ( ; pos < end ; pos++)
 
469
      {
 
470
        nr *=16777619; 
 
471
        nr ^=(uint) *pos;
 
472
      }
 
473
    }
 
474
  }
 
475
  DBUG_PRINT("exit", ("hash: 0x%lx", nr));
 
476
  return(nr);
 
477
}
 
478
 
 
479
#endif
 
480
 
 
481
 
 
482
/*
 
483
  Compare keys for two records. Returns 0 if they are identical
 
484
 
 
485
  SYNOPSIS
 
486
    hp_rec_key_cmp()
 
487
    keydef              Key definition
 
488
    rec1                Record to compare
 
489
    rec2                Other record to compare
 
490
    diff_if_only_endspace_difference
 
491
                        Different number of end space is significant    
 
492
 
 
493
  NOTES
 
494
    diff_if_only_endspace_difference is used to allow us to insert
 
495
    'a' and 'a ' when there is an an unique key.
 
496
 
 
497
  RETURN
 
498
    0           Key is identical
 
499
    <> 0        Key differes
 
500
*/
 
501
 
 
502
int hp_rec_key_cmp(HP_KEYDEF *keydef, const uchar *rec1, const uchar *rec2,
 
503
                   my_bool diff_if_only_endspace_difference)
 
504
{
 
505
  HA_KEYSEG *seg,*endseg;
 
506
 
 
507
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
 
508
  {
 
509
    if (seg->null_bit)
 
510
    {
 
511
      if ((rec1[seg->null_pos] & seg->null_bit) !=
 
512
          (rec2[seg->null_pos] & seg->null_bit))
 
513
        return 1;
 
514
      if (rec1[seg->null_pos] & seg->null_bit)
 
515
        continue;
 
516
    }
 
517
    if (seg->type == HA_KEYTYPE_TEXT)
 
518
    {
 
519
      CHARSET_INFO *cs= seg->charset;
 
520
      uint char_length1;
 
521
      uint char_length2;
 
522
      uchar *pos1= (uchar*)rec1 + seg->start;
 
523
      uchar *pos2= (uchar*)rec2 + seg->start;
 
524
      if (cs->mbmaxlen > 1)
 
525
      {
 
526
        uint char_length= seg->length / cs->mbmaxlen;
 
527
        char_length1= my_charpos(cs, pos1, pos1 + seg->length, char_length);
 
528
        set_if_smaller(char_length1, seg->length);
 
529
        char_length2= my_charpos(cs, pos2, pos2 + seg->length, char_length);
 
530
        set_if_smaller(char_length2, seg->length);
 
531
      }
 
532
      else
 
533
      {
 
534
        char_length1= char_length2= seg->length;
 
535
      }
 
536
      if (seg->charset->coll->strnncollsp(seg->charset,
 
537
                                          pos1,char_length1,
 
538
                                          pos2,char_length2, 0))
 
539
        return 1;
 
540
    }
 
541
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
 
542
    {
 
543
      uchar *pos1= (uchar*) rec1 + seg->start;
 
544
      uchar *pos2= (uchar*) rec2 + seg->start;
 
545
      uint char_length1, char_length2;
 
546
      uint pack_length= seg->bit_start;
 
547
      CHARSET_INFO *cs= seg->charset;
 
548
      if (pack_length == 1)
 
549
      {
 
550
        char_length1= (uint) *(uchar*) pos1++;
 
551
        char_length2= (uint) *(uchar*) pos2++;
 
552
      }
 
553
      else
 
554
      {
 
555
        char_length1= uint2korr(pos1);
 
556
        char_length2= uint2korr(pos2);
 
557
        pos1+= 2;
 
558
        pos2+= 2;
 
559
      }
 
560
      if (cs->mbmaxlen > 1)
 
561
      {
 
562
        uint safe_length1= char_length1;
 
563
        uint safe_length2= char_length2;
 
564
        uint char_length= seg->length / cs->mbmaxlen;
 
565
        char_length1= my_charpos(cs, pos1, pos1 + char_length1, char_length);
 
566
        set_if_smaller(char_length1, safe_length1);
 
567
        char_length2= my_charpos(cs, pos2, pos2 + char_length2, char_length);
 
568
        set_if_smaller(char_length2, safe_length2);
 
569
      }
 
570
 
 
571
      if (cs->coll->strnncollsp(seg->charset,
 
572
                                pos1, char_length1,
 
573
                                pos2, char_length2,
 
574
                                seg->flag & HA_END_SPACE_ARE_EQUAL ?
 
575
                                0 : diff_if_only_endspace_difference))
 
576
        return 1;
 
577
    }
 
578
    else
 
579
    {
 
580
      if (bcmp(rec1+seg->start,rec2+seg->start,seg->length))
 
581
        return 1;
 
582
    }
 
583
  }
 
584
  return 0;
 
585
}
 
586
 
 
587
        /* Compare a key in a record to a whole key */
 
588
 
 
589
int hp_key_cmp(HP_KEYDEF *keydef, const uchar *rec, const uchar *key)
 
590
{
 
591
  HA_KEYSEG *seg,*endseg;
 
592
 
 
593
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ;
 
594
       seg < endseg ;
 
595
       key+= (seg++)->length)
 
596
  {
 
597
    if (seg->null_bit)
 
598
    {
 
599
      int found_null=test(rec[seg->null_pos] & seg->null_bit);
 
600
      if (found_null != (int) *key++)
 
601
        return 1;
 
602
      if (found_null)
 
603
      {
 
604
        /* Add key pack length (2) to key for VARCHAR segments */
 
605
        if (seg->type == HA_KEYTYPE_VARTEXT1)
 
606
          key+= 2;
 
607
        continue;
 
608
      }
 
609
    }
 
610
    if (seg->type == HA_KEYTYPE_TEXT)
 
611
    {
 
612
      CHARSET_INFO *cs= seg->charset;
 
613
      uint char_length_key;
 
614
      uint char_length_rec;
 
615
      uchar *pos= (uchar*) rec + seg->start;
 
616
      if (cs->mbmaxlen > 1)
 
617
      {
 
618
        uint char_length= seg->length / cs->mbmaxlen;
 
619
        char_length_key= my_charpos(cs, key, key + seg->length, char_length);
 
620
        set_if_smaller(char_length_key, seg->length);
 
621
        char_length_rec= my_charpos(cs, pos, pos + seg->length, char_length);
 
622
        set_if_smaller(char_length_rec, seg->length);
 
623
      }
 
624
      else
 
625
      {
 
626
        char_length_key= seg->length;
 
627
        char_length_rec= seg->length;
 
628
      }
 
629
      
 
630
      if (seg->charset->coll->strnncollsp(seg->charset,
 
631
                                          (uchar*) pos, char_length_rec,
 
632
                                          (uchar*) key, char_length_key, 0))
 
633
        return 1;
 
634
    }
 
635
    else if (seg->type == HA_KEYTYPE_VARTEXT1)  /* Any VARCHAR segments */
 
636
    {
 
637
      uchar *pos= (uchar*) rec + seg->start;
 
638
      CHARSET_INFO *cs= seg->charset;
 
639
      uint pack_length= seg->bit_start;
 
640
      uint char_length_rec= (pack_length == 1 ? (uint) *(uchar*) pos :
 
641
                             uint2korr(pos));
 
642
      /* Key segments are always packed with 2 bytes */
 
643
      uint char_length_key= uint2korr(key);
 
644
      pos+= pack_length;
 
645
      key+= 2;                                  /* skip key pack length */
 
646
      if (cs->mbmaxlen > 1)
 
647
      {
 
648
        uint char_length1, char_length2;
 
649
        char_length1= char_length2= seg->length / cs->mbmaxlen; 
 
650
        char_length1= my_charpos(cs, key, key + char_length_key, char_length1);
 
651
        set_if_smaller(char_length_key, char_length1);
 
652
        char_length2= my_charpos(cs, pos, pos + char_length_rec, char_length2);
 
653
        set_if_smaller(char_length_rec, char_length2);
 
654
      }
 
655
 
 
656
      if (cs->coll->strnncollsp(seg->charset,
 
657
                                (uchar*) pos, char_length_rec,
 
658
                                (uchar*) key, char_length_key, 0))
 
659
        return 1;
 
660
    }
 
661
    else
 
662
    {
 
663
      if (bcmp(rec+seg->start,key,seg->length))
 
664
        return 1;
 
665
    }
 
666
  }
 
667
  return 0;
 
668
}
 
669
 
 
670
 
 
671
        /* Copy a key from a record to a keybuffer */
 
672
 
 
673
void hp_make_key(HP_KEYDEF *keydef, uchar *key, const uchar *rec)
 
674
{
 
675
  HA_KEYSEG *seg,*endseg;
 
676
 
 
677
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
 
678
  {
 
679
    CHARSET_INFO *cs= seg->charset;
 
680
    uint char_length= seg->length;
 
681
    uchar *pos= (uchar*) rec + seg->start;
 
682
    if (seg->null_bit)
 
683
      *key++= test(rec[seg->null_pos] & seg->null_bit);
 
684
    if (cs->mbmaxlen > 1)
 
685
    {
 
686
      char_length= my_charpos(cs, pos, pos + seg->length,
 
687
                              char_length / cs->mbmaxlen);
 
688
      set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
 
689
    }
 
690
    if (seg->type == HA_KEYTYPE_VARTEXT1)
 
691
      char_length+= seg->bit_start;             /* Copy also length */
 
692
    memcpy(key,rec+seg->start,(size_t) char_length);
 
693
    key+= char_length;
 
694
  }
 
695
}
 
696
 
 
697
#define FIX_LENGTH(cs, pos, length, char_length)                        \
 
698
  do {                                                                  \
 
699
    if (length > char_length)                                           \
 
700
      char_length= my_charpos(cs, pos, pos+length, char_length);        \
 
701
    set_if_smaller(char_length,length);                                 \
 
702
  } while(0)
 
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
 
 
897
/*
 
898
  Test if any of the key parts are NULL.
 
899
  Return:
 
900
    1 if any of the key parts was NULL
 
901
    0 otherwise
 
902
*/
 
903
 
 
904
my_bool hp_if_null_in_key(HP_KEYDEF *keydef, const uchar *record)
 
905
{
 
906
  HA_KEYSEG *seg,*endseg;
 
907
  for (seg=keydef->seg,endseg=seg+keydef->keysegs ; seg < endseg ; seg++)
 
908
  {
 
909
    if (seg->null_bit && (record[seg->null_pos] & seg->null_bit))
 
910
      return 1;
 
911
  }
 
912
  return 0;
 
913
}
 
914
 
 
915
 
 
916
/*
 
917
  Update auto_increment info
 
918
 
 
919
  SYNOPSIS
 
920
    update_auto_increment()
 
921
    info                        MyISAM handler
 
922
    record                      Row to update
 
923
 
 
924
  IMPLEMENTATION
 
925
    Only replace the auto_increment value if it is higher than the previous
 
926
    one. For signed columns we don't update the auto increment value if it's
 
927
    less than zero.
 
928
*/
 
929
 
 
930
void heap_update_auto_increment(HP_INFO *info, const uchar *record)
 
931
{
 
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;
 
942
  case HA_KEYTYPE_BINARY:
 
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);
 
950
    break;
 
951
  case HA_KEYTYPE_LONG_INT:
 
952
    s_value= (longlong) sint4korr(key);
 
953
    break;
 
954
  case HA_KEYTYPE_ULONG_INT:
 
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
  }
 
971
  case HA_KEYTYPE_DOUBLE:                       /* This shouldn't be used */
 
972
  {
 
973
    double f_1;
 
974
    float8get(f_1,key);
 
975
    /* Ignore negative values */
 
976
    value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
 
977
    break;
 
978
  }
 
979
  case HA_KEYTYPE_LONGLONG:
 
980
    s_value= sint8korr(key);
 
981
    break;
 
982
  case HA_KEYTYPE_ULONGLONG:
 
983
    value= uint8korr(key);
 
984
    break;
 
985
  default:
 
986
    DBUG_ASSERT(0);
 
987
    value=0;                                    /* Error */
 
988
    break;
 
989
  }
 
990
 
 
991
  /*
 
992
    The following code works becasue if s_value < 0 then value is 0
 
993
    and if s_value == 0 then value will contain either s_value or the
 
994
    correct value.
 
995
  */
 
996
  set_if_bigger(info->s->auto_increment,
 
997
                (s_value > 0) ? (ulonglong) s_value : value);
 
998
}