~drizzle-trunk/drizzle/development

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