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 (info->rec_cache.block_write(*record - head_length,
00721 length+extra_length+del_length,filepos))
00722 goto err;
00723 }
00724 else if (info->rec_cache.write(*record-head_length, length+extra_length+del_length))
00725 goto err;
00726 }
00727 else
00728 {
00729 info->rec_cache.seek_not_done=1;
00730 if (info->s->file_write(info,(unsigned char*) *record-head_length,length+extra_length+
00731 del_length,filepos,info->s->write_flag))
00732 goto err;
00733 }
00734 memcpy(record_end, temp, extra_length + del_length);
00735 *record=record_end;
00736 *reclength-=(length-head_length);
00737 *flag=6;
00738
00739 if (del_length)
00740 {
00741
00742 if (update_backward_delete_link(info, next_delete_block,
00743 info->s->state.dellink))
00744 goto err;
00745 }
00746
00747 return(0);
00748 err:
00749 return(1);
00750 }
00751
00752
00753
00754
00755 static int update_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *record,
00756 ulong reclength)
00757 {
00758 int flag;
00759 uint32_t error;
00760 ulong length;
00761 MI_BLOCK_INFO block_info;
00762
00763 flag=block_info.second_read=0;
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777 if (unlikely(info->s->base.max_data_file_length -
00778 info->state->data_file_length < reclength))
00779 {
00780
00781
00782
00783
00784 if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
00785 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR))
00786 {
00787 if (!(error & BLOCK_FATAL_ERROR))
00788 errno=HA_ERR_WRONG_IN_RECORD;
00789 goto err;
00790 }
00791
00792
00793
00794
00795 if (block_info.rec_len < reclength)
00796 {
00797 if (info->s->base.max_data_file_length - info->state->data_file_length +
00798 info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
00799 reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER)
00800 {
00801 errno=HA_ERR_RECORD_FILE_FULL;
00802 goto err;
00803 }
00804 }
00805 block_info.second_read=0;
00806 }
00807
00808 while (reclength > 0)
00809 {
00810 if (filepos != info->s->state.dellink)
00811 {
00812 block_info.next_filepos= HA_OFFSET_ERROR;
00813 if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
00814 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
00815 BLOCK_FATAL_ERROR))
00816 {
00817 if (!(error & BLOCK_FATAL_ERROR))
00818 errno=HA_ERR_WRONG_IN_RECORD;
00819 goto err;
00820 }
00821 length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
00822 if (length < reclength)
00823 {
00824 uint32_t tmp=MY_ALIGN(reclength - length + 3 +
00825 test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
00826
00827 tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
00828
00829 if (block_info.filepos + block_info.block_len ==
00830 info->state->data_file_length &&
00831 info->state->data_file_length <
00832 info->s->base.max_data_file_length-tmp)
00833 {
00834
00835 if (info->nextpos == info->state->data_file_length)
00836 info->nextpos+= tmp;
00837 info->state->data_file_length+= tmp;
00838 info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
00839 length+=tmp;
00840 }
00841 else if (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH)
00842 {
00843
00844
00845
00846
00847
00848
00849
00850 MI_BLOCK_INFO del_block;
00851 del_block.second_read=0;
00852 if (_mi_get_block_info(&del_block,info->dfile,
00853 block_info.filepos + block_info.block_len) &
00854 BLOCK_DELETED)
00855 {
00856
00857 if (unlink_deleted_block(info,&del_block))
00858 goto err;
00859 if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH)
00860 {
00861
00862
00863
00864
00865 internal::my_off_t next_pos;
00866 ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
00867 set_if_bigger(rest_length, (ulong)MI_MIN_BLOCK_LENGTH);
00868 next_pos= del_block.filepos+ del_block.block_len - rest_length;
00869
00870 if (update_backward_delete_link(info, info->s->state.dellink,
00871 next_pos))
00872 return(1);
00873
00874
00875 del_block.header[0]=0;
00876 mi_int3store(del_block.header+1, rest_length);
00877 mi_sizestore(del_block.header+4,info->s->state.dellink);
00878 memset(del_block.header+12, 255, 8);
00879 if (info->s->file_write(info,(unsigned char*) del_block.header,20, next_pos,
00880 MYF(MY_NABP)))
00881 return(1);
00882 info->s->state.dellink= next_pos;
00883 info->s->state.split++;
00884 info->state->del++;
00885 info->state->empty+= rest_length;
00886 length-= rest_length;
00887 }
00888 }
00889 }
00890 }
00891 }
00892 else
00893 {
00894 if (_mi_find_writepos(info,reclength,&filepos,&length))
00895 goto err;
00896 }
00897 if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
00898 &record,&reclength,&flag))
00899 goto err;
00900 if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
00901 {
00902
00903 filepos=info->s->state.dellink;
00904 }
00905 }
00906
00907 if (block_info.next_filepos != HA_OFFSET_ERROR)
00908 if (delete_dynamic_record(info,block_info.next_filepos,1))
00909 goto err;
00910 return(0);
00911 err:
00912 return(1);
00913 }
00914
00915
00916
00917
00918 uint32_t _mi_rec_pack(MI_INFO *info, register unsigned char *to,
00919 register const unsigned char *from)
00920 {
00921 uint length,new_length,flag,bit,i;
00922 unsigned char *pos,*end,*startpos,*packpos;
00923 enum en_fieldtype type;
00924 register MI_COLUMNDEF *rec;
00925 MI_BLOB *blob;
00926
00927 flag=0 ; bit=1;
00928 startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
00929 rec=info->s->rec;
00930
00931 for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
00932 {
00933 length=(uint) rec->length;
00934 if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
00935 {
00936 if (type == FIELD_BLOB)
00937 {
00938 if (!blob->length)
00939 flag|=bit;
00940 else
00941 {
00942 char *temp_pos;
00943 size_t tmp_length=length-portable_sizeof_char_ptr;
00944 memcpy(to,from,tmp_length);
00945 memcpy(&temp_pos,from+tmp_length,sizeof(char*));
00946 memcpy(to + tmp_length, temp_pos, blob->length);
00947 to+=tmp_length+blob->length;
00948 }
00949 blob++;
00950 }
00951 else if (type == FIELD_SKIP_ZERO)
00952 {
00953 if (memcmp(from,zero_string,length) == 0)
00954 flag|=bit;
00955 else
00956 {
00957 memcpy(to, from, length);
00958 to+=length;
00959 }
00960 }
00961 else if (type == FIELD_SKIP_ENDSPACE ||
00962 type == FIELD_SKIP_PRESPACE)
00963 {
00964 pos= (unsigned char*) from; end= (unsigned char*) from + length;
00965 if (type == FIELD_SKIP_ENDSPACE)
00966 {
00967 while (end > from && *(end-1) == ' ')
00968 end--;
00969 }
00970 else
00971 {
00972 while (pos < end && *pos == ' ')
00973 pos++;
00974 }
00975 new_length=(uint) (end-pos);
00976 if (new_length +1 + test(rec->length > 255 && new_length > 127)
00977 < length)
00978 {
00979 if (rec->length > 255 && new_length > 127)
00980 {
00981 to[0]= (unsigned char) ((new_length & 127) + 128);
00982 to[1]= (unsigned char) (new_length >> 7);
00983 to+=2;
00984 }
00985 else
00986 *to++= (unsigned char) new_length;
00987 memcpy(to, pos, new_length);
00988 to+=new_length;
00989 flag|=bit;
00990 }
00991 else
00992 {
00993 memcpy(to, from, length);
00994 to+=length;
00995 }
00996 }
00997 else if (type == FIELD_VARCHAR)
00998 {
00999 uint32_t pack_length= ha_varchar_packlength(rec->length -1);
01000 uint32_t tmp_length;
01001 if (pack_length == 1)
01002 {
01003 tmp_length= (uint) *(unsigned char*) from;
01004 *to++= *from;
01005 }
01006 else
01007 {
01008 tmp_length= uint2korr(from);
01009 store_key_length_inc(to,tmp_length);
01010 }
01011 memcpy(to, from+pack_length, tmp_length);
01012 to+= tmp_length;
01013 continue;
01014 }
01015 else
01016 {
01017 memcpy(to, from, length);
01018 to+=length;
01019 continue;
01020 }
01021 if ((bit= bit << 1) >= 256)
01022 {
01023 *packpos++= (unsigned char) flag;
01024 bit=1; flag=0;
01025 }
01026 }
01027 else
01028 {
01029 memcpy(to, from, length);
01030 to+=length;
01031 }
01032 }
01033 if (bit != 1)
01034 *packpos= (unsigned char) flag;
01035 if (info->s->calc_checksum)
01036 *to++= (unsigned char) info->checksum;
01037 return((uint) (to-startpos));
01038 }
01039
01040
01041
01042
01043
01044
01045
01046
01047 bool _mi_rec_check(MI_INFO *info,const unsigned char *record, unsigned char *rec_buff,
01048 ulong packed_length, bool with_checksum)
01049 {
01050 uint length,new_length,flag,bit,i;
01051 unsigned char *pos,*end,*packpos,*to;
01052 enum en_fieldtype type;
01053 register MI_COLUMNDEF *rec;
01054
01055 packpos=rec_buff; to= rec_buff+info->s->base.pack_bits;
01056 rec=info->s->rec;
01057 flag= *packpos; bit=1;
01058
01059 for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
01060 {
01061 length=(uint) rec->length;
01062 if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
01063 {
01064 if (type == FIELD_BLOB)
01065 {
01066 uint32_t blob_length=
01067 _mi_calc_blob_length(length-portable_sizeof_char_ptr,record);
01068 if (!blob_length && !(flag & bit))
01069 goto err;
01070 if (blob_length)
01071 to+=length - portable_sizeof_char_ptr+ blob_length;
01072 }
01073 else if (type == FIELD_SKIP_ZERO)
01074 {
01075 if (memcmp(record,zero_string,length) == 0)
01076 {
01077 if (!(flag & bit))
01078 goto err;
01079 }
01080 else
01081 to+=length;
01082 }
01083 else if (type == FIELD_SKIP_ENDSPACE ||
01084 type == FIELD_SKIP_PRESPACE)
01085 {
01086 pos= (unsigned char*) record; end= (unsigned char*) record + length;
01087 if (type == FIELD_SKIP_ENDSPACE)
01088 {
01089 while (end > record && *(end-1) == ' ')
01090 end--;
01091 }
01092 else
01093 {
01094 while (pos < end && *pos == ' ')
01095 pos++;
01096 }
01097 new_length=(uint) (end-pos);
01098 if (new_length +1 + test(rec->length > 255 && new_length > 127)
01099 < length)
01100 {
01101 if (!(flag & bit))
01102 goto err;
01103 if (rec->length > 255 && new_length > 127)
01104 {
01105 if (to[0] != (unsigned char) ((new_length & 127) + 128) ||
01106 to[1] != (unsigned char) (new_length >> 7))
01107 goto err;
01108 to+=2;
01109 }
01110 else if (*to++ != (unsigned char) new_length)
01111 goto err;
01112 to+=new_length;
01113 }
01114 else
01115 to+=length;
01116 }
01117 else if (type == FIELD_VARCHAR)
01118 {
01119 uint32_t pack_length= ha_varchar_packlength(rec->length -1);
01120 uint32_t tmp_length;
01121 if (pack_length == 1)
01122 {
01123 tmp_length= (uint) *(unsigned char*) record;
01124 to+= 1+ tmp_length;
01125 continue;
01126 }
01127 else
01128 {
01129 tmp_length= uint2korr(record);
01130 to+= get_pack_length(tmp_length)+tmp_length;
01131 }
01132 continue;
01133 }
01134 else
01135 {
01136 to+=length;
01137 continue;
01138 }
01139 if ((bit= bit << 1) >= 256)
01140 {
01141 flag= *++packpos;
01142 bit=1;
01143 }
01144 }
01145 else
01146 to+= length;
01147 }
01148 if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) ||
01149 (bit != 1 && (flag & ~(bit - 1))))
01150 goto err;
01151 if (with_checksum && ((unsigned char) info->checksum != (unsigned char) *to))
01152 {
01153 goto err;
01154 }
01155 return(0);
01156
01157 err:
01158 return(1);
01159 }
01160
01161
01162
01163
01164
01165
01166
01167 ulong _mi_rec_unpack(register MI_INFO *info, register unsigned char *to, unsigned char *from,
01168 ulong found_length)
01169 {
01170 uint32_t flag,bit,length,rec_length,min_pack_length;
01171 enum en_fieldtype type;
01172 unsigned char *from_end,*to_end,*packpos;
01173 register MI_COLUMNDEF *rec,*end_field;
01174
01175 to_end=to + info->s->base.reclength;
01176 from_end=from+found_length;
01177 flag= (unsigned char) *from; bit=1; packpos=from;
01178 if (found_length < info->s->base.min_pack_length)
01179 goto err;
01180 from+= info->s->base.pack_bits;
01181 min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
01182
01183 for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
01184 rec < end_field ; to+= rec_length, rec++)
01185 {
01186 rec_length=rec->length;
01187 if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL &&
01188 (type != FIELD_CHECK))
01189 {
01190 if (type == FIELD_VARCHAR)
01191 {
01192 uint32_t pack_length= ha_varchar_packlength(rec_length-1);
01193 if (pack_length == 1)
01194 {
01195 length= (uint) *(unsigned char*) from;
01196 if (length > rec_length-1)
01197 goto err;
01198 *to= *from++;
01199 }
01200 else
01201 {
01202 get_key_length(length, from);
01203 if (length > rec_length-2)
01204 goto err;
01205 int2store(to,length);
01206 }
01207 if (from+length > from_end)
01208 goto err;
01209 memcpy(to+pack_length, from, length);
01210 from+= length;
01211 min_pack_length--;
01212 continue;
01213 }
01214 if (flag & bit)
01215 {
01216 if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
01217 memset(to, 0, rec_length);
01218 else if (type == FIELD_SKIP_ENDSPACE ||
01219 type == FIELD_SKIP_PRESPACE)
01220 {
01221 if (rec->length > 255 && *from & 128)
01222 {
01223 if (from + 1 >= from_end)
01224 goto err;
01225 length= (*from & 127)+ ((uint) (unsigned char) *(from+1) << 7); from+=2;
01226 }
01227 else
01228 {
01229 if (from == from_end)
01230 goto err;
01231 length= (unsigned char) *from++;
01232 }
01233 min_pack_length--;
01234 if (length >= rec_length ||
01235 min_pack_length + length > (uint) (from_end - from))
01236 goto err;
01237 if (type == FIELD_SKIP_ENDSPACE)
01238 {
01239 memcpy(to, from, length);
01240 memset(to+length, ' ', rec_length-length);
01241 }
01242 else
01243 {
01244 memset(to, ' ', rec_length-length);
01245 memcpy(to + rec_length - length, from, length);
01246 }
01247 from+=length;
01248 }
01249 }
01250 else if (type == FIELD_BLOB)
01251 {
01252 uint32_t size_length=rec_length- portable_sizeof_char_ptr;
01253 ulong blob_length=_mi_calc_blob_length(size_length,from);
01254 ulong from_left= (ulong) (from_end - from);
01255 if (from_left < size_length ||
01256 from_left - size_length < blob_length ||
01257 from_left - size_length - blob_length < min_pack_length)
01258 goto err;
01259 memcpy(to, from, size_length);
01260 from+=size_length;
01261 memcpy(to+size_length, &from, sizeof(char*));
01262 from+=blob_length;
01263 }
01264 else
01265 {
01266 if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
01267 min_pack_length--;
01268 if (min_pack_length + rec_length > (uint) (from_end - from))
01269 goto err;
01270 memcpy(to, from, rec_length);
01271 from+=rec_length;
01272 }
01273 if ((bit= bit << 1) >= 256)
01274 {
01275 flag= (unsigned char) *++packpos; bit=1;
01276 }
01277 }
01278 else
01279 {
01280 if (min_pack_length > (uint) (from_end - from))
01281 goto err;
01282 min_pack_length-=rec_length;
01283 memcpy(to, from, rec_length);
01284 from+=rec_length;
01285 }
01286 }
01287 if (info->s->calc_checksum)
01288 from++;
01289 if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
01290 return(found_length);
01291
01292 err:
01293 errno= HA_ERR_WRONG_IN_RECORD;
01294 return(MY_FILE_ERROR);
01295 }
01296
01297
01298
01299
01300 ulong _my_calc_total_blob_length(MI_INFO *info, const unsigned char *record)
01301 {
01302 ulong length;
01303 MI_BLOB *blob,*end;
01304
01305 for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
01306 blob != end;
01307 blob++)
01308 {
01309 blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
01310 length+=blob->length;
01311 }
01312 return length;
01313 }
01314
01315
01316 ulong _mi_calc_blob_length(uint32_t length, const unsigned char *pos)
01317 {
01318 switch (length) {
01319 case 1:
01320 return (uint) (unsigned char) *pos;
01321 case 2:
01322 return (uint) uint2korr(pos);
01323 case 3:
01324 return uint3korr(pos);
01325 case 4:
01326 return uint4korr(pos);
01327 default:
01328 break;
01329 }
01330 return 0;
01331 }
01332
01333
01334 void _my_store_blob_length(unsigned char *pos,uint32_t pack_length,uint32_t length)
01335 {
01336 switch (pack_length) {
01337 case 1:
01338 *pos= (unsigned char) length;
01339 break;
01340 case 2:
01341 int2store(pos,length);
01342 break;
01343 case 3:
01344 int3store(pos,length);
01345 break;
01346 case 4:
01347 int4store(pos,length);
01348 default:
01349 break;
01350 }
01351 return;
01352 }
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 int _mi_read_dynamic_record(MI_INFO *info, internal::my_off_t filepos, unsigned char *buf)
01388 {
01389 int block_of_record;
01390 uint32_t b_type, left_length= 0;
01391 unsigned char *to= NULL;
01392 MI_BLOCK_INFO block_info;
01393 int file;
01394
01395 if (filepos != HA_OFFSET_ERROR)
01396 {
01397 file=info->dfile;
01398 block_of_record= 0;
01399 block_info.second_read= 0;
01400 do
01401 {
01402
01403 if (filepos == HA_OFFSET_ERROR)
01404 goto panic;
01405 if (info->opt_flag & WRITE_CACHE_USED &&
01406 info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
01407 info->rec_cache.flush())
01408 goto err;
01409 info->rec_cache.seek_not_done=1;
01410 if ((b_type= _mi_get_block_info(&block_info, file, filepos))
01411 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
01412 BLOCK_FATAL_ERROR))
01413 {
01414 if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
01415 errno=HA_ERR_RECORD_DELETED;
01416 goto err;
01417 }
01418 if (block_of_record++ == 0)
01419 {
01420 if (block_info.rec_len > (uint) info->s->base.max_pack_length)
01421 goto panic;
01422 if (info->s->base.blobs)
01423 {
01424 if (!(to=mi_alloc_rec_buff(info, block_info.rec_len,
01425 &info->rec_buff)))
01426 goto err;
01427 }
01428 else
01429 to= info->rec_buff;
01430 left_length=block_info.rec_len;
01431 }
01432 if (left_length < block_info.data_len || ! block_info.data_len)
01433 goto panic;
01434
01435 {
01436 uint32_t offset= (uint) (block_info.filepos - filepos);
01437 uint32_t prefetch_len= (sizeof(block_info.header) - offset);
01438 filepos+= sizeof(block_info.header);
01439
01440 if (prefetch_len > block_info.data_len)
01441 prefetch_len= block_info.data_len;
01442 if (prefetch_len)
01443 {
01444 memcpy(to, block_info.header + offset, prefetch_len);
01445 block_info.data_len-= prefetch_len;
01446 left_length-= prefetch_len;
01447 to+= prefetch_len;
01448 }
01449 }
01450
01451 if (block_info.data_len)
01452 {
01453 if (info->opt_flag & WRITE_CACHE_USED &&
01454 info->rec_cache.pos_in_file < filepos + block_info.data_len &&
01455 info->rec_cache.flush())
01456 goto err;
01457
01458
01459
01460
01461
01462 if (info->s->file_read(info, (unsigned char*) to, block_info.data_len,
01463 filepos, MYF(MY_NABP)))
01464 goto panic;
01465 left_length-=block_info.data_len;
01466 to+=block_info.data_len;
01467 }
01468 filepos= block_info.next_filepos;
01469 } while (left_length);
01470
01471 info->update|= HA_STATE_AKTIV;
01472 fast_mi_writeinfo(info);
01473 return(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
01474 MY_FILE_ERROR ? 0 : -1);
01475 }
01476 fast_mi_writeinfo(info);
01477 return(-1);
01478
01479 panic:
01480 errno=HA_ERR_WRONG_IN_RECORD;
01481 err:
01482 _mi_writeinfo(info,0);
01483 return(-1);
01484 }
01485
01486
01487
01488 int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
01489 const unsigned char *record, internal::my_off_t pos)
01490 {
01491 unsigned char *rec_buff,*old_record;
01492 int error;
01493
01494 if (!(old_record=(unsigned char *)malloc(info->s->base.reclength)))
01495 return(1);
01496
01497
01498 rec_buff=info->rec_buff;
01499 if (info->s->base.blobs)
01500 info->rec_buff=0;
01501 error=_mi_read_dynamic_record(info,pos,old_record);
01502 if (!error)
01503 error=mi_unique_comp(def, record, old_record, def->null_are_equal);
01504 if (info->s->base.blobs)
01505 {
01506 void * rec_buff_ptr= mi_get_rec_buff_ptr(info, info->rec_buff);
01507 free(rec_buff_ptr);
01508 info->rec_buff=rec_buff;
01509 }
01510 free(old_record);
01511 return(error);
01512 }
01513
01514
01515
01516
01517 int _mi_cmp_dynamic_record(register MI_INFO *info, register const unsigned char *record)
01518 {
01519 uint32_t flag,reclength,b_type;
01520 internal::my_off_t filepos;
01521 unsigned char *buffer;
01522 MI_BLOCK_INFO block_info;
01523
01524 if (info->opt_flag & WRITE_CACHE_USED)
01525 {
01526 info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
01527 if (info->rec_cache.flush())
01528 return(-1);
01529 }
01530 info->rec_cache.seek_not_done=1;
01531
01532
01533
01534 buffer=info->rec_buff;
01535 if ((info->opt_flag & READ_CHECK_USED))
01536 {
01537 if (info->s->base.blobs)
01538 {
01539 if (!(buffer=(unsigned char*) malloc(info->s->base.pack_reclength+
01540 _my_calc_total_blob_length(info,record))))
01541 return(-1);
01542 }
01543 reclength=_mi_rec_pack(info,buffer,record);
01544 record= buffer;
01545
01546 filepos=info->lastpos;
01547 flag=block_info.second_read=0;
01548 block_info.next_filepos=filepos;
01549 while (reclength > 0)
01550 {
01551 if ((b_type=_mi_get_block_info(&block_info,info->dfile,
01552 block_info.next_filepos))
01553 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
01554 BLOCK_FATAL_ERROR))
01555 {
01556 if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
01557 errno=HA_ERR_RECORD_CHANGED;
01558 goto err;
01559 }
01560 if (flag == 0)
01561 {
01562 flag=1;
01563 if (reclength != block_info.rec_len)
01564 {
01565 errno=HA_ERR_RECORD_CHANGED;
01566 goto err;
01567 }
01568 } else if (reclength < block_info.data_len)
01569 {
01570 errno=HA_ERR_WRONG_IN_RECORD;
01571 goto err;
01572 }
01573 reclength-=block_info.data_len;
01574 if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
01575 block_info.data_len))
01576 {
01577 errno=HA_ERR_RECORD_CHANGED;
01578 goto err;
01579 }
01580 flag=1;
01581 record+=block_info.data_len;
01582 }
01583 }
01584 errno=0;
01585 err:
01586 if (buffer != info->rec_buff)
01587 free((unsigned char*) buffer);
01588 return(errno);
01589 }
01590
01591
01592
01593
01594 static int _mi_cmp_buffer(int file, const unsigned char *buff, internal::my_off_t filepos,
01595 uint32_t length)
01596 {
01597 uint32_t next_length;
01598 unsigned char temp_buff[IO_SIZE*2];
01599
01600 next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
01601
01602 while (length > IO_SIZE*2)
01603 {
01604 if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
01605 memcmp(buff, temp_buff, next_length))
01606 goto err;
01607 filepos+=next_length;
01608 buff+=next_length;
01609 length-= next_length;
01610 next_length=IO_SIZE*2;
01611 }
01612 if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
01613 goto err;
01614 return(memcmp(buff,temp_buff,length));
01615 err:
01616 return(1);
01617 }
01618
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 int _mi_read_rnd_dynamic_record(MI_INFO *info, unsigned char *buf,
01655 register internal::my_off_t filepos,
01656 bool skip_deleted_blocks)
01657 {
01658 int block_of_record, info_read, save_errno;
01659 uint32_t left_len,b_type;
01660 unsigned char *to= NULL;
01661 MI_BLOCK_INFO block_info;
01662 MYISAM_SHARE *share=info->s;
01663
01664 info_read=0;
01665
01666 if (info->lock_type == F_UNLCK)
01667 {
01668 info->tmp_lock_type=F_RDLCK;
01669 }
01670 else
01671 info_read=1;
01672
01673 block_of_record= 0;
01674 block_info.second_read= 0;
01675 left_len=1;
01676 do
01677 {
01678 if (filepos >= info->state->data_file_length)
01679 {
01680 if (!info_read)
01681 {
01682 info_read=1;
01683 info->rec_cache.seek_not_done=1;
01684 if (mi_state_info_read_dsk(share->kfile,&share->state,1))
01685 goto panic;
01686 }
01687 if (filepos >= info->state->data_file_length)
01688 {
01689 errno= HA_ERR_END_OF_FILE;
01690 goto err;
01691 }
01692 }
01693 if (info->opt_flag & READ_CACHE_USED)
01694 {
01695 if (_mi_read_cache(&info->rec_cache,(unsigned char*) block_info.header,filepos,
01696 sizeof(block_info.header),
01697 (!block_of_record && skip_deleted_blocks ?
01698 READING_NEXT : 0) | READING_HEADER))
01699 goto panic;
01700 b_type=_mi_get_block_info(&block_info,-1,filepos);
01701 }
01702 else
01703 {
01704 if (info->opt_flag & WRITE_CACHE_USED &&
01705 info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
01706 info->rec_cache.flush())
01707 return(errno);
01708 info->rec_cache.seek_not_done=1;
01709 b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
01710 }
01711
01712 if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
01713 BLOCK_FATAL_ERROR))
01714 {
01715 if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
01716 && skip_deleted_blocks)
01717 {
01718 filepos=block_info.filepos+block_info.block_len;
01719 block_info.second_read=0;
01720 continue;
01721 }
01722 if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
01723 {
01724 errno=HA_ERR_RECORD_DELETED;
01725 info->lastpos=block_info.filepos;
01726 info->nextpos=block_info.filepos+block_info.block_len;
01727 }
01728 goto err;
01729 }
01730 if (block_of_record == 0)
01731 {
01732 if (block_info.rec_len > (uint) share->base.max_pack_length)
01733 goto panic;
01734 info->lastpos=filepos;
01735 if (share->base.blobs)
01736 {
01737 if (!(to= mi_alloc_rec_buff(info, block_info.rec_len,
01738 &info->rec_buff)))
01739 goto err;
01740 }
01741 else
01742 to= info->rec_buff;
01743 left_len=block_info.rec_len;
01744 }
01745 if (left_len < block_info.data_len)
01746 goto panic;
01747
01748
01749 {
01750 uint32_t offset=(uint) (block_info.filepos - filepos);
01751 uint32_t tmp_length= (sizeof(block_info.header) - offset);
01752 filepos=block_info.filepos;
01753
01754 if (tmp_length > block_info.data_len)
01755 tmp_length= block_info.data_len;
01756 if (tmp_length)
01757 {
01758 memcpy(to, block_info.header+offset,tmp_length);
01759 block_info.data_len-=tmp_length;
01760 left_len-=tmp_length;
01761 to+=tmp_length;
01762 filepos+=tmp_length;
01763 }
01764 }
01765
01766 if (block_info.data_len)
01767 {
01768 if (info->opt_flag & READ_CACHE_USED)
01769 {
01770 if (_mi_read_cache(&info->rec_cache,(unsigned char*) to,filepos,
01771 block_info.data_len,
01772 (!block_of_record && skip_deleted_blocks) ?
01773 READING_NEXT : 0))
01774 goto panic;
01775 }
01776 else
01777 {
01778 if (info->opt_flag & WRITE_CACHE_USED &&
01779 info->rec_cache.pos_in_file <
01780 block_info.filepos + block_info.data_len &&
01781 info->rec_cache.flush())
01782 goto err;
01783
01784 if (internal::my_read(info->dfile,(unsigned char*) to,block_info.data_len,MYF(MY_NABP)))
01785 {
01786 if (errno == -1)
01787 errno= HA_ERR_WRONG_IN_RECORD;
01788 goto err;
01789 }
01790 }
01791 }
01792
01793
01794
01795
01796 if (block_of_record++ == 0)
01797 {
01798 info->nextpos= block_info.filepos + block_info.block_len;
01799 skip_deleted_blocks= 0;
01800 }
01801 left_len-=block_info.data_len;
01802 to+=block_info.data_len;
01803 filepos=block_info.next_filepos;
01804 } while (left_len);
01805
01806 info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
01807 fast_mi_writeinfo(info);
01808 if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
01809 MY_FILE_ERROR)
01810 return(0);
01811 return(errno);
01812
01813 panic:
01814 errno=HA_ERR_WRONG_IN_RECORD;
01815 err:
01816 save_errno=errno;
01817 _mi_writeinfo(info,0);
01818 return(errno=save_errno);
01819 }
01820
01821
01822
01823
01824 uint32_t _mi_get_block_info(MI_BLOCK_INFO *info, int file, internal::my_off_t filepos)
01825 {
01826 uint32_t return_val=0;
01827 unsigned char *header=info->header;
01828
01829 if (file >= 0)
01830 {
01831
01832
01833
01834
01835
01836 lseek(file,filepos,SEEK_SET);
01837 if (internal::my_read(file, header, sizeof(info->header),MYF(0)) !=
01838 sizeof(info->header))
01839 goto err;
01840 }
01841 if (info->second_read)
01842 {
01843 if (info->header[0] <= 6 || info->header[0] == 13)
01844 return_val=BLOCK_SYNC_ERROR;
01845 }
01846 else
01847 {
01848 if (info->header[0] > 6 && info->header[0] != 13)
01849 return_val=BLOCK_SYNC_ERROR;
01850 }
01851 info->next_filepos= HA_OFFSET_ERROR;
01852
01853 switch (info->header[0]) {
01854 case 0:
01855 if ((info->block_len=(uint) mi_uint3korr(header+1)) <
01856 MI_MIN_BLOCK_LENGTH ||
01857 (info->block_len & (MI_DYN_ALIGN_SIZE -1)))
01858 goto err;
01859 info->filepos=filepos;
01860 info->next_filepos=mi_sizekorr(header+4);
01861 info->prev_filepos=mi_sizekorr(header+12);
01862 #if SIZEOF_OFF_T == 4
01863 if ((mi_uint4korr(header+4) != 0 &&
01864 (mi_uint4korr(header+4) != UINT32_MAX ||
01865 info->next_filepos != UINT32_MAX) ||
01866 (mi_uint4korr(header+12) != 0 &&
01867 (mi_uint4korr(header+12) != UINT32_MAX ||
01868 info->prev_filepos != UINT32_MAX))
01869 goto err;
01870 #endif
01871 return return_val | BLOCK_DELETED;
01872
01873 case 1:
01874 info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
01875 info->filepos=filepos+3;
01876 return return_val | BLOCK_FIRST | BLOCK_LAST;
01877 case 2:
01878 info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
01879 info->filepos=filepos+4;
01880 return return_val | BLOCK_FIRST | BLOCK_LAST;
01881
01882 case 13:
01883 info->rec_len=mi_uint4korr(header+1);
01884 info->block_len=info->data_len=mi_uint3korr(header+5);
01885 info->next_filepos=mi_sizekorr(header+8);
01886 info->second_read=1;
01887 info->filepos=filepos+16;
01888 return return_val | BLOCK_FIRST;
01889
01890 case 3:
01891 info->rec_len=info->data_len=mi_uint2korr(header+1);
01892 info->block_len=info->rec_len+ (uint) header[3];
01893 info->filepos=filepos+4;
01894 return return_val | BLOCK_FIRST | BLOCK_LAST;
01895 case 4:
01896 info->rec_len=info->data_len=mi_uint3korr(header+1);
01897 info->block_len=info->rec_len+ (uint) header[4];
01898 info->filepos=filepos+5;
01899 return return_val | BLOCK_FIRST | BLOCK_LAST;
01900
01901 case 5:
01902 info->rec_len=mi_uint2korr(header+1);
01903 info->block_len=info->data_len=mi_uint2korr(header+3);
01904 info->next_filepos=mi_sizekorr(header+5);
01905 info->second_read=1;
01906 info->filepos=filepos+13;
01907 return return_val | BLOCK_FIRST;
01908 case 6:
01909 info->rec_len=mi_uint3korr(header+1);
01910 info->block_len=info->data_len=mi_uint3korr(header+4);
01911 info->next_filepos=mi_sizekorr(header+7);
01912 info->second_read=1;
01913 info->filepos=filepos+15;
01914 return return_val | BLOCK_FIRST;
01915
01916
01917 case 7:
01918 info->data_len=info->block_len=mi_uint2korr(header+1);
01919 info->filepos=filepos+3;
01920 return return_val | BLOCK_LAST;
01921 case 8:
01922 info->data_len=info->block_len=mi_uint3korr(header+1);
01923 info->filepos=filepos+4;
01924 return return_val | BLOCK_LAST;
01925
01926 case 9:
01927 info->data_len=mi_uint2korr(header+1);
01928 info->block_len=info->data_len+ (uint) header[3];
01929 info->filepos=filepos+4;
01930 return return_val | BLOCK_LAST;
01931 case 10:
01932 info->data_len=mi_uint3korr(header+1);
01933 info->block_len=info->data_len+ (uint) header[4];
01934 info->filepos=filepos+5;
01935 return return_val | BLOCK_LAST;
01936
01937 case 11:
01938 info->data_len=info->block_len=mi_uint2korr(header+1);
01939 info->next_filepos=mi_sizekorr(header+3);
01940 info->second_read=1;
01941 info->filepos=filepos+11;
01942 return return_val;
01943 case 12:
01944 info->data_len=info->block_len=mi_uint3korr(header+1);
01945 info->next_filepos=mi_sizekorr(header+4);
01946 info->second_read=1;
01947 info->filepos=filepos+12;
01948 return return_val;
01949 }
01950
01951 err:
01952 errno=HA_ERR_WRONG_IN_RECORD;
01953 return BLOCK_ERROR;
01954 }