Drizzled Public API Documentation

mi_key.cc
00001 /* Copyright (C) 2000-2006 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 /* Functions to handle keys */
00017 
00018 #include "myisam_priv.h"
00019 #include <drizzled/charset_info.h>
00020 #ifdef HAVE_IEEEFP_H
00021 #include <ieeefp.h>
00022 #endif
00023 #include <math.h>
00024 #include <cassert>
00025 
00026 using namespace drizzled;
00027 using namespace std;
00028 
00029 #define CHECK_KEYS                              /* Enable safety checks */
00030 
00031 #define FIX_LENGTH(cs, pos, length, char_length)                            \
00032             do {                                                            \
00033               if (length > char_length)                                     \
00034                 char_length= my_charpos(cs, pos, pos+length, char_length);  \
00035               drizzled::set_if_smaller(char_length,length);                           \
00036             } while(0)
00037 
00038 static int _mi_put_key_in_record(MI_INFO *info,uint32_t keynr,unsigned char *record);
00039 
00040 /*
00041   Make a intern key from a record
00042 
00043   SYNOPSIS
00044     _mi_make_key()
00045     info    MyiSAM handler
00046     keynr   key number
00047     key     Store created key here
00048     record    Record
00049     filepos   Position to record in the data file
00050 
00051   RETURN
00052     Length of key
00053 */
00054 
00055 uint32_t _mi_make_key(register MI_INFO *info, uint32_t keynr, unsigned char *key,
00056                       const unsigned char *record, drizzled::internal::my_off_t filepos)
00057 {
00058   unsigned char *pos;
00059   unsigned char *start;
00060   register HA_KEYSEG *keyseg;
00061 
00062   start=key;
00063   for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
00064   {
00065     enum drizzled::ha_base_keytype type=(enum drizzled::ha_base_keytype) keyseg->type;
00066     uint32_t length=keyseg->length;
00067     uint32_t char_length;
00068     const drizzled::CHARSET_INFO * const cs=keyseg->charset;
00069 
00070     if (keyseg->null_bit)
00071     {
00072       if (record[keyseg->null_pos] & keyseg->null_bit)
00073       {
00074   *key++= 0;        /* NULL in key */
00075   continue;
00076       }
00077       *key++=1;         /* Not NULL */
00078     }
00079 
00080     char_length= ((cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
00081                   length);
00082 
00083     pos= (unsigned char*) record+keyseg->start;
00084 
00085     if (keyseg->flag & HA_SPACE_PACK)
00086     {
00087       length= cs->cset->lengthsp(cs, (char*) pos, length);
00088 
00089       FIX_LENGTH(cs, pos, length, char_length);
00090       store_key_length_inc(key,char_length);
00091       memcpy(key, pos, char_length);
00092       key+=char_length;
00093       continue;
00094     }
00095     if (keyseg->flag & HA_VAR_LENGTH_PART)
00096     {
00097       uint32_t pack_length= (keyseg->bit_start == 1 ? 1 : 2);
00098       uint32_t tmp_length= (pack_length == 1 ? (uint) *(unsigned char*) pos :
00099                         uint2korr(pos));
00100       pos+= pack_length;      /* Skip VARCHAR length */
00101       drizzled::set_if_smaller(length,tmp_length);
00102       FIX_LENGTH(cs, pos, length, char_length);
00103       store_key_length_inc(key,char_length);
00104       memcpy(key, pos, char_length);
00105       key+= char_length;
00106       continue;
00107     }
00108     else if (keyseg->flag & HA_BLOB_PART)
00109     {
00110       uint32_t tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
00111       memcpy(&pos, pos+keyseg->bit_start, sizeof(char*));
00112       drizzled::set_if_smaller(length,tmp_length);
00113       FIX_LENGTH(cs, pos, length, char_length);
00114       store_key_length_inc(key,char_length);
00115       memcpy(key, pos, char_length);
00116       key+= char_length;
00117       continue;
00118     }
00119     else if (keyseg->flag & HA_SWAP_KEY)
00120     {           /* Numerical column */
00121       if (type == drizzled::HA_KEYTYPE_DOUBLE)
00122       {
00123   double nr;
00124   float8get(nr,pos);
00125   if (isnan(nr))
00126   {
00127     memset(key, 0, length);
00128     key+=length;
00129     continue;
00130   }
00131       }
00132       pos+=length;
00133       while (length--)
00134       {
00135   *key++ = *--pos;
00136       }
00137       continue;
00138     }
00139     FIX_LENGTH(cs, pos, length, char_length);
00140     memcpy(key, pos, char_length);
00141     if (length > char_length)
00142       cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
00143     key+= length;
00144   }
00145   _mi_dpointer(info,key,filepos);
00146   return((uint) (key-start));   /* Return keylength */
00147 } /* _mi_make_key */
00148 
00149 
00150 /*
00151   Pack a key to intern format from given format (c_rkey)
00152 
00153   SYNOPSIS
00154     _mi_pack_key()
00155     info    MyISAM handler
00156     uint32_t keynr    key number
00157     key     Store packed key here
00158     old     Not packed key
00159     keypart_map         bitmap of used keyparts
00160     last_used_keyseg  out parameter.  May be NULL
00161 
00162    RETURN
00163      length of packed key
00164 
00165      last_use_keyseg    Store pointer to the keyseg after the last used one
00166 */
00167 
00168 uint32_t _mi_pack_key(register MI_INFO *info, uint32_t keynr, unsigned char *key, unsigned char *old,
00169                       drizzled::key_part_map keypart_map, HA_KEYSEG **last_used_keyseg)
00170 {
00171   unsigned char *start_key=key;
00172   HA_KEYSEG *keyseg;
00173 
00174   /* only key prefixes are supported */
00175   assert(((keypart_map+1) & keypart_map) == 0);
00176 
00177   for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
00178        old+= keyseg->length, keyseg++)
00179   {
00180     enum drizzled::ha_base_keytype type= (enum drizzled::ha_base_keytype) keyseg->type;
00181     uint32_t length= keyseg->length;
00182     uint32_t char_length;
00183     unsigned char *pos;
00184     const drizzled::CHARSET_INFO * const cs=keyseg->charset;
00185     keypart_map>>= 1;
00186     if (keyseg->null_bit)
00187     {
00188       if (!(*key++= (char) 1-*old++))     /* Copy null marker */
00189       {
00190         if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
00191           old+= 2;
00192   continue;         /* Found NULL */
00193       }
00194     }
00195     char_length= (cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
00196     pos=old;
00197     if (keyseg->flag & HA_SPACE_PACK)
00198     {
00199       unsigned char *end=pos+length;
00200 
00201       if (type != drizzled::HA_KEYTYPE_BINARY)
00202       {
00203   while (end > pos && end[-1] == ' ')
00204     end--;
00205       }
00206       length=(uint) (end-pos);
00207       FIX_LENGTH(cs, pos, length, char_length);
00208       store_key_length_inc(key,char_length);
00209       memcpy(key, pos, char_length);
00210       key+= char_length;
00211       continue;
00212     }
00213     else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
00214     {
00215       /* Length of key-part used with mi_rkey() always 2 */
00216       uint32_t tmp_length=uint2korr(pos);
00217       pos+=2;
00218       drizzled::set_if_smaller(length,tmp_length);  /* Safety */
00219       FIX_LENGTH(cs, pos, length, char_length);
00220       store_key_length_inc(key,char_length);
00221       old+=2;         /* Skip length */
00222       memcpy(key, pos, char_length);
00223       key+= char_length;
00224       continue;
00225     }
00226     else if (keyseg->flag & HA_SWAP_KEY)
00227     {           /* Numerical column */
00228       pos+=length;
00229       while (length--)
00230   *key++ = *--pos;
00231       continue;
00232     }
00233     FIX_LENGTH(cs, pos, length, char_length);
00234     memcpy(key, pos, char_length);
00235     if (length > char_length)
00236       cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
00237     key+= length;
00238   }
00239   if (last_used_keyseg)
00240     *last_used_keyseg= keyseg;
00241 
00242   return((uint) (key-start_key));
00243 } /* _mi_pack_key */
00244 
00245 
00246 
00247 /*
00248   Store found key in record
00249 
00250   SYNOPSIS
00251     _mi_put_key_in_record()
00252     info    MyISAM handler
00253     keynr   Key number that was used
00254     record    Store key here
00255 
00256     Last read key is in info->lastkey
00257 
00258  NOTES
00259    Used when only-keyread is wanted
00260 
00261  RETURN
00262    0   ok
00263    1   error
00264 */
00265 
00266 static int _mi_put_key_in_record(register MI_INFO *info, uint32_t keynr,
00267          unsigned char *record)
00268 {
00269   register unsigned char *key;
00270   unsigned char *pos,*key_end;
00271   register HA_KEYSEG *keyseg;
00272   unsigned char *blob_ptr;
00273 
00274   blob_ptr= (unsigned char*) info->lastkey2;             /* Place to put blob parts */
00275   key=(unsigned char*) info->lastkey;                    /* KEy that was read */
00276   key_end=key+info->lastkey_length;
00277   for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
00278   {
00279     if (keyseg->null_bit)
00280     {
00281       if (!*key++)
00282       {
00283   record[keyseg->null_pos]|= keyseg->null_bit;
00284   continue;
00285       }
00286       record[keyseg->null_pos]&= ~keyseg->null_bit;
00287     }
00288 
00289     if (keyseg->flag & HA_SPACE_PACK)
00290     {
00291       uint32_t length;
00292       get_key_length(length,key);
00293 #ifdef CHECK_KEYS
00294       if (length > keyseg->length || key+length > key_end)
00295   goto err;
00296 #endif
00297       pos= record+keyseg->start;
00298 
00299       memcpy(pos, key, length);
00300       keyseg->charset->cset->fill(keyseg->charset,
00301                                   (char*) pos + length,
00302                                   keyseg->length - length,
00303                                   ' ');
00304       key+=length;
00305       continue;
00306     }
00307 
00308     if (keyseg->flag & HA_VAR_LENGTH_PART)
00309     {
00310       uint32_t length;
00311       get_key_length(length,key);
00312 #ifdef CHECK_KEYS
00313       if (length > keyseg->length || key+length > key_end)
00314   goto err;
00315 #endif
00316       /* Store key length */
00317       if (keyseg->bit_start == 1)
00318         *(unsigned char*) (record+keyseg->start)= (unsigned char) length;
00319       else
00320         int2store(record+keyseg->start, length);
00321       /* And key data */
00322       memcpy(record+keyseg->start + keyseg->bit_start, key, length);
00323       key+= length;
00324     }
00325     else if (keyseg->flag & HA_BLOB_PART)
00326     {
00327       uint32_t length;
00328       get_key_length(length,key);
00329 #ifdef CHECK_KEYS
00330       if (length > keyseg->length || key+length > key_end)
00331   goto err;
00332 #endif
00333       memcpy(record+keyseg->start+keyseg->bit_start,
00334        &blob_ptr,sizeof(char*));
00335       memcpy(blob_ptr,key,length);
00336       blob_ptr+=length;
00337 
00338       /* The above changed info->lastkey2. Inform mi_rnext_same(). */
00339       info->update&= ~HA_STATE_RNEXT_SAME;
00340 
00341       _my_store_blob_length(record+keyseg->start,
00342           (uint) keyseg->bit_start,length);
00343       key+=length;
00344     }
00345     else if (keyseg->flag & HA_SWAP_KEY)
00346     {
00347       unsigned char *to=  record+keyseg->start+keyseg->length;
00348       unsigned char *end= key+keyseg->length;
00349 #ifdef CHECK_KEYS
00350       if (end > key_end)
00351   goto err;
00352 #endif
00353       do
00354       {
00355    *--to= *key++;
00356       } while (key != end);
00357       continue;
00358     }
00359     else
00360     {
00361 #ifdef CHECK_KEYS
00362       if (key+keyseg->length > key_end)
00363   goto err;
00364 #endif
00365       memcpy(record+keyseg->start, key, keyseg->length);
00366       key+= keyseg->length;
00367     }
00368   }
00369   return(0);
00370 
00371 err:
00372   return(1);        /* Crashed row */
00373 } /* _mi_put_key_in_record */
00374 
00375 
00376   /* Here when key reads are used */
00377 
00378 int _mi_read_key_record(MI_INFO *info, drizzled::internal::my_off_t filepos, unsigned char *buf)
00379 {
00380   fast_mi_writeinfo(info);
00381   if (filepos != HA_OFFSET_ERROR)
00382   {
00383     if (info->lastinx >= 0)
00384     {       /* Read only key */
00385       if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
00386       {
00387         mi_print_error(info->s, HA_ERR_CRASHED);
00388   errno=HA_ERR_CRASHED;
00389   return -1;
00390       }
00391       info->update|= HA_STATE_AKTIV; /* We should find a record */
00392       return 0;
00393     }
00394     errno=HA_ERR_WRONG_INDEX;
00395   }
00396   return(-1);       /* Wrong data to read */
00397 }
00398 
00399 
00400 /*
00401   Save current key tuple to record and call index condition check function
00402 
00403   SYNOPSIS
00404     mi_check_index_cond()
00405       info    MyISAM handler
00406       keynr   Index we're running a scan on
00407       record  Record buffer to use (it is assumed that index check function
00408               will look for column values there)
00409 
00410   RETURN
00411     -1  Error
00412     0   Index condition is not satisfied, continue scanning
00413     1   Index condition is satisfied
00414     2   Index condition is not satisfied, end the scan.
00415 */
00416 
00417 int mi_check_index_cond(register MI_INFO *info, uint32_t keynr, unsigned char *record)
00418 {
00419   if (_mi_put_key_in_record(info, keynr, record))
00420   {
00421     mi_print_error(info->s, HA_ERR_CRASHED);
00422     errno=HA_ERR_CRASHED;
00423     return -1;
00424   }
00425   return info->index_cond_func(info->index_cond_func_arg);
00426 }
00427 
00428 
00429 /*
00430   Retrieve auto_increment info
00431 
00432   SYNOPSIS
00433     retrieve_auto_increment()
00434     info      MyISAM handler
00435     record      Row to update
00436 
00437   IMPLEMENTATION
00438     For signed columns we don't retrieve the auto increment value if it's
00439     less than zero.
00440 */
00441 
00442 uint64_t retrieve_auto_increment(MI_INFO *info,const unsigned char *record)
00443 {
00444   uint64_t value= 0;      /* Store unsigned values here */
00445   int64_t s_value= 0;     /* Store signed values here */
00446   HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
00447   const unsigned char *key= (unsigned char*) record + keyseg->start;
00448 
00449   switch (keyseg->type) {
00450   case drizzled::HA_KEYTYPE_BINARY:
00451     value=(uint64_t)  *(unsigned char*) key;
00452     break;
00453   case drizzled::HA_KEYTYPE_LONG_INT:
00454     s_value= (int64_t) sint4korr(key);
00455     break;
00456   case drizzled::HA_KEYTYPE_ULONG_INT:
00457     value=(uint64_t) uint4korr(key);
00458     break;
00459   case drizzled::HA_KEYTYPE_DOUBLE:                       /* This shouldn't be used */
00460   {
00461     double f_1;
00462     float8get(f_1,key);
00463     /* Ignore negative values */
00464     value = (f_1 < 0.0) ? 0 : (uint64_t) f_1;
00465     break;
00466   }
00467   case drizzled::HA_KEYTYPE_LONGLONG:
00468     s_value= sint8korr(key);
00469     break;
00470   case drizzled::HA_KEYTYPE_ULONGLONG:
00471     value= uint8korr(key);
00472     break;
00473   default:
00474     assert(0);
00475     value=0;                                    /* Error */
00476     break;
00477   }
00478 
00479   /*
00480     The following code works becasue if s_value < 0 then value is 0
00481     and if s_value == 0 then value will contain either s_value or the
00482     correct value.
00483   */
00484   return (s_value > 0) ? (uint64_t) s_value : value;
00485 }