Drizzled Public API Documentation

mi_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 /* Functions to handle keys */
17 
18 #include "myisam_priv.h"
19 #include <drizzled/charset.h>
20 #ifdef HAVE_IEEEFP_H
21 #include <ieeefp.h>
22 #endif
23 #include <math.h>
24 #include <cassert>
25 
26 using namespace drizzled;
27 using namespace std;
28 
29 #define CHECK_KEYS /* Enable safety checks */
30 
31 #define FIX_LENGTH(cs, pos, length, char_length) \
32  do { \
33  if (length > char_length) \
34  char_length= my_charpos(cs, pos, pos+length, char_length); \
35  drizzled::set_if_smaller(char_length,length); \
36  } while(0)
37 
38 static int _mi_put_key_in_record(MI_INFO *info,uint32_t keynr,unsigned char *record);
39 
40 /*
41  Make a intern key from a record
42 
43  SYNOPSIS
44  _mi_make_key()
45  info MyiSAM handler
46  keynr key number
47  key Store created key here
48  record Record
49  filepos Position to record in the data file
50 
51  RETURN
52  Length of key
53 */
54 
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)
57 {
58  unsigned char *pos;
59  unsigned char *start;
60  register HA_KEYSEG *keyseg;
61 
62  start=key;
63  for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
64  {
65  enum drizzled::ha_base_keytype type=(enum drizzled::ha_base_keytype) keyseg->type;
66  uint32_t length=keyseg->length;
67  uint32_t char_length;
68  const drizzled::charset_info_st * const cs=keyseg->charset;
69 
70  if (keyseg->null_bit)
71  {
72  if (record[keyseg->null_pos] & keyseg->null_bit)
73  {
74  *key++= 0; /* NULL in key */
75  continue;
76  }
77  *key++=1; /* Not NULL */
78  }
79 
80  char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
81  length);
82 
83  pos= (unsigned char*) record+keyseg->start;
84 
85  if (keyseg->flag & HA_SPACE_PACK)
86  {
87  length= cs->cset->lengthsp(cs, (char*) pos, length);
88 
89  FIX_LENGTH(cs, pos, length, char_length);
90  store_key_length_inc(key,char_length);
91  memcpy(key, pos, char_length);
92  key+=char_length;
93  continue;
94  }
95  if (keyseg->flag & HA_VAR_LENGTH_PART)
96  {
97  uint32_t pack_length= (keyseg->bit_start == 1 ? 1 : 2);
98  uint32_t tmp_length= (pack_length == 1 ? (uint) *(unsigned char*) pos :
99  uint2korr(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);
105  key+= char_length;
106  continue;
107  }
108  else if (keyseg->flag & HA_BLOB_PART)
109  {
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);
116  key+= char_length;
117  continue;
118  }
119  else if (keyseg->flag & HA_SWAP_KEY)
120  { /* Numerical column */
121  if (type == drizzled::HA_KEYTYPE_DOUBLE)
122  {
123  double nr;
124  float8get(nr,pos);
125  if (isnan(nr))
126  {
127  memset(key, 0, length);
128  key+=length;
129  continue;
130  }
131  }
132  pos+=length;
133  while (length--)
134  {
135  *key++ = *--pos;
136  }
137  continue;
138  }
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, ' ');
143  key+= length;
144  }
145  _mi_dpointer(info,key,filepos);
146  return((uint) (key-start)); /* Return keylength */
147 } /* _mi_make_key */
148 
149 
150 /*
151  Pack a key to intern format from given format (c_rkey)
152 
153  SYNOPSIS
154  _mi_pack_key()
155  info MyISAM handler
156  uint32_t keynr key number
157  key Store packed key here
158  old Not packed key
159  keypart_map bitmap of used keyparts
160  last_used_keyseg out parameter. May be NULL
161 
162  RETURN
163  length of packed key
164 
165  last_use_keyseg Store pointer to the keyseg after the last used one
166 */
167 
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)
170 {
171  unsigned char *start_key=key;
172  HA_KEYSEG *keyseg;
173 
174  /* only key prefixes are supported */
175  assert(((keypart_map+1) & keypart_map) == 0);
176 
177  for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
178  old+= keyseg->length, keyseg++)
179  {
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;
183  unsigned char *pos;
184  const drizzled::charset_info_st * const cs=keyseg->charset;
185  keypart_map>>= 1;
186  if (keyseg->null_bit)
187  {
188  if (!(*key++= (char) 1-*old++)) /* Copy null marker */
189  {
190  if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
191  old+= 2;
192  continue; /* Found NULL */
193  }
194  }
195  char_length= (cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
196  pos=old;
197  if (keyseg->flag & HA_SPACE_PACK)
198  {
199  unsigned char *end=pos+length;
200 
201  if (type != drizzled::HA_KEYTYPE_BINARY)
202  {
203  while (end > pos && end[-1] == ' ')
204  end--;
205  }
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);
210  key+= char_length;
211  continue;
212  }
213  else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
214  {
215  /* Length of key-part used with mi_rkey() always 2 */
216  uint32_t tmp_length=uint2korr(pos);
217  pos+=2;
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);
223  key+= char_length;
224  continue;
225  }
226  else if (keyseg->flag & HA_SWAP_KEY)
227  { /* Numerical column */
228  pos+=length;
229  while (length--)
230  *key++ = *--pos;
231  continue;
232  }
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, ' ');
237  key+= length;
238  }
239  if (last_used_keyseg)
240  *last_used_keyseg= keyseg;
241 
242  return((uint) (key-start_key));
243 } /* _mi_pack_key */
244 
245 
246 
247 /*
248  Store found key in record
249 
250  SYNOPSIS
251  _mi_put_key_in_record()
252  info MyISAM handler
253  keynr Key number that was used
254  record Store key here
255 
256  Last read key is in info->lastkey
257 
258  NOTES
259  Used when only-keyread is wanted
260 
261  RETURN
262  0 ok
263  1 error
264 */
265 
266 static int _mi_put_key_in_record(register MI_INFO *info, uint32_t keynr,
267  unsigned char *record)
268 {
269  register unsigned char *key;
270  unsigned char *pos,*key_end;
271  register HA_KEYSEG *keyseg;
272  unsigned char *blob_ptr;
273 
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++)
278  {
279  if (keyseg->null_bit)
280  {
281  if (!*key++)
282  {
283  record[keyseg->null_pos]|= keyseg->null_bit;
284  continue;
285  }
286  record[keyseg->null_pos]&= ~keyseg->null_bit;
287  }
288 
289  if (keyseg->flag & HA_SPACE_PACK)
290  {
291  uint32_t length;
292  get_key_length(length,key);
293 #ifdef CHECK_KEYS
294  if (length > keyseg->length || key+length > key_end)
295  goto err;
296 #endif
297  pos= record+keyseg->start;
298 
299  memcpy(pos, key, length);
300  keyseg->charset->cset->fill(keyseg->charset,
301  (char*) pos + length,
302  keyseg->length - length,
303  ' ');
304  key+=length;
305  continue;
306  }
307 
308  if (keyseg->flag & HA_VAR_LENGTH_PART)
309  {
310  uint32_t length;
311  get_key_length(length,key);
312 #ifdef CHECK_KEYS
313  if (length > keyseg->length || key+length > key_end)
314  goto err;
315 #endif
316  /* Store key length */
317  if (keyseg->bit_start == 1)
318  *(unsigned char*) (record+keyseg->start)= (unsigned char) length;
319  else
320  int2store(record+keyseg->start, length);
321  /* And key data */
322  memcpy(record+keyseg->start + keyseg->bit_start, key, length);
323  key+= length;
324  }
325  else if (keyseg->flag & HA_BLOB_PART)
326  {
327  uint32_t length;
328  get_key_length(length,key);
329 #ifdef CHECK_KEYS
330  if (length > keyseg->length || key+length > key_end)
331  goto err;
332 #endif
333  memcpy(record+keyseg->start+keyseg->bit_start,
334  &blob_ptr,sizeof(char*));
335  memcpy(blob_ptr,key,length);
336  blob_ptr+=length;
337 
338  /* The above changed info->lastkey2. Inform mi_rnext_same(). */
339  info->update&= ~HA_STATE_RNEXT_SAME;
340 
341  _my_store_blob_length(record+keyseg->start,
342  (uint) keyseg->bit_start,length);
343  key+=length;
344  }
345  else if (keyseg->flag & HA_SWAP_KEY)
346  {
347  unsigned char *to= record+keyseg->start+keyseg->length;
348  unsigned char *end= key+keyseg->length;
349 #ifdef CHECK_KEYS
350  if (end > key_end)
351  goto err;
352 #endif
353  do
354  {
355  *--to= *key++;
356  } while (key != end);
357  continue;
358  }
359  else
360  {
361 #ifdef CHECK_KEYS
362  if (key+keyseg->length > key_end)
363  goto err;
364 #endif
365  memcpy(record+keyseg->start, key, keyseg->length);
366  key+= keyseg->length;
367  }
368  }
369  return(0);
370 
371 err:
372  return(1); /* Crashed row */
373 } /* _mi_put_key_in_record */
374 
375 
376  /* Here when key reads are used */
377 
378 int _mi_read_key_record(MI_INFO *info, drizzled::internal::my_off_t filepos, unsigned char *buf)
379 {
380  fast_mi_writeinfo(info);
381  if (filepos != HA_OFFSET_ERROR)
382  {
383  if (info->lastinx >= 0)
384  { /* Read only key */
385  if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
386  {
387  mi_print_error(info->s, HA_ERR_CRASHED);
388  errno=HA_ERR_CRASHED;
389  return -1;
390  }
391  info->update|= HA_STATE_AKTIV; /* We should find a record */
392  return 0;
393  }
394  errno=HA_ERR_WRONG_INDEX;
395  }
396  return(-1); /* Wrong data to read */
397 }
398 
399 
400 /*
401  Save current key tuple to record and call index condition check function
402 
403  SYNOPSIS
404  mi_check_index_cond()
405  info MyISAM handler
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)
409 
410  RETURN
411  -1 Error
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.
415 */
416 
417 int mi_check_index_cond(register MI_INFO *info, uint32_t keynr, unsigned char *record)
418 {
419  if (_mi_put_key_in_record(info, keynr, record))
420  {
421  mi_print_error(info->s, HA_ERR_CRASHED);
422  errno=HA_ERR_CRASHED;
423  return -1;
424  }
425  return info->index_cond_func(info->index_cond_func_arg);
426 }
427 
428 
429 /*
430  Retrieve auto_increment info
431 
432  SYNOPSIS
433  retrieve_auto_increment()
434  info MyISAM handler
435  record Row to update
436 
437  IMPLEMENTATION
438  For signed columns we don't retrieve the auto increment value if it's
439  less than zero.
440 */
441 
442 uint64_t retrieve_auto_increment(MI_INFO *info,const unsigned char *record)
443 {
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;
448 
449  switch (keyseg->type) {
450  case drizzled::HA_KEYTYPE_BINARY:
451  value=(uint64_t) *(unsigned char*) key;
452  break;
453  case drizzled::HA_KEYTYPE_LONG_INT:
454  s_value= (int64_t) sint4korr(key);
455  break;
456  case drizzled::HA_KEYTYPE_ULONG_INT:
457  value=(uint64_t) uint4korr(key);
458  break;
459  case drizzled::HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
460  {
461  double f_1;
462  float8get(f_1,key);
463  /* Ignore negative values */
464  value = (f_1 < 0.0) ? 0 : (uint64_t) f_1;
465  break;
466  }
467  case drizzled::HA_KEYTYPE_LONGLONG:
468  s_value= sint8korr(key);
469  break;
470  case drizzled::HA_KEYTYPE_ULONGLONG:
471  value= uint8korr(key);
472  break;
473  default:
474  assert(0);
475  value=0; /* Error */
476  break;
477  }
478 
479  /*
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
482  correct value.
483  */
484  return (s_value > 0) ? (uint64_t) s_value : value;
485 }
TODO: Rename this file - func.h is stupid.