00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "myisam_priv.h"
00027
00028 #ifdef HAVE_SYS_TYPES
00029 #include <sys/types.h>
00030 #endif
00031 #ifdef HAVE_SYS_MMAN_H
00032 #include <sys/mman.h>
00033 #endif
00034 #include <drizzled/util/test.h>
00035 #include <drizzled/error.h>
00036
00037 #include <cassert>
00038 #include <algorithm>
00039
00040 using namespace drizzled;
00041 using namespace std;
00042
00043
00044 static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
00045
00046 static int write_dynamic_record(MI_INFO *info,const unsigned char *record,
00047 ulong reclength);
00048 static int _mi_find_writepos(MI_INFO *info,ulong reclength,internal::my_off_t *filepos,
00049 ulong *length);
00050 static int update_dynamic_record(MI_INFO *info,internal::my_off_t filepos,unsigned char *record,
00051 ulong reclength);
00052 static int delete_dynamic_record(MI_INFO *info,internal::my_off_t filepos,
00053 uint32_t second_read);
00054 static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
00055 uint32_t length);
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072 bool mi_dynmap_file(MI_INFO *info, internal::my_off_t size)
00073 {
00074 if (size > (internal::my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
00075 {
00076 return(1);
00077 }
00078
00079
00080
00081
00082
00083
00084
00085
00086 info->s->file_map= (unsigned char*)
00087 mmap(NULL, (size_t)(size + MEMMAP_EXTRA_MARGIN),
00088 info->s->mode==O_RDONLY ? PROT_READ :
00089 PROT_READ | PROT_WRITE,
00090 MAP_SHARED | MAP_NORESERVE,
00091 info->dfile, 0L);
00092 if (info->s->file_map == (unsigned char*) MAP_FAILED)
00093 {
00094 info->s->file_map= NULL;
00095 return(1);
00096 }
00097
00098 #if !defined(TARGET_OS_SOLARIS)
00099 madvise((char*) info->s->file_map, size, MADV_RANDOM);
00100 #endif
00101 info->s->mmaped_length= size;
00102 return(0);
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 void mi_remap_file(MI_INFO *info, internal::my_off_t size)
00117 {
00118 if (info->s->file_map)
00119 {
00120 munmap((char*) info->s->file_map,
00121 (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN);
00122 mi_dynmap_file(info, size);
00123 }
00124 }
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 size_t mi_mmap_pread(MI_INFO *info, unsigned char *Buffer,
00143 size_t Count, internal::my_off_t offset, myf MyFlags)
00144 {
00145
00146
00147
00148
00149
00150
00151
00152 if (info->s->mmaped_length >= offset + Count)
00153 {
00154 memcpy(Buffer, info->s->file_map + offset, Count);
00155 return 0;
00156 }
00157 else
00158 {
00159 return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
00160 }
00161 }
00162
00163
00164
00165
00166 size_t mi_nommap_pread(MI_INFO *info, unsigned char *Buffer,
00167 size_t Count, internal::my_off_t offset, myf MyFlags)
00168 {
00169 return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
00170 }
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 size_t mi_mmap_pwrite(MI_INFO *info, const unsigned char *Buffer,
00190 size_t Count, internal::my_off_t offset, myf MyFlags)
00191 {
00192
00193
00194
00195
00196
00197
00198
00199
00200 if (info->s->mmaped_length >= offset + Count)
00201 {
00202 memcpy(info->s->file_map + offset, Buffer, Count);
00203 return 0;
00204 }
00205 else
00206 {
00207 info->s->nonmmaped_inserts++;
00208 return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
00209 }
00210
00211 }
00212
00213
00214
00215
00216 size_t mi_nommap_pwrite(MI_INFO *info, const unsigned char *Buffer,
00217 size_t Count, internal::my_off_t offset, myf MyFlags)
00218 {
00219 return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
00220 }
00221
00222
00223 int _mi_write_dynamic_record(MI_INFO *info, const unsigned char *record)
00224 {
00225 ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
00226 return (write_dynamic_record(info,info->rec_buff,reclength));
00227 }
00228
00229 int _mi_update_dynamic_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
00230 {
00231 uint32_t length=_mi_rec_pack(info,info->rec_buff,record);
00232 return (update_dynamic_record(info,pos,info->rec_buff,length));
00233 }
00234
00235 int _mi_write_blob_record(MI_INFO *info, const unsigned char *record)
00236 {
00237 unsigned char *rec_buff;
00238 int error;
00239 ulong reclength,reclength2,extra;
00240
00241 extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
00242 MI_DYN_DELETE_BLOCK_HEADER+1);
00243 reclength= (info->s->base.pack_reclength +
00244 _my_calc_total_blob_length(info,record)+ extra);
00245 #ifdef NOT_USED
00246 if (reclength > MI_DYN_MAX_ROW_LENGTH)
00247 {
00248 errno=HA_ERR_TO_BIG_ROW;
00249 return -1;
00250 }
00251 #endif
00252 if (!(rec_buff=(unsigned char*) malloc(reclength)))
00253 {
00254 errno= HA_ERR_OUT_OF_MEM;
00255 return(-1);
00256 }
00257 reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
00258 record);
00259 assert(reclength2 <= reclength);
00260 error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
00261 reclength2);
00262 free(rec_buff);
00263 return(error);
00264 }
00265
00266
00267 int _mi_update_blob_record(MI_INFO *info, internal::my_off_t pos, const unsigned char *record)
00268 {
00269 unsigned char *rec_buff;
00270 int error;
00271 ulong reclength,extra;
00272
00273 extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
00274 MI_DYN_DELETE_BLOCK_HEADER);
00275 reclength= (info->s->base.pack_reclength+
00276 _my_calc_total_blob_length(info,record)+ extra);
00277 #ifdef NOT_USED
00278 if (reclength > MI_DYN_MAX_ROW_LENGTH)
00279 {
00280 errno=HA_ERR_TO_BIG_ROW;
00281 return -1;
00282 }
00283 #endif
00284 if (!(rec_buff=(unsigned char*) malloc(reclength)))
00285 {
00286 errno= HA_ERR_OUT_OF_MEM;
00287 return(-1);
00288 }
00289 reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
00290 record);
00291 error=update_dynamic_record(info,pos,
00292 rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
00293 reclength);
00294 free(rec_buff);
00295 return(error);
00296 }
00297
00298
00299 int _mi_delete_dynamic_record(MI_INFO *info)
00300 {
00301 return delete_dynamic_record(info,info->lastpos,0);
00302 }
00303
00304
00305
00306
00307 static int write_dynamic_record(MI_INFO *info, const unsigned char *record,
00308 ulong reclength)
00309 {
00310 int flag;
00311 ulong length;
00312 internal::my_off_t filepos;
00313
00314 flag=0;
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325 if (unlikely(info->s->base.max_data_file_length -
00326 info->state->data_file_length <
00327 reclength + MI_MAX_DYN_BLOCK_HEADER))
00328 {
00329 if (info->s->base.max_data_file_length - info->state->data_file_length +
00330 info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
00331 reclength + MI_MAX_DYN_BLOCK_HEADER)
00332 {
00333 errno=HA_ERR_RECORD_FILE_FULL;
00334 return(1);
00335 }
00336 }
00337
00338 do
00339 {
00340 if (_mi_find_writepos(info,reclength,&filepos,&length))
00341 goto err;
00342 if (_mi_write_part_record(info,filepos,length,
00343 (info->append_insert_at_end ?
00344 HA_OFFSET_ERROR : info->s->state.dellink),
00345 (unsigned char**) &record,&reclength,&flag))
00346 goto err;
00347 } while (reclength);
00348
00349 return(0);
00350 err:
00351 return(1);
00352 }
00353
00354
00355
00356
00357 static int _mi_find_writepos(MI_INFO *info,
00358 ulong reclength,
00359 internal::my_off_t *filepos,
00360 ulong *length)
00361 {
00362 MI_BLOCK_INFO block_info;
00363 ulong tmp;
00364
00365 if (info->s->state.dellink != HA_OFFSET_ERROR &&
00366 !info->append_insert_at_end)
00367 {
00368
00369 *filepos=info->s->state.dellink;
00370 block_info.second_read=0;
00371 info->rec_cache.seek_not_done=1;
00372 if (!(_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
00373 BLOCK_DELETED))
00374 {
00375 errno=HA_ERR_WRONG_IN_RECORD;
00376 return(-1);
00377 }
00378 info->s->state.dellink=block_info.next_filepos;
00379 info->state->del--;
00380 info->state->empty-= block_info.block_len;
00381 *length= block_info.block_len;
00382 }
00383 else
00384 {
00385
00386 *filepos=info->state->data_file_length;
00387 if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
00388 info->s->base.min_block_length)
00389 tmp= info->s->base.min_block_length;
00390 else
00391 tmp= ((tmp+MI_DYN_ALIGN_SIZE-1) &
00392 (~ (ulong) (MI_DYN_ALIGN_SIZE-1)));
00393 if (info->state->data_file_length >
00394 (info->s->base.max_data_file_length - tmp))
00395 {
00396 errno=HA_ERR_RECORD_FILE_FULL;
00397 return(-1);
00398 }
00399 if (tmp > MI_MAX_BLOCK_LENGTH)
00400 tmp=MI_MAX_BLOCK_LENGTH;
00401 *length= tmp;
00402 info->state->data_file_length+= tmp;
00403 info->s->state.split++;
00404 info->update|=HA_STATE_WRITE_AT_END;
00405 }
00406 return(0);
00407 }
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 static bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info)
00418 {
00419 if (block_info->filepos == info->s->state.dellink)
00420 {
00421
00422 info->s->state.dellink=block_info->next_filepos;
00423 }
00424 else
00425 {
00426 MI_BLOCK_INFO tmp;
00427 tmp.second_read=0;
00428
00429 if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
00430 & BLOCK_DELETED))
00431 return(1);
00432 mi_sizestore(tmp.header+4,block_info->next_filepos);
00433 if (info->s->file_write(info, tmp.header+4,8,
00434 block_info->prev_filepos+4, MYF(MY_NABP)))
00435 return(1);
00436
00437 if (block_info->next_filepos != HA_OFFSET_ERROR)
00438 {
00439 if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
00440 & BLOCK_DELETED))
00441 return(1);
00442 mi_sizestore(tmp.header+12,block_info->prev_filepos);
00443 if (info->s->file_write(info, tmp.header+12,8,
00444 block_info->next_filepos+12,
00445 MYF(MY_NABP)))
00446 return(1);
00447 }
00448 }
00449
00450 info->state->del--;
00451 info->state->empty-= block_info->block_len;
00452 info->s->state.split--;
00453
00454
00455
00456
00457
00458
00459 if (info->nextpos == block_info->filepos)
00460 info->nextpos+=block_info->block_len;
00461 return(0);
00462 }
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 static int update_backward_delete_link(MI_INFO *info, internal::my_off_t delete_block,
00481 internal::my_off_t filepos)
00482 {
00483 MI_BLOCK_INFO block_info;
00484
00485 if (delete_block != HA_OFFSET_ERROR)
00486 {
00487 block_info.second_read=0;
00488 if (_mi_get_block_info(&block_info,info->dfile,delete_block)
00489 & BLOCK_DELETED)
00490 {
00491 unsigned char buff[8];
00492 mi_sizestore(buff,filepos);
00493 if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
00494 return(1);
00495 }
00496 else
00497 {
00498 errno=HA_ERR_WRONG_IN_RECORD;
00499 return(1);
00500 }
00501 }
00502 return(0);
00503 }
00504
00505
00506
00507
00508 static int delete_dynamic_record(MI_INFO *info, internal::my_off_t filepos,
00509 uint32_t second_read)
00510 {
00511 uint32_t length,b_type;
00512 MI_BLOCK_INFO block_info,del_block;
00513 int error;
00514 bool remove_next_block;
00515
00516
00517 error= update_backward_delete_link(info, info->s->state.dellink, filepos);
00518
00519 block_info.second_read=second_read;
00520 do
00521 {
00522
00523 if ((b_type=_mi_get_block_info(&block_info,info->dfile,filepos))
00524 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
00525 BLOCK_FATAL_ERROR) ||
00526 (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
00527 MI_MIN_BLOCK_LENGTH)
00528 {
00529 errno=HA_ERR_WRONG_IN_RECORD;
00530 return(1);
00531 }
00532
00533 del_block.second_read=0;
00534 remove_next_block=0;
00535 if (_mi_get_block_info(&del_block,info->dfile,filepos+length) &
00536 BLOCK_DELETED && del_block.block_len+length < MI_DYN_MAX_BLOCK_LENGTH)
00537 {
00538
00539 remove_next_block=1;
00540 length+=del_block.block_len;
00541 }
00542
00543 block_info.header[0]=0;
00544 mi_int3store(block_info.header+1,length);
00545 mi_sizestore(block_info.header+4,info->s->state.dellink);
00546 if (b_type & BLOCK_LAST)
00547 memset(block_info.header+12, 255, 8);
00548 else
00549 mi_sizestore(block_info.header+12,block_info.next_filepos);
00550 if (info->s->file_write(info,(unsigned char*) block_info.header,20,filepos,
00551 MYF(MY_NABP)))
00552 return(1);
00553 info->s->state.dellink = filepos;
00554 info->state->del++;
00555 info->state->empty+=length;
00556 filepos=block_info.next_filepos;
00557
00558
00559 if (remove_next_block && unlink_deleted_block(info,&del_block))
00560 error=1;
00561 } while (!(b_type & BLOCK_LAST));
00562
00563 return(error);
00564 }
00565
00566
00567
00568
00569 int _mi_write_part_record(MI_INFO *info,
00570 internal::my_off_t filepos,
00571 ulong length,
00572 internal::my_off_t next_filepos,
00573 unsigned char **record,
00574 ulong *reclength,
00575 int *flag)
00576 {
00577 ulong head_length,res_length,extra_length,long_block,del_length;
00578 unsigned char *pos,*record_end;
00579 internal::my_off_t next_delete_block;
00580 unsigned char temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
00581
00582 next_delete_block=HA_OFFSET_ERROR;
00583
00584 res_length=extra_length=0;
00585 if (length > *reclength + MI_SPLIT_LENGTH)
00586 {
00587 res_length=MY_ALIGN(length- *reclength - MI_EXTEND_BLOCK_LENGTH,
00588 MI_DYN_ALIGN_SIZE);
00589 length-= res_length;
00590 }
00591 long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
00592 if (length == *reclength+ 3 + long_block)
00593 {
00594
00595 temp[0]=(unsigned char) (1+ *flag)+(unsigned char) long_block;
00596 if (long_block)
00597 {
00598 mi_int3store(temp+1,*reclength);
00599 head_length=4;
00600 }
00601 else
00602 {
00603 mi_int2store(temp+1,*reclength);
00604 head_length=3;
00605 }
00606 }
00607 else if (length-long_block < *reclength+4)
00608 {
00609 if (next_filepos == HA_OFFSET_ERROR)
00610 next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
00611 !info->append_insert_at_end ?
00612 info->s->state.dellink : info->state->data_file_length);
00613 if (*flag == 0)
00614 {
00615 if (*reclength > MI_MAX_BLOCK_LENGTH)
00616 {
00617 head_length= 16;
00618 temp[0]=13;
00619 mi_int4store(temp+1,*reclength);
00620 mi_int3store(temp+5,length-head_length);
00621 mi_sizestore((unsigned char*) temp+8,next_filepos);
00622 }
00623 else
00624 {
00625 head_length=5+8+long_block*2;
00626 temp[0]=5+(unsigned char) long_block;
00627 if (long_block)
00628 {
00629 mi_int3store(temp+1,*reclength);
00630 mi_int3store(temp+4,length-head_length);
00631 mi_sizestore((unsigned char*) temp+7,next_filepos);
00632 }
00633 else
00634 {
00635 mi_int2store(temp+1,*reclength);
00636 mi_int2store(temp+3,length-head_length);
00637 mi_sizestore((unsigned char*) temp+5,next_filepos);
00638 }
00639 }
00640 }
00641 else
00642 {
00643 head_length=3+8+long_block;
00644 temp[0]=11+(unsigned char) long_block;
00645 if (long_block)
00646 {
00647 mi_int3store(temp+1,length-head_length);
00648 mi_sizestore((unsigned char*) temp+4,next_filepos);
00649 }
00650 else
00651 {
00652 mi_int2store(temp+1,length-head_length);
00653 mi_sizestore((unsigned char*) temp+3,next_filepos);
00654 }
00655 }
00656 }
00657 else
00658 {
00659 head_length=4+long_block;
00660 extra_length= length- *reclength-head_length;
00661 temp[0]= (unsigned char) (3+ *flag)+(unsigned char) long_block;
00662 if (long_block)
00663 {
00664 mi_int3store(temp+1,*reclength);
00665 temp[4]= (unsigned char) (extra_length);
00666 }
00667 else
00668 {
00669 mi_int2store(temp+1,*reclength);
00670 temp[3]= (unsigned char) (extra_length);
00671 }
00672 length= *reclength+head_length;
00673 }
00674
00675
00676 record_end= *record+length-head_length;
00677 del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
00678 memmove(*record - head_length, temp, head_length);
00679 memcpy(temp,record_end,(size_t) (extra_length+del_length));
00680 memset(record_end, 0, extra_length);
00681
00682 if (res_length)
00683 {
00684
00685 MI_BLOCK_INFO del_block;
00686 internal::my_off_t next_block=filepos+length+extra_length+res_length;
00687
00688 del_block.second_read=0;
00689 if (next_block < info->state->data_file_length &&
00690 info->s->state.dellink != HA_OFFSET_ERROR)
00691 {
00692 if ((_mi_get_block_info(&del_block,info->dfile,next_block)
00693 & BLOCK_DELETED) &&
00694 res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
00695 {
00696 if (unlink_deleted_block(info,&del_block))
00697 goto err;
00698 res_length+=del_block.block_len;
00699 }
00700 }
00701
00702
00703 pos=record_end+extra_length;
00704 pos[0]= '\0';
00705 mi_int3store(pos+1,res_length);
00706 mi_sizestore(pos+4,info->s->state.dellink);
00707 memset(pos+12, 255, 8);
00708 next_delete_block=info->s->state.dellink;
00709 info->s->state.dellink= filepos+length+extra_length;
00710 info->state->del++;
00711 info->state->empty+=res_length;
00712 info->s->state.split++;
00713 }
00714 if (info->opt_flag & WRITE_CACHE_USED &&
00715 info->update & HA_STATE_WRITE_AT_END)
00716 {
00717 if (info->update & HA_STATE_EXTEND_BLOCK)
00718 {
00719 info->update&= ~HA_STATE_EXTEND_BLOCK;
00720 if (my_block_write(&info->rec_cache,(unsigned char*) *record-head_length,
00721 length+extra_length+del_length,filepos))
00722 goto err;
00723 }
00724 else if (my_b_write(&info->rec_cache,(unsigned char*) *record-head_length,
00725 length+extra_length+del_length))
00726 goto err;
00727 }
00728 else
00729 {
00730 info->rec_cache.seek_not_done=1;
00731 if (info->s->file_write(info,(unsigned char*) *record-head_length,length+extra_length+
00732 del_length,filepos,info->s->write_flag))
00733 goto err;
00734 }
00735 memcpy(record_end, temp, extra_length + del_length);
00736 *record=record_end;
00737 *reclength-=(length-head_length);
00738 *flag=6;
00739
00740 if (del_length)
00741 {
00742
00743 if (update_backward_delete_link(info, next_delete_block,
00744 info->s->state.dellink))
00745 goto err;
00746 }
00747
00748 return(0);
00749 err:
00750 return(1);
00751 }
00752
00753
00754
00755
00756 static int update_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *record,
00757 ulong reclength)
00758 {
00759 int flag;
00760 uint32_t error;
00761 ulong length;
00762 MI_BLOCK_INFO block_info;
00763
00764 flag=block_info.second_read=0;
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778 if (unlikely(info->s->base.max_data_file_length -
00779 info->state->data_file_length < reclength))
00780 {
00781
00782
00783
00784
00785 if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
00786 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR))
00787 {
00788 if (!(error & BLOCK_FATAL_ERROR))
00789 errno=HA_ERR_WRONG_IN_RECORD;
00790 goto err;
00791 }
00792
00793
00794
00795
00796 if (block_info.rec_len < reclength)
00797 {
00798 if (info->s->base.max_data_file_length - info->state->data_file_length +
00799 info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
00800 reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER)
00801 {
00802 errno=HA_ERR_RECORD_FILE_FULL;
00803 goto err;
00804 }
00805 }
00806 block_info.second_read=0;
00807 }
00808
00809 while (reclength > 0)
00810 {
00811 if (filepos != info->s->state.dellink)
00812 {
00813 block_info.next_filepos= HA_OFFSET_ERROR;
00814 if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
00815 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
00816 BLOCK_FATAL_ERROR))
00817 {
00818 if (!(error & BLOCK_FATAL_ERROR))
00819 errno=HA_ERR_WRONG_IN_RECORD;
00820 goto err;
00821 }
00822 length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
00823 if (length < reclength)
00824 {
00825 uint32_t tmp=MY_ALIGN(reclength - length + 3 +
00826 test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
00827
00828 tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
00829
00830 if (block_info.filepos + block_info.block_len ==
00831 info->state->data_file_length &&
00832 info->state->data_file_length <
00833 info->s->base.max_data_file_length-tmp)
00834 {
00835
00836 if (info->nextpos == info->state->data_file_length)
00837 info->nextpos+= tmp;
00838 info->state->data_file_length+= tmp;
00839 info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
00840 length+=tmp;
00841 }
00842 else if (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH)
00843 {
00844
00845
00846
00847
00848
00849
00850
00851 MI_BLOCK_INFO del_block;
00852 del_block.second_read=0;
00853 if (_mi_get_block_info(&del_block,info->dfile,
00854 block_info.filepos + block_info.block_len) &
00855 BLOCK_DELETED)
00856 {
00857
00858 if (unlink_deleted_block(info,&del_block))
00859 goto err;
00860 if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH)
00861 {
00862
00863
00864
00865
00866 internal::my_off_t next_pos;
00867 ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
00868 set_if_bigger(rest_length, (ulong)MI_MIN_BLOCK_LENGTH);
00869 next_pos= del_block.filepos+ del_block.block_len - rest_length;
00870
00871 if (update_backward_delete_link(info, info->s->state.dellink,
00872 next_pos))
00873 return(1);
00874
00875
00876 del_block.header[0]=0;
00877 mi_int3store(del_block.header+1, rest_length);
00878 mi_sizestore(del_block.header+4,info->s->state.dellink);
00879 memset(del_block.header+12, 255, 8);
00880 if (info->s->file_write(info,(unsigned char*) del_block.header,20, next_pos,
00881 MYF(MY_NABP)))
00882 return(1);
00883 info->s->state.dellink= next_pos;
00884 info->s->state.split++;
00885 info->state->del++;
00886 info->state->empty+= rest_length;
00887 length-= rest_length;
00888 }
00889 }
00890 }
00891 }
00892 }
00893 else
00894 {
00895 if (_mi_find_writepos(info,reclength,&filepos,&length))
00896 goto err;
00897 }
00898 if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
00899 &record,&reclength,&flag))
00900 goto err;
00901 if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
00902 {
00903
00904 filepos=info->s->state.dellink;
00905 }
00906 }
00907
00908 if (block_info.next_filepos != HA_OFFSET_ERROR)
00909 if (delete_dynamic_record(info,block_info.next_filepos,1))
00910 goto err;
00911 return(0);
00912 err:
00913 return(1);
00914 }
00915
00916
00917
00918
00919 uint32_t _mi_rec_pack(MI_INFO *info, register unsigned char *to,
00920 register const unsigned char *from)
00921 {
00922 uint length,new_length,flag,bit,i;
00923 unsigned char *pos,*end,*startpos,*packpos;
00924 enum en_fieldtype type;
00925 register MI_COLUMNDEF *rec;
00926 MI_BLOB *blob;
00927
00928 flag=0 ; bit=1;
00929 startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
00930 rec=info->s->rec;
00931
00932 for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
00933 {
00934 length=(uint) rec->length;
00935 if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
00936 {
00937 if (type == FIELD_BLOB)
00938 {
00939 if (!blob->length)
00940 flag|=bit;
00941 else
00942 {
00943 char *temp_pos;
00944 size_t tmp_length=length-portable_sizeof_char_ptr;
00945 memcpy(to,from,tmp_length);
00946 memcpy(&temp_pos,from+tmp_length,sizeof(char*));
00947 memcpy(to + tmp_length, temp_pos, blob->length);
00948 to+=tmp_length+blob->length;
00949 }
00950 blob++;
00951 }
00952 else if (type == FIELD_SKIP_ZERO)
00953 {
00954 if (memcmp(from,zero_string,length) == 0)
00955 flag|=bit;
00956 else
00957 {
00958 memcpy(to, from, length);
00959 to+=length;
00960 }
00961 }
00962 else if (type == FIELD_SKIP_ENDSPACE ||
00963 type == FIELD_SKIP_PRESPACE)
00964 {
00965 pos= (unsigned char*) from; end= (unsigned char*) from + length;
00966 if (type == FIELD_SKIP_ENDSPACE)
00967 {
00968 while (end > from && *(end-1) == ' ')
00969 end--;
00970 }
00971 else
00972 {
00973 while (pos < end && *pos == ' ')
00974 pos++;
00975 }
00976 new_length=(uint) (end-pos);
00977 if (new_length +1 + test(rec->length > 255 && new_length > 127)
00978 < length)
00979 {
00980 if (rec->length > 255 && new_length > 127)
00981 {
00982 to[0]= (unsigned char) ((new_length & 127) + 128);
00983 to[1]= (unsigned char) (new_length >> 7);
00984 to+=2;
00985 }
00986 else
00987 *to++= (unsigned char) new_length;
00988 memcpy(to, pos, new_length);
00989 to+=new_length;
00990 flag|=bit;
00991 }
00992 else
00993 {
00994 memcpy(to, from, length);
00995 to+=length;
00996 }
00997 }
00998 else if (type == FIELD_VARCHAR)
00999 {
01000 uint32_t pack_length= ha_varchar_packlength(rec->length -1);
01001 uint32_t tmp_length;
01002 if (pack_length == 1)
01003 {
01004 tmp_length= (uint) *(unsigned char*) from;
01005 *to++= *from;
01006 }
01007 else
01008 {
01009 tmp_length= uint2korr(from);
01010 store_key_length_inc(to,tmp_length);
01011 }
01012 memcpy(to, from+pack_length, tmp_length);
01013 to+= tmp_length;
01014 continue;
01015 }
01016 else
01017 {
01018 memcpy(to, from, length);
01019 to+=length;
01020 continue;
01021 }
01022 if ((bit= bit << 1) >= 256)
01023 {
01024 *packpos++= (unsigned char) flag;
01025 bit=1; flag=0;
01026 }
01027 }
01028 else
01029 {
01030 memcpy(to, from, length);
01031 to+=length;
01032 }
01033 }
01034 if (bit != 1)
01035 *packpos= (unsigned char) flag;
01036 if (info->s->calc_checksum)
01037 *to++= (unsigned char) info->checksum;
01038 return((uint) (to-startpos));
01039 }
01040
01041
01042
01043
01044
01045
01046
01047
01048 bool _mi_rec_check(MI_INFO *info,const unsigned char *record, unsigned char *rec_buff,
01049 ulong packed_length, bool with_checksum)
01050 {
01051 uint length,new_length,flag,bit,i;
01052 unsigned char *pos,*end,*packpos,*to;
01053 enum en_fieldtype type;
01054 register MI_COLUMNDEF *rec;
01055
01056 packpos=rec_buff; to= rec_buff+info->s->base.pack_bits;
01057 rec=info->s->rec;
01058 flag= *packpos; bit=1;
01059
01060 for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
01061 {
01062 length=(uint) rec->length;
01063 if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
01064 {
01065 if (type == FIELD_BLOB)
01066 {
01067 uint32_t blob_length=
01068 _mi_calc_blob_length(length-portable_sizeof_char_ptr,record);
01069 if (!blob_length && !(flag & bit))
01070 goto err;
01071 if (blob_length)
01072 to+=length - portable_sizeof_char_ptr+ blob_length;
01073 }
01074 else if (type == FIELD_SKIP_ZERO)
01075 {
01076 if (memcmp(record,zero_string,length) == 0)
01077 {
01078 if (!(flag & bit))
01079 goto err;
01080 }
01081 else
01082 to+=length;
01083 }
01084 else if (type == FIELD_SKIP_ENDSPACE ||
01085 type == FIELD_SKIP_PRESPACE)
01086 {
01087 pos= (unsigned char*) record; end= (unsigned char*) record + length;
01088 if (type == FIELD_SKIP_ENDSPACE)
01089 {
01090 while (end > record && *(end-1) == ' ')
01091 end--;
01092 }
01093 else
01094 {
01095 while (pos < end && *pos == ' ')
01096 pos++;
01097 }
01098 new_length=(uint) (end-pos);
01099 if (new_length +1 + test(rec->length > 255 && new_length > 127)
01100 < length)
01101 {
01102 if (!(flag & bit))
01103 goto err;
01104 if (rec->length > 255 && new_length > 127)
01105 {
01106 if (to[0] != (unsigned char) ((new_length & 127) + 128) ||
01107 to[1] != (unsigned char) (new_length >> 7))
01108 goto err;
01109 to+=2;
01110 }
01111 else if (*to++ != (unsigned char) new_length)
01112 goto err;
01113 to+=new_length;
01114 }
01115 else
01116 to+=length;
01117 }
01118 else if (type == FIELD_VARCHAR)
01119 {
01120 uint32_t pack_length= ha_varchar_packlength(rec->length -1);
01121 uint32_t tmp_length;
01122 if (pack_length == 1)
01123 {
01124 tmp_length= (uint) *(unsigned char*) record;
01125 to+= 1+ tmp_length;
01126 continue;
01127 }
01128 else
01129 {
01130 tmp_length= uint2korr(record);
01131 to+= get_pack_length(tmp_length)+tmp_length;
01132 }
01133 continue;
01134 }
01135 else
01136 {
01137 to+=length;
01138 continue;
01139 }
01140 if ((bit= bit << 1) >= 256)
01141 {
01142 flag= *++packpos;
01143 bit=1;
01144 }
01145 }
01146 else
01147 to+= length;
01148 }
01149 if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) ||
01150 (bit != 1 && (flag & ~(bit - 1))))
01151 goto err;
01152 if (with_checksum && ((unsigned char) info->checksum != (unsigned char) *to))
01153 {
01154 goto err;
01155 }
01156 return(0);
01157
01158 err:
01159 return(1);
01160 }
01161
01162
01163
01164
01165
01166
01167
01168 ulong _mi_rec_unpack(register MI_INFO *info, register unsigned char *to, unsigned char *from,
01169 ulong found_length)
01170 {
01171 uint32_t flag,bit,length,rec_length,min_pack_length;
01172 enum en_fieldtype type;
01173 unsigned char *from_end,*to_end,*packpos;
01174 register MI_COLUMNDEF *rec,*end_field;
01175
01176 to_end=to + info->s->base.reclength;
01177 from_end=from+found_length;
01178 flag= (unsigned char) *from; bit=1; packpos=from;
01179 if (found_length < info->s->base.min_pack_length)
01180 goto err;
01181 from+= info->s->base.pack_bits;
01182 min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
01183
01184 for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
01185 rec < end_field ; to+= rec_length, rec++)
01186 {
01187 rec_length=rec->length;
01188 if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL &&
01189 (type != FIELD_CHECK))
01190 {
01191 if (type == FIELD_VARCHAR)
01192 {
01193 uint32_t pack_length= ha_varchar_packlength(rec_length-1);
01194 if (pack_length == 1)
01195 {
01196 length= (uint) *(unsigned char*) from;
01197 if (length > rec_length-1)
01198 goto err;
01199 *to= *from++;
01200 }
01201 else
01202 {
01203 get_key_length(length, from);
01204 if (length > rec_length-2)
01205 goto err;
01206 int2store(to,length);
01207 }
01208 if (from+length > from_end)
01209 goto err;
01210 memcpy(to+pack_length, from, length);
01211 from+= length;
01212 min_pack_length--;
01213 continue;
01214 }
01215 if (flag & bit)
01216 {
01217 if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
01218 memset(to, 0, rec_length);
01219 else if (type == FIELD_SKIP_ENDSPACE ||
01220 type == FIELD_SKIP_PRESPACE)
01221 {
01222 if (rec->length > 255 && *from & 128)
01223 {
01224 if (from + 1 >= from_end)
01225 goto err;
01226 length= (*from & 127)+ ((uint) (unsigned char) *(from+1) << 7); from+=2;
01227 }
01228 else
01229 {
01230 if (from == from_end)
01231 goto err;
01232 length= (unsigned char) *from++;
01233 }
01234 min_pack_length--;
01235 if (length >= rec_length ||
01236 min_pack_length + length > (uint) (from_end - from))
01237 goto err;
01238 if (type == FIELD_SKIP_ENDSPACE)
01239 {
01240 memcpy(to, from, length);
01241 memset(to+length, ' ', rec_length-length);
01242 }
01243 else
01244 {
01245 memset(to, ' ', rec_length-length);
01246 memcpy(to + rec_length - length, from, length);
01247 }
01248 from+=length;
01249 }
01250 }
01251 else if (type == FIELD_BLOB)
01252 {
01253 uint32_t size_length=rec_length- portable_sizeof_char_ptr;
01254 ulong blob_length=_mi_calc_blob_length(size_length,from);
01255 ulong from_left= (ulong) (from_end - from);
01256 if (from_left < size_length ||
01257 from_left - size_length < blob_length ||
01258 from_left - size_length - blob_length < min_pack_length)
01259 goto err;
01260 memcpy(to, from, size_length);
01261 from+=size_length;
01262 memcpy(to+size_length, &from, sizeof(char*));
01263 from+=blob_length;
01264 }
01265 else
01266 {
01267 if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
01268 min_pack_length--;
01269 if (min_pack_length + rec_length > (uint) (from_end - from))
01270 goto err;
01271 memcpy(to, from, rec_length);
01272 from+=rec_length;
01273 }
01274 if ((bit= bit << 1) >= 256)
01275 {
01276 flag= (unsigned char) *++packpos; bit=1;
01277 }
01278 }
01279 else
01280 {
01281 if (min_pack_length > (uint) (from_end - from))
01282 goto err;
01283 min_pack_length-=rec_length;
01284 memcpy(to, from, rec_length);
01285 from+=rec_length;
01286 }
01287 }
01288 if (info->s->calc_checksum)
01289 from++;
01290 if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
01291 return(found_length);
01292
01293 err:
01294 errno= HA_ERR_WRONG_IN_RECORD;
01295 return(MY_FILE_ERROR);
01296 }
01297
01298
01299
01300
01301 ulong _my_calc_total_blob_length(MI_INFO *info, const unsigned char *record)
01302 {
01303 ulong length;
01304 MI_BLOB *blob,*end;
01305
01306 for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
01307 blob != end;
01308 blob++)
01309 {
01310 blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
01311 length+=blob->length;
01312 }
01313 return length;
01314 }
01315
01316
01317 ulong _mi_calc_blob_length(uint32_t length, const unsigned char *pos)
01318 {
01319 switch (length) {
01320 case 1:
01321 return (uint) (unsigned char) *pos;
01322 case 2:
01323 return (uint) uint2korr(pos);
01324 case 3:
01325 return uint3korr(pos);
01326 case 4:
01327 return uint4korr(pos);
01328 default:
01329 break;
01330 }
01331 return 0;
01332 }
01333
01334
01335 void _my_store_blob_length(unsigned char *pos,uint32_t pack_length,uint32_t length)
01336 {
01337 switch (pack_length) {
01338 case 1:
01339 *pos= (unsigned char) length;
01340 break;
01341 case 2:
01342 int2store(pos,length);
01343 break;
01344 case 3:
01345 int3store(pos,length);
01346 break;
01347 case 4:
01348 int4store(pos,length);
01349 default:
01350 break;
01351 }
01352 return;
01353 }
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388 int _mi_read_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *buf)
01389 {
01390 int block_of_record;
01391 uint32_t b_type, left_length= 0;
01392 unsigned char *to= NULL;
01393 MI_BLOCK_INFO block_info;
01394 int file;
01395
01396 if (filepos != HA_OFFSET_ERROR)
01397 {
01398 file=info->dfile;
01399 block_of_record= 0;
01400 block_info.second_read= 0;
01401 do
01402 {
01403
01404 if (filepos == HA_OFFSET_ERROR)
01405 goto panic;
01406 if (info->opt_flag & WRITE_CACHE_USED &&
01407 info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
01408 flush_io_cache(&info->rec_cache))
01409 goto err;
01410 info->rec_cache.seek_not_done=1;
01411 if ((b_type= _mi_get_block_info(&block_info, file, filepos))
01412 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
01413 BLOCK_FATAL_ERROR))
01414 {
01415 if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
01416 errno=HA_ERR_RECORD_DELETED;
01417 goto err;
01418 }
01419 if (block_of_record++ == 0)
01420 {
01421 if (block_info.rec_len > (uint) info->s->base.max_pack_length)
01422 goto panic;
01423 if (info->s->base.blobs)
01424 {
01425 if (!(to=mi_alloc_rec_buff(info, block_info.rec_len,
01426 &info->rec_buff)))
01427 goto err;
01428 }
01429 else
01430 to= info->rec_buff;
01431 left_length=block_info.rec_len;
01432 }
01433 if (left_length < block_info.data_len || ! block_info.data_len)
01434 goto panic;
01435
01436 {
01437 uint32_t offset= (uint) (block_info.filepos - filepos);
01438 uint32_t prefetch_len= (sizeof(block_info.header) - offset);
01439 filepos+= sizeof(block_info.header);
01440
01441 if (prefetch_len > block_info.data_len)
01442 prefetch_len= block_info.data_len;
01443 if (prefetch_len)
01444 {
01445 memcpy(to, block_info.header + offset, prefetch_len);
01446 block_info.data_len-= prefetch_len;
01447 left_length-= prefetch_len;
01448 to+= prefetch_len;
01449 }
01450 }
01451
01452 if (block_info.data_len)
01453 {
01454 if (info->opt_flag & WRITE_CACHE_USED &&
01455 info->rec_cache.pos_in_file < filepos + block_info.data_len &&
01456 flush_io_cache(&info->rec_cache))
01457 goto err;
01458
01459
01460
01461
01462
01463 if (info->s->file_read(info, (unsigned char*) to, block_info.data_len,
01464 filepos, MYF(MY_NABP)))
01465 goto panic;
01466 left_length-=block_info.data_len;
01467 to+=block_info.data_len;
01468 }
01469 filepos= block_info.next_filepos;
01470 } while (left_length);
01471
01472 info->update|= HA_STATE_AKTIV;
01473 fast_mi_writeinfo(info);
01474 return(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
01475 MY_FILE_ERROR ? 0 : -1);
01476 }
01477 fast_mi_writeinfo(info);
01478 return(-1);
01479
01480 panic:
01481 errno=HA_ERR_WRONG_IN_RECORD;
01482 err:
01483 _mi_writeinfo(info,0);
01484 return(-1);
01485 }
01486
01487
01488
01489 int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
01490 const unsigned char *record, internal::my_off_t pos)
01491 {
01492 unsigned char *rec_buff,*old_record;
01493 int error;
01494
01495 if (!(old_record=(unsigned char *)malloc(info->s->base.reclength)))
01496 return(1);
01497
01498
01499 rec_buff=info->rec_buff;
01500 if (info->s->base.blobs)
01501 info->rec_buff=0;
01502 error=_mi_read_dynamic_record(info,pos,old_record);
01503 if (!error)
01504 error=mi_unique_comp(def, record, old_record, def->null_are_equal);
01505 if (info->s->base.blobs)
01506 {
01507 void * rec_buff_ptr= mi_get_rec_buff_ptr(info, info->rec_buff);
01508 if (rec_buff_ptr != NULL)
01509 free(rec_buff_ptr);
01510 info->rec_buff=rec_buff;
01511 }
01512 free(old_record);
01513 return(error);
01514 }
01515
01516
01517
01518
01519 int _mi_cmp_dynamic_record(register MI_INFO *info, register const unsigned char *record)
01520 {
01521 uint32_t flag,reclength,b_type;
01522 internal::my_off_t filepos;
01523 unsigned char *buffer;
01524 MI_BLOCK_INFO block_info;
01525
01526 if (info->opt_flag & WRITE_CACHE_USED)
01527 {
01528 info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
01529 if (flush_io_cache(&info->rec_cache))
01530 return(-1);
01531 }
01532 info->rec_cache.seek_not_done=1;
01533
01534
01535
01536 buffer=info->rec_buff;
01537 if ((info->opt_flag & READ_CHECK_USED))
01538 {
01539 if (info->s->base.blobs)
01540 {
01541 if (!(buffer=(unsigned char*) malloc(info->s->base.pack_reclength+
01542 _my_calc_total_blob_length(info,record))))
01543 return(-1);
01544 }
01545 reclength=_mi_rec_pack(info,buffer,record);
01546 record= buffer;
01547
01548 filepos=info->lastpos;
01549 flag=block_info.second_read=0;
01550 block_info.next_filepos=filepos;
01551 while (reclength > 0)
01552 {
01553 if ((b_type=_mi_get_block_info(&block_info,info->dfile,
01554 block_info.next_filepos))
01555 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
01556 BLOCK_FATAL_ERROR))
01557 {
01558 if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
01559 errno=HA_ERR_RECORD_CHANGED;
01560 goto err;
01561 }
01562 if (flag == 0)
01563 {
01564 flag=1;
01565 if (reclength != block_info.rec_len)
01566 {
01567 errno=HA_ERR_RECORD_CHANGED;
01568 goto err;
01569 }
01570 } else if (reclength < block_info.data_len)
01571 {
01572 errno=HA_ERR_WRONG_IN_RECORD;
01573 goto err;
01574 }
01575 reclength-=block_info.data_len;
01576 if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
01577 block_info.data_len))
01578 {
01579 errno=HA_ERR_RECORD_CHANGED;
01580 goto err;
01581 }
01582 flag=1;
01583 record+=block_info.data_len;
01584 }
01585 }
01586 errno=0;
01587 err:
01588 if (buffer != info->rec_buff)
01589 free((unsigned char*) buffer);
01590 return(errno);
01591 }
01592
01593
01594
01595
01596 static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
01597 uint32_t length)
01598 {
01599 uint32_t next_length;
01600 unsigned char temp_buff[IO_SIZE*2];
01601
01602 next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
01603
01604 while (length > IO_SIZE*2)
01605 {
01606 if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
01607 memcmp(buff, temp_buff, next_length))
01608 goto err;
01609 filepos+=next_length;
01610 buff+=next_length;
01611 length-= next_length;
01612 next_length=IO_SIZE*2;
01613 }
01614 if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
01615 goto err;
01616 return(memcmp(buff,temp_buff,length));
01617 err:
01618 return(1);
01619 }
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656 int _mi_read_rnd_dynamic_record(MI_INFO *info, unsigned char *buf,
01657 register internal::my_off_t filepos,
01658 bool skip_deleted_blocks)
01659 {
01660 int block_of_record, info_read, save_errno;
01661 uint32_t left_len,b_type;
01662 unsigned char *to= NULL;
01663 MI_BLOCK_INFO block_info;
01664 MYISAM_SHARE *share=info->s;
01665
01666 info_read=0;
01667
01668 if (info->lock_type == F_UNLCK)
01669 {
01670 info->tmp_lock_type=F_RDLCK;
01671 }
01672 else
01673 info_read=1;
01674
01675 block_of_record= 0;
01676 block_info.second_read= 0;
01677 left_len=1;
01678 do
01679 {
01680 if (filepos >= info->state->data_file_length)
01681 {
01682 if (!info_read)
01683 {
01684 info_read=1;
01685 info->rec_cache.seek_not_done=1;
01686 if (mi_state_info_read_dsk(share->kfile,&share->state,1))
01687 goto panic;
01688 }
01689 if (filepos >= info->state->data_file_length)
01690 {
01691 errno= HA_ERR_END_OF_FILE;
01692 goto err;
01693 }
01694 }
01695 if (info->opt_flag & READ_CACHE_USED)
01696 {
01697 if (_mi_read_cache(&info->rec_cache,(unsigned char*) block_info.header,filepos,
01698 sizeof(block_info.header),
01699 (!block_of_record && skip_deleted_blocks ?
01700 READING_NEXT : 0) | READING_HEADER))
01701 goto panic;
01702 b_type=_mi_get_block_info(&block_info,-1,filepos);
01703 }
01704 else
01705 {
01706 if (info->opt_flag & WRITE_CACHE_USED &&
01707 info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
01708 flush_io_cache(&info->rec_cache))
01709 return(errno);
01710 info->rec_cache.seek_not_done=1;
01711 b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
01712 }
01713
01714 if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
01715 BLOCK_FATAL_ERROR))
01716 {
01717 if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
01718 && skip_deleted_blocks)
01719 {
01720 filepos=block_info.filepos+block_info.block_len;
01721 block_info.second_read=0;
01722 continue;
01723 }
01724 if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
01725 {
01726 errno=HA_ERR_RECORD_DELETED;
01727 info->lastpos=block_info.filepos;
01728 info->nextpos=block_info.filepos+block_info.block_len;
01729 }
01730 goto err;
01731 }
01732 if (block_of_record == 0)
01733 {
01734 if (block_info.rec_len > (uint) share->base.max_pack_length)
01735 goto panic;
01736 info->lastpos=filepos;
01737 if (share->base.blobs)
01738 {
01739 if (!(to= mi_alloc_rec_buff(info, block_info.rec_len,
01740 &info->rec_buff)))
01741 goto err;
01742 }
01743 else
01744 to= info->rec_buff;
01745 left_len=block_info.rec_len;
01746 }
01747 if (left_len < block_info.data_len)
01748 goto panic;
01749
01750
01751 {
01752 uint32_t offset=(uint) (block_info.filepos - filepos);
01753 uint32_t tmp_length= (sizeof(block_info.header) - offset);
01754 filepos=block_info.filepos;
01755
01756 if (tmp_length > block_info.data_len)
01757 tmp_length= block_info.data_len;
01758 if (tmp_length)
01759 {
01760 memcpy(to, block_info.header+offset,tmp_length);
01761 block_info.data_len-=tmp_length;
01762 left_len-=tmp_length;
01763 to+=tmp_length;
01764 filepos+=tmp_length;
01765 }
01766 }
01767
01768 if (block_info.data_len)
01769 {
01770 if (info->opt_flag & READ_CACHE_USED)
01771 {
01772 if (_mi_read_cache(&info->rec_cache,(unsigned char*) to,filepos,
01773 block_info.data_len,
01774 (!block_of_record && skip_deleted_blocks) ?
01775 READING_NEXT : 0))
01776 goto panic;
01777 }
01778 else
01779 {
01780 if (info->opt_flag & WRITE_CACHE_USED &&
01781 info->rec_cache.pos_in_file <
01782 block_info.filepos + block_info.data_len &&
01783 flush_io_cache(&info->rec_cache))
01784 goto err;
01785
01786 if (internal::my_read(info->dfile,(unsigned char*) to,block_info.data_len,MYF(MY_NABP)))
01787 {
01788 if (errno == -1)
01789 errno= HA_ERR_WRONG_IN_RECORD;
01790 goto err;
01791 }
01792 }
01793 }
01794
01795
01796
01797
01798 if (block_of_record++ == 0)
01799 {
01800 info->nextpos= block_info.filepos + block_info.block_len;
01801 skip_deleted_blocks= 0;
01802 }
01803 left_len-=block_info.data_len;
01804 to+=block_info.data_len;
01805 filepos=block_info.next_filepos;
01806 } while (left_len);
01807
01808 info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
01809 fast_mi_writeinfo(info);
01810 if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
01811 MY_FILE_ERROR)
01812 return(0);
01813 return(errno);
01814
01815 panic:
01816 errno=HA_ERR_WRONG_IN_RECORD;
01817 err:
01818 save_errno=errno;
01819 _mi_writeinfo(info,0);
01820 return(errno=save_errno);
01821 }
01822
01823
01824
01825
01826 uint32_t _mi_get_block_info(MI_BLOCK_INFO *info, int file, internal::my_off_t filepos)
01827 {
01828 uint32_t return_val=0;
01829 unsigned char *header=info->header;
01830
01831 if (file >= 0)
01832 {
01833
01834
01835
01836
01837
01838 lseek(file,filepos,SEEK_SET);
01839 if (internal::my_read(file, header, sizeof(info->header),MYF(0)) !=
01840 sizeof(info->header))
01841 goto err;
01842 }
01843 if (info->second_read)
01844 {
01845 if (info->header[0] <= 6 || info->header[0] == 13)
01846 return_val=BLOCK_SYNC_ERROR;
01847 }
01848 else
01849 {
01850 if (info->header[0] > 6 && info->header[0] != 13)
01851 return_val=BLOCK_SYNC_ERROR;
01852 }
01853 info->next_filepos= HA_OFFSET_ERROR;
01854
01855 switch (info->header[0]) {
01856 case 0:
01857 if ((info->block_len=(uint) mi_uint3korr(header+1)) <
01858 MI_MIN_BLOCK_LENGTH ||
01859 (info->block_len & (MI_DYN_ALIGN_SIZE -1)))
01860 goto err;
01861 info->filepos=filepos;
01862 info->next_filepos=mi_sizekorr(header+4);
01863 info->prev_filepos=mi_sizekorr(header+12);
01864 #if SIZEOF_OFF_T == 4
01865 if ((mi_uint4korr(header+4) != 0 &&
01866 (mi_uint4korr(header+4) != UINT32_MAX ||
01867 info->next_filepos != UINT32_MAX) ||
01868 (mi_uint4korr(header+12) != 0 &&
01869 (mi_uint4korr(header+12) != UINT32_MAX ||
01870 info->prev_filepos != UINT32_MAX))
01871 goto err;
01872 #endif
01873 return return_val | BLOCK_DELETED;
01874
01875 case 1:
01876 info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
01877 info->filepos=filepos+3;
01878 return return_val | BLOCK_FIRST | BLOCK_LAST;
01879 case 2:
01880 info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
01881 info->filepos=filepos+4;
01882 return return_val | BLOCK_FIRST | BLOCK_LAST;
01883
01884 case 13:
01885 info->rec_len=mi_uint4korr(header+1);
01886 info->block_len=info->data_len=mi_uint3korr(header+5);
01887 info->next_filepos=mi_sizekorr(header+8);
01888 info->second_read=1;
01889 info->filepos=filepos+16;
01890 return return_val | BLOCK_FIRST;
01891
01892 case 3:
01893 info->rec_len=info->data_len=mi_uint2korr(header+1);
01894 info->block_len=info->rec_len+ (uint) header[3];
01895 info->filepos=filepos+4;
01896 return return_val | BLOCK_FIRST | BLOCK_LAST;
01897 case 4:
01898 info->rec_len=info->data_len=mi_uint3korr(header+1);
01899 info->block_len=info->rec_len+ (uint) header[4];
01900 info->filepos=filepos+5;
01901 return return_val | BLOCK_FIRST | BLOCK_LAST;
01902
01903 case 5:
01904 info->rec_len=mi_uint2korr(header+1);
01905 info->block_len=info->data_len=mi_uint2korr(header+3);
01906 info->next_filepos=mi_sizekorr(header+5);
01907 info->second_read=1;
01908 info->filepos=filepos+13;
01909 return return_val | BLOCK_FIRST;
01910 case 6:
01911 info->rec_len=mi_uint3korr(header+1);
01912 info->block_len=info->data_len=mi_uint3korr(header+4);
01913 info->next_filepos=mi_sizekorr(header+7);
01914 info->second_read=1;
01915 info->filepos=filepos+15;
01916 return return_val | BLOCK_FIRST;
01917
01918
01919 case 7:
01920 info->data_len=info->block_len=mi_uint2korr(header+1);
01921 info->filepos=filepos+3;
01922 return return_val | BLOCK_LAST;
01923 case 8:
01924 info->data_len=info->block_len=mi_uint3korr(header+1);
01925 info->filepos=filepos+4;
01926 return return_val | BLOCK_LAST;
01927
01928 case 9:
01929 info->data_len=mi_uint2korr(header+1);
01930 info->block_len=info->data_len+ (uint) header[3];
01931 info->filepos=filepos+4;
01932 return return_val | BLOCK_LAST;
01933 case 10:
01934 info->data_len=mi_uint3korr(header+1);
01935 info->block_len=info->data_len+ (uint) header[4];
01936 info->filepos=filepos+5;
01937 return return_val | BLOCK_LAST;
01938
01939 case 11:
01940 info->data_len=info->block_len=mi_uint2korr(header+1);
01941 info->next_filepos=mi_sizekorr(header+3);
01942 info->second_read=1;
01943 info->filepos=filepos+11;
01944 return return_val;
01945 case 12:
01946 info->data_len=info->block_len=mi_uint3korr(header+1);
01947 info->next_filepos=mi_sizekorr(header+4);
01948 info->second_read=1;
01949 info->filepos=filepos+12;
01950 return return_val;
01951 }
01952
01953 err:
01954 errno=HA_ERR_WRONG_IN_RECORD;
01955 return BLOCK_ERROR;
01956 }