1
/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
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.
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.
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 */
16
/* Functions to handle keys */
18
#include "maria_def.h"
20
#include "ma_sp_defs.h"
21
#include "ma_blockrec.h" /* For ROW_FLAG_TRANSID */
27
#define CHECK_KEYS /* Enable safety checks */
29
static int _ma_put_key_in_record(MARIA_HA *info,uint keynr,uchar *record);
31
#define FIX_LENGTH(cs, pos, length, char_length) \
33
if (length > char_length) \
34
char_length= (uint) my_charpos(cs, pos, pos+length, char_length); \
35
set_if_smaller(char_length,length); \
40
Store trid in a packed format as part of a key
42
@fn transid_store_packed
43
@param info Maria handler
44
@param to End of key to which we should store a packed transid
45
@param trid Trid to be stored
49
Keys that have a transid has the lowest bit set for the last byte of the key
50
This function sets this bit for the key.
52
Trid is max 6 bytes long
54
First Trid it's converted to a smaller number by using
55
trid= trid - create_trid.
56
Then trid is then shifted up one bit so that we can use the
57
lowest bit as a marker if it's followed by another trid.
59
Trid is then stored as follows:
64
one byte prefix (256-length_of_trid_in_bytes) followed by data
65
in high-byte-first order
67
Prefix bytes 244 to 249 are reserved for negative transid, that can be used
68
when we pack transid relative to each other on a key block.
70
We have to store transid in high-byte-first order to be able to do a
71
fast byte-per-byte comparision of them without packing them up.
74
uint transid_store_packed(MARIA_HA *info, uchar *to, ulonglong trid)
79
DBUG_ASSERT(trid < (LL(1) << (MAX_PACK_TRANSID_SIZE*8)));
80
DBUG_ASSERT(trid >= info->s->state.create_trid);
82
trid= (trid - info->s->state.create_trid) << 1;
84
/* Mark that key contains transid */
87
if (trid < MIN_TRANSID_PACK_PREFIX)
94
/* store things in low-byte-first-order in buff */
102
length= (uint) (to - buff);
103
start[0]= (uchar) (256 - length); /* Store length prefix */
105
/* Copy things in high-byte-first order to output buffer */
109
} while (to != buff);
117
@fn transid_get_packed
118
@param info Maria handler
119
@param from Transid is stored here
121
See transid_store_packed() for how transid is packed
125
ulonglong transid_get_packed(MARIA_SHARE *share, const uchar *from)
130
if (from[0] < MIN_TRANSID_PACK_PREFIX)
131
value= (ulonglong) from[0];
135
for (length= (uint) (256 - from[0]), value= (ulonglong) from[1], from+=2;
138
value= (value << 8) + ((ulonglong) *from);
140
return (value >> 1) + share->state.create_trid;
145
Make a normal (not spatial or fulltext) intern key from a record
150
int_key Store created key here
152
key Buffer used to store key data
154
filepos Position to record in the data file
157
This is used to generate keys from the record on insert, update and delete
163
MARIA_KEY *_ma_make_key(MARIA_HA *info, MARIA_KEY *int_key, uint keynr,
164
uchar *key, const uchar *record,
165
MARIA_RECORD_POS filepos, ulonglong trid)
168
reg1 HA_KEYSEG *keyseg;
170
DBUG_ENTER("_ma_make_key");
173
int_key->flag= 0; /* Always return full key */
174
int_key->keyinfo= info->s->keyinfo + keynr;
176
is_ft= int_key->keyinfo->flag & HA_FULLTEXT;
177
for (keyseg= int_key->keyinfo->seg ; keyseg->type ;keyseg++)
179
enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
180
uint length=keyseg->length;
182
CHARSET_INFO *cs=keyseg->charset;
184
if (keyseg->null_bit)
186
if (record[keyseg->null_pos] & keyseg->null_bit)
188
*key++= 0; /* NULL in key */
191
*key++=1; /* Not NULL */
194
char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
197
pos= record+keyseg->start;
198
if (type == HA_KEYTYPE_BIT)
200
if (keyseg->bit_length)
202
uchar bits= get_rec_bits(record + keyseg->bit_pos,
203
keyseg->bit_start, keyseg->bit_length);
207
memcpy(key, pos, length);
211
if (keyseg->flag & HA_SPACE_PACK)
213
if (type != HA_KEYTYPE_NUM)
215
length= (uint) cs->cset->lengthsp(cs, (const char*)pos, length);
219
const uchar *end= pos + length;
220
while (pos < end && pos[0] == ' ')
222
length= (uint) (end-pos);
224
FIX_LENGTH(cs, pos, length, char_length);
225
store_key_length_inc(key,char_length);
226
memcpy(key, pos, (size_t) char_length);
230
if (keyseg->flag & HA_VAR_LENGTH_PART)
232
uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
233
uint tmp_length= (pack_length == 1 ? (uint) *pos :
235
pos+= pack_length; /* Skip VARCHAR length */
236
set_if_smaller(length,tmp_length);
237
FIX_LENGTH(cs, pos, length, char_length);
238
store_key_length_inc(key,char_length);
239
memcpy(key,pos,(size_t) char_length);
243
else if (keyseg->flag & HA_BLOB_PART)
245
uint tmp_length= _ma_calc_blob_length(keyseg->bit_start,pos);
247
memcpy_fixed(&blob_pos, pos+keyseg->bit_start,sizeof(char*));
248
set_if_smaller(length,tmp_length);
249
FIX_LENGTH(cs, blob_pos, length, char_length);
250
store_key_length_inc(key,char_length);
251
memcpy(key, blob_pos, (size_t) char_length);
255
else if (keyseg->flag & HA_SWAP_KEY)
256
{ /* Numerical column */
258
if (type == HA_KEYTYPE_FLOAT)
264
/* Replace NAN with zero */
270
else if (type == HA_KEYTYPE_DOUBLE)
289
FIX_LENGTH(cs, pos, length, char_length);
290
memcpy(key, pos, char_length);
291
if (length > char_length)
292
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
295
_ma_dpointer(info->s, key, filepos);
296
int_key->data_length= (key - int_key->data);
297
int_key->ref_length= info->s->rec_reflength;
299
if (_ma_have_versioning(info) && trid)
301
int_key->ref_length+= transid_store_packed(info,
302
key + int_key->ref_length,
304
int_key->flag|= SEARCH_USER_KEY_HAS_TRANSID;
307
DBUG_PRINT("exit",("keynr: %d",keynr));
308
DBUG_DUMP_KEY("key", int_key);
309
DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, int_key););
310
DBUG_RETURN(int_key);
315
Pack a key to intern format from given format (c_rkey)
320
int_key Store key here
322
key Buffer for key data
323
old Original not packed key
324
keypart_map bitmap of used keyparts
325
last_used_keyseg out parameter. May be NULL
330
last_use_keyseg Store pointer to the keyseg after the last used one
333
MARIA_KEY *_ma_pack_key(register MARIA_HA *info, MARIA_KEY *int_key,
334
uint keynr, uchar *key,
335
const uchar *old, key_part_map keypart_map,
336
HA_KEYSEG **last_used_keyseg)
340
DBUG_ENTER("_ma_pack_key");
343
int_key->keyinfo= info->s->keyinfo + keynr;
345
/* "one part" rtree key is 2*SPDIMS part key in Maria */
346
if (int_key->keyinfo->key_alg == HA_KEY_ALG_RTREE)
347
keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1;
349
/* only key prefixes are supported */
350
DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0);
352
is_ft= int_key->keyinfo->flag & HA_FULLTEXT;
353
for (keyseg=int_key->keyinfo->seg ; keyseg->type && keypart_map;
354
old+= keyseg->length, keyseg++)
356
enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type;
357
uint length= keyseg->length;
360
CHARSET_INFO *cs=keyseg->charset;
363
if (keyseg->null_bit)
365
if (!(*key++= (char) 1-*old++)) /* Copy null marker */
367
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
369
continue; /* Found NULL */
372
char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
375
if (keyseg->flag & HA_SPACE_PACK)
377
const uchar *end= pos + length;
378
if (type == HA_KEYTYPE_NUM)
380
while (pos < end && pos[0] == ' ')
383
else if (type != HA_KEYTYPE_BINARY)
385
while (end > pos && end[-1] == ' ')
388
length=(uint) (end-pos);
389
FIX_LENGTH(cs, pos, length, char_length);
390
store_key_length_inc(key,char_length);
391
memcpy(key,pos,(size_t) char_length);
395
else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
397
/* Length of key-part used with maria_rkey() always 2 */
398
uint tmp_length=uint2korr(pos);
400
set_if_smaller(length,tmp_length); /* Safety */
401
FIX_LENGTH(cs, pos, length, char_length);
402
store_key_length_inc(key,char_length);
403
old+=2; /* Skip length */
404
memcpy(key, pos,(size_t) char_length);
408
else if (keyseg->flag & HA_SWAP_KEY)
409
{ /* Numerical column */
415
FIX_LENGTH(cs, pos, length, char_length);
416
memcpy(key, pos, char_length);
417
if (length > char_length)
418
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
421
if (last_used_keyseg)
422
*last_used_keyseg= keyseg;
424
/* set flag to SEARCH_PART_KEY if we are not using all key parts */
425
int_key->flag= keyseg->type ? SEARCH_PART_KEY : 0;
426
int_key->ref_length= 0;
427
int_key->data_length= (key - int_key->data);
429
DBUG_PRINT("exit", ("length: %u", int_key->data_length));
430
DBUG_RETURN(int_key);
438
void _ma_copy_key(MARIA_KEY *to, const MARIA_KEY *from)
440
memcpy(to->data, from->data, from->data_length + from->ref_length);
441
to->keyinfo= from->keyinfo;
442
to->data_length= from->data_length;
443
to->ref_length= from->ref_length;
444
to->flag= from->flag;
449
Store found key in record
452
_ma_put_key_in_record()
454
keynr Key number that was used
455
record Store key here
457
Last read key is in info->lastkey
460
Used when only-keyread is wanted
467
static int _ma_put_key_in_record(register MARIA_HA *info, uint keynr,
472
reg1 HA_KEYSEG *keyseg;
474
DBUG_ENTER("_ma_put_key_in_record");
476
blob_ptr= info->lastkey_buff2; /* Place to put blob parts */
477
key= info->last_key.data; /* Key that was read */
478
key_end= key + info->last_key.data_length;
479
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
481
if (keyseg->null_bit)
485
record[keyseg->null_pos]|= keyseg->null_bit;
488
record[keyseg->null_pos]&= ~keyseg->null_bit;
490
if (keyseg->type == HA_KEYTYPE_BIT)
492
uint length= keyseg->length;
494
if (keyseg->bit_length)
497
set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
503
clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
506
memcpy(record + keyseg->start, key, length);
510
if (keyseg->flag & HA_SPACE_PACK)
513
get_key_length(length,key);
515
if (length > keyseg->length || key+length > key_end)
518
pos= record+keyseg->start;
519
if (keyseg->type != (int) HA_KEYTYPE_NUM)
521
memcpy(pos,key,(size_t) length);
522
keyseg->charset->cset->fill(keyseg->charset,
523
(char*) pos + length,
524
keyseg->length - length,
529
bfill(pos,keyseg->length-length,' ');
530
memcpy(pos+keyseg->length-length,key,(size_t) length);
536
if (keyseg->flag & HA_VAR_LENGTH_PART)
539
get_key_length(length,key);
541
if (length > keyseg->length || key+length > key_end)
544
/* Store key length */
545
if (keyseg->bit_start == 1)
546
*(uchar*) (record+keyseg->start)= (uchar) length;
548
int2store(record+keyseg->start, length);
550
memcpy(record+keyseg->start + keyseg->bit_start, key, length);
553
else if (keyseg->flag & HA_BLOB_PART)
556
get_key_length(length,key);
558
if (length > keyseg->length || key+length > key_end)
561
memcpy(record+keyseg->start+keyseg->bit_start,
562
(char*) &blob_ptr,sizeof(char*));
563
memcpy(blob_ptr,key,length);
566
/* The above changed info->lastkey2. Inform maria_rnext_same(). */
567
info->update&= ~HA_STATE_RNEXT_SAME;
569
_ma_store_blob_length(record+keyseg->start,
570
(uint) keyseg->bit_start,length);
573
else if (keyseg->flag & HA_SWAP_KEY)
575
uchar *to= record+keyseg->start+keyseg->length;
576
uchar *end= key+keyseg->length;
584
} while (key != end);
590
if (key+keyseg->length > key_end)
593
memcpy(record+keyseg->start, key, (size_t) keyseg->length);
594
key+= keyseg->length;
600
DBUG_RETURN(1); /* Crashed row */
601
} /* _ma_put_key_in_record */
604
/* Here when key reads are used */
606
int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos)
608
fast_ma_writeinfo(info);
609
if (filepos != HA_OFFSET_ERROR)
611
if (info->lastinx >= 0)
612
{ /* Read only key */
613
if (_ma_put_key_in_record(info,(uint) info->lastinx,buf))
615
maria_print_error(info->s, HA_ERR_CRASHED);
616
my_errno=HA_ERR_CRASHED;
619
info->update|= HA_STATE_AKTIV; /* We should find a record */
622
my_errno=HA_ERR_WRONG_INDEX;
624
return(-1); /* Wrong data to read */
629
Retrieve auto_increment info
632
retrieve_auto_increment()
633
key Auto-increment key
637
'key' should in "record" format, that is, how it is packed in a record
638
(this matters with HA_SWAP_KEY).
641
For signed columns we don't retrieve the auto increment value if it's
645
ulonglong ma_retrieve_auto_increment(const uchar *key, uint8 key_type)
647
ulonglong value= 0; /* Store unsigned values here */
648
longlong s_value= 0; /* Store signed values here */
651
case HA_KEYTYPE_INT8:
652
s_value= (longlong) *(const char*)key;
654
case HA_KEYTYPE_BINARY:
655
value=(ulonglong) *key;
657
case HA_KEYTYPE_SHORT_INT:
658
s_value= (longlong) sint2korr(key);
660
case HA_KEYTYPE_USHORT_INT:
661
value=(ulonglong) uint2korr(key);
663
case HA_KEYTYPE_LONG_INT:
664
s_value= (longlong) sint4korr(key);
666
case HA_KEYTYPE_ULONG_INT:
667
value=(ulonglong) uint4korr(key);
669
case HA_KEYTYPE_INT24:
670
s_value= (longlong) sint3korr(key);
672
case HA_KEYTYPE_UINT24:
673
value=(ulonglong) uint3korr(key);
675
case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
679
/* Ignore negative values */
680
value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
683
case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
687
/* Ignore negative values */
688
value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
691
case HA_KEYTYPE_LONGLONG:
692
s_value= sint8korr(key);
694
case HA_KEYTYPE_ULONGLONG:
695
value= uint8korr(key);
704
The following code works becasue if s_value < 0 then value is 0
705
and if s_value == 0 then value will contain either s_value or the
708
return (s_value > 0) ? (ulonglong) s_value : value;