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