1/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
15
16/* Functions to handle keys */
17
18#include "maria_def.h"
19#include "m_ctype.h"
20#include "ma_sp_defs.h"
21#include "ma_blockrec.h" /* For ROW_FLAG_TRANSID */
22#include "trnman.h"
23#ifdef HAVE_IEEEFP_H
24#include <ieeefp.h>
25#endif
26
27#define CHECK_KEYS /* Enable safety checks */
28
29static int _ma_put_key_in_record(MARIA_HA *info, uint keynr,
30 my_bool unpack_blobs, uchar *record);
31
32#define FIX_LENGTH(cs, pos, length, char_length) \
33 do { \
34 if (length > char_length) \
35 char_length= (uint) my_charpos(cs, pos, pos+length, char_length); \
36 set_if_smaller(char_length,length); \
37 } while(0)
38
39
40/**
41 Store trid in a packed format as part of a key
42
43 @fn transid_store_packed
44 @param info Maria handler
45 @param to End of key to which we should store a packed transid
46 @param trid Trid to be stored
47
48 @notes
49
50 Keys that have a transid has the lowest bit set for the last byte of the key
51 This function sets this bit for the key.
52
53 Trid is max 6 bytes long
54
55 First Trid it's converted to a smaller number by using
56 trid= trid - create_trid.
57 Then trid is then shifted up one bit so that we can use the
58 lowest bit as a marker if it's followed by another trid.
59
60 Trid is then stored as follows:
61
62 if trid < 256-12
63 one byte
64 else
65 one byte prefix length_of_trid_in_bytes + 249 followed by data
66 in high-byte-first order
67
68 Prefix bytes 244 to 249 are reserved for negative transid, that can be used
69 when we pack transid relative to each other on a key block.
70
71 We have to store transid in high-byte-first order so that we can compare
72 them unpacked byte per byte and as soon we find a difference we know
73 which is smaller.
74
75 For example, assuming we the following data:
76
77 key_data: 1 (4 byte integer)
78 pointer_to_row: 2 << 8 + 3 = 515 (page 2, row 3)
79 table_create_transid 1000 Defined at create table time and
80 stored in table definition
81 transid 1010 Transaction that created row
82 delete_transid 2011 Transaction that deleted row
83
84 In addition we assume the table is created with a data pointer length
85 of 4 bytes (this is automatically calculated based on the medium
86 length of rows and the given max number of rows)
87
88 The binary data for the key would then look like this in hex:
89
90 00 00 00 01 Key data (1 stored high byte first)
91 00 00 00 47 (515 << 1) + 1 ; The last 1 is marker that key cont.
92 15 ((1010-1000) << 1) + 1 ; The last 1 is marker that key cont.
93 FB 07 E6 Length byte (FE = 249 + 2 means 2 bytes) and
94 ((2011 - 1000) << 1) = 07 E6
95*/
96
97uint transid_store_packed(MARIA_HA *info, uchar *to, ulonglong trid)
98{
99 uchar *start;
100 uint length;
101 uchar buff[8];
102 DBUG_ASSERT(trid < (1LL << (MARIA_MAX_PACK_TRANSID_SIZE*8)));
103 DBUG_ASSERT(trid >= info->s->state.create_trid);
104
105 trid= (trid - info->s->state.create_trid) << 1;
106
107 /* Mark that key contains transid */
108 to[-1]|= 1;
109
110 if (trid < MARIA_MIN_TRANSID_PACK_OFFSET)
111 {
112 to[0]= (uchar) trid;
113 return 1;
114 }
115 start= to;
116
117 /* store things in low-byte-first-order in buff */
118 to= buff;
119 do
120 {
121 *to++= (uchar) trid;
122 trid= trid>>8;
123 } while (trid);
124
125 length= (uint) (to - buff);
126 /* Store length prefix */
127 start[0]= (uchar) (length + MARIA_TRANSID_PACK_OFFSET);
128 start++;
129 /* Copy things in high-byte-first order to output buffer */
130 do
131 {
132 *start++= *--to;
133 } while (to != buff);
134 return length+1;
135}
136
137
138/**
139 Read packed transid
140
141 @fn transid_get_packed
142 @param info Maria handler
143 @param from Transid is stored here
144
145 See transid_store_packed() for how transid is packed
146
147*/
148
149ulonglong transid_get_packed(MARIA_SHARE *share, const uchar *from)
150{
151 ulonglong value;
152 uint length;
153
154 if (from[0] < MARIA_MIN_TRANSID_PACK_OFFSET)
155 value= (ulonglong) from[0];
156 else
157 {
158 value= 0;
159 for (length= (uint) (from[0] - MARIA_TRANSID_PACK_OFFSET),
160 value= (ulonglong) from[1], from+=2;
161 --length ;
162 from++)
163 value= (value << 8) + ((ulonglong) *from);
164 }
165 return (value >> 1) + share->state.create_trid;
166}
167
168
169/*
170 Make a normal (not spatial or fulltext) intern key from a record
171
172 SYNOPSIS
173 _ma_make_key()
174 info MyiSAM handler
175 int_key Store created key here
176 keynr key number
177 key Buffer used to store key data
178 record Record
179 filepos Position to record in the data file
180
181 NOTES
182 This is used to generate keys from the record on insert, update and delete
183
184 RETURN
185 key
186*/
187
188MARIA_KEY *_ma_make_key(MARIA_HA *info, MARIA_KEY *int_key, uint keynr,
189 uchar *key, const uchar *record,
190 MARIA_RECORD_POS filepos, ulonglong trid)
191{
192 const uchar *pos;
193 reg1 HA_KEYSEG *keyseg;
194 my_bool is_ft;
195 DBUG_ENTER("_ma_make_key");
196
197 int_key->data= key;
198 int_key->flag= 0; /* Always return full key */
199 int_key->keyinfo= info->s->keyinfo + keynr;
200
201 is_ft= int_key->keyinfo->flag & HA_FULLTEXT;
202 for (keyseg= int_key->keyinfo->seg ; keyseg->type ;keyseg++)
203 {
204 enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
205 uint length=keyseg->length;
206 uint char_length;
207 CHARSET_INFO *cs=keyseg->charset;
208
209 if (keyseg->null_bit)
210 {
211 if (record[keyseg->null_pos] & keyseg->null_bit)
212 {
213 *key++= 0; /* NULL in key */
214 continue;
215 }
216 *key++=1; /* Not NULL */
217 }
218
219 char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
220 length);
221
222 pos= record+keyseg->start;
223 if (type == HA_KEYTYPE_BIT)
224 {
225 if (keyseg->bit_length)
226 {
227 uchar bits= get_rec_bits(record + keyseg->bit_pos,
228 keyseg->bit_start, keyseg->bit_length);
229 *key++= (char) bits;
230 length--;
231 }
232 memcpy(key, pos, length);
233 key+= length;
234 continue;
235 }
236 if (keyseg->flag & HA_SPACE_PACK)
237 {
238 if (type != HA_KEYTYPE_NUM)
239 {
240 length= (uint) cs->cset->lengthsp(cs, (const char*)pos, length);
241 }
242 else
243 {
244 const uchar *end= pos + length;
245 while (pos < end && pos[0] == ' ')
246 pos++;
247 length= (uint) (end-pos);
248 }
249 FIX_LENGTH(cs, pos, length, char_length);
250 store_key_length_inc(key,char_length);
251 memcpy(key, pos, (size_t) char_length);
252 key+=char_length;
253 continue;
254 }
255 if (keyseg->flag & HA_VAR_LENGTH_PART)
256 {
257 uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
258 uint tmp_length= (pack_length == 1 ? (uint) *pos :
259 uint2korr(pos));
260 pos+= pack_length; /* Skip VARCHAR length */
261 set_if_smaller(length,tmp_length);
262 FIX_LENGTH(cs, pos, length, char_length);
263 store_key_length_inc(key,char_length);
264 memcpy(key,pos,(size_t) char_length);
265 key+= char_length;
266 continue;
267 }
268 else if (keyseg->flag & HA_BLOB_PART)
269 {
270 uint tmp_length= _ma_calc_blob_length(keyseg->bit_start,pos);
271 uchar *blob_pos;
272 memcpy(&blob_pos, pos+keyseg->bit_start,sizeof(char*));
273 set_if_smaller(length,tmp_length);
274 FIX_LENGTH(cs, blob_pos, length, char_length);
275 store_key_length_inc(key,char_length);
276 memcpy(key, blob_pos, (size_t) char_length);
277 key+= char_length;
278 continue;
279 }
280 else if (keyseg->flag & HA_SWAP_KEY)
281 { /* Numerical column */
282#ifdef HAVE_ISNAN
283 if (type == HA_KEYTYPE_FLOAT)
284 {
285 float nr;
286 float4get(nr,pos);
287 if (isnan(nr))
288 {
289 /* Replace NAN with zero */
290 bzero(key,length);
291 key+=length;
292 continue;
293 }
294 }
295 else if (type == HA_KEYTYPE_DOUBLE)
296 {
297 double nr;
298 float8get(nr,pos);
299 if (isnan(nr))
300 {
301 bzero(key,length);
302 key+=length;
303 continue;
304 }
305 }
306#endif
307 pos+=length;
308 while (length--)
309 {
310 *key++ = *--pos;
311 }
312 continue;
313 }
314 FIX_LENGTH(cs, pos, length, char_length);
315 memcpy(key, pos, char_length);
316 if (length > char_length)
317 cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
318 key+= length;
319 }
320 _ma_dpointer(info->s, key, filepos);
321 int_key->data_length= (uint)(key - int_key->data);
322 int_key->ref_length= info->s->rec_reflength;
323 int_key->flag= 0;
324 if (_ma_have_versioning(info) && trid)
325 {
326 int_key->ref_length+= transid_store_packed(info,
327 key + int_key->ref_length,
328 (TrID) trid);
329 int_key->flag|= SEARCH_USER_KEY_HAS_TRANSID;
330 }
331
332 DBUG_PRINT("exit",("keynr: %d",keynr));
333 DBUG_DUMP_KEY("key", int_key);
334 DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, int_key););
335 DBUG_RETURN(int_key);
336} /* _ma_make_key */
337
338
339/*
340 Pack a key to intern format from given format (c_rkey)
341
342 SYNOPSIS
343 _ma_pack_key()
344 info MARIA handler
345 int_key Store key here
346 keynr key number
347 key Buffer for key data
348 old Original not packed key
349 keypart_map bitmap of used keyparts
350 last_used_keyseg out parameter. May be NULL
351
352 RETURN
353 int_key
354
355 last_use_keyseg Store pointer to the keyseg after the last used one
356*/
357
358MARIA_KEY *_ma_pack_key(register MARIA_HA *info, MARIA_KEY *int_key,
359 uint keynr, uchar *key,
360 const uchar *old, key_part_map keypart_map,
361 HA_KEYSEG **last_used_keyseg)
362{
363 HA_KEYSEG *keyseg;
364 my_bool is_ft;
365 DBUG_ENTER("_ma_pack_key");
366
367 int_key->data= key;
368 int_key->keyinfo= info->s->keyinfo + keynr;
369
370 /* "one part" rtree key is 2*SPDIMS part key in Maria */
371 if (int_key->keyinfo->key_alg == HA_KEY_ALG_RTREE)
372 keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1;
373
374 /* only key prefixes are supported */
375 DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0);
376
377 is_ft= int_key->keyinfo->flag & HA_FULLTEXT;
378 for (keyseg=int_key->keyinfo->seg ; keyseg->type && keypart_map;
379 old+= keyseg->length, keyseg++)
380 {
381 enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type;
382 uint length= keyseg->length;
383 uint char_length;
384 const uchar *pos;
385 CHARSET_INFO *cs=keyseg->charset;
386
387 keypart_map>>= 1;
388 if (keyseg->null_bit)
389 {
390 if (!(*key++= (char) 1-*old++)) /* Copy null marker */
391 {
392 if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
393 old+= 2;
394 continue; /* Found NULL */
395 }
396 }
397 char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
398 length);
399 pos= old;
400 if (keyseg->flag & HA_SPACE_PACK)
401 {
402 const uchar *end= pos + length;
403 if (type == HA_KEYTYPE_NUM)
404 {
405 while (pos < end && pos[0] == ' ')
406 pos++;
407 }
408 else if (type != HA_KEYTYPE_BINARY)
409 {
410 while (end > pos && end[-1] == ' ')
411 end--;
412 }
413 length=(uint) (end-pos);
414 FIX_LENGTH(cs, pos, length, char_length);
415 store_key_length_inc(key,char_length);
416 memcpy(key,pos,(size_t) char_length);
417 key+= char_length;
418 continue;
419 }
420 else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
421 {
422 /* Length of key-part used with maria_rkey() always 2 */
423 uint tmp_length=uint2korr(pos);
424 pos+=2;
425 set_if_smaller(length,tmp_length); /* Safety */
426 FIX_LENGTH(cs, pos, length, char_length);
427 store_key_length_inc(key,char_length);
428 old+=2; /* Skip length */
429 memcpy(key, pos,(size_t) char_length);
430 key+= char_length;
431 continue;
432 }
433 else if (keyseg->flag & HA_SWAP_KEY)
434 { /* Numerical column */
435 pos+=length;
436 while (length--)
437 *key++ = *--pos;
438 continue;
439 }
440 FIX_LENGTH(cs, pos, length, char_length);
441 memcpy(key, pos, char_length);
442 if (length > char_length)
443 cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
444 key+= length;
445 }
446 if (last_used_keyseg)
447 *last_used_keyseg= keyseg;
448
449 /* set flag to SEARCH_PART_KEY if we are not using all key parts */
450 int_key->flag= keyseg->type ? SEARCH_PART_KEY : 0;
451 int_key->ref_length= 0;
452 int_key->data_length= (uint)(key - int_key->data);
453
454 DBUG_PRINT("exit", ("length: %u", int_key->data_length));
455 DBUG_RETURN(int_key);
456} /* _ma_pack_key */
457
458
459/**
460 Copy a key
461*/
462
463void _ma_copy_key(MARIA_KEY *to, const MARIA_KEY *from)
464{
465 memcpy(to->data, from->data, from->data_length + from->ref_length);
466 to->keyinfo= from->keyinfo;
467 to->data_length= from->data_length;
468 to->ref_length= from->ref_length;
469 to->flag= from->flag;
470}
471
472
473/*
474 Store found key in record
475
476 SYNOPSIS
477 _ma_put_key_in_record()
478 info MARIA handler
479 keynr Key number that was used
480 unpack_blobs TRUE <=> Unpack blob columns
481 FALSE <=> Skip them. This is used by index condition
482 pushdown check function
483 record Store key here
484
485 Last read key is in info->lastkey
486
487 NOTES
488 Used when only-keyread is wanted
489
490 RETURN
491 0 ok
492 1 error
493*/
494
495static int _ma_put_key_in_record(register MARIA_HA *info, uint keynr,
496 my_bool unpack_blobs, uchar *record)
497{
498 reg2 uchar *key;
499 uchar *pos,*key_end;
500 reg1 HA_KEYSEG *keyseg;
501 uchar *blob_ptr;
502 DBUG_ENTER("_ma_put_key_in_record");
503
504 blob_ptr= info->lastkey_buff2; /* Place to put blob parts */
505 key= info->last_key.data; /* Key that was read */
506 key_end= key + info->last_key.data_length;
507 for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
508 {
509 if (keyseg->null_bit)
510 {
511 if (!*key++)
512 {
513 record[keyseg->null_pos]|= keyseg->null_bit;
514 continue;
515 }
516 record[keyseg->null_pos]&= ~keyseg->null_bit;
517 }
518 if (keyseg->type == HA_KEYTYPE_BIT)
519 {
520 uint length= keyseg->length;
521
522 if (keyseg->bit_length)
523 {
524 uchar bits= *key++;
525 set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
526 keyseg->bit_length);
527 length--;
528 }
529 else
530 {
531 clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
532 keyseg->bit_length);
533 }
534 memcpy(record + keyseg->start, key, length);
535 key+= length;
536 continue;
537 }
538 if (keyseg->flag & HA_SPACE_PACK)
539 {
540 uint length;
541 get_key_length(length,key);
542#ifdef CHECK_KEYS
543 if (length > keyseg->length || key+length > key_end)
544 goto err;
545#endif
546 pos= record+keyseg->start;
547 if (keyseg->type != (int) HA_KEYTYPE_NUM)
548 {
549 memcpy(pos,key,(size_t) length);
550 keyseg->charset->cset->fill(keyseg->charset,
551 (char*) pos + length,
552 keyseg->length - length,
553 ' ');
554 }
555 else
556 {
557 bfill(pos,keyseg->length-length,' ');
558 memcpy(pos+keyseg->length-length,key,(size_t) length);
559 }
560 key+=length;
561 continue;
562 }
563
564 if (keyseg->flag & HA_VAR_LENGTH_PART)
565 {
566 uint length;
567 get_key_length(length,key);
568#ifdef CHECK_KEYS
569 if (length > keyseg->length || key+length > key_end)
570 goto err;
571#endif
572 /* Store key length */
573 if (keyseg->bit_start == 1)
574 *(uchar*) (record+keyseg->start)= (uchar) length;
575 else
576 int2store(record+keyseg->start, length);
577 /* And key data */
578 memcpy(record+keyseg->start + keyseg->bit_start, key, length);
579 key+= length;
580 }
581 else if (keyseg->flag & HA_BLOB_PART)
582 {
583 uint length;
584 get_key_length(length,key);
585#ifdef CHECK_KEYS
586 if (length > keyseg->length || key+length > key_end)
587 goto err;
588#endif
589 if (unpack_blobs)
590 {
591 memcpy(record+keyseg->start+keyseg->bit_start,
592 &blob_ptr, sizeof(char*));
593 memcpy(blob_ptr,key,length);
594 blob_ptr+=length;
595
596 /* The above changed info->lastkey2. Inform maria_rnext_same(). */
597 info->update&= ~HA_STATE_RNEXT_SAME;
598
599 _ma_store_blob_length(record+keyseg->start,
600 (uint) keyseg->bit_start,length);
601 }
602 key+=length;
603 }
604 else if (keyseg->flag & HA_SWAP_KEY)
605 {
606 uchar *to= record+keyseg->start+keyseg->length;
607 uchar *end= key+keyseg->length;
608#ifdef CHECK_KEYS
609 if (end > key_end)
610 goto err;
611#endif
612 do
613 {
614 *--to= *key++;
615 } while (key != end);
616 continue;
617 }
618 else
619 {
620#ifdef CHECK_KEYS
621 if (key+keyseg->length > key_end)
622 goto err;
623#endif
624 memcpy(record+keyseg->start, key, (size_t) keyseg->length);
625 key+= keyseg->length;
626 }
627 }
628 DBUG_RETURN(0);
629
630err:
631 DBUG_PRINT("info",("error"));
632 DBUG_RETURN(1); /* Crashed row */
633} /* _ma_put_key_in_record */
634
635
636 /* Here when key reads are used */
637
638int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos)
639{
640 fast_ma_writeinfo(info);
641 if (filepos != HA_OFFSET_ERROR)
642 {
643 if (info->lastinx >= 0)
644 { /* Read only key */
645 if (_ma_put_key_in_record(info, (uint)info->lastinx, TRUE, buf))
646 {
647 _ma_set_fatal_error(info->s, HA_ERR_CRASHED);
648 return -1;
649 }
650 info->update|= HA_STATE_AKTIV; /* We should find a record */
651 return 0;
652 }
653 my_errno=HA_ERR_WRONG_INDEX;
654 }
655 return(-1); /* Wrong data to read */
656}
657
658
659
660/*
661 Save current key tuple to record and call index condition check function
662
663 SYNOPSIS
664 ma_check_index_cond()
665 info MyISAM handler
666 keynr Index we're running a scan on
667 record Record buffer to use (it is assumed that index check function
668 will look for column values there)
669
670 RETURN
671 ICP_ERROR Error ; my_errno set to HA_ERR_CRASHED
672 ICP_NO_MATCH Index condition is not satisfied, continue scanning
673 ICP_MATCH Index condition is satisfied
674 ICP_OUT_OF_RANGE Index condition is not satisfied, end the scan.
675 my_errno set to HA_ERR_END_OF_FILE
676
677 info->cur_row.lastpos is set to HA_OFFSET_ERROR in case of ICP_ERROR or
678 ICP_OUT_OF_RANGE to indicate that we don't have any active row.
679*/
680
681ICP_RESULT ma_check_index_cond(register MARIA_HA *info, uint keynr,
682 uchar *record)
683{
684 ICP_RESULT res= ICP_MATCH;
685 if (info->index_cond_func)
686 {
687 if (_ma_put_key_in_record(info, keynr, FALSE, record))
688 {
689 /* Impossible case; Can only happen if bug in code */
690 maria_print_error(info->s, HA_ERR_CRASHED);
691 info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */
692 my_errno= HA_ERR_CRASHED;
693 res= ICP_ERROR;
694 }
695 else if ((res= info->index_cond_func(info->index_cond_func_arg)) ==
696 ICP_OUT_OF_RANGE)
697 {
698 /* We got beyond the end of scanned range */
699 info->cur_row.lastpos= HA_OFFSET_ERROR; /* No active record */
700 my_errno= HA_ERR_END_OF_FILE;
701 }
702 }
703 return res;
704}
705
706
707/*
708 Retrieve auto_increment info
709
710 SYNOPSIS
711 retrieve_auto_increment()
712 key Auto-increment key
713 key_type Key's type
714
715 NOTE
716 'key' should in "record" format, that is, how it is packed in a record
717 (this matters with HA_SWAP_KEY).
718
719 IMPLEMENTATION
720 For signed columns we don't retrieve the auto increment value if it's
721 less than zero.
722*/
723
724ulonglong ma_retrieve_auto_increment(const uchar *key, uint8 key_type)
725{
726 ulonglong value= 0; /* Store unsigned values here */
727 longlong s_value= 0; /* Store signed values here */
728
729 switch (key_type) {
730 case HA_KEYTYPE_INT8:
731 s_value= (longlong) *(const char*)key;
732 break;
733 case HA_KEYTYPE_BINARY:
734 value=(ulonglong) *key;
735 break;
736 case HA_KEYTYPE_SHORT_INT:
737 s_value= (longlong) sint2korr(key);
738 break;
739 case HA_KEYTYPE_USHORT_INT:
740 value=(ulonglong) uint2korr(key);
741 break;
742 case HA_KEYTYPE_LONG_INT:
743 s_value= (longlong) sint4korr(key);
744 break;
745 case HA_KEYTYPE_ULONG_INT:
746 value=(ulonglong) uint4korr(key);
747 break;
748 case HA_KEYTYPE_INT24:
749 s_value= (longlong) sint3korr(key);
750 break;
751 case HA_KEYTYPE_UINT24:
752 value=(ulonglong) uint3korr(key);
753 break;
754 case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
755 {
756 float f_1;
757 float4get(f_1,key);
758 /* Ignore negative values */
759 value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
760 break;
761 }
762 case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
763 {
764 double f_1;
765 float8get(f_1,key);
766 /* Ignore negative values */
767 value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
768 break;
769 }
770 case HA_KEYTYPE_LONGLONG:
771 s_value= sint8korr(key);
772 break;
773 case HA_KEYTYPE_ULONGLONG:
774 value= uint8korr(key);
775 break;
776 default:
777 DBUG_ASSERT(0);
778 value=0; /* Error */
779 break;
780 }
781
782 /*
783 The following code works becasue if s_value < 0 then value is 0
784 and if s_value == 0 then value will contain either s_value or the
785 correct value.
786 */
787 return (s_value > 0) ? (ulonglong) s_value : value;
788}
789