1
/* Copyright (C) 2000-2006 MySQL 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 "myisamdef.h"
25
#define CHECK_KEYS /* Enable safety checks */
27
#define FIX_LENGTH(cs, pos, length, char_length) \
29
if (length > char_length) \
30
char_length= my_charpos(cs, pos, pos+length, char_length); \
31
set_if_smaller(char_length,length); \
34
static int _mi_put_key_in_record(MI_INFO *info,uint keynr,uchar *record);
37
Make a intern key from a record
43
key Store created key here
45
filepos Position to record in the data file
51
uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
52
const uchar *record, my_off_t filepos)
56
register HA_KEYSEG *keyseg;
57
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
58
DBUG_ENTER("_mi_make_key");
60
if (info->s->keyinfo[keynr].flag & HA_SPATIAL)
63
TODO: nulls processing
66
DBUG_RETURN(sp_make_key(info,keynr,key,record,filepos));
68
DBUG_ASSERT(0); /* mi_open should check that this never happens*/
73
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
75
enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
76
uint length=keyseg->length;
78
CHARSET_INFO *cs=keyseg->charset;
82
if (record[keyseg->null_pos] & keyseg->null_bit)
84
*key++= 0; /* NULL in key */
87
*key++=1; /* Not NULL */
90
char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
93
pos= (uchar*) record+keyseg->start;
94
if (type == HA_KEYTYPE_BIT)
96
if (keyseg->bit_length)
98
uchar bits= get_rec_bits((uchar*) record + keyseg->bit_pos,
99
keyseg->bit_start, keyseg->bit_length);
103
memcpy((uchar*) key, pos, length);
107
if (keyseg->flag & HA_SPACE_PACK)
109
if (type != HA_KEYTYPE_NUM)
111
length= cs->cset->lengthsp(cs, (char*) pos, length);
115
uchar *end= pos + length;
116
while (pos < end && pos[0] == ' ')
118
length=(uint) (end-pos);
120
FIX_LENGTH(cs, pos, length, char_length);
121
store_key_length_inc(key,char_length);
122
memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
126
if (keyseg->flag & HA_VAR_LENGTH_PART)
128
uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
129
uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
131
pos+= pack_length; /* Skip VARCHAR length */
132
set_if_smaller(length,tmp_length);
133
FIX_LENGTH(cs, pos, length, char_length);
134
store_key_length_inc(key,char_length);
135
memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
139
else if (keyseg->flag & HA_BLOB_PART)
141
uint tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
142
memcpy_fixed((uchar*) &pos,pos+keyseg->bit_start,sizeof(char*));
143
set_if_smaller(length,tmp_length);
144
FIX_LENGTH(cs, pos, length, char_length);
145
store_key_length_inc(key,char_length);
146
memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
150
else if (keyseg->flag & HA_SWAP_KEY)
151
{ /* Numerical column */
153
if (type == HA_KEYTYPE_FLOAT)
159
/* Replace NAN with zero */
165
else if (type == HA_KEYTYPE_DOUBLE)
184
FIX_LENGTH(cs, pos, length, char_length);
185
memcpy((uchar*) key, pos, char_length);
186
if (length > char_length)
187
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
190
_mi_dpointer(info,key,filepos);
191
DBUG_PRINT("exit",("keynr: %d",keynr));
192
DBUG_DUMP("key",(uchar*) start,(uint) (key-start)+keyseg->length);
194
_mi_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start,
195
(uint) (key-start)););
196
DBUG_RETURN((uint) (key-start)); /* Return keylength */
201
Pack a key to intern format from given format (c_rkey)
206
uint keynr key number
207
key Store packed key here
209
keypart_map bitmap of used keyparts
210
last_used_keyseg out parameter. May be NULL
215
last_use_keyseg Store pointer to the keyseg after the last used one
218
uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
219
key_part_map keypart_map, HA_KEYSEG **last_used_keyseg)
221
uchar *start_key=key;
223
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
224
DBUG_ENTER("_mi_pack_key");
226
/* "one part" rtree key is 2*SPDIMS part key in MyISAM */
227
if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE)
228
keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1;
230
/* only key prefixes are supported */
231
DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0);
233
for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
234
old+= keyseg->length, keyseg++)
236
enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type;
237
uint length= keyseg->length;
240
CHARSET_INFO *cs=keyseg->charset;
242
if (keyseg->null_bit)
244
if (!(*key++= (char) 1-*old++)) /* Copy null marker */
246
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
248
continue; /* Found NULL */
251
char_length= (!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
253
if (keyseg->flag & HA_SPACE_PACK)
255
uchar *end=pos+length;
256
if (type == HA_KEYTYPE_NUM)
258
while (pos < end && pos[0] == ' ')
261
else if (type != HA_KEYTYPE_BINARY)
263
while (end > pos && end[-1] == ' ')
266
length=(uint) (end-pos);
267
FIX_LENGTH(cs, pos, length, char_length);
268
store_key_length_inc(key,char_length);
269
memcpy((uchar*) key,pos,(size_t) char_length);
273
else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
275
/* Length of key-part used with mi_rkey() always 2 */
276
uint tmp_length=uint2korr(pos);
278
set_if_smaller(length,tmp_length); /* Safety */
279
FIX_LENGTH(cs, pos, length, char_length);
280
store_key_length_inc(key,char_length);
281
old+=2; /* Skip length */
282
memcpy((uchar*) key, pos,(size_t) char_length);
286
else if (keyseg->flag & HA_SWAP_KEY)
287
{ /* Numerical column */
293
FIX_LENGTH(cs, pos, length, char_length);
294
memcpy((uchar*) key, pos, char_length);
295
if (length > char_length)
296
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
299
if (last_used_keyseg)
300
*last_used_keyseg= keyseg;
302
DBUG_RETURN((uint) (key-start_key));
308
Store found key in record
311
_mi_put_key_in_record()
313
keynr Key number that was used
314
record Store key here
316
Last read key is in info->lastkey
319
Used when only-keyread is wanted
326
static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
331
register HA_KEYSEG *keyseg;
333
DBUG_ENTER("_mi_put_key_in_record");
335
blob_ptr= (uchar*) info->lastkey2; /* Place to put blob parts */
336
key=(uchar*) info->lastkey; /* KEy that was read */
337
key_end=key+info->lastkey_length;
338
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
340
if (keyseg->null_bit)
344
record[keyseg->null_pos]|= keyseg->null_bit;
347
record[keyseg->null_pos]&= ~keyseg->null_bit;
349
if (keyseg->type == HA_KEYTYPE_BIT)
351
uint length= keyseg->length;
353
if (keyseg->bit_length)
356
set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
362
clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
365
memcpy(record + keyseg->start, (uchar*) key, length);
369
if (keyseg->flag & HA_SPACE_PACK)
372
get_key_length(length,key);
374
if (length > keyseg->length || key+length > key_end)
377
pos= record+keyseg->start;
378
if (keyseg->type != (int) HA_KEYTYPE_NUM)
380
memcpy(pos,key,(size_t) length);
381
keyseg->charset->cset->fill(keyseg->charset,
382
(char*) pos + length,
383
keyseg->length - length,
388
bfill(pos,keyseg->length-length,' ');
389
memcpy(pos+keyseg->length-length,key,(size_t) length);
395
if (keyseg->flag & HA_VAR_LENGTH_PART)
398
get_key_length(length,key);
400
if (length > keyseg->length || key+length > key_end)
403
/* Store key length */
404
if (keyseg->bit_start == 1)
405
*(uchar*) (record+keyseg->start)= (uchar) length;
407
int2store(record+keyseg->start, length);
409
memcpy(record+keyseg->start + keyseg->bit_start, (uchar*) key, length);
412
else if (keyseg->flag & HA_BLOB_PART)
415
get_key_length(length,key);
417
if (length > keyseg->length || key+length > key_end)
420
memcpy(record+keyseg->start+keyseg->bit_start,
421
(char*) &blob_ptr,sizeof(char*));
422
memcpy(blob_ptr,key,length);
425
/* The above changed info->lastkey2. Inform mi_rnext_same(). */
426
info->update&= ~HA_STATE_RNEXT_SAME;
428
_my_store_blob_length(record+keyseg->start,
429
(uint) keyseg->bit_start,length);
432
else if (keyseg->flag & HA_SWAP_KEY)
434
uchar *to= record+keyseg->start+keyseg->length;
435
uchar *end= key+keyseg->length;
443
} while (key != end);
449
if (key+keyseg->length > key_end)
452
memcpy(record+keyseg->start,(uchar*) key,
453
(size_t) keyseg->length);
454
key+= keyseg->length;
460
DBUG_RETURN(1); /* Crashed row */
461
} /* _mi_put_key_in_record */
464
/* Here when key reads are used */
466
int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf)
468
fast_mi_writeinfo(info);
469
if (filepos != HA_OFFSET_ERROR)
471
if (info->lastinx >= 0)
472
{ /* Read only key */
473
if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
475
mi_print_error(info->s, HA_ERR_CRASHED);
476
my_errno=HA_ERR_CRASHED;
479
info->update|= HA_STATE_AKTIV; /* We should find a record */
482
my_errno=HA_ERR_WRONG_INDEX;
484
return(-1); /* Wrong data to read */
489
Save current key tuple to record and call index condition check function
492
mi_check_index_cond()
494
keynr Index we're running a scan on
495
record Record buffer to use (it is assumed that index check function
496
will look for column values there)
500
0 Index condition is not satisfied, continue scanning
501
1 Index condition is satisfied
502
2 Index condition is not satisfied, end the scan.
505
int mi_check_index_cond(register MI_INFO *info, uint keynr, uchar *record)
507
if (_mi_put_key_in_record(info, keynr, record))
509
mi_print_error(info->s, HA_ERR_CRASHED);
510
my_errno=HA_ERR_CRASHED;
513
return info->index_cond_func(info->index_cond_func_arg);
518
Retrieve auto_increment info
521
retrieve_auto_increment()
526
For signed columns we don't retrieve the auto increment value if it's
530
ulonglong retrieve_auto_increment(MI_INFO *info,const uchar *record)
532
ulonglong value= 0; /* Store unsigned values here */
533
longlong s_value= 0; /* Store signed values here */
534
HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
535
const uchar *key= (uchar*) record + keyseg->start;
537
switch (keyseg->type) {
538
case HA_KEYTYPE_INT8:
539
s_value= (longlong) *(char*)key;
541
case HA_KEYTYPE_BINARY:
542
value=(ulonglong) *(uchar*) key;
544
case HA_KEYTYPE_SHORT_INT:
545
s_value= (longlong) sint2korr(key);
547
case HA_KEYTYPE_USHORT_INT:
548
value=(ulonglong) uint2korr(key);
550
case HA_KEYTYPE_LONG_INT:
551
s_value= (longlong) sint4korr(key);
553
case HA_KEYTYPE_ULONG_INT:
554
value=(ulonglong) uint4korr(key);
556
case HA_KEYTYPE_INT24:
557
s_value= (longlong) sint3korr(key);
559
case HA_KEYTYPE_UINT24:
560
value=(ulonglong) uint3korr(key);
562
case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
566
/* Ignore negative values */
567
value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
570
case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
574
/* Ignore negative values */
575
value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
578
case HA_KEYTYPE_LONGLONG:
579
s_value= sint8korr(key);
581
case HA_KEYTYPE_ULONGLONG:
582
value= uint8korr(key);
591
The following code works becasue if s_value < 0 then value is 0
592
and if s_value == 0 then value will contain either s_value or the
595
return (s_value > 0) ? (ulonglong) s_value : value;