~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to storage/myisam/mi_update.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
15
 
 
16
/* Update an old row in a MyISAM table */
 
17
 
 
18
#include "fulltext.h"
 
19
#include "rt_index.h"
 
20
 
 
21
int mi_update(register MI_INFO *info, const uchar *oldrec, uchar *newrec)
 
22
{
 
23
  int flag,key_changed,save_errno;
 
24
  register my_off_t pos;
 
25
  uint i;
 
26
  uchar old_key[MI_MAX_KEY_BUFF],*new_key;
 
27
  my_bool auto_key_changed=0;
 
28
  ulonglong changed;
 
29
  MYISAM_SHARE *share= info->s;
 
30
  ha_checksum old_checksum= 0;
 
31
  DBUG_ENTER("mi_update");
 
32
 
 
33
  DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_usage",
 
34
                  mi_print_error(info->s, HA_ERR_CRASHED);
 
35
                  DBUG_RETURN(my_errno= HA_ERR_CRASHED););
 
36
  if (!(info->update & HA_STATE_AKTIV))
 
37
  {
 
38
    DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND);
 
39
  }
 
40
  if (share->options & HA_OPTION_READ_ONLY_DATA)
 
41
  {
 
42
    DBUG_RETURN(my_errno=EACCES);
 
43
  }
 
44
  if (info->state->key_file_length >= share->base.margin_key_file_length)
 
45
  {
 
46
    DBUG_RETURN(my_errno=HA_ERR_INDEX_FILE_FULL);
 
47
  }
 
48
  pos=info->lastpos;
 
49
  if (_mi_readinfo(info,F_WRLCK,1))
 
50
    DBUG_RETURN(my_errno);
 
51
 
 
52
  if (share->calc_checksum)
 
53
    old_checksum=info->checksum=(*share->calc_checksum)(info,oldrec);
 
54
  if ((*share->compare_record)(info,oldrec))
 
55
  {
 
56
    save_errno=my_errno;
 
57
    goto err_end;                       /* Record has changed */
 
58
  }
 
59
 
 
60
 
 
61
  /* Calculate and check all unique constraints */
 
62
  key_changed=0;
 
63
  for (i=0 ; i < share->state.header.uniques ; i++)
 
64
  {
 
65
    MI_UNIQUEDEF *def=share->uniqueinfo+i;
 
66
    if (mi_unique_comp(def, newrec, oldrec,1) &&
 
67
        mi_check_unique(info, def, newrec, mi_unique_hash(def, newrec),
 
68
                        info->lastpos))
 
69
    {
 
70
      save_errno=my_errno;
 
71
      goto err_end;
 
72
    }
 
73
  }
 
74
  if (_mi_mark_file_changed(info))
 
75
  {
 
76
    save_errno=my_errno;
 
77
    goto err_end;
 
78
  }
 
79
 
 
80
  /* Check which keys changed from the original row */
 
81
 
 
82
  new_key=info->lastkey2;
 
83
  changed=0;
 
84
  for (i=0 ; i < share->base.keys ; i++)
 
85
  {
 
86
    if (mi_is_key_active(share->state.key_map, i))
 
87
    {
 
88
      if (share->keyinfo[i].flag & HA_FULLTEXT )
 
89
      {
 
90
        if (_mi_ft_cmp(info,i,oldrec, newrec))
 
91
        {
 
92
          if ((int) i == info->lastinx)
 
93
          {
 
94
          /*
 
95
            We are changeing the index we are reading on.  Mark that
 
96
            the index data has changed and we need to do a full search
 
97
            when doing read-next
 
98
          */
 
99
            key_changed|=HA_STATE_WRITTEN;
 
100
          }
 
101
          changed|=((ulonglong) 1 << i);
 
102
          if (_mi_ft_update(info,i, old_key,oldrec,newrec,pos))
 
103
            goto err;
 
104
        }
 
105
      }
 
106
      else
 
107
      {
 
108
        uint new_length=_mi_make_key(info,i,new_key,newrec,pos);
 
109
        uint old_length=_mi_make_key(info,i,old_key,oldrec,pos);
 
110
 
 
111
        /* The above changed info->lastkey2. Inform mi_rnext_same(). */
 
112
        info->update&= ~HA_STATE_RNEXT_SAME;
 
113
 
 
114
        if (new_length != old_length ||
 
115
            memcmp((uchar*) old_key,(uchar*) new_key,new_length))
 
116
        {
 
117
          if ((int) i == info->lastinx)
 
118
            key_changed|=HA_STATE_WRITTEN;      /* Mark that keyfile changed */
 
119
          changed|=((ulonglong) 1 << i);
 
120
          share->keyinfo[i].version++;
 
121
          if (share->keyinfo[i].ck_delete(info,i,old_key,old_length)) goto err;
 
122
          if (share->keyinfo[i].ck_insert(info,i,new_key,new_length)) goto err;
 
123
          if (share->base.auto_key == i+1)
 
124
            auto_key_changed=1;
 
125
        }
 
126
      }
 
127
    }
 
128
  }
 
129
  /*
 
130
    If we are running with external locking, we must update the index file
 
131
    that something has changed.
 
132
  */
 
133
  if (changed || !my_disable_locking)
 
134
    key_changed|= HA_STATE_CHANGED;
 
135
 
 
136
  if (share->calc_checksum)
 
137
  {
 
138
    info->checksum=(*share->calc_checksum)(info,newrec);
 
139
    /* Store new checksum in index file header */
 
140
    key_changed|= HA_STATE_CHANGED;
 
141
  }
 
142
  {
 
143
    /*
 
144
      Don't update index file if data file is not extended and no status
 
145
      information changed
 
146
    */
 
147
    MI_STATUS_INFO state;
 
148
    ha_rows org_split;
 
149
    my_off_t org_delete_link;
 
150
 
 
151
    memcpy((char*) &state, (char*) info->state, sizeof(state));
 
152
    org_split=       share->state.split;
 
153
    org_delete_link= share->state.dellink;
 
154
    if ((*share->update_record)(info,pos,newrec))
 
155
      goto err;
 
156
    if (!key_changed &&
 
157
        (memcmp((char*) &state, (char*) info->state, sizeof(state)) ||
 
158
         org_split != share->state.split ||
 
159
         org_delete_link != share->state.dellink))
 
160
      key_changed|= HA_STATE_CHANGED;           /* Must update index file */
 
161
  }
 
162
  if (auto_key_changed)
 
163
    set_if_bigger(info->s->state.auto_increment,
 
164
                  retrieve_auto_increment(info, newrec));
 
165
  if (share->calc_checksum)
 
166
    info->state->checksum+=(info->checksum - old_checksum);
 
167
 
 
168
  info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | HA_STATE_AKTIV |
 
169
                 key_changed);
 
170
  myisam_log_record(MI_LOG_UPDATE,info,newrec,info->lastpos,0);
 
171
  /*
 
172
    Every myisam function that updates myisam table must end with
 
173
    call to _mi_writeinfo(). If operation (second param of
 
174
    _mi_writeinfo()) is not 0 it sets share->changed to 1, that is
 
175
    flags that data has changed. If operation is 0, this function
 
176
    equals to no-op in this case.
 
177
 
 
178
    mi_update() must always pass !0 value as operation, since even if
 
179
    there is no index change there could be data change.
 
180
  */
 
181
  VOID(_mi_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
 
182
  allow_break();                                /* Allow SIGHUP & SIGINT */
 
183
  if (info->invalidator != 0)
 
184
  {
 
185
    DBUG_PRINT("info", ("invalidator... '%s' (update)", info->filename));
 
186
    (*info->invalidator)(info->filename);
 
187
    info->invalidator=0;
 
188
  }
 
189
  DBUG_RETURN(0);
 
190
 
 
191
err:
 
192
  DBUG_PRINT("error",("key: %d  errno: %d",i,my_errno));
 
193
  save_errno=my_errno;
 
194
  if (changed)
 
195
    key_changed|= HA_STATE_CHANGED;
 
196
  if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_OUT_OF_MEM ||
 
197
      my_errno == HA_ERR_RECORD_FILE_FULL)
 
198
  {
 
199
    info->errkey= (int) i;
 
200
    flag=0;
 
201
    do
 
202
    {
 
203
      if (((ulonglong) 1 << i) & changed)
 
204
      {
 
205
        if (share->keyinfo[i].flag & HA_FULLTEXT)
 
206
        {
 
207
          if ((flag++ && _mi_ft_del(info,i, new_key,newrec,pos)) ||
 
208
              _mi_ft_add(info,i, old_key,oldrec,pos))
 
209
            break;
 
210
        }
 
211
        else
 
212
        {
 
213
          uint new_length=_mi_make_key(info,i,new_key,newrec,pos);
 
214
          uint old_length= _mi_make_key(info,i,old_key,oldrec,pos);
 
215
          if ((flag++ && _mi_ck_delete(info,i,new_key,new_length)) ||
 
216
              _mi_ck_write(info,i,old_key,old_length))
 
217
            break;
 
218
        }
 
219
      }
 
220
    } while (i-- != 0);
 
221
  }
 
222
  else
 
223
  {
 
224
    mi_print_error(info->s, HA_ERR_CRASHED);
 
225
    mi_mark_crashed(info);
 
226
  }
 
227
  info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED |
 
228
                 key_changed);
 
229
 
 
230
 err_end:
 
231
  myisam_log_record(MI_LOG_UPDATE,info,newrec,info->lastpos,my_errno);
 
232
  VOID(_mi_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
 
233
  allow_break();                                /* Allow SIGHUP & SIGINT */
 
234
  if (save_errno == HA_ERR_KEY_NOT_FOUND)
 
235
  {
 
236
    mi_print_error(info->s, HA_ERR_CRASHED);
 
237
    save_errno=HA_ERR_CRASHED;
 
238
  }
 
239
  DBUG_RETURN(my_errno=save_errno);
 
240
} /* mi_update */