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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
/* Functions to handle keys */
18
#include "myisam_priv.h"
19
#include "drizzled/charset_info.h"
26
using namespace drizzled;
29
#define CHECK_KEYS /* Enable safety checks */
31
#define FIX_LENGTH(cs, pos, length, char_length) \
33
if (length > char_length) \
34
char_length= my_charpos(cs, pos, pos+length, char_length); \
35
drizzled::set_if_smaller(char_length,length); \
38
static int _mi_put_key_in_record(MI_INFO *info,uint32_t keynr,unsigned char *record);
41
Make a intern key from a record
47
key Store created key here
49
filepos Position to record in the data file
55
uint32_t _mi_make_key(register MI_INFO *info, uint32_t keynr, unsigned char *key,
56
const unsigned char *record, drizzled::internal::my_off_t filepos)
60
register HA_KEYSEG *keyseg;
63
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
65
enum drizzled::ha_base_keytype type=(enum drizzled::ha_base_keytype) keyseg->type;
66
uint32_t length=keyseg->length;
68
const drizzled::CHARSET_INFO * const cs=keyseg->charset;
72
if (record[keyseg->null_pos] & keyseg->null_bit)
74
*key++= 0; /* NULL in key */
77
*key++=1; /* Not NULL */
80
char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
83
pos= (unsigned char*) record+keyseg->start;
85
if (keyseg->flag & HA_SPACE_PACK)
87
length= cs->cset->lengthsp(cs, (char*) pos, length);
89
FIX_LENGTH(cs, pos, length, char_length);
90
store_key_length_inc(key,char_length);
91
memcpy(key, pos, char_length);
95
if (keyseg->flag & HA_VAR_LENGTH_PART)
97
uint32_t pack_length= (keyseg->bit_start == 1 ? 1 : 2);
98
uint32_t tmp_length= (pack_length == 1 ? (uint) *(unsigned char*) pos :
100
pos+= pack_length; /* Skip VARCHAR length */
101
drizzled::set_if_smaller(length,tmp_length);
102
FIX_LENGTH(cs, pos, length, char_length);
103
store_key_length_inc(key,char_length);
104
memcpy(key, pos, char_length);
108
else if (keyseg->flag & HA_BLOB_PART)
110
uint32_t tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
111
memcpy(&pos, pos+keyseg->bit_start, sizeof(char*));
112
drizzled::set_if_smaller(length,tmp_length);
113
FIX_LENGTH(cs, pos, length, char_length);
114
store_key_length_inc(key,char_length);
115
memcpy(key, pos, char_length);
119
else if (keyseg->flag & HA_SWAP_KEY)
120
{ /* Numerical column */
121
if (type == drizzled::HA_KEYTYPE_DOUBLE)
127
memset(key, 0, length);
139
FIX_LENGTH(cs, pos, length, char_length);
140
memcpy(key, pos, char_length);
141
if (length > char_length)
142
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
145
_mi_dpointer(info,key,filepos);
146
return((uint) (key-start)); /* Return keylength */
151
Pack a key to intern format from given format (c_rkey)
156
uint32_t keynr key number
157
key Store packed key here
159
keypart_map bitmap of used keyparts
160
last_used_keyseg out parameter. May be NULL
165
last_use_keyseg Store pointer to the keyseg after the last used one
168
uint32_t _mi_pack_key(register MI_INFO *info, uint32_t keynr, unsigned char *key, unsigned char *old,
169
drizzled::key_part_map keypart_map, HA_KEYSEG **last_used_keyseg)
171
unsigned char *start_key=key;
174
/* only key prefixes are supported */
175
assert(((keypart_map+1) & keypart_map) == 0);
177
for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
178
old+= keyseg->length, keyseg++)
180
enum drizzled::ha_base_keytype type= (enum drizzled::ha_base_keytype) keyseg->type;
181
uint32_t length= keyseg->length;
182
uint32_t char_length;
184
const drizzled::CHARSET_INFO * const cs=keyseg->charset;
186
if (keyseg->null_bit)
188
if (!(*key++= (char) 1-*old++)) /* Copy null marker */
190
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
192
continue; /* Found NULL */
195
char_length= (cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
197
if (keyseg->flag & HA_SPACE_PACK)
199
unsigned char *end=pos+length;
201
if (type != drizzled::HA_KEYTYPE_BINARY)
203
while (end > pos && end[-1] == ' ')
206
length=(uint) (end-pos);
207
FIX_LENGTH(cs, pos, length, char_length);
208
store_key_length_inc(key,char_length);
209
memcpy(key, pos, char_length);
213
else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
215
/* Length of key-part used with mi_rkey() always 2 */
216
uint32_t tmp_length=uint2korr(pos);
218
drizzled::set_if_smaller(length,tmp_length); /* Safety */
219
FIX_LENGTH(cs, pos, length, char_length);
220
store_key_length_inc(key,char_length);
221
old+=2; /* Skip length */
222
memcpy(key, pos, char_length);
226
else if (keyseg->flag & HA_SWAP_KEY)
227
{ /* Numerical column */
233
FIX_LENGTH(cs, pos, length, char_length);
234
memcpy(key, pos, char_length);
235
if (length > char_length)
236
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
239
if (last_used_keyseg)
240
*last_used_keyseg= keyseg;
242
return((uint) (key-start_key));
248
Store found key in record
251
_mi_put_key_in_record()
253
keynr Key number that was used
254
record Store key here
256
Last read key is in info->lastkey
259
Used when only-keyread is wanted
266
static int _mi_put_key_in_record(register MI_INFO *info, uint32_t keynr,
267
unsigned char *record)
269
register unsigned char *key;
270
unsigned char *pos,*key_end;
271
register HA_KEYSEG *keyseg;
272
unsigned char *blob_ptr;
274
blob_ptr= (unsigned char*) info->lastkey2; /* Place to put blob parts */
275
key=(unsigned char*) info->lastkey; /* KEy that was read */
276
key_end=key+info->lastkey_length;
277
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
279
if (keyseg->null_bit)
283
record[keyseg->null_pos]|= keyseg->null_bit;
286
record[keyseg->null_pos]&= ~keyseg->null_bit;
289
if (keyseg->flag & HA_SPACE_PACK)
292
get_key_length(length,key);
294
if (length > keyseg->length || key+length > key_end)
297
pos= record+keyseg->start;
299
memcpy(pos, key, length);
300
keyseg->charset->cset->fill(keyseg->charset,
301
(char*) pos + length,
302
keyseg->length - length,
308
if (keyseg->flag & HA_VAR_LENGTH_PART)
311
get_key_length(length,key);
313
if (length > keyseg->length || key+length > key_end)
316
/* Store key length */
317
if (keyseg->bit_start == 1)
318
*(unsigned char*) (record+keyseg->start)= (unsigned char) length;
320
int2store(record+keyseg->start, length);
322
memcpy(record+keyseg->start + keyseg->bit_start, key, length);
325
else if (keyseg->flag & HA_BLOB_PART)
328
get_key_length(length,key);
330
if (length > keyseg->length || key+length > key_end)
333
memcpy(record+keyseg->start+keyseg->bit_start,
334
&blob_ptr,sizeof(char*));
335
memcpy(blob_ptr,key,length);
338
/* The above changed info->lastkey2. Inform mi_rnext_same(). */
339
info->update&= ~HA_STATE_RNEXT_SAME;
341
_my_store_blob_length(record+keyseg->start,
342
(uint) keyseg->bit_start,length);
345
else if (keyseg->flag & HA_SWAP_KEY)
347
unsigned char *to= record+keyseg->start+keyseg->length;
348
unsigned char *end= key+keyseg->length;
356
} while (key != end);
362
if (key+keyseg->length > key_end)
365
memcpy(record+keyseg->start, key, keyseg->length);
366
key+= keyseg->length;
372
return(1); /* Crashed row */
373
} /* _mi_put_key_in_record */
376
/* Here when key reads are used */
378
int _mi_read_key_record(MI_INFO *info, drizzled::internal::my_off_t filepos, unsigned char *buf)
380
fast_mi_writeinfo(info);
381
if (filepos != HA_OFFSET_ERROR)
383
if (info->lastinx >= 0)
384
{ /* Read only key */
385
if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
387
mi_print_error(info->s, HA_ERR_CRASHED);
388
errno=HA_ERR_CRASHED;
391
info->update|= HA_STATE_AKTIV; /* We should find a record */
394
errno=HA_ERR_WRONG_INDEX;
396
return(-1); /* Wrong data to read */
401
Save current key tuple to record and call index condition check function
404
mi_check_index_cond()
406
keynr Index we're running a scan on
407
record Record buffer to use (it is assumed that index check function
408
will look for column values there)
412
0 Index condition is not satisfied, continue scanning
413
1 Index condition is satisfied
414
2 Index condition is not satisfied, end the scan.
417
int mi_check_index_cond(register MI_INFO *info, uint32_t keynr, unsigned char *record)
419
if (_mi_put_key_in_record(info, keynr, record))
421
mi_print_error(info->s, HA_ERR_CRASHED);
422
errno=HA_ERR_CRASHED;
425
return info->index_cond_func(info->index_cond_func_arg);
430
Retrieve auto_increment info
433
retrieve_auto_increment()
438
For signed columns we don't retrieve the auto increment value if it's
442
uint64_t retrieve_auto_increment(MI_INFO *info,const unsigned char *record)
444
uint64_t value= 0; /* Store unsigned values here */
445
int64_t s_value= 0; /* Store signed values here */
446
HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
447
const unsigned char *key= (unsigned char*) record + keyseg->start;
449
switch (keyseg->type) {
450
case drizzled::HA_KEYTYPE_BINARY:
451
value=(uint64_t) *(unsigned char*) key;
453
case drizzled::HA_KEYTYPE_LONG_INT:
454
s_value= (int64_t) sint4korr(key);
456
case drizzled::HA_KEYTYPE_ULONG_INT:
457
value=(uint64_t) uint4korr(key);
459
case drizzled::HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
463
/* Ignore negative values */
464
value = (f_1 < 0.0) ? 0 : (uint64_t) f_1;
467
case drizzled::HA_KEYTYPE_LONGLONG:
468
s_value= sint8korr(key);
470
case drizzled::HA_KEYTYPE_ULONGLONG:
471
value= uint8korr(key);
480
The following code works becasue if s_value < 0 then value is 0
481
and if s_value == 0 then value will contain either s_value or the
484
return (s_value > 0) ? (uint64_t) s_value : value;