26 #include "myisam_priv.h"
29 #include <sys/types.h>
31 #ifdef HAVE_SYS_MMAN_H
34 #include <drizzled/util/test.h>
35 #include <drizzled/error.h>
44 static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
46 static int write_dynamic_record(
MI_INFO *info,
const unsigned char *record,
48 static int _mi_find_writepos(
MI_INFO *info,ulong reclength,internal::my_off_t *filepos,
50 static int update_dynamic_record(
MI_INFO *info,internal::my_off_t filepos,
unsigned char *record,
52 static int delete_dynamic_record(
MI_INFO *info,internal::my_off_t filepos,
53 uint32_t second_read);
54 static int _mi_cmp_buffer(
int file,
const unsigned char *buff, internal::my_off_t filepos,
72 bool mi_dynmap_file(
MI_INFO *info, internal::my_off_t size)
74 if (size > (internal::my_off_t) (~((
size_t) 0)) - MEMMAP_EXTRA_MARGIN)
86 info->s->file_map= (
unsigned char*)
87 mmap(NULL, (
size_t)(size + MEMMAP_EXTRA_MARGIN),
88 info->s->mode==O_RDONLY ? PROT_READ :
89 PROT_READ | PROT_WRITE,
90 MAP_SHARED | MAP_NORESERVE,
92 if (info->s->file_map == (
unsigned char*) MAP_FAILED)
94 info->s->file_map= NULL;
98 #if !defined(TARGET_OS_SOLARIS)
99 madvise((
char*) info->s->file_map, size, MADV_RANDOM);
101 info->s->mmaped_length= size;
116 void mi_remap_file(
MI_INFO *info, internal::my_off_t size)
118 if (info->s->file_map)
120 munmap((
char*) info->s->file_map,
121 (
size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN);
122 mi_dynmap_file(info, size);
142 size_t mi_mmap_pread(
MI_INFO *info,
unsigned char *Buffer,
143 size_t Count, internal::my_off_t offset, myf MyFlags)
152 if (info->s->mmaped_length >= offset + Count)
154 memcpy(Buffer, info->s->file_map + offset, Count);
159 return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
166 size_t mi_nommap_pread(
MI_INFO *info,
unsigned char *Buffer,
167 size_t Count, internal::my_off_t offset, myf MyFlags)
169 return my_pread(info->dfile, Buffer, Count, offset, MyFlags);
189 size_t mi_mmap_pwrite(
MI_INFO *info,
const unsigned char *Buffer,
190 size_t Count, internal::my_off_t offset, myf MyFlags)
200 if (info->s->mmaped_length >= offset + Count)
202 memcpy(info->s->file_map + offset, Buffer, Count);
207 info->s->nonmmaped_inserts++;
208 return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
216 size_t mi_nommap_pwrite(
MI_INFO *info,
const unsigned char *Buffer,
217 size_t Count, internal::my_off_t offset, myf MyFlags)
219 return my_pwrite(info->dfile, Buffer, Count, offset, MyFlags);
223 int _mi_write_dynamic_record(
MI_INFO *info,
const unsigned char *record)
225 ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
226 return (write_dynamic_record(info,info->rec_buff,reclength));
229 int _mi_update_dynamic_record(
MI_INFO *info, internal::my_off_t pos,
const unsigned char *record)
231 uint32_t length=_mi_rec_pack(info,info->rec_buff,record);
232 return (update_dynamic_record(info,pos,info->rec_buff,length));
235 int _mi_write_blob_record(
MI_INFO *info,
const unsigned char *record)
237 unsigned char *rec_buff;
239 ulong reclength,reclength2,extra;
241 extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
242 MI_DYN_DELETE_BLOCK_HEADER+1);
243 reclength= (info->s->base.pack_reclength +
244 _my_calc_total_blob_length(info,record)+ extra);
246 if (reclength > MI_DYN_MAX_ROW_LENGTH)
248 errno=HA_ERR_TO_BIG_ROW;
252 if (!(rec_buff=(
unsigned char*) malloc(reclength)))
254 errno= HA_ERR_OUT_OF_MEM;
257 reclength2= _mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
259 assert(reclength2 <= reclength);
260 error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
267 int _mi_update_blob_record(
MI_INFO *info, internal::my_off_t pos,
const unsigned char *record)
269 unsigned char *rec_buff;
271 ulong reclength,extra;
273 extra= (ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
274 MI_DYN_DELETE_BLOCK_HEADER);
275 reclength= (info->s->base.pack_reclength+
276 _my_calc_total_blob_length(info,record)+ extra);
278 if (reclength > MI_DYN_MAX_ROW_LENGTH)
280 errno=HA_ERR_TO_BIG_ROW;
284 if (!(rec_buff=(
unsigned char*) malloc(reclength)))
286 errno= HA_ERR_OUT_OF_MEM;
289 reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
291 error=update_dynamic_record(info,pos,
292 rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
299 int _mi_delete_dynamic_record(
MI_INFO *info)
301 return delete_dynamic_record(info,info->lastpos,0);
307 static int write_dynamic_record(
MI_INFO *info,
const unsigned char *record,
312 internal::my_off_t filepos;
325 if (unlikely(info->s->base.max_data_file_length -
326 info->state->data_file_length <
327 reclength + MI_MAX_DYN_BLOCK_HEADER))
329 if (info->s->base.max_data_file_length - info->state->data_file_length +
330 info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
331 reclength + MI_MAX_DYN_BLOCK_HEADER)
333 errno=HA_ERR_RECORD_FILE_FULL;
340 if (_mi_find_writepos(info,reclength,&filepos,&length))
342 if (_mi_write_part_record(info,filepos,length,
343 (info->append_insert_at_end ?
344 HA_OFFSET_ERROR : info->s->state.dellink),
345 (
unsigned char**) &record,&reclength,&flag))
357 static int _mi_find_writepos(
MI_INFO *info,
359 internal::my_off_t *filepos,
365 if (info->s->state.dellink != HA_OFFSET_ERROR &&
366 !info->append_insert_at_end)
369 *filepos=info->s->state.dellink;
370 block_info.second_read=0;
371 info->rec_cache.seek_not_done=1;
372 if (!(_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
375 errno=HA_ERR_WRONG_IN_RECORD;
378 info->s->state.dellink=block_info.next_filepos;
380 info->state->empty-= block_info.block_len;
381 *length= block_info.block_len;
386 *filepos=info->state->data_file_length;
387 if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
388 info->s->base.min_block_length)
389 tmp= info->s->base.min_block_length;
391 tmp= ((tmp+MI_DYN_ALIGN_SIZE-1) &
392 (~ (ulong) (MI_DYN_ALIGN_SIZE-1)));
393 if (info->state->data_file_length >
394 (info->s->base.max_data_file_length - tmp))
396 errno=HA_ERR_RECORD_FILE_FULL;
399 if (tmp > MI_MAX_BLOCK_LENGTH)
400 tmp=MI_MAX_BLOCK_LENGTH;
402 info->state->data_file_length+= tmp;
403 info->s->state.split++;
404 info->update|=HA_STATE_WRITE_AT_END;
419 if (block_info->filepos == info->s->state.dellink)
422 info->s->state.dellink=block_info->next_filepos;
429 if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
432 mi_sizestore(tmp.header+4,block_info->next_filepos);
433 if (info->s->file_write(info, tmp.header+4,8,
434 block_info->prev_filepos+4, MYF(MY_NABP)))
437 if (block_info->next_filepos != HA_OFFSET_ERROR)
439 if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
442 mi_sizestore(tmp.header+12,block_info->prev_filepos);
443 if (info->s->file_write(info, tmp.header+12,8,
444 block_info->next_filepos+12,
451 info->state->empty-= block_info->block_len;
452 info->s->state.split--;
459 if (info->nextpos == block_info->filepos)
460 info->nextpos+=block_info->block_len;
480 static int update_backward_delete_link(
MI_INFO *info, internal::my_off_t delete_block,
481 internal::my_off_t filepos)
485 if (delete_block != HA_OFFSET_ERROR)
487 block_info.second_read=0;
488 if (_mi_get_block_info(&block_info,info->dfile,delete_block)
491 unsigned char buff[8];
492 mi_sizestore(buff,filepos);
493 if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
498 errno=HA_ERR_WRONG_IN_RECORD;
508 static int delete_dynamic_record(
MI_INFO *info, internal::my_off_t filepos,
509 uint32_t second_read)
511 uint32_t length,b_type;
514 bool remove_next_block;
517 error= update_backward_delete_link(info, info->s->state.dellink, filepos);
519 block_info.second_read=second_read;
523 if ((b_type=_mi_get_block_info(&block_info,info->dfile,filepos))
524 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
525 BLOCK_FATAL_ERROR) ||
526 (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
529 errno=HA_ERR_WRONG_IN_RECORD;
533 del_block.second_read=0;
535 if (_mi_get_block_info(&del_block,info->dfile,filepos+length) &
536 BLOCK_DELETED && del_block.block_len+length < MI_DYN_MAX_BLOCK_LENGTH)
540 length+=del_block.block_len;
543 block_info.header[0]=0;
544 mi_int3store(block_info.header+1,length);
545 mi_sizestore(block_info.header+4,info->s->state.dellink);
546 if (b_type & BLOCK_LAST)
547 memset(block_info.header+12, 255, 8);
549 mi_sizestore(block_info.header+12,block_info.next_filepos);
550 if (info->s->file_write(info,(
unsigned char*) block_info.header,20,filepos,
553 info->s->state.dellink = filepos;
555 info->state->empty+=length;
556 filepos=block_info.next_filepos;
559 if (remove_next_block && unlink_deleted_block(info,&del_block))
561 }
while (!(b_type & BLOCK_LAST));
569 int _mi_write_part_record(
MI_INFO *info,
570 internal::my_off_t filepos,
572 internal::my_off_t next_filepos,
573 unsigned char **record,
577 ulong head_length,res_length,extra_length,long_block,del_length;
578 unsigned char *pos,*record_end;
579 internal::my_off_t next_delete_block;
580 unsigned char temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
582 next_delete_block=HA_OFFSET_ERROR;
584 res_length=extra_length=0;
585 if (length > *reclength + MI_SPLIT_LENGTH)
587 res_length=MY_ALIGN(length- *reclength - MI_EXTEND_BLOCK_LENGTH,
591 long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
592 if (length == *reclength+ 3 + long_block)
595 temp[0]=(
unsigned char) (1+ *flag)+(
unsigned char) long_block;
598 mi_int3store(temp+1,*reclength);
603 mi_int2store(temp+1,*reclength);
607 else if (length-long_block < *reclength+4)
609 if (next_filepos == HA_OFFSET_ERROR)
610 next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
611 !info->append_insert_at_end ?
612 info->s->state.dellink : info->state->data_file_length);
615 if (*reclength > MI_MAX_BLOCK_LENGTH)
619 mi_int4store(temp+1,*reclength);
620 mi_int3store(temp+5,length-head_length);
621 mi_sizestore((
unsigned char*) temp+8,next_filepos);
625 head_length=5+8+long_block*2;
626 temp[0]=5+(
unsigned char) long_block;
629 mi_int3store(temp+1,*reclength);
630 mi_int3store(temp+4,length-head_length);
631 mi_sizestore((
unsigned char*) temp+7,next_filepos);
635 mi_int2store(temp+1,*reclength);
636 mi_int2store(temp+3,length-head_length);
637 mi_sizestore((
unsigned char*) temp+5,next_filepos);
643 head_length=3+8+long_block;
644 temp[0]=11+(
unsigned char) long_block;
647 mi_int3store(temp+1,length-head_length);
648 mi_sizestore((
unsigned char*) temp+4,next_filepos);
652 mi_int2store(temp+1,length-head_length);
653 mi_sizestore((
unsigned char*) temp+3,next_filepos);
659 head_length=4+long_block;
660 extra_length= length- *reclength-head_length;
661 temp[0]= (
unsigned char) (3+ *flag)+(
unsigned char) long_block;
664 mi_int3store(temp+1,*reclength);
665 temp[4]= (
unsigned char) (extra_length);
669 mi_int2store(temp+1,*reclength);
670 temp[3]= (
unsigned char) (extra_length);
672 length= *reclength+head_length;
676 record_end= *record+length-head_length;
677 del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
678 memmove(*record - head_length, temp, head_length);
679 memcpy(temp,record_end,(
size_t) (extra_length+del_length));
680 memset(record_end, 0, extra_length);
686 internal::my_off_t next_block=filepos+length+extra_length+res_length;
688 del_block.second_read=0;
689 if (next_block < info->state->data_file_length &&
690 info->s->state.dellink != HA_OFFSET_ERROR)
692 if ((_mi_get_block_info(&del_block,info->dfile,next_block)
694 res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
696 if (unlink_deleted_block(info,&del_block))
698 res_length+=del_block.block_len;
703 pos=record_end+extra_length;
705 mi_int3store(pos+1,res_length);
706 mi_sizestore(pos+4,info->s->state.dellink);
707 memset(pos+12, 255, 8);
708 next_delete_block=info->s->state.dellink;
709 info->s->state.dellink= filepos+length+extra_length;
711 info->state->empty+=res_length;
712 info->s->state.split++;
714 if (info->opt_flag & WRITE_CACHE_USED &&
715 info->update & HA_STATE_WRITE_AT_END)
717 if (info->update & HA_STATE_EXTEND_BLOCK)
719 info->update&= ~HA_STATE_EXTEND_BLOCK;
720 if (info->rec_cache.block_write(*record - head_length,
721 length+extra_length+del_length,filepos))
724 else if (info->rec_cache.write(*record-head_length, length+extra_length+del_length))
729 info->rec_cache.seek_not_done=1;
730 if (info->s->file_write(info,(
unsigned char*) *record-head_length,length+extra_length+
731 del_length,filepos,info->s->write_flag))
734 memcpy(record_end, temp, extra_length + del_length);
736 *reclength-=(length-head_length);
742 if (update_backward_delete_link(info, next_delete_block,
743 info->s->state.dellink))
755 static int update_dynamic_record(
MI_INFO *info, internal::my_off_t filepos,
unsigned char *record,
763 flag=block_info.second_read=0;
777 if (unlikely(info->s->base.max_data_file_length -
778 info->state->data_file_length < reclength))
784 if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
785 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR))
787 if (!(error & BLOCK_FATAL_ERROR))
788 errno=HA_ERR_WRONG_IN_RECORD;
795 if (block_info.rec_len < reclength)
797 if (info->s->base.max_data_file_length - info->state->data_file_length +
798 info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
799 reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER)
801 errno=HA_ERR_RECORD_FILE_FULL;
805 block_info.second_read=0;
808 while (reclength > 0)
810 if (filepos != info->s->state.dellink)
812 block_info.next_filepos= HA_OFFSET_ERROR;
813 if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
814 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
817 if (!(error & BLOCK_FATAL_ERROR))
818 errno=HA_ERR_WRONG_IN_RECORD;
821 length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
822 if (length < reclength)
824 uint32_t tmp=MY_ALIGN(reclength - length + 3 +
825 test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
827 tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length;
829 if (block_info.filepos + block_info.block_len ==
830 info->state->data_file_length &&
831 info->state->data_file_length <
832 info->s->base.max_data_file_length-tmp)
835 if (info->nextpos == info->state->data_file_length)
837 info->state->data_file_length+= tmp;
838 info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
841 else if (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH)
851 del_block.second_read=0;
852 if (_mi_get_block_info(&del_block,info->dfile,
853 block_info.filepos + block_info.block_len) &
857 if (unlink_deleted_block(info,&del_block))
859 if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH)
865 internal::my_off_t next_pos;
866 ulong rest_length= length-MI_MAX_BLOCK_LENGTH;
867 set_if_bigger(rest_length, (ulong)MI_MIN_BLOCK_LENGTH);
868 next_pos= del_block.filepos+ del_block.block_len - rest_length;
870 if (update_backward_delete_link(info, info->s->state.dellink,
875 del_block.header[0]=0;
876 mi_int3store(del_block.header+1, rest_length);
877 mi_sizestore(del_block.header+4,info->s->state.dellink);
878 memset(del_block.header+12, 255, 8);
879 if (info->s->file_write(info,(
unsigned char*) del_block.header,20, next_pos,
882 info->s->state.dellink= next_pos;
883 info->s->state.split++;
885 info->state->empty+= rest_length;
886 length-= rest_length;
894 if (_mi_find_writepos(info,reclength,&filepos,&length))
897 if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
898 &record,&reclength,&flag))
900 if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
903 filepos=info->s->state.dellink;
907 if (block_info.next_filepos != HA_OFFSET_ERROR)
908 if (delete_dynamic_record(info,block_info.next_filepos,1))
918 uint32_t _mi_rec_pack(
MI_INFO *info,
register unsigned char *to,
919 register const unsigned char *from)
921 uint length,new_length,flag,bit,i;
922 unsigned char *pos,*end,*startpos,*packpos;
923 enum en_fieldtype type;
928 startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
931 for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
933 length=(uint) rec->length;
934 if ((type = (
enum en_fieldtype) rec->type) != FIELD_NORMAL)
936 if (type == FIELD_BLOB)
943 size_t tmp_length=length-portable_sizeof_char_ptr;
944 memcpy(to,from,tmp_length);
945 memcpy(&temp_pos,from+tmp_length,
sizeof(
char*));
946 memcpy(to + tmp_length, temp_pos, blob->length);
947 to+=tmp_length+blob->length;
951 else if (type == FIELD_SKIP_ZERO)
953 if (memcmp(from,zero_string,length) == 0)
957 memcpy(to, from, length);
961 else if (type == FIELD_SKIP_ENDSPACE ||
962 type == FIELD_SKIP_PRESPACE)
964 pos= (
unsigned char*) from; end= (
unsigned char*) from + length;
965 if (type == FIELD_SKIP_ENDSPACE)
967 while (end > from && *(end-1) ==
' ')
972 while (pos < end && *pos ==
' ')
975 new_length=(uint) (end-pos);
976 if (new_length +1 + test(rec->length > 255 && new_length > 127)
979 if (rec->length > 255 && new_length > 127)
981 to[0]= (
unsigned char) ((new_length & 127) + 128);
982 to[1]= (
unsigned char) (new_length >> 7);
986 *to++= (
unsigned char) new_length;
987 memcpy(to, pos, new_length);
993 memcpy(to, from, length);
997 else if (type == FIELD_VARCHAR)
999 uint32_t pack_length= ha_varchar_packlength(rec->length -1);
1000 uint32_t tmp_length;
1001 if (pack_length == 1)
1003 tmp_length= (uint) *(
unsigned char*) from;
1008 tmp_length= uint2korr(from);
1009 store_key_length_inc(to,tmp_length);
1011 memcpy(to, from+pack_length, tmp_length);
1017 memcpy(to, from, length);
1021 if ((bit= bit << 1) >= 256)
1023 *packpos++= (
unsigned char) flag;
1029 memcpy(to, from, length);
1034 *packpos= (
unsigned char) flag;
1035 if (info->s->calc_checksum)
1036 *to++= (
unsigned char) info->checksum;
1037 return((uint) (to-startpos));
1047 bool _mi_rec_check(
MI_INFO *info,
const unsigned char *record,
unsigned char *rec_buff,
1048 ulong packed_length,
bool with_checksum)
1050 uint length,new_length,flag,bit,i;
1051 unsigned char *pos,*end,*packpos,*to;
1052 enum en_fieldtype type;
1055 packpos=rec_buff; to= rec_buff+info->s->base.pack_bits;
1057 flag= *packpos; bit=1;
1059 for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
1061 length=(uint) rec->length;
1062 if ((type = (
enum en_fieldtype) rec->type) != FIELD_NORMAL)
1064 if (type == FIELD_BLOB)
1066 uint32_t blob_length=
1067 _mi_calc_blob_length(length-portable_sizeof_char_ptr,record);
1068 if (!blob_length && !(flag & bit))
1071 to+=length - portable_sizeof_char_ptr+ blob_length;
1073 else if (type == FIELD_SKIP_ZERO)
1075 if (memcmp(record,zero_string,length) == 0)
1083 else if (type == FIELD_SKIP_ENDSPACE ||
1084 type == FIELD_SKIP_PRESPACE)
1086 pos= (
unsigned char*) record; end= (
unsigned char*) record + length;
1087 if (type == FIELD_SKIP_ENDSPACE)
1089 while (end > record && *(end-1) ==
' ')
1094 while (pos < end && *pos ==
' ')
1097 new_length=(uint) (end-pos);
1098 if (new_length +1 + test(rec->length > 255 && new_length > 127)
1103 if (rec->length > 255 && new_length > 127)
1105 if (to[0] != (
unsigned char) ((new_length & 127) + 128) ||
1106 to[1] != (
unsigned char) (new_length >> 7))
1110 else if (*to++ != (
unsigned char) new_length)
1117 else if (type == FIELD_VARCHAR)
1119 uint32_t pack_length= ha_varchar_packlength(rec->length -1);
1120 uint32_t tmp_length;
1121 if (pack_length == 1)
1123 tmp_length= (uint) *(
unsigned char*) record;
1129 tmp_length= uint2korr(record);
1130 to+= get_pack_length(tmp_length)+tmp_length;
1139 if ((bit= bit << 1) >= 256)
1148 if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) ||
1149 (bit != 1 && (flag & ~(bit - 1))))
1151 if (with_checksum && ((
unsigned char) info->checksum != (
unsigned char) *to))
1167 ulong _mi_rec_unpack(
register MI_INFO *info,
register unsigned char *to,
unsigned char *from,
1170 uint32_t flag,bit,length,rec_length,min_pack_length;
1171 enum en_fieldtype type;
1172 unsigned char *from_end,*to_end,*packpos;
1175 to_end=to + info->s->base.reclength;
1176 from_end=from+found_length;
1177 flag= (
unsigned char) *from; bit=1; packpos=from;
1178 if (found_length < info->s->base.min_pack_length)
1180 from+= info->s->base.pack_bits;
1181 min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
1183 for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
1184 rec < end_field ; to+= rec_length, rec++)
1186 rec_length=rec->length;
1187 if ((type = (
enum en_fieldtype) rec->type) != FIELD_NORMAL &&
1188 (type != FIELD_CHECK))
1190 if (type == FIELD_VARCHAR)
1192 uint32_t pack_length= ha_varchar_packlength(rec_length-1);
1193 if (pack_length == 1)
1195 length= (uint) *(
unsigned char*) from;
1196 if (length > rec_length-1)
1202 get_key_length(length, from);
1203 if (length > rec_length-2)
1205 int2store(to,length);
1207 if (from+length > from_end)
1209 memcpy(to+pack_length, from, length);
1216 if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
1217 memset(to, 0, rec_length);
1218 else if (type == FIELD_SKIP_ENDSPACE ||
1219 type == FIELD_SKIP_PRESPACE)
1221 if (rec->length > 255 && *from & 128)
1223 if (from + 1 >= from_end)
1225 length= (*from & 127)+ ((uint) (
unsigned char) *(from+1) << 7); from+=2;
1229 if (from == from_end)
1231 length= (
unsigned char) *from++;
1234 if (length >= rec_length ||
1235 min_pack_length + length > (uint) (from_end - from))
1237 if (type == FIELD_SKIP_ENDSPACE)
1239 memcpy(to, from, length);
1240 memset(to+length,
' ', rec_length-length);
1244 memset(to,
' ', rec_length-length);
1245 memcpy(to + rec_length - length, from, length);
1250 else if (type == FIELD_BLOB)
1252 uint32_t size_length=rec_length- portable_sizeof_char_ptr;
1253 ulong blob_length=_mi_calc_blob_length(size_length,from);
1254 ulong from_left= (ulong) (from_end - from);
1255 if (from_left < size_length ||
1256 from_left - size_length < blob_length ||
1257 from_left - size_length - blob_length < min_pack_length)
1259 memcpy(to, from, size_length);
1261 memcpy(to+size_length, &from,
sizeof(
char*));
1266 if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
1268 if (min_pack_length + rec_length > (uint) (from_end - from))
1270 memcpy(to, from, rec_length);
1273 if ((bit= bit << 1) >= 256)
1275 flag= (
unsigned char) *++packpos; bit=1;
1280 if (min_pack_length > (uint) (from_end - from))
1282 min_pack_length-=rec_length;
1283 memcpy(to, from, rec_length);
1287 if (info->s->calc_checksum)
1289 if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
1290 return(found_length);
1293 errno= HA_ERR_WRONG_IN_RECORD;
1294 return(MY_FILE_ERROR);
1300 ulong _my_calc_total_blob_length(
MI_INFO *info,
const unsigned char *record)
1305 for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
1309 blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
1310 length+=blob->length;
1316 ulong _mi_calc_blob_length(uint32_t length,
const unsigned char *pos)
1320 return (uint) (
unsigned char) *pos;
1322 return (uint) uint2korr(pos);
1324 return uint3korr(pos);
1326 return uint4korr(pos);
1334 void _my_store_blob_length(
unsigned char *pos,uint32_t pack_length,uint32_t length)
1336 switch (pack_length) {
1338 *pos= (
unsigned char) length;
1341 int2store(pos,length);
1344 int3store(pos,length);
1347 int4store(pos,length);
1387 int _mi_read_dynamic_record(
MI_INFO *info, internal::my_off_t filepos,
unsigned char *buf)
1389 int block_of_record;
1390 uint32_t b_type, left_length= 0;
1391 unsigned char *to= NULL;
1395 if (filepos != HA_OFFSET_ERROR)
1399 block_info.second_read= 0;
1403 if (filepos == HA_OFFSET_ERROR)
1405 if (info->opt_flag & WRITE_CACHE_USED &&
1406 info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1407 info->rec_cache.flush())
1409 info->rec_cache.seek_not_done=1;
1410 if ((b_type= _mi_get_block_info(&block_info, file, filepos))
1411 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1414 if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1415 errno=HA_ERR_RECORD_DELETED;
1418 if (block_of_record++ == 0)
1420 if (block_info.rec_len > (uint) info->s->base.max_pack_length)
1422 if (info->s->base.blobs)
1424 if (!(to=mi_alloc_rec_buff(info, block_info.rec_len,
1430 left_length=block_info.rec_len;
1432 if (left_length < block_info.data_len || ! block_info.data_len)
1436 uint32_t offset= (uint) (block_info.filepos - filepos);
1437 uint32_t prefetch_len= (
sizeof(block_info.header) - offset);
1438 filepos+=
sizeof(block_info.header);
1440 if (prefetch_len > block_info.data_len)
1441 prefetch_len= block_info.data_len;
1444 memcpy(to, block_info.header + offset, prefetch_len);
1445 block_info.data_len-= prefetch_len;
1446 left_length-= prefetch_len;
1451 if (block_info.data_len)
1453 if (info->opt_flag & WRITE_CACHE_USED &&
1454 info->rec_cache.pos_in_file < filepos + block_info.data_len &&
1455 info->rec_cache.flush())
1462 if (info->s->file_read(info, (
unsigned char*) to, block_info.data_len,
1463 filepos, MYF(MY_NABP)))
1465 left_length-=block_info.data_len;
1466 to+=block_info.data_len;
1468 filepos= block_info.next_filepos;
1469 }
while (left_length);
1471 info->update|= HA_STATE_AKTIV;
1472 fast_mi_writeinfo(info);
1473 return(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1474 MY_FILE_ERROR ? 0 : -1);
1476 fast_mi_writeinfo(info);
1480 errno=HA_ERR_WRONG_IN_RECORD;
1482 _mi_writeinfo(info,0);
1489 const unsigned char *record, internal::my_off_t pos)
1491 unsigned char *rec_buff,*old_record;
1494 if (!(old_record=(
unsigned char *)malloc(info->s->base.reclength)))
1498 rec_buff=info->rec_buff;
1499 if (info->s->base.blobs)
1501 error=_mi_read_dynamic_record(info,pos,old_record);
1503 error=mi_unique_comp(def, record, old_record, def->null_are_equal);
1504 if (info->s->base.blobs)
1506 void * rec_buff_ptr= mi_get_rec_buff_ptr(info, info->rec_buff);
1508 info->rec_buff=rec_buff;
1517 int _mi_cmp_dynamic_record(
register MI_INFO *info,
register const unsigned char *record)
1519 uint32_t flag,reclength,b_type;
1520 internal::my_off_t filepos;
1521 unsigned char *buffer;
1524 if (info->opt_flag & WRITE_CACHE_USED)
1526 info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
1527 if (info->rec_cache.flush())
1530 info->rec_cache.seek_not_done=1;
1534 buffer=info->rec_buff;
1535 if ((info->opt_flag & READ_CHECK_USED))
1537 if (info->s->base.blobs)
1539 if (!(buffer=(
unsigned char*) malloc(info->s->base.pack_reclength+
1540 _my_calc_total_blob_length(info,record))))
1543 reclength=_mi_rec_pack(info,buffer,record);
1546 filepos=info->lastpos;
1547 flag=block_info.second_read=0;
1548 block_info.next_filepos=filepos;
1549 while (reclength > 0)
1551 if ((b_type=_mi_get_block_info(&block_info,info->dfile,
1552 block_info.next_filepos))
1553 & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1556 if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
1557 errno=HA_ERR_RECORD_CHANGED;
1563 if (reclength != block_info.rec_len)
1565 errno=HA_ERR_RECORD_CHANGED;
1568 }
else if (reclength < block_info.data_len)
1570 errno=HA_ERR_WRONG_IN_RECORD;
1573 reclength-=block_info.data_len;
1574 if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
1575 block_info.data_len))
1577 errno=HA_ERR_RECORD_CHANGED;
1581 record+=block_info.data_len;
1586 if (buffer != info->rec_buff)
1587 free((
unsigned char*) buffer);
1594 static int _mi_cmp_buffer(
int file,
const unsigned char *buff, internal::my_off_t filepos,
1597 uint32_t next_length;
1598 unsigned char temp_buff[IO_SIZE*2];
1600 next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
1602 while (length > IO_SIZE*2)
1604 if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
1605 memcmp(buff, temp_buff, next_length))
1607 filepos+=next_length;
1609 length-= next_length;
1610 next_length=IO_SIZE*2;
1612 if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
1614 return(memcmp(buff,temp_buff,length));
1654 int _mi_read_rnd_dynamic_record(
MI_INFO *info,
unsigned char *buf,
1655 register internal::my_off_t filepos,
1656 bool skip_deleted_blocks)
1658 int block_of_record, info_read, save_errno;
1659 uint32_t left_len,b_type;
1660 unsigned char *to= NULL;
1666 if (info->lock_type == F_UNLCK)
1668 info->tmp_lock_type=F_RDLCK;
1674 block_info.second_read= 0;
1678 if (filepos >= info->state->data_file_length)
1683 info->rec_cache.seek_not_done=1;
1684 if (mi_state_info_read_dsk(share->kfile,&share->state,1))
1687 if (filepos >= info->state->data_file_length)
1689 errno= HA_ERR_END_OF_FILE;
1693 if (info->opt_flag & READ_CACHE_USED)
1695 if (_mi_read_cache(&info->rec_cache,(
unsigned char*) block_info.header,filepos,
1696 sizeof(block_info.header),
1697 (!block_of_record && skip_deleted_blocks ?
1698 READING_NEXT : 0) | READING_HEADER))
1700 b_type=_mi_get_block_info(&block_info,-1,filepos);
1704 if (info->opt_flag & WRITE_CACHE_USED &&
1705 info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH &&
1706 info->rec_cache.flush())
1708 info->rec_cache.seek_not_done=1;
1709 b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
1712 if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
1715 if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1716 && skip_deleted_blocks)
1718 filepos=block_info.filepos+block_info.block_len;
1719 block_info.second_read=0;
1722 if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
1724 errno=HA_ERR_RECORD_DELETED;
1725 info->lastpos=block_info.filepos;
1726 info->nextpos=block_info.filepos+block_info.block_len;
1730 if (block_of_record == 0)
1732 if (block_info.rec_len > (uint) share->base.max_pack_length)
1734 info->lastpos=filepos;
1735 if (share->base.blobs)
1737 if (!(to= mi_alloc_rec_buff(info, block_info.rec_len,
1743 left_len=block_info.rec_len;
1745 if (left_len < block_info.data_len)
1750 uint32_t offset=(uint) (block_info.filepos - filepos);
1751 uint32_t tmp_length= (
sizeof(block_info.header) - offset);
1752 filepos=block_info.filepos;
1754 if (tmp_length > block_info.data_len)
1755 tmp_length= block_info.data_len;
1758 memcpy(to, block_info.header+offset,tmp_length);
1759 block_info.data_len-=tmp_length;
1760 left_len-=tmp_length;
1762 filepos+=tmp_length;
1766 if (block_info.data_len)
1768 if (info->opt_flag & READ_CACHE_USED)
1770 if (_mi_read_cache(&info->rec_cache,(
unsigned char*) to,filepos,
1771 block_info.data_len,
1772 (!block_of_record && skip_deleted_blocks) ?
1778 if (info->opt_flag & WRITE_CACHE_USED &&
1779 info->rec_cache.pos_in_file <
1780 block_info.filepos + block_info.data_len &&
1781 info->rec_cache.flush())
1784 if (internal::my_read(info->dfile,(
unsigned char*) to,block_info.data_len,MYF(MY_NABP)))
1787 errno= HA_ERR_WRONG_IN_RECORD;
1796 if (block_of_record++ == 0)
1798 info->nextpos= block_info.filepos + block_info.block_len;
1799 skip_deleted_blocks= 0;
1801 left_len-=block_info.data_len;
1802 to+=block_info.data_len;
1803 filepos=block_info.next_filepos;
1806 info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
1807 fast_mi_writeinfo(info);
1808 if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
1814 errno=HA_ERR_WRONG_IN_RECORD;
1817 _mi_writeinfo(info,0);
1818 return(errno=save_errno);
1824 uint32_t _mi_get_block_info(
MI_BLOCK_INFO *info,
int file, internal::my_off_t filepos)
1826 uint32_t return_val=0;
1827 unsigned char *header=info->header;
1836 lseek(file,filepos,SEEK_SET);
1837 if (internal::my_read(file, header,
sizeof(info->header),MYF(0)) !=
1838 sizeof(info->header))
1841 if (info->second_read)
1843 if (info->header[0] <= 6 || info->header[0] == 13)
1844 return_val=BLOCK_SYNC_ERROR;
1848 if (info->header[0] > 6 && info->header[0] != 13)
1849 return_val=BLOCK_SYNC_ERROR;
1851 info->next_filepos= HA_OFFSET_ERROR;
1853 switch (info->header[0]) {
1855 if ((info->block_len=(uint) mi_uint3korr(header+1)) <
1856 MI_MIN_BLOCK_LENGTH ||
1857 (info->block_len & (MI_DYN_ALIGN_SIZE -1)))
1859 info->filepos=filepos;
1860 info->next_filepos=mi_sizekorr(header+4);
1861 info->prev_filepos=mi_sizekorr(header+12);
1862 #if SIZEOF_OFF_T == 4
1863 if ((mi_uint4korr(header+4) != 0 &&
1864 (mi_uint4korr(header+4) != UINT32_MAX ||
1865 info->next_filepos != UINT32_MAX) ||
1866 (mi_uint4korr(header+12) != 0 &&
1867 (mi_uint4korr(header+12) != UINT32_MAX ||
1868 info->prev_filepos != UINT32_MAX))
1871 return return_val | BLOCK_DELETED;
1874 info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
1875 info->filepos=filepos+3;
1876 return return_val | BLOCK_FIRST | BLOCK_LAST;
1878 info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
1879 info->filepos=filepos+4;
1880 return return_val | BLOCK_FIRST | BLOCK_LAST;
1883 info->rec_len=mi_uint4korr(header+1);
1884 info->block_len=info->data_len=mi_uint3korr(header+5);
1885 info->next_filepos=mi_sizekorr(header+8);
1886 info->second_read=1;
1887 info->filepos=filepos+16;
1888 return return_val | BLOCK_FIRST;
1891 info->rec_len=info->data_len=mi_uint2korr(header+1);
1892 info->block_len=info->rec_len+ (uint) header[3];
1893 info->filepos=filepos+4;
1894 return return_val | BLOCK_FIRST | BLOCK_LAST;
1896 info->rec_len=info->data_len=mi_uint3korr(header+1);
1897 info->block_len=info->rec_len+ (uint) header[4];
1898 info->filepos=filepos+5;
1899 return return_val | BLOCK_FIRST | BLOCK_LAST;
1902 info->rec_len=mi_uint2korr(header+1);
1903 info->block_len=info->data_len=mi_uint2korr(header+3);
1904 info->next_filepos=mi_sizekorr(header+5);
1905 info->second_read=1;
1906 info->filepos=filepos+13;
1907 return return_val | BLOCK_FIRST;
1909 info->rec_len=mi_uint3korr(header+1);
1910 info->block_len=info->data_len=mi_uint3korr(header+4);
1911 info->next_filepos=mi_sizekorr(header+7);
1912 info->second_read=1;
1913 info->filepos=filepos+15;
1914 return return_val | BLOCK_FIRST;
1918 info->data_len=info->block_len=mi_uint2korr(header+1);
1919 info->filepos=filepos+3;
1920 return return_val | BLOCK_LAST;
1922 info->data_len=info->block_len=mi_uint3korr(header+1);
1923 info->filepos=filepos+4;
1924 return return_val | BLOCK_LAST;
1927 info->data_len=mi_uint2korr(header+1);
1928 info->block_len=info->data_len+ (uint) header[3];
1929 info->filepos=filepos+4;
1930 return return_val | BLOCK_LAST;
1932 info->data_len=mi_uint3korr(header+1);
1933 info->block_len=info->data_len+ (uint) header[4];
1934 info->filepos=filepos+5;
1935 return return_val | BLOCK_LAST;
1938 info->data_len=info->block_len=mi_uint2korr(header+1);
1939 info->next_filepos=mi_sizekorr(header+3);
1940 info->second_read=1;
1941 info->filepos=filepos+11;
1944 info->data_len=info->block_len=mi_uint3korr(header+1);
1945 info->next_filepos=mi_sizekorr(header+4);
1946 info->second_read=1;
1947 info->filepos=filepos+12;
1952 errno=HA_ERR_WRONG_IN_RECORD;
TODO: Rename this file - func.h is stupid.