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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */ |
15 | |
16 | /* Functions to handle fixed-length-records */ |
17 | |
18 | #include "maria_def.h" |
19 | |
20 | |
21 | my_bool _ma_write_static_record(MARIA_HA *info, const uchar *record) |
22 | { |
23 | uchar temp[8]; /* max pointer length */ |
24 | if (info->s->state.dellink != HA_OFFSET_ERROR && |
25 | !info->append_insert_at_end) |
26 | { |
27 | my_off_t filepos=info->s->state.dellink; |
28 | info->rec_cache.seek_not_done=1; /* We have done a seek */ |
29 | if (info->s->file_read(info, &temp[0],info->s->base.rec_reflength, |
30 | info->s->state.dellink+1, |
31 | MYF(MY_NABP))) |
32 | goto err; |
33 | info->s->state.dellink= _ma_rec_pos(info->s, temp); |
34 | info->state->del--; |
35 | info->state->empty-=info->s->base.pack_reclength; |
36 | if (info->s->file_write(info, record, info->s->base.reclength, |
37 | filepos, MYF(MY_NABP))) |
38 | goto err; |
39 | } |
40 | else |
41 | { |
42 | if (info->state->data_file_length > info->s->base.max_data_file_length- |
43 | info->s->base.pack_reclength) |
44 | { |
45 | my_errno=HA_ERR_RECORD_FILE_FULL; |
46 | return(2); |
47 | } |
48 | if (info->opt_flag & WRITE_CACHE_USED) |
49 | { /* Cash in use */ |
50 | if (my_b_write(&info->rec_cache, record, |
51 | info->s->base.reclength)) |
52 | goto err; |
53 | if (info->s->base.pack_reclength != info->s->base.reclength) |
54 | { |
55 | uint length=info->s->base.pack_reclength - info->s->base.reclength; |
56 | bzero(temp,length); |
57 | if (my_b_write(&info->rec_cache, temp,length)) |
58 | goto err; |
59 | } |
60 | } |
61 | else |
62 | { |
63 | info->rec_cache.seek_not_done=1; /* We have done a seek */ |
64 | if (info->s->file_write(info, record, info->s->base.reclength, |
65 | info->state->data_file_length, |
66 | info->s->write_flag)) |
67 | goto err; |
68 | if (info->s->base.pack_reclength != info->s->base.reclength) |
69 | { |
70 | uint length=info->s->base.pack_reclength - info->s->base.reclength; |
71 | bzero(temp,length); |
72 | if (info->s->file_write(info, temp,length, |
73 | info->state->data_file_length+ |
74 | info->s->base.reclength, |
75 | info->s->write_flag)) |
76 | goto err; |
77 | } |
78 | } |
79 | info->state->data_file_length+=info->s->base.pack_reclength; |
80 | info->s->state.split++; |
81 | } |
82 | return 0; |
83 | err: |
84 | return 1; |
85 | } |
86 | |
87 | my_bool _ma_update_static_record(MARIA_HA *info, MARIA_RECORD_POS pos, |
88 | const uchar *oldrec __attribute__ ((unused)), |
89 | const uchar *record) |
90 | { |
91 | info->rec_cache.seek_not_done=1; /* We have done a seek */ |
92 | return (info->s->file_write(info, |
93 | record, info->s->base.reclength, |
94 | pos, |
95 | MYF(MY_NABP)) != 0); |
96 | } |
97 | |
98 | |
99 | my_bool _ma_delete_static_record(MARIA_HA *info, |
100 | const uchar *record __attribute__ ((unused))) |
101 | { |
102 | uchar temp[9]; /* 1+sizeof(uint32) */ |
103 | info->state->del++; |
104 | info->state->empty+=info->s->base.pack_reclength; |
105 | temp[0]= '\0'; /* Mark that record is deleted */ |
106 | _ma_dpointer(info->s, temp+1, info->s->state.dellink); |
107 | info->s->state.dellink= info->cur_row.lastpos; |
108 | info->rec_cache.seek_not_done=1; |
109 | return (info->s->file_write(info, temp, 1+info->s->rec_reflength, |
110 | info->cur_row.lastpos, MYF(MY_NABP)) != 0); |
111 | } |
112 | |
113 | |
114 | my_bool _ma_cmp_static_record(register MARIA_HA *info, |
115 | register const uchar *old) |
116 | { |
117 | DBUG_ENTER("_ma_cmp_static_record" ); |
118 | |
119 | if (info->opt_flag & WRITE_CACHE_USED) |
120 | { |
121 | if (flush_io_cache(&info->rec_cache)) |
122 | { |
123 | DBUG_RETURN(1); |
124 | } |
125 | info->rec_cache.seek_not_done=1; /* We have done a seek */ |
126 | } |
127 | |
128 | if ((info->opt_flag & READ_CHECK_USED)) |
129 | { /* If check isn't disabled */ |
130 | info->rec_cache.seek_not_done=1; /* We have done a seek */ |
131 | if (info->s->file_read(info, info->rec_buff, info->s->base.reclength, |
132 | info->cur_row.lastpos, MYF(MY_NABP))) |
133 | DBUG_RETURN(1); |
134 | if (memcmp(info->rec_buff, old, (uint) info->s->base.reclength)) |
135 | { |
136 | DBUG_DUMP("read" ,old,info->s->base.reclength); |
137 | DBUG_DUMP("disk" ,info->rec_buff,info->s->base.reclength); |
138 | my_errno=HA_ERR_RECORD_CHANGED; /* Record have changed */ |
139 | DBUG_RETURN(1); |
140 | } |
141 | } |
142 | DBUG_RETURN(0); |
143 | } |
144 | |
145 | |
146 | my_bool _ma_cmp_static_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, |
147 | const uchar *record, MARIA_RECORD_POS pos) |
148 | { |
149 | DBUG_ENTER("_ma_cmp_static_unique" ); |
150 | |
151 | info->rec_cache.seek_not_done=1; /* We have done a seek */ |
152 | if (info->s->file_read(info, info->rec_buff, info->s->base.reclength, |
153 | pos, MYF(MY_NABP))) |
154 | DBUG_RETURN(1); |
155 | DBUG_RETURN(_ma_unique_comp(def, record, info->rec_buff, |
156 | def->null_are_equal)); |
157 | } |
158 | |
159 | |
160 | /* |
161 | Read a fixed-length-record |
162 | |
163 | RETURN |
164 | 0 Ok |
165 | 1 record delete |
166 | -1 on read-error or locking-error |
167 | */ |
168 | |
169 | int _ma_read_static_record(register MARIA_HA *info, register uchar *record, |
170 | MARIA_RECORD_POS pos) |
171 | { |
172 | int error; |
173 | DBUG_ENTER("_ma_read_static_record" ); |
174 | |
175 | if (pos != HA_OFFSET_ERROR) |
176 | { |
177 | if (info->opt_flag & WRITE_CACHE_USED && |
178 | info->rec_cache.pos_in_file <= pos && |
179 | flush_io_cache(&info->rec_cache)) |
180 | DBUG_RETURN(my_errno); |
181 | info->rec_cache.seek_not_done=1; /* We have done a seek */ |
182 | |
183 | error= (int) info->s->file_read(info, record,info->s->base.reclength, |
184 | pos, MYF(MY_NABP)); |
185 | if (! error) |
186 | { |
187 | fast_ma_writeinfo(info); |
188 | if (!*record) |
189 | { |
190 | /* Record is deleted */ |
191 | DBUG_PRINT("warning" , ("Record is deleted" )); |
192 | DBUG_RETURN((my_errno=HA_ERR_RECORD_DELETED)); |
193 | } |
194 | info->update|= HA_STATE_AKTIV; /* Record is read */ |
195 | DBUG_RETURN(0); |
196 | } |
197 | } |
198 | fast_ma_writeinfo(info); /* No such record */ |
199 | DBUG_RETURN(my_errno); |
200 | } |
201 | |
202 | |
203 | /** |
204 | @brief Read record from given position or next record |
205 | |
206 | @note |
207 | When scanning, this function will return HA_ERR_RECORD_DELETED |
208 | for deleted rows even if skip_deleted_blocks is set. |
209 | The reason for this is to allow the caller to calculate the record |
210 | position without having to do call maria_position() for each record. |
211 | */ |
212 | |
213 | int _ma_read_rnd_static_record(MARIA_HA *info, uchar *buf, |
214 | MARIA_RECORD_POS filepos, |
215 | my_bool skip_deleted_blocks) |
216 | { |
217 | int locked,error,cache_read; |
218 | uint cache_length; |
219 | MARIA_SHARE *share= info->s; |
220 | DBUG_ENTER("_ma_read_rnd_static_record" ); |
221 | |
222 | cache_read=0; |
223 | cache_length=0; |
224 | if (info->opt_flag & READ_CACHE_USED) |
225 | { /* Cache in use */ |
226 | if (filepos == my_b_tell(&info->rec_cache) && |
227 | (skip_deleted_blocks || !filepos)) |
228 | { |
229 | cache_read=1; /* Read record using cache */ |
230 | cache_length= (uint) (info->rec_cache.read_end - |
231 | info->rec_cache.read_pos); |
232 | } |
233 | else |
234 | info->rec_cache.seek_not_done=1; /* Filepos is changed */ |
235 | } |
236 | locked=0; |
237 | if (info->lock_type == F_UNLCK) |
238 | { |
239 | if (filepos >= info->state->data_file_length) |
240 | { /* Test if new records */ |
241 | if (_ma_readinfo(info,F_RDLCK,0)) |
242 | DBUG_RETURN(my_errno); |
243 | locked=1; |
244 | } |
245 | else |
246 | { /* We don't nead new info */ |
247 | #ifndef UNSAFE_LOCKING |
248 | if ((! cache_read || share->base.reclength > cache_length) && |
249 | share->tot_locks == 0) |
250 | { /* record not in cache */ |
251 | locked=1; |
252 | } |
253 | #else |
254 | info->tmp_lock_type=F_RDLCK; |
255 | #endif |
256 | } |
257 | } |
258 | if (filepos >= info->state->data_file_length) |
259 | { |
260 | DBUG_PRINT("test" ,("filepos: %ld (%ld) records: %ld del: %ld" , |
261 | (long) filepos/share->base.reclength, (long) filepos, |
262 | (long) info->state->records, (long) info->state->del)); |
263 | fast_ma_writeinfo(info); |
264 | DBUG_RETURN(my_errno=HA_ERR_END_OF_FILE); |
265 | } |
266 | info->cur_row.lastpos= filepos; |
267 | info->cur_row.nextpos= filepos+share->base.pack_reclength; |
268 | |
269 | if (! cache_read) /* No cacheing */ |
270 | { |
271 | error= _ma_read_static_record(info, buf, filepos); |
272 | DBUG_RETURN(error); |
273 | } |
274 | |
275 | /* Read record with cacheing */ |
276 | error=my_b_read(&info->rec_cache, buf, share->base.reclength); |
277 | if (info->s->base.pack_reclength != info->s->base.reclength && !error) |
278 | { |
279 | uchar tmp[8]; /* Skill fill bytes */ |
280 | error=my_b_read(&info->rec_cache, tmp, |
281 | info->s->base.pack_reclength - info->s->base.reclength); |
282 | } |
283 | if (locked) |
284 | _ma_writeinfo(info,0); /* Unlock keyfile */ |
285 | if (!error) |
286 | { |
287 | if (!buf[0]) |
288 | { /* Record is removed */ |
289 | DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED); |
290 | } |
291 | /* Found and may be updated */ |
292 | info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED; |
293 | DBUG_RETURN(0); |
294 | } |
295 | /* my_errno should be set if rec_cache.error == -1 */ |
296 | if (info->rec_cache.error != -1 || my_errno == 0) |
297 | _ma_set_fatal_error(share, HA_ERR_WRONG_IN_RECORD); |
298 | DBUG_RETURN(my_errno); /* Something wrong (EOF?) */ |
299 | } |
300 | |