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 */
17
/* Functions to handle keys and fields in forms */
20
#include <drizzled/table.h>
21
#include <drizzled/key.h>
22
#include <drizzled/field/blob.h>
23
#include <drizzled/util/test.h>
24
#include <drizzled/plugin/storage_engine.h>
26
#include <boost/dynamic_bitset.hpp>
38
Search after a key that starts with 'field'
42
key First key to check
43
key_count How many keys to check
44
record Start of record
45
field Field to search after
46
key_length On partial match, contains length of fields before
48
keypart key part # of a field
51
Used when calculating key for NEXT_NUMBER
54
If no key starts with field test if field is part of some key. If we find
55
one, then return first key and set key_length to the number of bytes
59
-1 field is not part of the key
60
# Key part for key matching key.
61
key_length is set to length of key before (not including) field
64
int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
65
uint32_t *key_length, uint32_t *keypart)
71
fieldpos= field->offset(record);
73
/* Test if some key starts as fieldpos */
74
for (i= 0, key_info= key ;
78
if (key_info->key_part[0].offset == fieldpos)
79
{ /* Found key. Calc keylength */
80
*key_length= *keypart= 0;
81
return i; /* Use this key */
85
/* Test if some key contains fieldpos */
86
for (i= 0, key_info= key;
91
KeyPartInfo *key_part;
93
for (j=0, key_part=key_info->key_part ;
94
j < key_info->key_parts ;
97
if (key_part->offset == fieldpos)
100
return i; /* Use this key */
102
*key_length+= key_part->store_length;
105
return(-1); /* No key is ok */
109
void key_copy(unsigned char *to_key, unsigned char *from_record, KeyInfo *key_info,
110
unsigned int key_length)
113
KeyPartInfo *key_part;
116
key_length= key_info->key_length;
117
for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
119
if (key_part->null_bit)
121
*to_key++= test(from_record[key_part->null_offset] &
125
if (key_part->key_part_flag & HA_BLOB_PART ||
126
key_part->key_part_flag & HA_VAR_LENGTH_PART)
128
key_length-= HA_KEY_BLOB_LENGTH;
129
length= min((uint16_t)key_length, key_part->length);
130
key_part->field->get_key_image(to_key, length);
131
to_key+= HA_KEY_BLOB_LENGTH;
135
length= min((uint16_t)key_length, key_part->length);
136
Field *field= key_part->field;
137
const CHARSET_INFO * const cs= field->charset();
138
uint32_t bytes= field->get_key_image(to_key, length);
140
cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
149
Zero the null components of key tuple.
152
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
154
KeyPartInfo *key_part= key_info->key_part;
155
KeyPartInfo *key_part_end= key_part + key_info->key_parts;
156
for (; key_part != key_part_end; key_part++)
158
if (key_part->null_bit && *tuple)
159
memset(tuple+1, 0, key_part->store_length-1);
160
tuple+= key_part->store_length;
166
Restore a key from some buffer to record.
168
This function converts a key into record format. It can be used in cases
169
when we want to return a key as a result row.
171
@param to_record record buffer where the key will be restored to
172
@param from_key buffer that contains a key
173
@param key_info descriptor of the index
174
@param key_length specifies length of all keyparts that will be restored
177
void key_restore(unsigned char *to_record, unsigned char *from_key, KeyInfo *key_info,
181
KeyPartInfo *key_part;
185
key_length= key_info->key_length;
187
for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
189
unsigned char used_uneven_bits= 0;
190
if (key_part->null_bit)
193
to_record[key_part->null_offset]|= key_part->null_bit;
195
to_record[key_part->null_offset]&= ~key_part->null_bit;
198
if (key_part->key_part_flag & HA_BLOB_PART)
201
This in fact never happens, as we have only partial BLOB
202
keys yet anyway, so it's difficult to find any sence to
203
restore the part of a record.
204
Maybe this branch is to be removed, but now we
205
have to ignore GCov compaining.
207
This may make more sense once we push down block lengths to the engine (aka partial retrieval).
209
uint32_t blob_length= uint2korr(from_key);
210
Field_blob *field= (Field_blob*) key_part->field;
213
from_key+= HA_KEY_BLOB_LENGTH;
214
key_length-= HA_KEY_BLOB_LENGTH;
215
field->set_ptr_offset(to_record - field->getTable()->getInsertRecord(),
216
(ulong) blob_length, from_key);
217
length= key_part->length;
219
else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
221
Field *field= key_part->field;
222
ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
225
field->setWriteSet();
226
field->move_field_offset(ptrdiff);
227
key_length-= HA_KEY_BLOB_LENGTH;
228
length= min(key_length, key_part->length);
229
field->set_key_image(from_key, length);
230
from_key+= HA_KEY_BLOB_LENGTH;
231
field->move_field_offset(-ptrdiff);
235
length= min(key_length, key_part->length);
236
/* skip the byte with 'uneven' bits, if used */
237
memcpy(to_record + key_part->offset, from_key + used_uneven_bits
238
, (size_t) length - used_uneven_bits);
247
Compare if a key has changed.
250
@param key key to compare to row
251
@param idx Index used
252
@param key_length Length of key
255
In theory we could just call field->cmp() for all field types,
256
but as we are only interested if a key has changed (not if the key is
257
larger or smaller than the previous value) we can do things a bit
258
faster by using memcmp() instead.
266
bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
268
uint32_t store_length;
269
KeyPartInfo *key_part;
270
const unsigned char *key_end= key + key_length;;
272
for (key_part=table->key_info[idx].key_part;
274
key_part++, key+= store_length)
277
store_length= key_part->store_length;
279
if (key_part->null_bit)
281
if (*key != test(table->getInsertRecord()[key_part->null_offset] &
289
if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
292
if (key_part->field->key_cmp(key, key_part->length))
296
length= min((uint32_t) (key_end-key), store_length);
297
if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
299
const CHARSET_INFO * const cs= key_part->field->charset();
300
uint32_t char_length= key_part->length / cs->mbmaxlen;
301
const unsigned char *pos= table->getInsertRecord() + key_part->offset;
302
if (length > char_length)
304
char_length= my_charpos(cs, pos, pos + length, char_length);
305
set_if_smaller(char_length, length);
307
if (cs->coll->strnncollsp(cs,
308
(const unsigned char*) key, length,
309
(const unsigned char*) pos, char_length, 0))
313
if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
320
unpack key-fields from record to some buffer.
322
This is used mainly to get a good error message. We temporary
323
change the column bitmap so that all columns are readable.
326
to Store value here in an easy to read form
333
void key_unpack(String *to, const Table *table, uint32_t idx)
335
KeyPartInfo *key_part,*key_part_end;
340
for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
341
table->key_info[idx].key_parts ;
342
key_part < key_part_end;
347
if (key_part->null_bit)
349
if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
351
to->append(STRING_WITH_LEN("NULL"));
355
if ((field= key_part->field))
357
const CHARSET_INFO * const cs= field->charset();
359
field->val_str_internal(&tmp);
360
if (cs->mbmaxlen > 1 &&
361
table->getField(key_part->fieldnr - 1)->field_length !=
365
Prefix key, multi-byte charset.
366
For the columns of type CHAR(N), the above val_str()
367
call will return exactly "key_part->length" bytes,
368
which can break a multi-byte characters in the middle.
369
Align, returning not more than "char_length" characters.
371
uint32_t charpos, char_length= key_part->length / cs->mbmaxlen;
372
if ((charpos= my_charpos(cs, tmp.c_ptr(),
373
tmp.c_ptr() + tmp.length(),
374
char_length)) < key_part->length)
378
if (key_part->length < field->pack_length())
379
tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
383
to->append(STRING_WITH_LEN("???"));
389
Check if key uses field that is marked in passed field bitmap.
393
table Table object with which keys and fields are associated.
394
idx Key to be checked.
395
fields Bitmap of fields to be checked.
398
This function uses Table::tmp_set bitmap so the caller should care
399
about saving/restoring its state if it also uses this bitmap.
402
TRUE Key uses field from bitmap
406
bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
408
table->tmp_set.reset();
409
table->mark_columns_used_by_index_no_reset(idx, table->tmp_set);
410
if (table->tmp_set.is_subset_of(fields))
414
If table handler has primary key as part of the index, check that primary
417
if (idx != table->getShare()->getPrimaryKey() && table->getShare()->hasPrimaryKey() &&
418
(table->cursor->getEngine()->check_flag(HTON_BIT_PRIMARY_KEY_IN_READ_INDEX)))
420
return is_key_used(table, table->getShare()->getPrimaryKey(), fields);
427
Compare key in row to a given key.
429
@param key_part Key part handler
430
@param key Key to compare to value in table->getInsertRecord()
431
@param key_length length of 'key'
434
The return value is SIGN(key_in_row - range_key):
435
- 0 Key is equal to range or 'range' == 0 (no range)
436
- -1 Key is less than range
437
- 1 Key is larger than range
440
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
442
uint32_t store_length;
444
for (const unsigned char *end=key + key_length;
446
key+= store_length, key_part++)
449
store_length= key_part->store_length;
450
if (key_part->null_bit)
452
/* This key part allows null values; NULL is lower than everything */
453
bool field_is_null= key_part->field->is_null();
454
if (*key) // If range key is null
456
/* the range is expecting a null value */
458
return 1; // Found key is > range
459
/* null -- exact match, go to next key part */
462
else if (field_is_null)
463
return -1; // NULL is less than any value
464
key++; // Skip null byte
467
if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
472
return 0; // Keys are equal
476
} /* namespace drizzled */