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
reg1 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;
243
if (keyseg->null_bit)
245
if (!(*key++= (char) 1-*old++)) /* Copy null marker */
247
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
249
continue; /* Found NULL */
252
char_length= (!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
254
if (keyseg->flag & HA_SPACE_PACK)
256
uchar *end=pos+length;
257
if (type == HA_KEYTYPE_NUM)
259
while (pos < end && pos[0] == ' ')
262
else if (type != HA_KEYTYPE_BINARY)
264
while (end > pos && end[-1] == ' ')
267
length=(uint) (end-pos);
268
FIX_LENGTH(cs, pos, length, char_length);
269
store_key_length_inc(key,char_length);
270
memcpy((uchar*) key,pos,(size_t) char_length);
274
else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
276
/* Length of key-part used with mi_rkey() always 2 */
277
uint tmp_length=uint2korr(pos);
279
set_if_smaller(length,tmp_length); /* Safety */
280
FIX_LENGTH(cs, pos, length, char_length);
281
store_key_length_inc(key,char_length);
282
old+=2; /* Skip length */
283
memcpy((uchar*) key, pos,(size_t) char_length);
287
else if (keyseg->flag & HA_SWAP_KEY)
288
{ /* Numerical column */
294
FIX_LENGTH(cs, pos, length, char_length);
295
memcpy((uchar*) key, pos, char_length);
296
if (length > char_length)
297
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
300
if (last_used_keyseg)
301
*last_used_keyseg= keyseg;
303
DBUG_RETURN((uint) (key-start_key));
309
Store found key in record
312
_mi_put_key_in_record()
314
keynr Key number that was used
315
record Store key here
317
Last read key is in info->lastkey
320
Used when only-keyread is wanted
327
static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
332
reg1 HA_KEYSEG *keyseg;
334
DBUG_ENTER("_mi_put_key_in_record");
336
blob_ptr= (uchar*) info->lastkey2; /* Place to put blob parts */
337
key=(uchar*) info->lastkey; /* KEy that was read */
338
key_end=key+info->lastkey_length;
339
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
341
if (keyseg->null_bit)
345
record[keyseg->null_pos]|= keyseg->null_bit;
348
record[keyseg->null_pos]&= ~keyseg->null_bit;
350
if (keyseg->type == HA_KEYTYPE_BIT)
352
uint length= keyseg->length;
354
if (keyseg->bit_length)
357
set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
363
clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
366
memcpy(record + keyseg->start, (uchar*) key, length);
370
if (keyseg->flag & HA_SPACE_PACK)
373
get_key_length(length,key);
375
if (length > keyseg->length || key+length > key_end)
378
pos= record+keyseg->start;
379
if (keyseg->type != (int) HA_KEYTYPE_NUM)
381
memcpy(pos,key,(size_t) length);
382
keyseg->charset->cset->fill(keyseg->charset,
383
(char*) pos + length,
384
keyseg->length - length,
389
bfill(pos,keyseg->length-length,' ');
390
memcpy(pos+keyseg->length-length,key,(size_t) length);
396
if (keyseg->flag & HA_VAR_LENGTH_PART)
399
get_key_length(length,key);
401
if (length > keyseg->length || key+length > key_end)
404
/* Store key length */
405
if (keyseg->bit_start == 1)
406
*(uchar*) (record+keyseg->start)= (uchar) length;
408
int2store(record+keyseg->start, length);
410
memcpy(record+keyseg->start + keyseg->bit_start, (uchar*) key, length);
413
else if (keyseg->flag & HA_BLOB_PART)
416
get_key_length(length,key);
418
if (length > keyseg->length || key+length > key_end)
421
memcpy(record+keyseg->start+keyseg->bit_start,
422
(char*) &blob_ptr,sizeof(char*));
423
memcpy(blob_ptr,key,length);
426
/* The above changed info->lastkey2. Inform mi_rnext_same(). */
427
info->update&= ~HA_STATE_RNEXT_SAME;
429
_my_store_blob_length(record+keyseg->start,
430
(uint) keyseg->bit_start,length);
433
else if (keyseg->flag & HA_SWAP_KEY)
435
uchar *to= record+keyseg->start+keyseg->length;
436
uchar *end= key+keyseg->length;
444
} while (key != end);
450
if (key+keyseg->length > key_end)
453
memcpy(record+keyseg->start,(uchar*) key,
454
(size_t) keyseg->length);
455
key+= keyseg->length;
461
DBUG_RETURN(1); /* Crashed row */
462
} /* _mi_put_key_in_record */
465
/* Here when key reads are used */
467
int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf)
469
fast_mi_writeinfo(info);
470
if (filepos != HA_OFFSET_ERROR)
472
if (info->lastinx >= 0)
473
{ /* Read only key */
474
if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
476
mi_print_error(info->s, HA_ERR_CRASHED);
477
my_errno=HA_ERR_CRASHED;
480
info->update|= HA_STATE_AKTIV; /* We should find a record */
483
my_errno=HA_ERR_WRONG_INDEX;
485
return(-1); /* Wrong data to read */
490
Retrieve auto_increment info
493
retrieve_auto_increment()
498
For signed columns we don't retrieve the auto increment value if it's
502
ulonglong retrieve_auto_increment(MI_INFO *info,const uchar *record)
504
ulonglong value= 0; /* Store unsigned values here */
505
longlong s_value= 0; /* Store signed values here */
506
HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
507
const uchar *key= (uchar*) record + keyseg->start;
509
switch (keyseg->type) {
510
case HA_KEYTYPE_INT8:
511
s_value= (longlong) *(char*)key;
513
case HA_KEYTYPE_BINARY:
514
value=(ulonglong) *(uchar*) key;
516
case HA_KEYTYPE_SHORT_INT:
517
s_value= (longlong) sint2korr(key);
519
case HA_KEYTYPE_USHORT_INT:
520
value=(ulonglong) uint2korr(key);
522
case HA_KEYTYPE_LONG_INT:
523
s_value= (longlong) sint4korr(key);
525
case HA_KEYTYPE_ULONG_INT:
526
value=(ulonglong) uint4korr(key);
528
case HA_KEYTYPE_INT24:
529
s_value= (longlong) sint3korr(key);
531
case HA_KEYTYPE_UINT24:
532
value=(ulonglong) uint3korr(key);
534
case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
538
/* Ignore negative values */
539
value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
542
case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
546
/* Ignore negative values */
547
value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
550
case HA_KEYTYPE_LONGLONG:
551
s_value= sint8korr(key);
553
case HA_KEYTYPE_ULONGLONG:
554
value= uint8korr(key);
563
The following code works becasue if s_value < 0 then value is 0
564
and if s_value == 0 then value will contain either s_value or the
567
return (s_value > 0) ? (ulonglong) s_value : value;