Drizzled Public API Documentation

mi_update.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 /* Update an old row in a MyISAM table */
00017 
00018 #include "myisam_priv.h"
00019 #include <drizzled/util/test.h>
00020 
00021 using namespace drizzled;
00022 
00023 int mi_update(register MI_INFO *info, const unsigned char *oldrec, unsigned char *newrec)
00024 {
00025   int flag,key_changed,save_errno;
00026   register internal::my_off_t pos;
00027   uint32_t i;
00028   unsigned char old_key[MI_MAX_KEY_BUFF],*new_key;
00029   bool auto_key_changed=0;
00030   uint64_t changed;
00031   MYISAM_SHARE *share= info->s;
00032   internal::ha_checksum old_checksum= 0;
00033 
00034   if (!(info->update & HA_STATE_AKTIV))
00035   {
00036     return(errno=HA_ERR_KEY_NOT_FOUND);
00037   }
00038   if (share->options & HA_OPTION_READ_ONLY_DATA)
00039   {
00040     return(errno=EACCES);
00041   }
00042   if (info->state->key_file_length >= share->base.margin_key_file_length)
00043   {
00044     return(errno=HA_ERR_INDEX_FILE_FULL);
00045   }
00046   pos=info->lastpos;
00047   if (_mi_readinfo(info,F_WRLCK,1))
00048     return(errno);
00049 
00050   if (share->calc_checksum)
00051     old_checksum=info->checksum=(*share->calc_checksum)(info,oldrec);
00052   if ((*share->compare_record)(info,oldrec))
00053   {
00054     save_errno=errno;
00055     goto err_end;     /* Record has changed */
00056   }
00057 
00058 
00059   /* Calculate and check all unique constraints */
00060   key_changed=0;
00061   for (i=0 ; i < share->state.header.uniques ; i++)
00062   {
00063     MI_UNIQUEDEF *def=share->uniqueinfo+i;
00064     if (mi_unique_comp(def, newrec, oldrec,1) &&
00065   mi_check_unique(info, def, newrec, mi_unique_hash(def, newrec),
00066       info->lastpos))
00067     {
00068       save_errno=errno;
00069       goto err_end;
00070     }
00071   }
00072   if (_mi_mark_file_changed(info))
00073   {
00074     save_errno=errno;
00075     goto err_end;
00076   }
00077 
00078   /* Check which keys changed from the original row */
00079 
00080   new_key=info->lastkey2;
00081   changed=0;
00082   for (i=0 ; i < share->base.keys ; i++)
00083   {
00084     if (mi_is_key_active(share->state.key_map, i))
00085     {
00086       {
00087   uint32_t new_length=_mi_make_key(info,i,new_key,newrec,pos);
00088   uint32_t old_length=_mi_make_key(info,i,old_key,oldrec,pos);
00089 
00090         /* The above changed info->lastkey2. Inform mi_rnext_same(). */
00091         info->update&= ~HA_STATE_RNEXT_SAME;
00092 
00093   if (new_length != old_length ||
00094       memcmp(old_key,new_key,new_length))
00095   {
00096     if ((int) i == info->lastinx)
00097       key_changed|=HA_STATE_WRITTEN;  /* Mark that keyfile changed */
00098     changed|=((uint64_t) 1 << i);
00099     share->keyinfo[i].version++;
00100     if (share->keyinfo[i].ck_delete(info,i,old_key,old_length)) goto err;
00101     if (share->keyinfo[i].ck_insert(info,i,new_key,new_length)) goto err;
00102     if (share->base.auto_key == i+1)
00103       auto_key_changed=1;
00104   }
00105       }
00106     }
00107   }
00108   /*
00109     If we are running with external locking, we must update the index file
00110     that something has changed.
00111   */
00112   if (changed)
00113     key_changed|= HA_STATE_CHANGED;
00114 
00115   if (share->calc_checksum)
00116   {
00117     info->checksum=(*share->calc_checksum)(info,newrec);
00118     /* Store new checksum in index file header */
00119     key_changed|= HA_STATE_CHANGED;
00120   }
00121   {
00122     /*
00123       Don't update index file if data file is not extended and no status
00124       information changed
00125     */
00126     MI_STATUS_INFO state;
00127     ha_rows org_split;
00128     internal::my_off_t org_delete_link;
00129 
00130     memcpy(&state, info->state, sizeof(state));
00131     org_split=       share->state.split;
00132     org_delete_link= share->state.dellink;
00133     if ((*share->update_record)(info,pos,newrec))
00134       goto err;
00135     if (!key_changed &&
00136   (memcmp(&state, info->state, sizeof(state)) ||
00137    org_split != share->state.split ||
00138    org_delete_link != share->state.dellink))
00139       key_changed|= HA_STATE_CHANGED;   /* Must update index file */
00140   }
00141   if (auto_key_changed)
00142     set_if_bigger(info->s->state.auto_increment,
00143                   retrieve_auto_increment(info, newrec));
00144   if (share->calc_checksum)
00145     info->state->checksum+=(info->checksum - old_checksum);
00146 
00147   info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
00148      key_changed);
00149   /*
00150     Every myisam function that updates myisam table must end with
00151     call to _mi_writeinfo(). If operation (second param of
00152     _mi_writeinfo()) is not 0 it sets share->changed to 1, that is
00153     flags that data has changed. If operation is 0, this function
00154     equals to no-op in this case.
00155 
00156     mi_update() must always pass !0 value as operation, since even if
00157     there is no index change there could be data change.
00158   */
00159   _mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE);
00160   return(0);
00161 
00162 err:
00163   save_errno=errno;
00164   if (changed)
00165     key_changed|= HA_STATE_CHANGED;
00166   if (errno == HA_ERR_FOUND_DUPP_KEY || errno == HA_ERR_OUT_OF_MEM ||
00167       errno == HA_ERR_RECORD_FILE_FULL)
00168   {
00169     info->errkey= (int) i;
00170     flag=0;
00171     do
00172     {
00173       if (((uint64_t) 1 << i) & changed)
00174       {
00175   {
00176     uint32_t new_length=_mi_make_key(info,i,new_key,newrec,pos);
00177     uint32_t old_length= _mi_make_key(info,i,old_key,oldrec,pos);
00178     if ((flag++ && _mi_ck_delete(info,i,new_key,new_length)) ||
00179         _mi_ck_write(info,i,old_key,old_length))
00180       break;
00181   }
00182       }
00183     } while (i-- != 0);
00184   }
00185   else
00186   {
00187     mi_print_error(info->s, HA_ERR_CRASHED);
00188     mi_mark_crashed(info);
00189   }
00190   info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED |
00191      key_changed);
00192 
00193  err_end:
00194   _mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE);
00195   if (save_errno == HA_ERR_KEY_NOT_FOUND)
00196   {
00197     mi_print_error(info->s, HA_ERR_CRASHED);
00198     save_errno=HA_ERR_CRASHED;
00199   }
00200   return(errno=save_errno);
00201 } /* mi_update */