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 : /*
17 : Functions to handle space-packed-records and blobs
18 :
19 : A row may be stored in one or more linked blocks.
20 : The block size is between MARIA_MIN_BLOCK_LENGTH and MARIA_MAX_BLOCK_LENGTH.
21 : Each block is aligned on MARIA_DYN_ALIGN_SIZE.
22 : The reson for the max block size is to not have too many different types
23 : of blocks. For the differnet block types, look at _ma_get_block_info()
24 : */
25 :
26 : #include "maria_def.h"
27 :
28 : static my_bool write_dynamic_record(MARIA_HA *info,const uchar *record,
29 : ulong reclength);
30 : static int _ma_find_writepos(MARIA_HA *info,ulong reclength,my_off_t *filepos,
31 : ulong *length);
32 : static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
33 : uchar *record, ulong reclength);
34 : static my_bool delete_dynamic_record(MARIA_HA *info,MARIA_RECORD_POS filepos,
35 : uint second_read);
36 : static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
37 : uint length);
38 :
39 : #ifdef THREAD
40 : /* Play it safe; We have a small stack when using threads */
41 : #undef my_alloca
42 : #undef my_afree
43 : #define my_alloca(A) my_malloc((A),MYF(0))
44 : #define my_afree(A) my_free((A),MYF(0))
45 : #endif
46 :
47 : /* Interface function from MARIA_HA */
48 :
49 : #ifdef HAVE_MMAP
50 :
51 : /*
52 : Create mmaped area for MARIA handler
53 :
54 : SYNOPSIS
55 : _ma_dynmap_file()
56 : info MARIA handler
57 :
58 : RETURN
59 : 0 ok
60 : 1 error.
61 : */
62 :
63 : my_bool _ma_dynmap_file(MARIA_HA *info, my_off_t size)
64 0 : {
65 0 : DBUG_ENTER("_ma_dynmap_file");
66 0 : if (size > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
67 : {
68 0 : DBUG_PRINT("warning", ("File is too large for mmap"));
69 0 : DBUG_RETURN(1);
70 : }
71 : /*
72 : Ingo wonders if it is good to use MAP_NORESERVE. From the Linux man page:
73 : MAP_NORESERVE
74 : Do not reserve swap space for this mapping. When swap space is
75 : reserved, one has the guarantee that it is possible to modify the
76 : mapping. When swap space is not reserved one might get SIGSEGV
77 : upon a write if no physical memory is available.
78 : */
79 0 : info->s->file_map= (uchar*)
80 : my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN),
81 : info->s->mode==O_RDONLY ? PROT_READ :
82 : PROT_READ | PROT_WRITE,
83 : MAP_SHARED | MAP_NORESERVE,
84 : info->dfile.file, 0L);
85 0 : if (info->s->file_map == (uchar*) MAP_FAILED)
86 : {
87 0 : info->s->file_map= NULL;
88 0 : DBUG_RETURN(1);
89 : }
90 : #if defined(HAVE_MADVISE)
91 0 : madvise((char*) info->s->file_map, size, MADV_RANDOM);
92 : #endif
93 0 : info->s->mmaped_length= size;
94 0 : DBUG_RETURN(0);
95 : }
96 :
97 :
98 : /*
99 : Resize mmaped area for MARIA handler
100 :
101 : SYNOPSIS
102 : _ma_remap_file()
103 : info MARIA handler
104 :
105 : RETURN
106 : */
107 :
108 : void _ma_remap_file(MARIA_HA *info, my_off_t size)
109 0 : {
110 0 : if (info->s->file_map)
111 : {
112 0 : VOID(my_munmap((char*) info->s->file_map,
113 : (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN));
114 0 : _ma_dynmap_file(info, size);
115 : }
116 : }
117 : #endif
118 :
119 :
120 : /*
121 : Read bytes from MySAM handler, using mmap or pread
122 :
123 : SYNOPSIS
124 : _ma_mmap_pread()
125 : info MARIA handler
126 : Buffer Input buffer
127 : Count Count of bytes for read
128 : offset Start position
129 : MyFlags
130 :
131 : RETURN
132 : 0 ok
133 : */
134 :
135 : size_t _ma_mmap_pread(MARIA_HA *info, uchar *Buffer,
136 : size_t Count, my_off_t offset, myf MyFlags)
137 0 : {
138 0 : DBUG_PRINT("info", ("maria_read with mmap %d\n", info->dfile.file));
139 0 : if (info->s->lock_key_trees)
140 0 : rw_rdlock(&info->s->mmap_lock);
141 :
142 : /*
143 : The following test may fail in the following cases:
144 : - We failed to remap a memory area (fragmented memory?)
145 : - This thread has done some writes, but not yet extended the
146 : memory mapped area.
147 : */
148 :
149 0 : if (info->s->mmaped_length >= offset + Count)
150 : {
151 0 : memcpy(Buffer, info->s->file_map + offset, Count);
152 0 : if (info->s->lock_key_trees)
153 0 : rw_unlock(&info->s->mmap_lock);
154 0 : return 0;
155 : }
156 : else
157 : {
158 0 : if (info->s->lock_key_trees)
159 0 : rw_unlock(&info->s->mmap_lock);
160 0 : return my_pread(info->dfile.file, Buffer, Count, offset, MyFlags);
161 : }
162 : }
163 :
164 :
165 : /* wrapper for my_pread in case if mmap isn't used */
166 :
167 : size_t _ma_nommap_pread(MARIA_HA *info, uchar *Buffer,
168 : size_t Count, my_off_t offset, myf MyFlags)
169 0 : {
170 0 : return my_pread(info->dfile.file, Buffer, Count, offset, MyFlags);
171 : }
172 :
173 :
174 : /*
175 : Write bytes to MySAM handler, using mmap or pwrite
176 :
177 : SYNOPSIS
178 : _ma_mmap_pwrite()
179 : info MARIA handler
180 : Buffer Output buffer
181 : Count Count of bytes for write
182 : offset Start position
183 : MyFlags
184 :
185 : RETURN
186 : 0 ok
187 : !=0 error. In this case return error from pwrite
188 : */
189 :
190 : size_t _ma_mmap_pwrite(MARIA_HA *info, const uchar *Buffer,
191 : size_t Count, my_off_t offset, myf MyFlags)
192 0 : {
193 0 : DBUG_PRINT("info", ("maria_write with mmap %d\n", info->dfile.file));
194 0 : if (info->s->lock_key_trees)
195 0 : rw_rdlock(&info->s->mmap_lock);
196 :
197 : /*
198 : The following test may fail in the following cases:
199 : - We failed to remap a memory area (fragmented memory?)
200 : - This thread has done some writes, but not yet extended the
201 : memory mapped area.
202 : */
203 :
204 0 : if (info->s->mmaped_length >= offset + Count)
205 : {
206 0 : memcpy(info->s->file_map + offset, Buffer, Count);
207 0 : if (info->s->lock_key_trees)
208 0 : rw_unlock(&info->s->mmap_lock);
209 0 : return 0;
210 : }
211 : else
212 : {
213 0 : info->s->nonmmaped_inserts++;
214 0 : if (info->s->lock_key_trees)
215 0 : rw_unlock(&info->s->mmap_lock);
216 0 : return my_pwrite(info->dfile.file, Buffer, Count, offset, MyFlags);
217 : }
218 :
219 : }
220 :
221 :
222 : /* wrapper for my_pwrite in case if mmap isn't used */
223 :
224 : size_t _ma_nommap_pwrite(MARIA_HA *info, const uchar *Buffer,
225 : size_t Count, my_off_t offset, myf MyFlags)
226 0 : {
227 0 : return my_pwrite(info->dfile.file, Buffer, Count, offset, MyFlags);
228 : }
229 :
230 :
231 : my_bool _ma_write_dynamic_record(MARIA_HA *info, const uchar *record)
232 0 : {
233 : ulong reclength= _ma_rec_pack(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
234 0 : record);
235 0 : return (write_dynamic_record(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
236 : reclength));
237 : }
238 :
239 : my_bool _ma_update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS pos,
240 : const uchar *oldrec __attribute__ ((unused)),
241 : const uchar *record)
242 0 : {
243 : uint length= _ma_rec_pack(info, info->rec_buff + MARIA_REC_BUFF_OFFSET,
244 0 : record);
245 0 : return (update_dynamic_record(info, pos,
246 : info->rec_buff + MARIA_REC_BUFF_OFFSET,
247 : length));
248 : }
249 :
250 :
251 : my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record)
252 0 : {
253 : uchar *rec_buff;
254 : int error;
255 : ulong reclength,reclength2,extra;
256 :
257 0 : extra= (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
258 : MARIA_DYN_DELETE_BLOCK_HEADER+1);
259 0 : reclength= (info->s->base.pack_reclength +
260 : _ma_calc_total_blob_length(info,record)+ extra);
261 0 : if (!(rec_buff=(uchar*) my_alloca(reclength)))
262 : {
263 0 : my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
264 0 : return(1);
265 : }
266 0 : reclength2= _ma_rec_pack(info,
267 : rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
268 : record);
269 0 : DBUG_PRINT("info",("reclength: %lu reclength2: %lu",
270 : reclength, reclength2));
271 0 : DBUG_ASSERT(reclength2 <= reclength);
272 0 : error= write_dynamic_record(info,
273 : rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
274 : reclength2);
275 0 : my_afree(rec_buff);
276 0 : return(error != 0);
277 : }
278 :
279 :
280 : my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
281 : const uchar *oldrec __attribute__ ((unused)),
282 : const uchar *record)
283 0 : {
284 : uchar *rec_buff;
285 : int error;
286 : ulong reclength,extra;
287 :
288 0 : extra= (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
289 : MARIA_DYN_DELETE_BLOCK_HEADER);
290 0 : reclength= (info->s->base.pack_reclength+
291 : _ma_calc_total_blob_length(info,record)+ extra);
292 : #ifdef NOT_USED /* We now support big rows */
293 : if (reclength > MARIA_DYN_MAX_ROW_LENGTH)
294 : {
295 : my_errno=HA_ERR_TO_BIG_ROW;
296 : return 1;
297 : }
298 : #endif
299 0 : if (!(rec_buff=(uchar*) my_alloca(reclength)))
300 : {
301 0 : my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
302 0 : return(1);
303 : }
304 0 : reclength= _ma_rec_pack(info,rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
305 : record);
306 0 : error=update_dynamic_record(info,pos,
307 : rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
308 : reclength);
309 0 : my_afree(rec_buff);
310 0 : return(error != 0);
311 : }
312 :
313 :
314 : my_bool _ma_delete_dynamic_record(MARIA_HA *info,
315 : const uchar *record __attribute__ ((unused)))
316 0 : {
317 0 : return delete_dynamic_record(info, info->cur_row.lastpos, 0);
318 : }
319 :
320 :
321 : /**
322 : Write record to data-file.
323 :
324 : @todo it's cheating: it casts "const uchar*" to uchar*.
325 : */
326 :
327 : static my_bool write_dynamic_record(MARIA_HA *info, const uchar *record,
328 : ulong reclength)
329 0 : {
330 : int flag;
331 : ulong length;
332 : my_off_t filepos;
333 0 : DBUG_ENTER("write_dynamic_record");
334 :
335 0 : flag=0;
336 :
337 : /*
338 : Check if we have enough room for the new record.
339 : First we do simplified check to make usual case faster.
340 : Then we do more precise check for the space left.
341 : Though it still is not absolutely precise, as
342 : we always use MARIA_MAX_DYN_BLOCK_HEADER while it can be
343 : less in the most of the cases.
344 : */
345 :
346 0 : if (unlikely(info->s->base.max_data_file_length -
347 : info->state->data_file_length <
348 : reclength + MARIA_MAX_DYN_BLOCK_HEADER))
349 : {
350 0 : if (info->s->base.max_data_file_length - info->state->data_file_length +
351 : info->state->empty - info->state->del * MARIA_MAX_DYN_BLOCK_HEADER <
352 : reclength + MARIA_MAX_DYN_BLOCK_HEADER)
353 : {
354 0 : my_errno=HA_ERR_RECORD_FILE_FULL;
355 0 : DBUG_RETURN(1);
356 : }
357 : }
358 :
359 : do
360 : {
361 0 : if (_ma_find_writepos(info,reclength,&filepos,&length))
362 0 : goto err;
363 0 : if (_ma_write_part_record(info,filepos,length,
364 : (info->append_insert_at_end ?
365 : HA_OFFSET_ERROR : info->s->state.dellink),
366 : (uchar**) &record,&reclength,&flag))
367 0 : goto err;
368 0 : } while (reclength);
369 :
370 0 : DBUG_RETURN(0);
371 0 : err:
372 0 : DBUG_RETURN(1);
373 : }
374 :
375 :
376 : /* Get a block for data ; The given data-area must be used !! */
377 :
378 : static int _ma_find_writepos(MARIA_HA *info,
379 : ulong reclength, /* record length */
380 : my_off_t *filepos, /* Return file pos */
381 : ulong *length) /* length of block at filepos */
382 0 : {
383 : MARIA_BLOCK_INFO block_info;
384 : ulong tmp;
385 0 : DBUG_ENTER("_ma_find_writepos");
386 :
387 0 : if (info->s->state.dellink != HA_OFFSET_ERROR &&
388 : !info->append_insert_at_end)
389 : {
390 : /* Deleted blocks exists; Get last used block */
391 0 : *filepos=info->s->state.dellink;
392 0 : block_info.second_read=0;
393 0 : info->rec_cache.seek_not_done=1;
394 0 : if (!(_ma_get_block_info(&block_info, info->dfile.file,
395 : info->s->state.dellink) &
396 : BLOCK_DELETED))
397 : {
398 0 : DBUG_PRINT("error",("Delete link crashed"));
399 0 : my_errno=HA_ERR_WRONG_IN_RECORD;
400 0 : DBUG_RETURN(-1);
401 : }
402 0 : info->s->state.dellink=block_info.next_filepos;
403 0 : info->state->del--;
404 0 : info->state->empty-= block_info.block_len;
405 0 : *length= block_info.block_len;
406 : }
407 : else
408 : {
409 : /* No deleted blocks; Allocate a new block */
410 0 : *filepos=info->state->data_file_length;
411 0 : if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
412 : info->s->base.min_block_length)
413 0 : tmp= info->s->base.min_block_length;
414 : else
415 0 : tmp= ((tmp+MARIA_DYN_ALIGN_SIZE-1) &
416 : (~ (ulong) (MARIA_DYN_ALIGN_SIZE-1)));
417 0 : if (info->state->data_file_length >
418 : (info->s->base.max_data_file_length - tmp))
419 : {
420 0 : my_errno=HA_ERR_RECORD_FILE_FULL;
421 0 : DBUG_RETURN(-1);
422 : }
423 0 : if (tmp > MARIA_MAX_BLOCK_LENGTH)
424 0 : tmp=MARIA_MAX_BLOCK_LENGTH;
425 0 : *length= tmp;
426 0 : info->state->data_file_length+= tmp;
427 0 : info->s->state.split++;
428 0 : info->update|=HA_STATE_WRITE_AT_END;
429 : }
430 0 : DBUG_RETURN(0);
431 : } /* _ma_find_writepos */
432 :
433 :
434 :
435 : /*
436 : Unlink a deleted block from the deleted list.
437 : This block will be combined with the preceding or next block to form
438 : a big block.
439 : */
440 :
441 : static my_bool unlink_deleted_block(MARIA_HA *info,
442 : MARIA_BLOCK_INFO *block_info)
443 0 : {
444 0 : DBUG_ENTER("unlink_deleted_block");
445 0 : if (block_info->filepos == info->s->state.dellink)
446 : {
447 : /* First deleted block; We can just use this ! */
448 0 : info->s->state.dellink=block_info->next_filepos;
449 : }
450 : else
451 : {
452 : MARIA_BLOCK_INFO tmp;
453 0 : tmp.second_read=0;
454 : /* Unlink block from the previous block */
455 0 : if (!(_ma_get_block_info(&tmp, info->dfile.file, block_info->prev_filepos)
456 : & BLOCK_DELETED))
457 0 : DBUG_RETURN(1); /* Something is wrong */
458 0 : mi_sizestore(tmp.header+4,block_info->next_filepos);
459 0 : if (info->s->file_write(info, tmp.header+4,8,
460 : block_info->prev_filepos+4, MYF(MY_NABP)))
461 0 : DBUG_RETURN(1);
462 : /* Unlink block from next block */
463 0 : if (block_info->next_filepos != HA_OFFSET_ERROR)
464 : {
465 0 : if (!(_ma_get_block_info(&tmp, info->dfile.file,
466 : block_info->next_filepos)
467 : & BLOCK_DELETED))
468 0 : DBUG_RETURN(1); /* Something is wrong */
469 0 : mi_sizestore(tmp.header+12,block_info->prev_filepos);
470 0 : if (info->s->file_write(info, tmp.header+12,8,
471 : block_info->next_filepos+12,
472 : MYF(MY_NABP)))
473 0 : DBUG_RETURN(1);
474 : }
475 : }
476 : /* We now have one less deleted block */
477 0 : info->state->del--;
478 0 : info->state->empty-= block_info->block_len;
479 0 : info->s->state.split--;
480 :
481 : /*
482 : If this was a block that we where accessing through table scan
483 : (maria_rrnd() or maria_scan(), then ensure that we skip over this block
484 : when doing next maria_rrnd() or maria_scan().
485 : */
486 0 : if (info->cur_row.nextpos == block_info->filepos)
487 0 : info->cur_row.nextpos+= block_info->block_len;
488 0 : DBUG_RETURN(0);
489 : }
490 :
491 :
492 : /*
493 : Add a backward link to delete block
494 :
495 : SYNOPSIS
496 : update_backward_delete_link()
497 : info MARIA handler
498 : delete_block Position to delete block to update.
499 : If this is 'HA_OFFSET_ERROR', nothing will be done
500 : filepos Position to block that 'delete_block' should point to
501 :
502 : RETURN
503 : 0 ok
504 : 1 error. In this case my_error is set.
505 : */
506 :
507 : static my_bool update_backward_delete_link(MARIA_HA *info,
508 : my_off_t delete_block,
509 : MARIA_RECORD_POS filepos)
510 0 : {
511 : MARIA_BLOCK_INFO block_info;
512 0 : DBUG_ENTER("update_backward_delete_link");
513 :
514 0 : if (delete_block != HA_OFFSET_ERROR)
515 : {
516 0 : block_info.second_read=0;
517 0 : if (_ma_get_block_info(&block_info, info->dfile.file, delete_block)
518 : & BLOCK_DELETED)
519 : {
520 : uchar buff[8];
521 0 : mi_sizestore(buff,filepos);
522 0 : if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
523 0 : DBUG_RETURN(1); /* Error on write */
524 : }
525 : else
526 : {
527 0 : my_errno=HA_ERR_WRONG_IN_RECORD;
528 0 : DBUG_RETURN(1); /* Wrong delete link */
529 : }
530 : }
531 0 : DBUG_RETURN(0);
532 : }
533 :
534 : /* Delete datarecord from database */
535 : /* info->rec_cache.seek_not_done is updated in cmp_record */
536 :
537 : static my_bool delete_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
538 : uint second_read)
539 0 : {
540 : uint length,b_type;
541 : MARIA_BLOCK_INFO block_info,del_block;
542 : int error;
543 : my_bool remove_next_block;
544 0 : DBUG_ENTER("delete_dynamic_record");
545 :
546 : /* First add a link from the last block to the new one */
547 0 : error= update_backward_delete_link(info, info->s->state.dellink, filepos);
548 :
549 0 : block_info.second_read=second_read;
550 : do
551 : {
552 : /* Remove block at 'filepos' */
553 0 : if ((b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos))
554 : & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
555 : BLOCK_FATAL_ERROR) ||
556 : (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
557 : MARIA_MIN_BLOCK_LENGTH)
558 : {
559 0 : my_errno=HA_ERR_WRONG_IN_RECORD;
560 0 : DBUG_RETURN(1);
561 : }
562 : /* Check if next block is a delete block */
563 0 : del_block.second_read=0;
564 0 : remove_next_block=0;
565 0 : if (_ma_get_block_info(&del_block, info->dfile.file, filepos + length) &
566 : BLOCK_DELETED && del_block.block_len+length <
567 : MARIA_DYN_MAX_BLOCK_LENGTH)
568 : {
569 : /* We can't remove this yet as this block may be the head block */
570 0 : remove_next_block=1;
571 0 : length+=del_block.block_len;
572 : }
573 :
574 0 : block_info.header[0]=0;
575 0 : mi_int3store(block_info.header+1,length);
576 0 : mi_sizestore(block_info.header+4,info->s->state.dellink);
577 0 : if (b_type & BLOCK_LAST)
578 0 : bfill(block_info.header+12,8,255);
579 : else
580 0 : mi_sizestore(block_info.header+12,block_info.next_filepos);
581 0 : if (info->s->file_write(info, block_info.header, 20, filepos,
582 : MYF(MY_NABP)))
583 0 : DBUG_RETURN(1);
584 0 : info->s->state.dellink = filepos;
585 0 : info->state->del++;
586 0 : info->state->empty+=length;
587 0 : filepos=block_info.next_filepos;
588 :
589 : /* Now it's safe to unlink the deleted block directly after this one */
590 0 : if (remove_next_block && unlink_deleted_block(info,&del_block))
591 0 : error=1;
592 0 : } while (!(b_type & BLOCK_LAST));
593 :
594 0 : DBUG_RETURN(error);
595 : }
596 :
597 :
598 : /* Write a block to datafile */
599 :
600 : int _ma_write_part_record(MARIA_HA *info,
601 : my_off_t filepos, /* points at empty block */
602 : ulong length, /* length of block */
603 : my_off_t next_filepos,/* Next empty block */
604 : uchar **record, /* pointer to record ptr */
605 : ulong *reclength, /* length of *record */
606 : int *flag) /* *flag == 0 if header */
607 0 : {
608 : ulong head_length,res_length,extra_length,long_block,del_length;
609 : uchar *pos,*record_end;
610 : my_off_t next_delete_block;
611 : uchar temp[MARIA_SPLIT_LENGTH+MARIA_DYN_DELETE_BLOCK_HEADER];
612 0 : DBUG_ENTER("_ma_write_part_record");
613 :
614 0 : next_delete_block=HA_OFFSET_ERROR;
615 :
616 0 : res_length=extra_length=0;
617 0 : if (length > *reclength + MARIA_SPLIT_LENGTH)
618 : { /* Splitt big block */
619 0 : res_length=MY_ALIGN(length- *reclength - MARIA_EXTEND_BLOCK_LENGTH,
620 : MARIA_DYN_ALIGN_SIZE);
621 0 : length-= res_length; /* Use this for first part */
622 : }
623 0 : long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
624 0 : if (length == *reclength+ 3 + long_block)
625 : {
626 : /* Block is exactly of the right length */
627 0 : temp[0]=(uchar) (1+ *flag)+(uchar) long_block; /* Flag is 0 or 6 */
628 0 : if (long_block)
629 : {
630 0 : mi_int3store(temp+1,*reclength);
631 0 : head_length=4;
632 : }
633 : else
634 : {
635 0 : mi_int2store(temp+1,*reclength);
636 0 : head_length=3;
637 : }
638 : }
639 0 : else if (length-long_block < *reclength+4)
640 : { /* To short block */
641 0 : if (next_filepos == HA_OFFSET_ERROR)
642 0 : next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
643 : !info->append_insert_at_end ?
644 : info->s->state.dellink : info->state->data_file_length);
645 0 : if (*flag == 0) /* First block */
646 : {
647 0 : if (*reclength > MARIA_MAX_BLOCK_LENGTH)
648 : {
649 0 : head_length= 16;
650 0 : temp[0]=13;
651 0 : mi_int4store(temp+1,*reclength);
652 0 : mi_int3store(temp+5,length-head_length);
653 0 : mi_sizestore(temp+8,next_filepos);
654 : }
655 : else
656 : {
657 0 : head_length=5+8+long_block*2;
658 0 : temp[0]=5+(uchar) long_block;
659 0 : if (long_block)
660 : {
661 0 : mi_int3store(temp+1,*reclength);
662 0 : mi_int3store(temp+4,length-head_length);
663 0 : mi_sizestore(temp+7,next_filepos);
664 : }
665 : else
666 : {
667 0 : mi_int2store(temp+1,*reclength);
668 0 : mi_int2store(temp+3,length-head_length);
669 0 : mi_sizestore(temp+5,next_filepos);
670 : }
671 : }
672 : }
673 : else
674 : {
675 0 : head_length=3+8+long_block;
676 0 : temp[0]=11+(uchar) long_block;
677 0 : if (long_block)
678 : {
679 0 : mi_int3store(temp+1,length-head_length);
680 0 : mi_sizestore(temp+4,next_filepos);
681 : }
682 : else
683 : {
684 0 : mi_int2store(temp+1,length-head_length);
685 0 : mi_sizestore(temp+3,next_filepos);
686 : }
687 : }
688 : }
689 : else
690 : { /* Block with empty info last */
691 0 : head_length=4+long_block;
692 0 : extra_length= length- *reclength-head_length;
693 0 : temp[0]= (uchar) (3+ *flag)+(uchar) long_block; /* 3,4 or 9,10 */
694 0 : if (long_block)
695 : {
696 0 : mi_int3store(temp+1,*reclength);
697 0 : temp[4]= (uchar) (extra_length);
698 : }
699 : else
700 : {
701 0 : mi_int2store(temp+1,*reclength);
702 0 : temp[3]= (uchar) (extra_length);
703 : }
704 0 : length= *reclength+head_length; /* Write only what is needed */
705 : }
706 0 : DBUG_DUMP("header", temp, head_length);
707 :
708 : /* Make a long block for one write */
709 0 : record_end= *record+length-head_length;
710 0 : del_length=(res_length ? MARIA_DYN_DELETE_BLOCK_HEADER : 0);
711 0 : bmove((*record-head_length), temp, head_length);
712 0 : memcpy(temp,record_end,(size_t) (extra_length+del_length));
713 0 : bzero(record_end, extra_length);
714 :
715 0 : if (res_length)
716 : {
717 : /* Check first if we can join this block with the next one */
718 : MARIA_BLOCK_INFO del_block;
719 0 : my_off_t next_block=filepos+length+extra_length+res_length;
720 :
721 0 : del_block.second_read=0;
722 0 : if (next_block < info->state->data_file_length &&
723 : info->s->state.dellink != HA_OFFSET_ERROR)
724 : {
725 0 : if ((_ma_get_block_info(&del_block, info->dfile.file, next_block)
726 : & BLOCK_DELETED) &&
727 : res_length + del_block.block_len < MARIA_DYN_MAX_BLOCK_LENGTH)
728 : {
729 0 : if (unlink_deleted_block(info,&del_block))
730 0 : goto err;
731 0 : res_length+=del_block.block_len;
732 : }
733 : }
734 :
735 : /* Create a delete link of the last part of the block */
736 0 : pos=record_end+extra_length;
737 0 : pos[0]= '\0';
738 0 : mi_int3store(pos+1,res_length);
739 0 : mi_sizestore(pos+4,info->s->state.dellink);
740 0 : bfill(pos+12,8,255); /* End link */
741 0 : next_delete_block=info->s->state.dellink;
742 0 : info->s->state.dellink= filepos+length+extra_length;
743 0 : info->state->del++;
744 0 : info->state->empty+=res_length;
745 0 : info->s->state.split++;
746 : }
747 0 : if (info->opt_flag & WRITE_CACHE_USED &&
748 : info->update & HA_STATE_WRITE_AT_END)
749 : {
750 0 : if (info->update & HA_STATE_EXTEND_BLOCK)
751 : {
752 0 : info->update&= ~HA_STATE_EXTEND_BLOCK;
753 0 : if (my_block_write(&info->rec_cache, *record-head_length,
754 : length+extra_length+del_length,filepos))
755 : goto err;
756 : }
757 0 : else if (my_b_write(&info->rec_cache, *record-head_length,
758 : length+extra_length+del_length))
759 : goto err;
760 : }
761 : else
762 : {
763 0 : info->rec_cache.seek_not_done=1;
764 0 : if (info->s->file_write(info, *record-head_length,
765 : length+extra_length+
766 : del_length,filepos,info->s->write_flag))
767 0 : goto err;
768 : }
769 0 : memcpy(record_end,temp,(size_t) (extra_length+del_length));
770 0 : *record=record_end;
771 0 : *reclength-=(length-head_length);
772 0 : *flag=6;
773 :
774 0 : if (del_length)
775 : {
776 : /* link the next delete block to this */
777 0 : if (update_backward_delete_link(info, next_delete_block,
778 : info->s->state.dellink))
779 0 : goto err;
780 : }
781 :
782 0 : DBUG_RETURN(0);
783 0 : err:
784 0 : DBUG_PRINT("exit",("errno: %d",my_errno));
785 0 : DBUG_RETURN(1);
786 : } /* _ma_write_part_record */
787 :
788 :
789 : /* update record from datafile */
790 :
791 : static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
792 : uchar *record, ulong reclength)
793 0 : {
794 : int flag;
795 : uint error;
796 : ulong length;
797 : MARIA_BLOCK_INFO block_info;
798 0 : DBUG_ENTER("update_dynamic_record");
799 :
800 0 : flag=block_info.second_read=0;
801 : /*
802 : Check if we have enough room for the record.
803 : First we do simplified check to make usual case faster.
804 : Then we do more precise check for the space left.
805 : Though it still is not absolutely precise, as
806 : we always use MARIA_MAX_DYN_BLOCK_HEADER while it can be
807 : less in the most of the cases.
808 : */
809 :
810 : /*
811 : compare with just the reclength as we're going
812 : to get some space from the old replaced record
813 : */
814 0 : if (unlikely(info->s->base.max_data_file_length -
815 : info->state->data_file_length < reclength))
816 : {
817 : /* If new record isn't longer, we can go on safely */
818 0 : if (info->cur_row.total_length < reclength)
819 : {
820 0 : if (info->s->base.max_data_file_length - info->state->data_file_length +
821 : info->state->empty - info->state->del * MARIA_MAX_DYN_BLOCK_HEADER <
822 : reclength - info->cur_row.total_length + MARIA_MAX_DYN_BLOCK_HEADER)
823 : {
824 0 : my_errno=HA_ERR_RECORD_FILE_FULL;
825 0 : goto err;
826 : }
827 : }
828 : }
829 : /* Remember length for updated row if it's updated again */
830 0 : info->cur_row.total_length= reclength;
831 :
832 0 : while (reclength > 0)
833 : {
834 0 : if (filepos != info->s->state.dellink)
835 : {
836 0 : block_info.next_filepos= HA_OFFSET_ERROR;
837 0 : if ((error= _ma_get_block_info(&block_info, info->dfile.file, filepos))
838 : & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
839 : BLOCK_FATAL_ERROR))
840 : {
841 0 : DBUG_PRINT("error",("Got wrong block info"));
842 0 : if (!(error & BLOCK_FATAL_ERROR))
843 0 : my_errno=HA_ERR_WRONG_IN_RECORD;
844 : goto err;
845 : }
846 0 : length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
847 0 : if (length < reclength)
848 : {
849 0 : uint tmp=MY_ALIGN(reclength - length + 3 +
850 : test(reclength >= 65520L),MARIA_DYN_ALIGN_SIZE);
851 : /* Don't create a block bigger than MARIA_MAX_BLOCK_LENGTH */
852 0 : tmp= min(length+tmp, MARIA_MAX_BLOCK_LENGTH)-length;
853 : /* Check if we can extend this block */
854 0 : if (block_info.filepos + block_info.block_len ==
855 : info->state->data_file_length &&
856 : info->state->data_file_length <
857 : info->s->base.max_data_file_length-tmp)
858 : {
859 : /* extend file */
860 0 : DBUG_PRINT("info",("Extending file with %d bytes",tmp));
861 0 : if (info->cur_row.nextpos == info->state->data_file_length)
862 0 : info->cur_row.nextpos+= tmp;
863 0 : info->state->data_file_length+= tmp;
864 0 : info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
865 0 : length+=tmp;
866 : }
867 0 : else if (length < MARIA_MAX_BLOCK_LENGTH - MARIA_MIN_BLOCK_LENGTH)
868 : {
869 : /*
870 : Check if next block is a deleted block
871 : Above we have MARIA_MIN_BLOCK_LENGTH to avoid the problem where
872 : the next block is so small it can't be splited which could
873 : casue problems
874 : */
875 :
876 : MARIA_BLOCK_INFO del_block;
877 0 : del_block.second_read=0;
878 0 : if (_ma_get_block_info(&del_block, info->dfile.file,
879 : block_info.filepos + block_info.block_len) &
880 : BLOCK_DELETED)
881 : {
882 : /* Use; Unlink it and extend the current block */
883 0 : DBUG_PRINT("info",("Extending current block"));
884 0 : if (unlink_deleted_block(info,&del_block))
885 0 : goto err;
886 0 : if ((length+=del_block.block_len) > MARIA_MAX_BLOCK_LENGTH)
887 : {
888 : /*
889 : New block was too big, link overflow part back to
890 : delete list
891 : */
892 : my_off_t next_pos;
893 0 : ulong rest_length= length-MARIA_MAX_BLOCK_LENGTH;
894 0 : set_if_bigger(rest_length, MARIA_MIN_BLOCK_LENGTH);
895 0 : next_pos= del_block.filepos+ del_block.block_len - rest_length;
896 :
897 0 : if (update_backward_delete_link(info, info->s->state.dellink,
898 : next_pos))
899 0 : DBUG_RETURN(1);
900 :
901 : /* create delete link for data that didn't fit into the page */
902 0 : del_block.header[0]=0;
903 0 : mi_int3store(del_block.header+1, rest_length);
904 0 : mi_sizestore(del_block.header+4,info->s->state.dellink);
905 0 : bfill(del_block.header+12,8,255);
906 0 : if (info->s->file_write(info, del_block.header, 20,
907 : next_pos, MYF(MY_NABP)))
908 0 : DBUG_RETURN(1);
909 0 : info->s->state.dellink= next_pos;
910 0 : info->s->state.split++;
911 0 : info->state->del++;
912 0 : info->state->empty+= rest_length;
913 0 : length-= rest_length;
914 : }
915 : }
916 : }
917 : }
918 : }
919 : else
920 : {
921 0 : if (_ma_find_writepos(info,reclength,&filepos,&length))
922 0 : goto err;
923 : }
924 0 : if (_ma_write_part_record(info,filepos,length,block_info.next_filepos,
925 : &record,&reclength,&flag))
926 0 : goto err;
927 0 : if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
928 : {
929 : /* Start writing data on deleted blocks */
930 0 : filepos=info->s->state.dellink;
931 : }
932 : }
933 :
934 0 : if (block_info.next_filepos != HA_OFFSET_ERROR)
935 0 : if (delete_dynamic_record(info,block_info.next_filepos,1))
936 0 : goto err;
937 :
938 0 : DBUG_RETURN(0);
939 0 : err:
940 0 : DBUG_RETURN(1);
941 : }
942 :
943 :
944 : /* Pack a record. Return new reclength */
945 :
946 : uint _ma_rec_pack(MARIA_HA *info, register uchar *to,
947 : register const uchar *from)
948 0 : {
949 : uint length,new_length,flag,bit,i;
950 : const uchar *pos,*end;
951 : uchar *startpos,*packpos;
952 : enum en_fieldtype type;
953 : reg3 MARIA_COLUMNDEF *column;
954 : MARIA_BLOB *blob;
955 0 : DBUG_ENTER("_ma_rec_pack");
956 :
957 0 : flag= 0;
958 0 : bit= 1;
959 0 : startpos= packpos=to;
960 0 : to+= info->s->base.pack_bytes;
961 0 : blob= info->blobs;
962 0 : column= info->s->columndef;
963 0 : if (info->s->base.null_bytes)
964 : {
965 0 : memcpy(to, from, info->s->base.null_bytes);
966 0 : from+= info->s->base.null_bytes;
967 0 : to+= info->s->base.null_bytes;
968 : }
969 :
970 0 : for (i=info->s->base.fields ; i-- > 0; from+= length, column++)
971 : {
972 0 : length=(uint) column->length;
973 0 : if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL)
974 : {
975 0 : if (type == FIELD_BLOB)
976 : {
977 0 : if (!blob->length)
978 0 : flag|=bit;
979 : else
980 : {
981 : char *temp_pos;
982 0 : size_t tmp_length=length-portable_sizeof_char_ptr;
983 0 : memcpy(to,from,tmp_length);
984 0 : memcpy_fixed(&temp_pos,from+tmp_length,sizeof(char*));
985 0 : memcpy(to+tmp_length,temp_pos,(size_t) blob->length);
986 0 : to+=tmp_length+blob->length;
987 : }
988 0 : blob++;
989 : }
990 0 : else if (type == FIELD_SKIP_ZERO)
991 : {
992 0 : if (memcmp(from, maria_zero_string, length) == 0)
993 0 : flag|=bit;
994 : else
995 : {
996 0 : memcpy(to, from, (size_t) length);
997 0 : to+=length;
998 : }
999 : }
1000 0 : else if (type == FIELD_SKIP_ENDSPACE ||
1001 : type == FIELD_SKIP_PRESPACE)
1002 : {
1003 0 : pos= from; end= from + length;
1004 0 : if (type == FIELD_SKIP_ENDSPACE)
1005 : { /* Pack trailing spaces */
1006 0 : while (end > from && *(end-1) == ' ')
1007 0 : end--;
1008 : }
1009 : else
1010 : { /* Pack pref-spaces */
1011 0 : while (pos < end && *pos == ' ')
1012 0 : pos++;
1013 : }
1014 0 : new_length=(uint) (end-pos);
1015 0 : if (new_length +1 + test(column->length > 255 && new_length > 127)
1016 : < length)
1017 : {
1018 0 : if (column->length > 255 && new_length > 127)
1019 : {
1020 0 : to[0]= (uchar) ((new_length & 127) + 128);
1021 0 : to[1]= (uchar) (new_length >> 7);
1022 0 : to+=2;
1023 : }
1024 : else
1025 0 : *to++= (uchar) new_length;
1026 0 : memcpy(to, pos, (size_t) new_length); to+=new_length;
1027 0 : flag|=bit;
1028 : }
1029 : else
1030 : {
1031 0 : memcpy(to,from,(size_t) length); to+=length;
1032 : }
1033 : }
1034 0 : else if (type == FIELD_VARCHAR)
1035 : {
1036 0 : uint pack_length= HA_VARCHAR_PACKLENGTH(column->length -1);
1037 : uint tmp_length;
1038 0 : if (pack_length == 1)
1039 : {
1040 0 : tmp_length= (uint) *from;
1041 0 : *to++= *from;
1042 : }
1043 : else
1044 : {
1045 0 : tmp_length= uint2korr(from);
1046 0 : store_key_length_inc(to,tmp_length);
1047 : }
1048 0 : memcpy(to, from+pack_length,tmp_length);
1049 0 : to+= tmp_length;
1050 0 : continue;
1051 : }
1052 : else
1053 : {
1054 0 : memcpy(to,from,(size_t) length); to+=length;
1055 0 : continue; /* Normal field */
1056 : }
1057 0 : if ((bit= bit << 1) >= 256)
1058 : {
1059 0 : *packpos++ = (uchar) flag;
1060 0 : bit=1; flag=0;
1061 : }
1062 : }
1063 : else
1064 : {
1065 0 : memcpy(to,from,(size_t) length); to+=length;
1066 : }
1067 : }
1068 0 : if (bit != 1)
1069 0 : *packpos= (uchar) flag;
1070 0 : if (info->s->calc_checksum)
1071 0 : *to++= (uchar) info->cur_row.checksum;
1072 0 : DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
1073 0 : DBUG_RETURN((uint) (to-startpos));
1074 : } /* _ma_rec_pack */
1075 :
1076 :
1077 :
1078 : /*
1079 : Check if a record was correctly packed. Used only by maria_chk
1080 : Returns 0 if record is ok.
1081 : */
1082 :
1083 : my_bool _ma_rec_check(MARIA_HA *info,const uchar *record, uchar *rec_buff,
1084 : ulong packed_length, my_bool with_checksum,
1085 : ha_checksum checksum)
1086 0 : {
1087 : uint length,new_length,flag,bit,i;
1088 : const uchar *pos,*end;
1089 : uchar *packpos,*to;
1090 : enum en_fieldtype type;
1091 : reg3 MARIA_COLUMNDEF *column;
1092 0 : DBUG_ENTER("_ma_rec_check");
1093 :
1094 0 : packpos=rec_buff; to= rec_buff+info->s->base.pack_bytes;
1095 0 : column= info->s->columndef;
1096 0 : flag= *packpos; bit=1;
1097 0 : record+= info->s->base.null_bytes;
1098 0 : to+= info->s->base.null_bytes;
1099 :
1100 0 : for (i=info->s->base.fields ; i-- > 0; record+= length, column++)
1101 : {
1102 0 : length=(uint) column->length;
1103 0 : if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL)
1104 : {
1105 0 : if (type == FIELD_BLOB)
1106 : {
1107 : uint blob_length=
1108 0 : _ma_calc_blob_length(length-portable_sizeof_char_ptr,record);
1109 0 : if (!blob_length && !(flag & bit))
1110 0 : goto err;
1111 0 : if (blob_length)
1112 0 : to+=length - portable_sizeof_char_ptr+ blob_length;
1113 : }
1114 0 : else if (type == FIELD_SKIP_ZERO)
1115 : {
1116 0 : if (memcmp(record, maria_zero_string, length) == 0)
1117 : {
1118 0 : if (!(flag & bit))
1119 : goto err;
1120 : }
1121 : else
1122 0 : to+=length;
1123 : }
1124 0 : else if (type == FIELD_SKIP_ENDSPACE ||
1125 : type == FIELD_SKIP_PRESPACE)
1126 : {
1127 0 : pos= record; end= record + length;
1128 0 : if (type == FIELD_SKIP_ENDSPACE)
1129 : { /* Pack trailing spaces */
1130 0 : while (end > record && *(end-1) == ' ')
1131 0 : end--;
1132 : }
1133 : else
1134 : { /* Pack pre-spaces */
1135 0 : while (pos < end && *pos == ' ')
1136 0 : pos++;
1137 : }
1138 0 : new_length=(uint) (end-pos);
1139 0 : if (new_length +1 + test(column->length > 255 && new_length > 127)
1140 : < length)
1141 : {
1142 0 : if (!(flag & bit))
1143 0 : goto err;
1144 0 : if (column->length > 255 && new_length > 127)
1145 : {
1146 : /* purecov: begin inspected */
1147 0 : if (to[0] != (uchar) ((new_length & 127) + 128) ||
1148 : to[1] != (uchar) (new_length >> 7))
1149 : goto err;
1150 0 : to+=2;
1151 : /* purecov: end */
1152 : }
1153 0 : else if (*to++ != (uchar) new_length)
1154 0 : goto err;
1155 0 : to+=new_length;
1156 : }
1157 : else
1158 0 : to+=length;
1159 : }
1160 0 : else if (type == FIELD_VARCHAR)
1161 : {
1162 0 : uint pack_length= HA_VARCHAR_PACKLENGTH(column->length -1);
1163 : uint tmp_length;
1164 0 : if (pack_length == 1)
1165 : {
1166 0 : tmp_length= (uint) *record;
1167 0 : to+= 1+ tmp_length;
1168 0 : continue;
1169 : }
1170 : else
1171 : {
1172 0 : tmp_length= uint2korr(record);
1173 0 : to+= get_pack_length(tmp_length)+tmp_length;
1174 : }
1175 0 : continue;
1176 : }
1177 : else
1178 : {
1179 0 : to+=length;
1180 0 : continue; /* Normal field */
1181 : }
1182 0 : if ((bit= bit << 1) >= 256)
1183 : {
1184 0 : flag= *++packpos;
1185 0 : bit=1;
1186 : }
1187 : }
1188 : else
1189 0 : to+= length;
1190 : }
1191 0 : if (packed_length != (uint) (to - rec_buff) +
1192 : test(info->s->calc_checksum) || (bit != 1 && (flag & ~(bit - 1))))
1193 : goto err;
1194 0 : if (with_checksum && ((uchar) checksum != (uchar) *to))
1195 : {
1196 0 : DBUG_PRINT("error",("wrong checksum for row"));
1197 0 : goto err;
1198 : }
1199 0 : DBUG_RETURN(0);
1200 :
1201 0 : err:
1202 0 : DBUG_RETURN(1);
1203 : }
1204 :
1205 :
1206 : /*
1207 : @brief Unpacks a record
1208 :
1209 : @return Recordlength
1210 : @retval >0 ok
1211 : @retval MY_FILE_ERROR (== -1) Error.
1212 : my_errno is set to HA_ERR_WRONG_IN_RECORD
1213 : */
1214 :
1215 : ulong _ma_rec_unpack(register MARIA_HA *info, register uchar *to, uchar *from,
1216 : ulong found_length)
1217 0 : {
1218 : uint flag,bit,length,min_pack_length, column_length;
1219 : enum en_fieldtype type;
1220 : uchar *from_end,*to_end,*packpos;
1221 : reg3 MARIA_COLUMNDEF *column, *end_column;
1222 0 : DBUG_ENTER("_ma_rec_unpack");
1223 :
1224 0 : to_end=to + info->s->base.reclength;
1225 0 : from_end=from+found_length;
1226 0 : flag= (uchar) *from; bit=1; packpos=from;
1227 0 : if (found_length < info->s->base.min_pack_length)
1228 0 : goto err;
1229 0 : from+= info->s->base.pack_bytes;
1230 0 : min_pack_length= info->s->base.min_pack_length - info->s->base.pack_bytes;
1231 :
1232 0 : if ((length= info->s->base.null_bytes))
1233 : {
1234 0 : memcpy(to, from, length);
1235 0 : from+= length;
1236 0 : to+= length;
1237 0 : min_pack_length-= length;
1238 : }
1239 :
1240 0 : for (column= info->s->columndef, end_column= column + info->s->base.fields;
1241 0 : column < end_column ; to+= column_length, column++)
1242 : {
1243 0 : column_length= column->length;
1244 0 : if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL &&
1245 : (type != FIELD_CHECK))
1246 : {
1247 0 : if (type == FIELD_VARCHAR)
1248 : {
1249 0 : uint pack_length= HA_VARCHAR_PACKLENGTH(column_length-1);
1250 0 : if (pack_length == 1)
1251 : {
1252 0 : length= (uint) *(uchar*) from;
1253 0 : if (length > column_length-1)
1254 0 : goto err;
1255 0 : *to= *from++;
1256 : }
1257 : else
1258 : {
1259 0 : get_key_length(length, from);
1260 0 : if (length > column_length-2)
1261 0 : goto err;
1262 0 : int2store(to,length);
1263 : }
1264 0 : if (from+length > from_end)
1265 0 : goto err;
1266 0 : memcpy(to+pack_length, from, length);
1267 0 : from+= length;
1268 0 : min_pack_length--;
1269 0 : continue;
1270 : }
1271 0 : if (flag & bit)
1272 : {
1273 0 : if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
1274 0 : bzero(to, column_length);
1275 0 : else if (type == FIELD_SKIP_ENDSPACE ||
1276 : type == FIELD_SKIP_PRESPACE)
1277 : {
1278 0 : if (column->length > 255 && *from & 128)
1279 : {
1280 0 : if (from + 1 >= from_end)
1281 0 : goto err;
1282 0 : length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
1283 : }
1284 : else
1285 : {
1286 0 : if (from == from_end)
1287 0 : goto err;
1288 0 : length= (uchar) *from++;
1289 : }
1290 0 : min_pack_length--;
1291 0 : if (length >= column_length ||
1292 : min_pack_length + length > (uint) (from_end - from))
1293 : goto err;
1294 0 : if (type == FIELD_SKIP_ENDSPACE)
1295 : {
1296 0 : memcpy(to, from, (size_t) length);
1297 0 : bfill(to+length, column_length-length, ' ');
1298 : }
1299 : else
1300 : {
1301 0 : bfill(to, column_length-length, ' ');
1302 0 : memcpy(to+column_length-length, from, (size_t) length);
1303 : }
1304 0 : from+=length;
1305 : }
1306 : }
1307 0 : else if (type == FIELD_BLOB)
1308 : {
1309 0 : uint size_length=column_length- portable_sizeof_char_ptr;
1310 0 : ulong blob_length= _ma_calc_blob_length(size_length,from);
1311 0 : ulong from_left= (ulong) (from_end - from);
1312 0 : if (from_left < size_length ||
1313 : from_left - size_length < blob_length ||
1314 : from_left - size_length - blob_length < min_pack_length)
1315 : goto err;
1316 0 : memcpy(to, from, (size_t) size_length);
1317 0 : from+=size_length;
1318 0 : memcpy_fixed(to+size_length,(uchar*) &from,sizeof(char*));
1319 0 : from+=blob_length;
1320 : }
1321 : else
1322 : {
1323 0 : if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
1324 0 : min_pack_length--;
1325 0 : if (min_pack_length + column_length > (uint) (from_end - from))
1326 0 : goto err;
1327 0 : memcpy(to, from, (size_t) column_length); from+=column_length;
1328 : }
1329 0 : if ((bit= bit << 1) >= 256)
1330 : {
1331 0 : flag= (uchar) *++packpos; bit=1;
1332 : }
1333 : }
1334 : else
1335 : {
1336 0 : if (min_pack_length > (uint) (from_end - from))
1337 0 : goto err;
1338 0 : min_pack_length-=column_length;
1339 0 : memcpy(to, from, (size_t) column_length);
1340 0 : from+=column_length;
1341 : }
1342 : }
1343 0 : if (info->s->calc_checksum)
1344 0 : info->cur_row.checksum= (uint) (uchar) *from++;
1345 0 : if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
1346 0 : DBUG_RETURN(found_length);
1347 :
1348 0 : err:
1349 0 : my_errno= HA_ERR_WRONG_IN_RECORD;
1350 0 : DBUG_PRINT("error",("to_end: 0x%lx -> 0x%lx from_end: 0x%lx -> 0x%lx",
1351 : (long) to, (long) to_end, (long) from, (long) from_end));
1352 0 : DBUG_DUMP("from", info->rec_buff, info->s->base.min_pack_length);
1353 0 : DBUG_RETURN(MY_FILE_ERROR);
1354 : } /* _ma_rec_unpack */
1355 :
1356 :
1357 : /* Calc length of blob. Update info in blobs->length */
1358 :
1359 : ulong _ma_calc_total_blob_length(MARIA_HA *info, const uchar *record)
1360 0 : {
1361 : ulong length;
1362 : MARIA_BLOB *blob,*end;
1363 :
1364 0 : for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
1365 0 : blob != end;
1366 0 : blob++)
1367 : {
1368 0 : blob->length= _ma_calc_blob_length(blob->pack_length,
1369 : record + blob->offset);
1370 0 : length+=blob->length;
1371 : }
1372 0 : return length;
1373 : }
1374 :
1375 :
1376 : ulong _ma_calc_blob_length(uint length, const uchar *pos)
1377 10969 : {
1378 10969 : switch (length) {
1379 : case 1:
1380 0 : return (uint) (uchar) *pos;
1381 : case 2:
1382 0 : return (uint) uint2korr(pos);
1383 : case 3:
1384 0 : return uint3korr(pos);
1385 : case 4:
1386 10969 : return uint4korr(pos);
1387 : default:
1388 : break;
1389 : }
1390 0 : return 0; /* Impossible */
1391 : }
1392 :
1393 :
1394 : void _ma_store_blob_length(uchar *pos,uint pack_length,uint length)
1395 0 : {
1396 0 : switch (pack_length) {
1397 : case 1:
1398 0 : *pos= (uchar) length;
1399 0 : break;
1400 : case 2:
1401 0 : int2store(pos,length);
1402 0 : break;
1403 : case 3:
1404 0 : int3store(pos,length);
1405 0 : break;
1406 : case 4:
1407 0 : int4store(pos,length);
1408 : default:
1409 : break;
1410 : }
1411 : return;
1412 : }
1413 :
1414 :
1415 : /*
1416 : Read record from datafile.
1417 :
1418 : SYNOPSIS
1419 : _ma_read_dynamic_record()
1420 : info MARIA_HA pointer to table.
1421 : filepos From where to read the record.
1422 : buf Destination for record.
1423 :
1424 : NOTE
1425 : If a write buffer is active, it needs to be flushed if its contents
1426 : intersects with the record to read. We always check if the position
1427 : of the first uchar of the write buffer is lower than the position
1428 : past the last uchar to read. In theory this is also true if the write
1429 : buffer is completely below the read segment. That is, if there is no
1430 : intersection. But this case is unusual. We flush anyway. Only if the
1431 : first uchar in the write buffer is above the last uchar to read, we do
1432 : not flush.
1433 :
1434 : A dynamic record may need several reads. So this check must be done
1435 : before every read. Reading a dynamic record starts with reading the
1436 : block header. If the record does not fit into the free space of the
1437 : header, the block may be longer than the header. In this case a
1438 : second read is necessary. These one or two reads repeat for every
1439 : part of the record.
1440 :
1441 : RETURN
1442 : 0 OK
1443 : # Error number
1444 : */
1445 :
1446 : int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf,
1447 : MARIA_RECORD_POS filepos)
1448 0 : {
1449 : int block_of_record;
1450 : uint b_type;
1451 : MARIA_BLOCK_INFO block_info;
1452 : File file;
1453 : uchar *to;
1454 : uint left_length;
1455 0 : DBUG_ENTER("_ma_read_dynamic_record");
1456 :
1457 0 : if (filepos == HA_OFFSET_ERROR)
1458 0 : goto err;
1459 :
1460 0 : LINT_INIT(to);
1461 0 : LINT_INIT(left_length);
1462 0 : file= info->dfile.file;
1463 0 : block_of_record= 0; /* First block of record is numbered as zero. */
1464 0 : block_info.second_read= 0;
1465 : do
1466 : {
1467 : /* A corrupted table can have wrong pointers. (Bug# 19835) */
1468 0 : if (filepos == HA_OFFSET_ERROR)
1469 0 : goto panic;
1470 0 : if (info->opt_flag & WRITE_CACHE_USED &&
1471 : (info->rec_cache.pos_in_file < filepos +
1472 : MARIA_BLOCK_INFO_HEADER_LENGTH) &&
1473 : flush_io_cache(&info->rec_cache))
1474 0 : goto err;
1475 0 : info->rec_cache.seek_not_done=1;
1476 0 : if ((b_type= _ma_get_block_info(&block_info, file, filepos)) &
1477 : (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1478 : BLOCK_FATAL_ERROR))
1479 : {
1480 0 : if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1481 0 : my_errno=HA_ERR_RECORD_DELETED;
1482 : goto err;
1483 : }
1484 0 : if (block_of_record++ == 0) /* First block */
1485 : {
1486 0 : info->cur_row.total_length= block_info.rec_len;
1487 0 : if (block_info.rec_len > (uint) info->s->base.max_pack_length)
1488 0 : goto panic;
1489 0 : if (info->s->base.blobs)
1490 : {
1491 0 : if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
1492 : block_info.rec_len +
1493 : info->s->base.extra_rec_buff_size))
1494 0 : goto err;
1495 : }
1496 0 : to= info->rec_buff;
1497 0 : left_length=block_info.rec_len;
1498 : }
1499 0 : if (left_length < block_info.data_len || ! block_info.data_len)
1500 : goto panic; /* Wrong linked record */
1501 : /* copy information that is already read */
1502 : {
1503 0 : uint offset= (uint) (block_info.filepos - filepos);
1504 0 : uint prefetch_len= (sizeof(block_info.header) - offset);
1505 0 : filepos+= sizeof(block_info.header);
1506 :
1507 0 : if (prefetch_len > block_info.data_len)
1508 0 : prefetch_len= block_info.data_len;
1509 0 : if (prefetch_len)
1510 : {
1511 0 : memcpy(to, block_info.header + offset, prefetch_len);
1512 0 : block_info.data_len-= prefetch_len;
1513 0 : left_length-= prefetch_len;
1514 0 : to+= prefetch_len;
1515 : }
1516 : }
1517 : /* read rest of record from file */
1518 0 : if (block_info.data_len)
1519 : {
1520 0 : if (info->opt_flag & WRITE_CACHE_USED &&
1521 : info->rec_cache.pos_in_file < filepos + block_info.data_len &&
1522 : flush_io_cache(&info->rec_cache))
1523 0 : goto err;
1524 : /*
1525 : What a pity that this method is not called 'file_pread' and that
1526 : there is no equivalent without seeking. We are at the right
1527 : position already. :(
1528 : */
1529 0 : if (info->s->file_read(info, to, block_info.data_len,
1530 : filepos, MYF(MY_NABP)))
1531 0 : goto panic;
1532 0 : left_length-=block_info.data_len;
1533 0 : to+=block_info.data_len;
1534 : }
1535 0 : filepos= block_info.next_filepos;
1536 0 : } while (left_length);
1537 :
1538 0 : info->update|= HA_STATE_AKTIV; /* We have a aktive record */
1539 0 : fast_ma_writeinfo(info);
1540 0 : DBUG_RETURN(_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1541 : MY_FILE_ERROR ? 0 : my_errno);
1542 :
1543 0 : err:
1544 0 : fast_ma_writeinfo(info);
1545 0 : DBUG_RETURN(my_errno);
1546 :
1547 0 : panic:
1548 0 : my_errno=HA_ERR_WRONG_IN_RECORD;
1549 0 : goto err;
1550 : }
1551 :
1552 : /* compare unique constraint between stored rows */
1553 :
1554 : my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
1555 : const uchar *record, MARIA_RECORD_POS pos)
1556 0 : {
1557 : uchar *old_rec_buff,*old_record;
1558 : size_t old_rec_buff_size;
1559 : my_bool error;
1560 0 : DBUG_ENTER("_ma_cmp_dynamic_unique");
1561 :
1562 0 : if (!(old_record=my_alloca(info->s->base.reclength)))
1563 0 : DBUG_RETURN(1);
1564 :
1565 : /* Don't let the compare destroy blobs that may be in use */
1566 0 : old_rec_buff= info->rec_buff;
1567 0 : old_rec_buff_size= info->rec_buff_size;
1568 :
1569 0 : if (info->s->base.blobs)
1570 : {
1571 0 : info->rec_buff= 0;
1572 0 : info->rec_buff_size= 0;
1573 : }
1574 0 : error= _ma_read_dynamic_record(info, old_record, pos) != 0;
1575 0 : if (!error)
1576 0 : error=_ma_unique_comp(def, record, old_record, def->null_are_equal) != 0;
1577 0 : if (info->s->base.blobs)
1578 : {
1579 0 : my_free(info->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
1580 0 : info->rec_buff= old_rec_buff;
1581 0 : info->rec_buff_size= old_rec_buff_size;
1582 : }
1583 0 : my_afree(old_record);
1584 0 : DBUG_RETURN(error);
1585 : }
1586 :
1587 :
1588 : /* Compare of record on disk with packed record in memory */
1589 :
1590 : my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
1591 : register const uchar *record)
1592 0 : {
1593 : uint flag, reclength, b_type,cmp_length;
1594 : my_off_t filepos;
1595 : uchar *buffer;
1596 : MARIA_BLOCK_INFO block_info;
1597 0 : my_bool error= 1;
1598 0 : DBUG_ENTER("_ma_cmp_dynamic_record");
1599 :
1600 : /* We are going to do changes; dont let anybody disturb */
1601 : dont_break(); /* Dont allow SIGHUP or SIGINT */
1602 :
1603 0 : if (info->opt_flag & WRITE_CACHE_USED)
1604 : {
1605 0 : info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
1606 0 : if (flush_io_cache(&info->rec_cache))
1607 0 : DBUG_RETURN(1);
1608 : }
1609 0 : info->rec_cache.seek_not_done=1;
1610 :
1611 : /* If nobody have touched the database we don't have to test rec */
1612 :
1613 0 : buffer=info->rec_buff;
1614 0 : if ((info->opt_flag & READ_CHECK_USED))
1615 : { /* If check isn't disabled */
1616 0 : if (info->s->base.blobs)
1617 : {
1618 0 : if (!(buffer=(uchar*) my_alloca(info->s->base.pack_reclength+
1619 : _ma_calc_total_blob_length(info,record))))
1620 0 : DBUG_RETURN(1);
1621 : }
1622 0 : reclength= _ma_rec_pack(info,buffer,record);
1623 0 : record= buffer;
1624 :
1625 0 : filepos= info->cur_row.lastpos;
1626 0 : flag=block_info.second_read=0;
1627 0 : block_info.next_filepos=filepos;
1628 0 : while (reclength > 0)
1629 : {
1630 0 : if ((b_type= _ma_get_block_info(&block_info, info->dfile.file,
1631 : block_info.next_filepos))
1632 : & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1633 : BLOCK_FATAL_ERROR))
1634 : {
1635 0 : if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1636 0 : my_errno=HA_ERR_RECORD_CHANGED;
1637 : goto err;
1638 : }
1639 0 : if (flag == 0) /* First block */
1640 : {
1641 0 : flag=1;
1642 0 : if (reclength != block_info.rec_len)
1643 : {
1644 0 : my_errno=HA_ERR_RECORD_CHANGED;
1645 0 : goto err;
1646 : }
1647 0 : } else if (reclength < block_info.data_len)
1648 : {
1649 0 : my_errno=HA_ERR_WRONG_IN_RECORD;
1650 0 : goto err;
1651 : }
1652 0 : reclength-= block_info.data_len;
1653 0 : cmp_length= block_info.data_len;
1654 0 : if (!reclength && info->s->calc_checksum)
1655 0 : cmp_length--; /* 'record' may not contain checksum */
1656 :
1657 0 : if (_ma_cmp_buffer(info->dfile.file, record, block_info.filepos,
1658 : cmp_length))
1659 : {
1660 0 : my_errno=HA_ERR_RECORD_CHANGED;
1661 0 : goto err;
1662 : }
1663 0 : flag=1;
1664 0 : record+=block_info.data_len;
1665 : }
1666 : }
1667 0 : my_errno=0;
1668 0 : error= 0;
1669 0 : err:
1670 0 : if (buffer != info->rec_buff)
1671 0 : my_afree(buffer);
1672 0 : DBUG_PRINT("exit", ("result: %d", error));
1673 0 : DBUG_RETURN(error);
1674 : }
1675 :
1676 :
1677 : /* Compare file to buffert */
1678 :
1679 : static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
1680 : uint length)
1681 0 : {
1682 : uint next_length;
1683 : uchar temp_buff[IO_SIZE*2];
1684 0 : DBUG_ENTER("_ma_cmp_buffer");
1685 :
1686 0 : next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
1687 :
1688 0 : while (length > IO_SIZE*2)
1689 : {
1690 0 : if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
1691 : memcmp(buff, temp_buff, next_length))
1692 : goto err;
1693 0 : filepos+=next_length;
1694 0 : buff+=next_length;
1695 0 : length-= next_length;
1696 0 : next_length=IO_SIZE*2;
1697 : }
1698 0 : if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
1699 0 : goto err;
1700 0 : DBUG_RETURN(memcmp(buff, temp_buff, length) != 0);
1701 0 : err:
1702 0 : DBUG_RETURN(1);
1703 : }
1704 :
1705 :
1706 : /*
1707 : Read next record from datafile during table scan.
1708 :
1709 : SYNOPSIS
1710 : _ma_read_rnd_dynamic_record()
1711 : info MARIA_HA pointer to table.
1712 : buf Destination for record.
1713 : filepos From where to read the record.
1714 : skip_deleted_blocks If to repeat reading until a non-deleted
1715 : record is found.
1716 :
1717 : NOTE
1718 : This is identical to _ma_read_dynamic_record(), except the following
1719 : cases:
1720 :
1721 : - If there is no active row at 'filepos', continue scanning for
1722 : an active row. (This is becasue the previous
1723 : _ma_read_rnd_dynamic_record() call stored the next block position
1724 : in filepos, but this position may not be a start block for a row
1725 : - We may have READ_CACHING enabled, in which case we use the cache
1726 : to read rows.
1727 :
1728 : For other comments, check _ma_read_dynamic_record()
1729 :
1730 : RETURN
1731 : 0 OK
1732 : != 0 Error number
1733 : */
1734 :
1735 : int _ma_read_rnd_dynamic_record(MARIA_HA *info,
1736 : uchar *buf,
1737 : MARIA_RECORD_POS filepos,
1738 : my_bool skip_deleted_blocks)
1739 0 : {
1740 : int block_of_record, info_read;
1741 : uint left_len,b_type;
1742 : uchar *to;
1743 : MARIA_BLOCK_INFO block_info;
1744 0 : MARIA_SHARE *share= info->s;
1745 0 : DBUG_ENTER("_ma_read_rnd_dynamic_record");
1746 :
1747 0 : info_read=0;
1748 0 : LINT_INIT(to);
1749 :
1750 0 : if (info->lock_type == F_UNLCK)
1751 : {
1752 : #ifndef UNSAFE_LOCKING
1753 : #else
1754 : info->tmp_lock_type=F_RDLCK;
1755 : #endif
1756 : }
1757 : else
1758 0 : info_read=1; /* memory-keyinfoblock is ok */
1759 :
1760 0 : block_of_record= 0; /* First block of record is numbered as zero. */
1761 0 : block_info.second_read= 0;
1762 0 : left_len=1;
1763 : do
1764 : {
1765 0 : if (filepos >= info->state->data_file_length)
1766 : {
1767 0 : if (!info_read)
1768 : { /* Check if changed */
1769 0 : info_read=1;
1770 0 : info->rec_cache.seek_not_done=1;
1771 0 : if (_ma_state_info_read_dsk(share->kfile.file, &share->state))
1772 0 : goto panic;
1773 : }
1774 0 : if (filepos >= info->state->data_file_length)
1775 : {
1776 0 : my_errno= HA_ERR_END_OF_FILE;
1777 0 : goto err;
1778 : }
1779 : }
1780 0 : if (info->opt_flag & READ_CACHE_USED)
1781 : {
1782 0 : if (_ma_read_cache(&info->rec_cache, block_info.header, filepos,
1783 : sizeof(block_info.header),
1784 : (!block_of_record && skip_deleted_blocks ?
1785 : READING_NEXT : 0) | READING_HEADER))
1786 0 : goto panic;
1787 0 : b_type= _ma_get_block_info(&block_info,-1,filepos);
1788 : }
1789 : else
1790 : {
1791 0 : if (info->opt_flag & WRITE_CACHE_USED &&
1792 : info->rec_cache.pos_in_file < filepos + MARIA_BLOCK_INFO_HEADER_LENGTH &&
1793 : flush_io_cache(&info->rec_cache))
1794 0 : DBUG_RETURN(my_errno);
1795 0 : info->rec_cache.seek_not_done=1;
1796 0 : b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos);
1797 : }
1798 :
1799 0 : if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1800 : BLOCK_FATAL_ERROR))
1801 : {
1802 0 : if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1803 : && skip_deleted_blocks)
1804 : {
1805 0 : filepos=block_info.filepos+block_info.block_len;
1806 0 : block_info.second_read=0;
1807 0 : continue; /* Search after next_record */
1808 : }
1809 0 : if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1810 : {
1811 0 : my_errno= HA_ERR_RECORD_DELETED;
1812 0 : info->cur_row.lastpos= block_info.filepos;
1813 0 : info->cur_row.nextpos= block_info.filepos+block_info.block_len;
1814 : }
1815 : goto err;
1816 : }
1817 0 : if (block_of_record == 0) /* First block */
1818 : {
1819 0 : info->cur_row.total_length= block_info.rec_len;
1820 0 : if (block_info.rec_len > (uint) share->base.max_pack_length)
1821 0 : goto panic;
1822 0 : info->cur_row.lastpos= filepos;
1823 0 : if (share->base.blobs)
1824 : {
1825 0 : if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
1826 : block_info.rec_len +
1827 : info->s->base.extra_rec_buff_size))
1828 0 : goto err;
1829 : }
1830 0 : to= info->rec_buff;
1831 0 : left_len=block_info.rec_len;
1832 : }
1833 0 : if (left_len < block_info.data_len)
1834 0 : goto panic; /* Wrong linked record */
1835 :
1836 : /* copy information that is already read */
1837 : {
1838 0 : uint offset=(uint) (block_info.filepos - filepos);
1839 0 : uint tmp_length= (sizeof(block_info.header) - offset);
1840 0 : filepos=block_info.filepos;
1841 :
1842 0 : if (tmp_length > block_info.data_len)
1843 0 : tmp_length= block_info.data_len;
1844 0 : if (tmp_length)
1845 : {
1846 0 : memcpy(to, block_info.header+offset, tmp_length);
1847 0 : block_info.data_len-=tmp_length;
1848 0 : left_len-=tmp_length;
1849 0 : to+=tmp_length;
1850 0 : filepos+=tmp_length;
1851 : }
1852 : }
1853 : /* read rest of record from file */
1854 0 : if (block_info.data_len)
1855 : {
1856 0 : if (info->opt_flag & READ_CACHE_USED)
1857 : {
1858 0 : if (_ma_read_cache(&info->rec_cache, to,filepos,
1859 : block_info.data_len,
1860 : (!block_of_record && skip_deleted_blocks) ?
1861 : READING_NEXT : 0))
1862 : goto panic;
1863 : }
1864 : else
1865 : {
1866 0 : if (info->opt_flag & WRITE_CACHE_USED &&
1867 : info->rec_cache.pos_in_file <
1868 : block_info.filepos + block_info.data_len &&
1869 : flush_io_cache(&info->rec_cache))
1870 0 : goto err;
1871 : /* VOID(my_seek(info->dfile.file, filepos, MY_SEEK_SET, MYF(0))); */
1872 0 : if (my_read(info->dfile.file, to, block_info.data_len, MYF(MY_NABP)))
1873 : {
1874 0 : if (my_errno == HA_ERR_FILE_TOO_SHORT)
1875 0 : my_errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
1876 : goto err;
1877 : }
1878 : }
1879 : }
1880 : /*
1881 : Increment block-of-record counter. If it was the first block,
1882 : remember the position behind the block for the next call.
1883 : */
1884 0 : if (block_of_record++ == 0)
1885 : {
1886 0 : info->cur_row.nextpos= block_info.filepos+block_info.block_len;
1887 0 : skip_deleted_blocks=0;
1888 : }
1889 0 : left_len-=block_info.data_len;
1890 0 : to+=block_info.data_len;
1891 0 : filepos=block_info.next_filepos;
1892 0 : } while (left_len);
1893 :
1894 0 : info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
1895 0 : fast_ma_writeinfo(info);
1896 0 : if (_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1897 : MY_FILE_ERROR)
1898 0 : DBUG_RETURN(0);
1899 0 : DBUG_RETURN(my_errno); /* Wrong record */
1900 :
1901 0 : panic:
1902 0 : my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
1903 0 : err:
1904 0 : fast_ma_writeinfo(info);
1905 0 : DBUG_RETURN(my_errno);
1906 : }
1907 :
1908 :
1909 : /* Read and process header from a dynamic-record-file */
1910 :
1911 : uint _ma_get_block_info(MARIA_BLOCK_INFO *info, File file, my_off_t filepos)
1912 0 : {
1913 0 : uint return_val=0;
1914 0 : uchar *header=info->header;
1915 :
1916 0 : if (file >= 0)
1917 : {
1918 : /*
1919 : We do not use my_pread() here because we want to have the file
1920 : pointer set to the end of the header after this function.
1921 : my_pread() may leave the file pointer untouched.
1922 : */
1923 0 : VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
1924 0 : if (my_read(file, header, sizeof(info->header),MYF(0)) !=
1925 : sizeof(info->header))
1926 0 : goto err;
1927 : }
1928 0 : DBUG_DUMP("header",header,MARIA_BLOCK_INFO_HEADER_LENGTH);
1929 0 : if (info->second_read)
1930 : {
1931 0 : if (info->header[0] <= 6 || info->header[0] == 13)
1932 0 : return_val=BLOCK_SYNC_ERROR;
1933 : }
1934 : else
1935 : {
1936 0 : if (info->header[0] > 6 && info->header[0] != 13)
1937 0 : return_val=BLOCK_SYNC_ERROR;
1938 : }
1939 0 : info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
1940 :
1941 0 : switch (info->header[0]) {
1942 : case 0:
1943 0 : if ((info->block_len=(uint) mi_uint3korr(header+1)) <
1944 : MARIA_MIN_BLOCK_LENGTH ||
1945 : (info->block_len & (MARIA_DYN_ALIGN_SIZE -1)))
1946 : goto err;
1947 0 : info->filepos=filepos;
1948 0 : info->next_filepos=mi_sizekorr(header+4);
1949 0 : info->prev_filepos=mi_sizekorr(header+12);
1950 : #if SIZEOF_OFF_T == 4
1951 : if ((mi_uint4korr(header+4) != 0 &&
1952 : (mi_uint4korr(header+4) != (ulong) ~0 ||
1953 : info->next_filepos != (ulong) ~0)) ||
1954 : (mi_uint4korr(header+12) != 0 &&
1955 : (mi_uint4korr(header+12) != (ulong) ~0 ||
1956 : info->prev_filepos != (ulong) ~0)))
1957 : goto err;
1958 : #endif
1959 0 : return return_val | BLOCK_DELETED; /* Deleted block */
1960 :
1961 : case 1:
1962 0 : info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
1963 0 : info->filepos=filepos+3;
1964 0 : return return_val | BLOCK_FIRST | BLOCK_LAST;
1965 : case 2:
1966 0 : info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
1967 0 : info->filepos=filepos+4;
1968 0 : return return_val | BLOCK_FIRST | BLOCK_LAST;
1969 :
1970 : case 13:
1971 0 : info->rec_len=mi_uint4korr(header+1);
1972 0 : info->block_len=info->data_len=mi_uint3korr(header+5);
1973 0 : info->next_filepos=mi_sizekorr(header+8);
1974 0 : info->second_read=1;
1975 0 : info->filepos=filepos+16;
1976 0 : return return_val | BLOCK_FIRST;
1977 :
1978 : case 3:
1979 0 : info->rec_len=info->data_len=mi_uint2korr(header+1);
1980 0 : info->block_len=info->rec_len+ (uint) header[3];
1981 0 : info->filepos=filepos+4;
1982 0 : return return_val | BLOCK_FIRST | BLOCK_LAST;
1983 : case 4:
1984 0 : info->rec_len=info->data_len=mi_uint3korr(header+1);
1985 0 : info->block_len=info->rec_len+ (uint) header[4];
1986 0 : info->filepos=filepos+5;
1987 0 : return return_val | BLOCK_FIRST | BLOCK_LAST;
1988 :
1989 : case 5:
1990 0 : info->rec_len=mi_uint2korr(header+1);
1991 0 : info->block_len=info->data_len=mi_uint2korr(header+3);
1992 0 : info->next_filepos=mi_sizekorr(header+5);
1993 0 : info->second_read=1;
1994 0 : info->filepos=filepos+13;
1995 0 : return return_val | BLOCK_FIRST;
1996 : case 6:
1997 0 : info->rec_len=mi_uint3korr(header+1);
1998 0 : info->block_len=info->data_len=mi_uint3korr(header+4);
1999 0 : info->next_filepos=mi_sizekorr(header+7);
2000 0 : info->second_read=1;
2001 0 : info->filepos=filepos+15;
2002 0 : return return_val | BLOCK_FIRST;
2003 :
2004 : /* The following blocks are identical to 1-6 without rec_len */
2005 : case 7:
2006 0 : info->data_len=info->block_len=mi_uint2korr(header+1);
2007 0 : info->filepos=filepos+3;
2008 0 : return return_val | BLOCK_LAST;
2009 : case 8:
2010 0 : info->data_len=info->block_len=mi_uint3korr(header+1);
2011 0 : info->filepos=filepos+4;
2012 0 : return return_val | BLOCK_LAST;
2013 :
2014 : case 9:
2015 0 : info->data_len=mi_uint2korr(header+1);
2016 0 : info->block_len=info->data_len+ (uint) header[3];
2017 0 : info->filepos=filepos+4;
2018 0 : return return_val | BLOCK_LAST;
2019 : case 10:
2020 0 : info->data_len=mi_uint3korr(header+1);
2021 0 : info->block_len=info->data_len+ (uint) header[4];
2022 0 : info->filepos=filepos+5;
2023 0 : return return_val | BLOCK_LAST;
2024 :
2025 : case 11:
2026 0 : info->data_len=info->block_len=mi_uint2korr(header+1);
2027 0 : info->next_filepos=mi_sizekorr(header+3);
2028 0 : info->second_read=1;
2029 0 : info->filepos=filepos+11;
2030 0 : return return_val;
2031 : case 12:
2032 0 : info->data_len=info->block_len=mi_uint3korr(header+1);
2033 0 : info->next_filepos=mi_sizekorr(header+4);
2034 0 : info->second_read=1;
2035 0 : info->filepos=filepos+12;
2036 0 : return return_val;
2037 : }
2038 :
2039 0 : err:
2040 0 : my_errno=HA_ERR_WRONG_IN_RECORD; /* Garbage */
2041 0 : return BLOCK_ERROR;
2042 : }
|