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