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 | |
29 | static 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 | |
97 | uint 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 | |
149 | ulonglong 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 | |
188 | MARIA_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 | |
358 | MARIA_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 | |
463 | void _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 | |
495 | static 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 | |
630 | err: |
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 | |
638 | int _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 | |
681 | ICP_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 | |
724 | ulonglong 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 | |