1 : /* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 : #include "ma_fulltext.h"
17 : #include "ma_rt_index.h"
18 : #include "trnman.h"
19 :
20 : /**
21 : Update an old row in a MARIA table
22 : */
23 :
24 : int maria_update(register MARIA_HA *info, const uchar *oldrec, uchar *newrec)
25 0 : {
26 : int flag,key_changed,save_errno;
27 : reg3 my_off_t pos;
28 : uint i;
29 : uchar old_key_buff[MARIA_MAX_KEY_BUFF],*new_key_buff;
30 0 : my_bool auto_key_changed= 0;
31 : ulonglong changed;
32 0 : MARIA_SHARE *share= info->s;
33 : MARIA_KEYDEF *keyinfo;
34 0 : DBUG_ENTER("maria_update");
35 0 : LINT_INIT(new_key_buff);
36 0 : LINT_INIT(changed);
37 :
38 0 : DBUG_EXECUTE_IF("maria_pretend_crashed_table_on_usage",
39 : maria_print_error(info->s, HA_ERR_CRASHED);
40 : DBUG_RETURN(my_errno= HA_ERR_CRASHED););
41 0 : if (!(info->update & HA_STATE_AKTIV))
42 : {
43 0 : DBUG_RETURN(my_errno=HA_ERR_KEY_NOT_FOUND);
44 : }
45 0 : if (share->options & HA_OPTION_READ_ONLY_DATA)
46 : {
47 0 : DBUG_RETURN(my_errno=EACCES);
48 : }
49 0 : if (share->state.state.key_file_length >= share->base.margin_key_file_length)
50 : {
51 0 : DBUG_RETURN(my_errno=HA_ERR_INDEX_FILE_FULL);
52 : }
53 0 : pos= info->cur_row.lastpos;
54 0 : if (_ma_readinfo(info,F_WRLCK,1))
55 0 : DBUG_RETURN(my_errno);
56 :
57 0 : if ((*share->compare_record)(info,oldrec))
58 : {
59 0 : save_errno= my_errno;
60 0 : DBUG_PRINT("warning", ("Got error from compare record"));
61 0 : goto err_end; /* Record has changed */
62 : }
63 :
64 : /* Calculate and check all unique constraints */
65 0 : key_changed=0;
66 0 : for (i=0 ; i < share->state.header.uniques ; i++)
67 : {
68 0 : MARIA_UNIQUEDEF *def=share->uniqueinfo+i;
69 0 : if (_ma_unique_comp(def, newrec, oldrec,1) &&
70 : _ma_check_unique(info, def, newrec, _ma_unique_hash(def, newrec),
71 : pos))
72 : {
73 0 : save_errno=my_errno;
74 0 : goto err_end;
75 : }
76 : }
77 0 : if (_ma_mark_file_changed(info))
78 : {
79 0 : save_errno=my_errno;
80 0 : goto err_end;
81 : }
82 :
83 : /* Ensure we don't try to restore auto_increment if it doesn't change */
84 0 : info->last_auto_increment= ~(ulonglong) 0;
85 :
86 : /* Check which keys changed from the original row */
87 :
88 0 : new_key_buff= info->lastkey_buff2;
89 0 : changed=0;
90 0 : for (i=0, keyinfo= share->keyinfo ; i < share->base.keys ; i++, keyinfo++)
91 : {
92 0 : if (maria_is_key_active(share->state.key_map, i))
93 : {
94 0 : if (keyinfo->flag & HA_FULLTEXT )
95 : {
96 0 : if (_ma_ft_cmp(info,i,oldrec, newrec))
97 : {
98 0 : if ((int) i == info->lastinx)
99 : {
100 : /*
101 : We are changeing the index we are reading on. Mark that
102 : the index data has changed and we need to do a full search
103 : when doing read-next
104 : */
105 0 : key_changed|=HA_STATE_WRITTEN;
106 : }
107 0 : changed|=((ulonglong) 1 << i);
108 0 : if (_ma_ft_update(info,i,old_key_buff,oldrec,newrec,pos))
109 : goto err;
110 : }
111 : }
112 : else
113 : {
114 : MARIA_KEY new_key, old_key;
115 :
116 0 : (*keyinfo->make_key)(info,&new_key, i, new_key_buff, newrec,
117 : pos, info->trn->trid);
118 0 : (*keyinfo->make_key)(info,&old_key, i, old_key_buff,
119 : oldrec, pos, info->cur_row.trid);
120 :
121 : /* The above changed info->lastkey2. Inform maria_rnext_same(). */
122 0 : info->update&= ~HA_STATE_RNEXT_SAME;
123 :
124 0 : if (new_key.data_length != old_key.data_length ||
125 : memcmp(old_key.data, new_key.data, new_key.data_length))
126 : {
127 0 : if ((int) i == info->lastinx)
128 0 : key_changed|=HA_STATE_WRITTEN; /* Mark that keyfile changed */
129 0 : changed|=((ulonglong) 1 << i);
130 0 : keyinfo->version++;
131 0 : if (keyinfo->ck_delete(info,&old_key))
132 0 : goto err;
133 0 : if (keyinfo->ck_insert(info,&new_key))
134 0 : goto err;
135 0 : if (share->base.auto_key == i+1)
136 0 : auto_key_changed=1;
137 : }
138 : }
139 : }
140 : }
141 :
142 0 : if (share->calc_checksum)
143 : {
144 : /*
145 : We can't use the row based checksum as this doesn't have enough
146 : precision (one byte, while the table's is more bytes).
147 : At least _ma_check_unique() modifies the 'newrec' record, so checksum
148 : has to be computed _after_ it. Nobody apparently modifies 'oldrec'.
149 : We need to pass the old row's checksum down to (*update_record)(), we do
150 : this via info->new_row.checksum (not intuitive but existing code
151 : mandated that cur_row is the new row).
152 : If (*update_record)() fails, table will be marked corrupted so no need
153 : to revert the live checksum change.
154 : */
155 0 : info->cur_row.checksum= (*share->calc_checksum)(info, newrec);
156 0 : info->new_row.checksum= (*share->calc_checksum)(info, oldrec);
157 0 : info->state->checksum+= info->cur_row.checksum - info->new_row.checksum;
158 : }
159 :
160 0 : if ((*share->update_record)(info, pos, oldrec, newrec))
161 0 : goto err;
162 :
163 0 : if (auto_key_changed & !share->now_transactional)
164 : {
165 0 : const HA_KEYSEG *keyseg= share->keyinfo[share->base.auto_key-1].seg;
166 0 : const uchar *key= newrec + keyseg->start;
167 0 : set_if_bigger(share->state.auto_increment,
168 : ma_retrieve_auto_increment(key, keyseg->type));
169 : }
170 :
171 : /*
172 : We can't yet have HA_STATE_AKTIV here, as block_record dosn't support it
173 : */
174 0 : info->update= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED | key_changed);
175 0 : share->state.changed|= STATE_NOT_MOVABLE | STATE_NOT_ZEROFILLED;
176 0 : info->state->changed= 1;
177 :
178 : /*
179 : Every Maria function that updates Maria table must end with
180 : call to _ma_writeinfo(). If operation (second param of
181 : _ma_writeinfo()) is not 0 it sets share->changed to 1, that is
182 : flags that data has changed. If operation is 0, this function
183 : equals to no-op in this case.
184 :
185 : ma_update() must always pass !0 value as operation, since even if
186 : there is no index change there could be data change.
187 : */
188 0 : VOID(_ma_writeinfo(info, WRITEINFO_UPDATE_KEYFILE));
189 : allow_break(); /* Allow SIGHUP & SIGINT */
190 0 : if (info->invalidator != 0)
191 : {
192 0 : DBUG_PRINT("info", ("invalidator... '%s' (update)",
193 : share->open_file_name.str));
194 0 : (*info->invalidator)(share->open_file_name.str);
195 0 : info->invalidator=0;
196 : }
197 0 : DBUG_RETURN(0);
198 :
199 0 : err:
200 0 : DBUG_PRINT("error",("key: %d errno: %d",i,my_errno));
201 0 : save_errno= my_errno;
202 0 : DBUG_ASSERT(save_errno);
203 0 : if (!save_errno)
204 0 : save_errno= HA_ERR_INTERNAL_ERROR; /* Should never happen */
205 :
206 0 : if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_OUT_OF_MEM ||
207 : my_errno == HA_ERR_RECORD_FILE_FULL)
208 : {
209 0 : info->errkey= (int) i;
210 0 : flag=0;
211 : do
212 : {
213 0 : if (((ulonglong) 1 << i) & changed)
214 : {
215 0 : if (share->keyinfo[i].flag & HA_FULLTEXT)
216 : {
217 0 : if ((flag++ && _ma_ft_del(info,i,new_key_buff,newrec,pos)) ||
218 : _ma_ft_add(info,i,old_key_buff,oldrec,pos))
219 : break;
220 : }
221 : else
222 : {
223 : MARIA_KEY new_key, old_key;
224 0 : (*share->keyinfo[i].make_key)(info, &new_key, i, new_key_buff,
225 : newrec, pos,
226 : info->trn->trid);
227 0 : (*share->keyinfo[i].make_key)(info, &old_key, i, old_key_buff,
228 : oldrec, pos, info->cur_row.trid);
229 0 : if ((flag++ && _ma_ck_delete(info, &new_key)) ||
230 : _ma_ck_write(info, &old_key))
231 : break;
232 : }
233 : }
234 0 : } while (i-- != 0);
235 : }
236 : else
237 : {
238 0 : maria_print_error(share, HA_ERR_CRASHED);
239 0 : maria_mark_crashed(info);
240 : }
241 0 : info->update= (HA_STATE_CHANGED | HA_STATE_AKTIV | HA_STATE_ROW_CHANGED |
242 : key_changed);
243 :
244 0 : err_end:
245 0 : VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
246 : allow_break(); /* Allow SIGHUP & SIGINT */
247 0 : if (save_errno == HA_ERR_KEY_NOT_FOUND)
248 : {
249 0 : maria_print_error(share, HA_ERR_CRASHED);
250 0 : save_errno=HA_ERR_CRASHED;
251 : }
252 0 : DBUG_RETURN(my_errno=save_errno);
253 : } /* maria_update */
|