Drizzled Public API Documentation

mi_rkey.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 /* Read record based on a key */
00017 
00018 #include "myisam_priv.h"
00019 
00020 using namespace drizzled;
00021 
00022   /* Read a record using key */
00023   /* Ordinary search_flag is 0 ; Give error if no record with key */
00024 
00025 int mi_rkey(MI_INFO *info, unsigned char *buf, int inx, const unsigned char *key,
00026             key_part_map keypart_map, enum ha_rkey_function search_flag)
00027 {
00028   unsigned char *key_buff;
00029   MYISAM_SHARE *share=info->s;
00030   MI_KEYDEF *keyinfo;
00031   HA_KEYSEG *last_used_keyseg;
00032   uint32_t pack_key_length, use_key_length, nextflag;
00033   uint32_t myisam_search_flag;
00034   int res= 0;
00035 
00036   if ((inx = _mi_check_index(info,inx)) < 0)
00037     return(errno);
00038 
00039   info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
00040   info->last_key_func= search_flag;
00041   keyinfo= share->keyinfo + inx;
00042 
00043   if (info->once_flags & USE_PACKED_KEYS)
00044   {
00045     info->once_flags&= ~USE_PACKED_KEYS;  /* Reset flag */
00046     /*
00047       key is already packed!;  This happens when we are using a MERGE TABLE
00048       In this key 'key_part_map' is the length of the key !
00049     */
00050     key_buff=info->lastkey+info->s->base.max_key_length;
00051     pack_key_length= keypart_map;
00052     memmove(key_buff, key, pack_key_length);
00053     last_used_keyseg= info->s->keyinfo[inx].seg + info->last_used_keyseg;
00054   }
00055   else
00056   {
00057     assert(keypart_map);
00058     /* Save the packed key for later use in the second buffer of lastkey. */
00059     key_buff=info->lastkey+info->s->base.max_key_length;
00060     pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (unsigned char*) key,
00061          keypart_map, &last_used_keyseg);
00062     /* Save packed_key_length for use by the MERGE engine. */
00063     info->pack_key_length= pack_key_length;
00064     info->last_used_keyseg= (uint16_t) (last_used_keyseg -
00065                                       info->s->keyinfo[inx].seg);
00066   }
00067 
00068   if (fast_mi_readinfo(info))
00069     goto err;
00070 
00071   nextflag=myisam_read_vec[search_flag];
00072   use_key_length=pack_key_length;
00073   if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
00074     use_key_length=USE_WHOLE_KEY;
00075 
00076   switch (info->s->keyinfo[inx].key_alg) {
00077   case HA_KEY_ALG_BTREE:
00078   default:
00079     myisam_search_flag= myisam_read_vec[search_flag];
00080     if (!_mi_search(info, keyinfo, key_buff, use_key_length,
00081                     myisam_search_flag, info->s->state.key_root[inx]))
00082     {
00083       /*
00084         Found a key, but it might not be usable. We cannot use rows that
00085         are inserted by other threads after we got our table lock
00086         ("concurrent inserts"). The record may not even be present yet.
00087         Keys are inserted into the index(es) before the record is
00088         inserted into the data file. When we got our table lock, we
00089         saved the current data_file_length. Concurrent inserts always go
00090         to the end of the file. So we can test if the found key
00091         references a new record.
00092 
00093         If we are searching for a partial key (or using >, >=, < or <=) and
00094         the data is outside of the data file, we need to continue searching
00095         for the first key inside the data file.
00096 
00097         We do also continue searching if an index condition check function
00098         is available.
00099       */
00100       while ((info->lastpos >= info->state->data_file_length &&
00101               (search_flag != HA_READ_KEY_EXACT ||
00102               last_used_keyseg != keyinfo->seg + keyinfo->keysegs)) ||
00103              (info->index_cond_func &&
00104               !(res= mi_check_index_cond(info, inx, buf))))
00105       {
00106         uint32_t not_used[2];
00107         /*
00108           Skip rows that are inserted by other threads since we got a lock
00109           Note that this can only happen if we are not searching after an
00110           full length exact key, because the keys are sorted
00111           according to position
00112         */
00113         if  (_mi_search_next(info, keyinfo, info->lastkey,
00114                              info->lastkey_length,
00115                              myisam_readnext_vec[search_flag],
00116                              info->s->state.key_root[inx]))
00117           break;
00118         /*
00119           Check that the found key does still match the search.
00120           _mi_search_next() delivers the next key regardless of its
00121           value.
00122         */
00123         if (search_flag == HA_READ_KEY_EXACT &&
00124             ha_key_cmp(keyinfo->seg, key_buff, info->lastkey, use_key_length,
00125                        SEARCH_FIND, not_used))
00126         {
00127           errno= HA_ERR_KEY_NOT_FOUND;
00128           info->lastpos= HA_OFFSET_ERROR;
00129           break;
00130         }
00131       }
00132       if (res == 2)
00133       {
00134         info->lastpos= HA_OFFSET_ERROR;
00135         return((errno= HA_ERR_KEY_NOT_FOUND));
00136       }
00137       /*
00138         Error if no row found within the data file. (Bug #29838)
00139         Do not overwrite errno if already at HA_OFFSET_ERROR.
00140       */
00141       if (info->lastpos != HA_OFFSET_ERROR &&
00142           info->lastpos >= info->state->data_file_length)
00143       {
00144         info->lastpos= HA_OFFSET_ERROR;
00145         errno= HA_ERR_KEY_NOT_FOUND;
00146       }
00147     }
00148   }
00149 
00150   /* Calculate length of the found key;  Used by mi_rnext_same */
00151   if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg &&
00152       info->lastpos != HA_OFFSET_ERROR)
00153     info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey,
00154                  last_used_keyseg);
00155   else
00156     info->last_rkey_length= pack_key_length;
00157 
00158   /* Check if we don't want to have record back, only error message */
00159   if (!buf)
00160     return(info->lastpos == HA_OFFSET_ERROR ? errno : 0);
00161 
00162   if (!(*info->read_record)(info,info->lastpos,buf))
00163   {
00164     info->update|= HA_STATE_AKTIV;    /* Record is read */
00165     return(0);
00166   }
00167 
00168   info->lastpos = HA_OFFSET_ERROR;    /* Didn't find key */
00169 
00170   /* Store last used key as a base for read next */
00171   memcpy(info->lastkey,key_buff,pack_key_length);
00172   info->last_rkey_length= pack_key_length;
00173   memset(info->lastkey+pack_key_length, 0, info->s->base.rec_reflength);
00174   info->lastkey_length=pack_key_length+info->s->base.rec_reflength;
00175 
00176   if (search_flag == HA_READ_AFTER_KEY)
00177     info->update|=HA_STATE_NEXT_FOUND;    /* Previous gives last row */
00178 err:
00179   return(errno);
00180 } /* _mi_rkey */