Drizzled Public API Documentation

key.cc
1 /* Copyright (C) 2000-2006 MySQL AB
2 
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.
6 
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.
11 
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 */
15 
16 
17 /* Functions to handle keys and fields in forms */
18 
19 #include <config.h>
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>
25 
26 #include <boost/dynamic_bitset.hpp>
27 
28 #include <string>
29 
30 #include <algorithm>
31 
32 using namespace std;
33 
34 namespace drizzled
35 {
36 
37 /*
38  Search after a key that starts with 'field'
39 
40  SYNOPSIS
41  find_ref_key()
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
47  field
48  keypart key part # of a field
49 
50  NOTES
51  Used when calculating key for NEXT_NUMBER
52 
53  IMPLEMENTATION
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
56  preceding 'field'.
57 
58  RETURN
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
62 */
63 
64 int find_ref_key(KeyInfo *key, uint32_t key_count, unsigned char *record, Field *field,
65  uint32_t *key_length, uint32_t *keypart)
66 {
67  int i;
68  KeyInfo *key_info;
69  uint32_t fieldpos;
70 
71  fieldpos= field->offset(record);
72 
73  /* Test if some key starts as fieldpos */
74  for (i= 0, key_info= key ;
75  i < (int) key_count ;
76  i++, key_info++)
77  {
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 */
82  }
83  }
84 
85  /* Test if some key contains fieldpos */
86  for (i= 0, key_info= key;
87  i < (int) key_count ;
88  i++, key_info++)
89  {
90  uint32_t j;
91  KeyPartInfo *key_part;
92  *key_length=0;
93  for (j=0, key_part=key_info->key_part ;
94  j < key_info->key_parts ;
95  j++, key_part++)
96  {
97  if (key_part->offset == fieldpos)
98  {
99  *keypart= j;
100  return i; /* Use this key */
101  }
102  *key_length+= key_part->store_length;
103  }
104  }
105  return(-1); /* No key is ok */
106 }
107 
108 
109 void key_copy(unsigned char *to_key, unsigned char *from_record, KeyInfo *key_info,
110  unsigned int key_length)
111 {
112  uint32_t length;
113  KeyPartInfo *key_part;
114 
115  if (key_length == 0)
116  key_length= key_info->key_length;
117  for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
118  {
119  if (key_part->null_bit)
120  {
121  *to_key++= test(from_record[key_part->null_offset] &
122  key_part->null_bit);
123  key_length--;
124  }
125  if (key_part->key_part_flag & HA_BLOB_PART ||
126  key_part->key_part_flag & HA_VAR_LENGTH_PART)
127  {
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;
132  }
133  else
134  {
135  length= min((uint16_t)key_length, key_part->length);
136  Field *field= key_part->field;
137  const charset_info_st * const cs= field->charset();
138  uint32_t bytes= field->get_key_image(to_key, length);
139  if (bytes < length)
140  cs->cset->fill(cs, (char*) to_key + bytes, length - bytes, ' ');
141  }
142  to_key+= length;
143  key_length-= length;
144  }
145 }
146 
147 
152 void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
153 {
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++)
157  {
158  if (key_part->null_bit && *tuple)
159  memset(tuple+1, 0, key_part->store_length-1);
160  tuple+= key_part->store_length;
161  }
162 }
163 
164 
165 /*
166  Restore a key from some buffer to record.
167 
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.
170 
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
175 */
176 
177 void key_restore(unsigned char *to_record, unsigned char *from_key, KeyInfo *key_info,
178  uint16_t key_length)
179 {
180  uint32_t length;
181  KeyPartInfo *key_part;
182 
183  if (key_length == 0)
184  {
185  key_length= key_info->key_length;
186  }
187  for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
188  {
189  unsigned char used_uneven_bits= 0;
190  if (key_part->null_bit)
191  {
192  if (*from_key++)
193  to_record[key_part->null_offset]|= key_part->null_bit;
194  else
195  to_record[key_part->null_offset]&= ~key_part->null_bit;
196  key_length--;
197  }
198  if (key_part->key_part_flag & HA_BLOB_PART)
199  {
200  /*
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.
206 
207  This may make more sense once we push down block lengths to the engine (aka partial retrieval).
208  */
209  uint32_t blob_length= uint2korr(from_key);
210  Field_blob *field= (Field_blob*) key_part->field;
211 
212  field->setReadSet();
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;
218  }
219  else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
220  {
221  Field *field= key_part->field;
222  ptrdiff_t ptrdiff= to_record - field->getTable()->getInsertRecord();
223 
224  field->setReadSet();
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);
232  }
233  else
234  {
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);
239  }
240  from_key+= length;
241  key_length-= length;
242  }
243 }
244 
245 
266 bool key_cmp_if_same(Table *table,const unsigned char *key,uint32_t idx,uint32_t key_length)
267 {
268  uint32_t store_length;
269  KeyPartInfo *key_part;
270  const unsigned char *key_end= key + key_length;;
271 
272  for (key_part=table->key_info[idx].key_part;
273  key < key_end ;
274  key_part++, key+= store_length)
275  {
276  uint32_t length;
277  store_length= key_part->store_length;
278 
279  if (key_part->null_bit)
280  {
281  if (*key != test(table->getInsertRecord()[key_part->null_offset] &
282  key_part->null_bit))
283  return 1;
284  if (*key)
285  continue;
286  key++;
287  store_length--;
288  }
289  if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART |
290  HA_BIT_PART))
291  {
292  if (key_part->field->key_cmp(key, key_part->length))
293  return 1;
294  continue;
295  }
296  length= min((uint32_t) (key_end-key), store_length);
297  if (key_part->field->type() == DRIZZLE_TYPE_VARCHAR)
298  {
299  const charset_info_st * 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)
303  {
304  char_length= my_charpos(cs, pos, pos + length, char_length);
305  set_if_smaller(char_length, length);
306  }
307  if (cs->coll->strnncollsp(cs,
308  (const unsigned char*) key, length,
309  (const unsigned char*) pos, char_length, 0))
310  return 1;
311  continue;
312  }
313  if (memcmp(key,table->getInsertRecord()+key_part->offset,length))
314  return 1;
315  }
316  return 0;
317 }
318 
319 /*
320  unpack key-fields from record to some buffer.
321 
322  This is used mainly to get a good error message. We temporary
323  change the column bitmap so that all columns are readable.
324 
325  @param
326  to Store value here in an easy to read form
327  @param
328  table Table to use
329  @param
330  idx Key number
331 */
332 
333 void key_unpack(String *to, const Table *table, uint32_t idx)
334 {
335  KeyPartInfo *key_part,*key_part_end;
336  Field *field;
337  String tmp;
338 
339  to->length(0);
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;
343  key_part++)
344  {
345  if (to->length())
346  to->append('-');
347  if (key_part->null_bit)
348  {
349  if (table->getInsertRecord()[key_part->null_offset] & key_part->null_bit)
350  {
351  to->append(STRING_WITH_LEN("NULL"));
352  continue;
353  }
354  }
355  if ((field= key_part->field))
356  {
357  const charset_info_st * const cs= field->charset();
358  field->setReadSet();
359  field->val_str_internal(&tmp);
360  if (cs->mbmaxlen > 1 &&
361  table->getField(key_part->fieldnr - 1)->field_length !=
362  key_part->length)
363  {
364  /*
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.
370  */
371  uint32_t charpos, char_length= key_part->length / cs->mbmaxlen;
372  if ((charpos= my_charpos(cs, tmp.c_ptr(), tmp.c_ptr() + tmp.length(), char_length)) < key_part->length)
373  tmp.length(charpos);
374  }
375 
376  if (key_part->length < field->pack_length())
377  tmp.length(min(tmp.length(), static_cast<size_t>(key_part->length)));
378  to->append(tmp);
379  }
380  else
381  to->append(STRING_WITH_LEN("???"));
382  }
383 }
384 
385 
386 /*
387  Check if key uses field that is marked in passed field bitmap.
388 
389  SYNOPSIS
390  is_key_used()
391  table Table object with which keys and fields are associated.
392  idx Key to be checked.
393  fields Bitmap of fields to be checked.
394 
395  NOTE
396  This function uses Table::tmp_set bitmap so the caller should care
397  about saving/restoring its state if it also uses this bitmap.
398 
399  RETURN VALUE
400  TRUE Key uses field from bitmap
401  FALSE Otherwise
402 */
403 
404 bool is_key_used(Table *table, uint32_t idx, const boost::dynamic_bitset<>& fields)
405 {
406  table->tmp_set.reset();
407  table->mark_columns_used_by_index_no_reset(idx, table->tmp_set);
408  if (table->tmp_set.is_subset_of(fields))
409  return 1;
410 
411  /*
412  If table handler has primary key as part of the index, check that primary
413  key is not updated
414  */
415  if (idx != table->getShare()->getPrimaryKey() && table->getShare()->hasPrimaryKey() &&
416  (table->cursor->getEngine()->check_flag(HTON_BIT_PRIMARY_KEY_IN_READ_INDEX)))
417  {
418  return is_key_used(table, table->getShare()->getPrimaryKey(), fields);
419  }
420  return 0;
421 }
422 
423 
438 int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
439 {
440  uint32_t store_length;
441 
442  for (const unsigned char *end=key + key_length;
443  key < end;
444  key+= store_length, key_part++)
445  {
446  int cmp;
447  store_length= key_part->store_length;
448  if (key_part->null_bit)
449  {
450  /* This key part allows null values; NULL is lower than everything */
451  bool field_is_null= key_part->field->is_null();
452  if (*key) // If range key is null
453  {
454  /* the range is expecting a null value */
455  if (!field_is_null)
456  return 1; // Found key is > range
457  /* null -- exact match, go to next key part */
458  continue;
459  }
460  else if (field_is_null)
461  return -1; // NULL is less than any value
462  key++; // Skip null byte
463  store_length--;
464  }
465  if ((cmp=key_part->field->key_cmp(key, key_part->length)) < 0)
466  return -1;
467  if (cmp > 0)
468  return 1;
469  }
470  return 0; // Keys are equal
471 }
472 
473 
474 } /* namespace drizzled */
TODO: Rename this file - func.h is stupid.
void key_zero_nulls(unsigned char *tuple, KeyInfo *key_info)
Definition: key.cc:152
int key_cmp(KeyPartInfo *key_part, const unsigned char *key, uint32_t key_length)
Definition: key.cc:438
KeyInfo * key_info
Definition: table.h:141
static void store_length(unsigned char *to, uint32_t length, uint32_t pack_length)
Definition: filesort.cc:753
bool key_cmp_if_same(Table *table, const unsigned char *key, uint32_t idx, uint32_t key_length)
Definition: key.cc:266