mi_dynrec.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:41k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    
  3.    This program is free software; you can redistribute it and/or modify
  4.    it under the terms of the GNU General Public License as published by
  5.    the Free Software Foundation; either version 2 of the License, or
  6.    (at your option) any later version.
  7.    
  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.
  12.    
  13.    You should have received a copy of the GNU General Public License
  14.    along with this program; if not, write to the Free Software
  15.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  16. /* Functions to handle space-packed-records and blobs */
  17. #include "myisamdef.h"
  18. /* Enough for comparing if number is zero */
  19. static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  20. static int write_dynamic_record(MI_INFO *info,const byte *record,
  21. ulong reclength);
  22. static int _mi_find_writepos(MI_INFO *info,ulong reclength,my_off_t *filepos,
  23.      ulong *length);
  24. static int update_dynamic_record(MI_INFO *info,my_off_t filepos,byte *record,
  25.  ulong reclength);
  26. static int delete_dynamic_record(MI_INFO *info,my_off_t filepos,
  27.  uint second_read);
  28. static int _mi_cmp_buffer(File file, const byte *buff, my_off_t filepos,
  29.   uint length);
  30. #ifdef THREAD
  31. /* Play it safe; We have a small stack when using threads */
  32. #undef my_alloca
  33. #undef my_afree
  34. #define my_alloca(A) my_malloc((A),MYF(0))
  35. #define my_afree(A) my_free((A),MYF(0))
  36. #endif
  37. /* Interface function from MI_INFO */
  38. int _mi_write_dynamic_record(MI_INFO *info, const byte *record)
  39. {
  40.   ulong reclength=_mi_rec_pack(info,info->rec_buff,record);
  41.   return (write_dynamic_record(info,info->rec_buff,reclength));
  42. }
  43. int _mi_update_dynamic_record(MI_INFO *info, my_off_t pos, const byte *record)
  44. {
  45.   uint length=_mi_rec_pack(info,info->rec_buff,record);
  46.   return (update_dynamic_record(info,pos,info->rec_buff,length));
  47. }
  48. int _mi_write_blob_record(MI_INFO *info, const byte *record)
  49. {
  50.   byte *rec_buff;
  51.   int error;
  52.   ulong reclength,extra;
  53.   extra=ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
  54.     MI_DYN_DELETE_BLOCK_HEADER+1;
  55.   reclength=info->s->base.pack_reclength+
  56.     _my_calc_total_blob_length(info,record)+ extra;
  57.   if (reclength > MI_DYN_MAX_ROW_LENGTH)
  58.   {
  59.     my_errno=HA_ERR_TO_BIG_ROW;
  60.     return -1;
  61.   }
  62.   if (!(rec_buff=(byte*) my_alloca(reclength)))
  63.   {
  64.     my_errno=ENOMEM;
  65.     return(-1);
  66.   }
  67.   reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
  68.  record);
  69.   error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
  70.      reclength);
  71.   my_afree(rec_buff);
  72.   return(error);
  73. }
  74. int _mi_update_blob_record(MI_INFO *info, my_off_t pos, const byte *record)
  75. {
  76.   byte *rec_buff;
  77.   int error;
  78.   ulong reclength,extra;
  79.   extra=ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
  80.     MI_DYN_DELETE_BLOCK_HEADER;
  81.   reclength=info->s->base.pack_reclength+
  82.     _my_calc_total_blob_length(info,record)+ extra;
  83.   if (reclength > MI_DYN_MAX_ROW_LENGTH)
  84.   {
  85.     my_errno=HA_ERR_TO_BIG_ROW;
  86.     return -1;
  87.   }
  88.   if (!(rec_buff=(byte*) my_alloca(reclength)))
  89.   {
  90.     my_errno=ENOMEM;
  91.     return(-1);
  92.   }
  93.   reclength=_mi_rec_pack(info,rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
  94.  record);
  95.   error=update_dynamic_record(info,pos,
  96.       rec_buff+ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER),
  97.       reclength);
  98.   my_afree(rec_buff);
  99.   return(error);
  100. }
  101. int _mi_delete_dynamic_record(MI_INFO *info)
  102. {
  103.   return delete_dynamic_record(info,info->lastpos,0);
  104. }
  105. /* Write record to data-file */
  106. static int write_dynamic_record(MI_INFO *info, const byte *record,
  107. ulong reclength)
  108. {
  109.   int flag;
  110.   ulong length;
  111.   my_off_t filepos;
  112.   DBUG_ENTER("write_dynamic_record");
  113.   flag=0;
  114.   while (reclength)
  115.   {
  116.     if (_mi_find_writepos(info,reclength,&filepos,&length))
  117.       goto err;
  118.     if (_mi_write_part_record(info,filepos,length,info->s->state.dellink,
  119.       (byte**) &record,&reclength,&flag))
  120.       goto err;
  121.   }
  122.   DBUG_RETURN(0);
  123.  err:
  124.   DBUG_RETURN(1);
  125. }
  126. /* Get a block for data ; The given data-area must be used !! */
  127. static int _mi_find_writepos(MI_INFO *info,
  128.      ulong reclength, /* record length */
  129.      my_off_t *filepos, /* Return file pos */
  130.      ulong *length)   /* length of block at filepos */
  131. {
  132.   MI_BLOCK_INFO block_info;
  133.   DBUG_ENTER("_mi_find_writepos");
  134.   if (info->s->state.dellink != HA_OFFSET_ERROR)
  135.   {
  136.     /* Deleted blocks exists;  Get last used block */
  137.     *filepos=info->s->state.dellink;
  138.     block_info.second_read=0;
  139.     info->rec_cache.seek_not_done=1;
  140.     if (!(_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) &
  141.    BLOCK_DELETED))
  142.     {
  143.       DBUG_PRINT("error",("Delete link crashed"));
  144.       my_errno=HA_ERR_WRONG_IN_RECORD;
  145.       DBUG_RETURN(-1);
  146.     }
  147.     info->s->state.dellink=block_info.next_filepos;
  148.     info->state->del--;
  149.     info->state->empty-= block_info.block_len;
  150.     *length= block_info.block_len;
  151.   }
  152.   else
  153.   {
  154.     /* No deleted blocks;  Allocate a new block */
  155.     *filepos=info->state->data_file_length;
  156.     if ((*length=reclength+3 + test(reclength > 65520)) <
  157. info->s->base.min_block_length)
  158.       *length=info->s->base.min_block_length;
  159.     else
  160.       *length= ((*length+MI_DYN_ALIGN_SIZE-1) &
  161. (~ (ulong) (MI_DYN_ALIGN_SIZE-1)));
  162.     if (info->state->data_file_length >
  163. (info->s->base.max_data_file_length- *length))
  164.     {
  165.       my_errno=HA_ERR_RECORD_FILE_FULL;
  166.       DBUG_RETURN(-1);
  167.     }
  168.     info->state->data_file_length+= *length;
  169.     info->s->state.split++;
  170.     info->update|=HA_STATE_WRITE_AT_END;
  171.   }
  172.   DBUG_RETURN(0);
  173. } /* _mi_find_writepos */
  174. /* Remove a deleted block from the deleted list */
  175. static bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info)
  176. {
  177.   DBUG_ENTER("unlink_deleted_block");
  178.   if (block_info->filepos == info->s->state.dellink)
  179.   {
  180.     /* First deleted block;  We can just use this ! */
  181.     info->s->state.dellink=block_info->next_filepos;
  182.   }
  183.   else
  184.   {
  185.     MI_BLOCK_INFO tmp;
  186.     tmp.second_read=0;
  187.     if (!(_mi_get_block_info(&tmp,info->dfile,block_info->prev_filepos)
  188.   & BLOCK_DELETED))
  189.       DBUG_RETURN(1); /* Something is wrong */
  190.     mi_sizestore(tmp.header+4,block_info->next_filepos);
  191.     if (my_pwrite(info->dfile,(char*) tmp.header+4,8,
  192.   block_info->prev_filepos+4, MYF(MY_NABP)))
  193.       DBUG_RETURN(1);
  194.     if (block_info->next_filepos != HA_OFFSET_ERROR)
  195.     {
  196.       if (!(_mi_get_block_info(&tmp,info->dfile,block_info->next_filepos)
  197.     & BLOCK_DELETED))
  198. DBUG_RETURN(1); /* Something is wrong */
  199.       mi_sizestore(tmp.header+12,block_info->prev_filepos);
  200.       if (my_pwrite(info->dfile,(char*) tmp.header+12,8,
  201.     block_info->next_filepos+12,
  202.     MYF(MY_NABP)))
  203. DBUG_RETURN(1);
  204.     }
  205.   }
  206.   info->state->del--;
  207.   info->state->empty-= block_info->block_len;
  208.   info->s->state.split--;
  209.   /* Removing block that we are using through mi_rrnd */
  210.   if (info->nextpos == block_info->filepos)
  211.     info->nextpos+=block_info->block_len;
  212.   DBUG_RETURN(0);
  213. }
  214. /* Delete datarecord from database */
  215. /* info->rec_cache.seek_not_done is updated in cmp_record */
  216. static int delete_dynamic_record(MI_INFO *info, my_off_t filepos,
  217.  uint second_read)
  218. {
  219.   uint length,b_type;
  220.   MI_BLOCK_INFO block_info,del_block;
  221.   int error=0;
  222.   my_bool remove_next_block;
  223.   DBUG_ENTER("delete_dynamic_record");
  224.   /* First add a link from the last block to the new one */
  225.   if (info->s->state.dellink != HA_OFFSET_ERROR)
  226.   {
  227.     block_info.second_read=0;
  228.     if (_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink)
  229. & BLOCK_DELETED)
  230.     {
  231.       char buff[8];
  232.       mi_sizestore(buff,filepos);
  233.       if (my_pwrite(info->dfile,buff,8,info->s->state.dellink+12,
  234.     MYF(MY_NABP)))
  235. error=1; /* Error on write */
  236.     }
  237.     else
  238.     {
  239.       error=1; /* Wrong delete link */
  240.       my_errno=HA_ERR_WRONG_IN_RECORD;
  241.     }
  242.   }
  243.   block_info.second_read=second_read;
  244.   do
  245.   {
  246.     /* Remove block at 'filepos' */
  247.     if ((b_type=_mi_get_block_info(&block_info,info->dfile,filepos))
  248. & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  249.    BLOCK_FATAL_ERROR) ||
  250. (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
  251. MI_MIN_BLOCK_LENGTH)
  252.     {
  253.       my_errno=HA_ERR_WRONG_IN_RECORD;
  254.       DBUG_RETURN(1);
  255.     }
  256.     /* Check if next block is a delete block */
  257.     del_block.second_read=0;
  258.     remove_next_block=0;
  259.     if (_mi_get_block_info(&del_block,info->dfile,filepos+length) &
  260. BLOCK_DELETED && del_block.block_len+length < MI_DYN_MAX_BLOCK_LENGTH)
  261.     {
  262.       /* We can't remove this yet as this block may be the head block */
  263.       remove_next_block=1;
  264.       length+=del_block.block_len;
  265.     }
  266.     block_info.header[0]=0;
  267.     mi_int3store(block_info.header+1,length);
  268.     mi_sizestore(block_info.header+4,info->s->state.dellink);
  269.     if (b_type & BLOCK_LAST)
  270.       bfill(block_info.header+12,8,255);
  271.     else
  272.       mi_sizestore(block_info.header+12,block_info.next_filepos);
  273.     if (my_pwrite(info->dfile,(byte*) block_info.header,20,filepos,
  274.   MYF(MY_NABP)))
  275.       DBUG_RETURN(1);
  276.     info->s->state.dellink = filepos;
  277.     info->state->del++;
  278.     info->state->empty+=length;
  279.     filepos=block_info.next_filepos;
  280.     /* Now it's safe to unlink the block */
  281.     if (remove_next_block && unlink_deleted_block(info,&del_block))
  282.       error=1;
  283.   } while (!(b_type & BLOCK_LAST));
  284.   DBUG_RETURN(error);
  285. }
  286. /* Write a block to datafile */
  287. int _mi_write_part_record(MI_INFO *info,
  288.   my_off_t filepos, /* points at empty block */
  289.   ulong length, /* length of block */
  290.   my_off_t next_filepos,/* Next empty block */
  291.   byte **record, /* pointer to record ptr */
  292.   ulong *reclength, /* length of *record */
  293.   int *flag) /* *flag == 0 if header */
  294. {
  295.   ulong head_length,res_length,extra_length,long_block,del_length;
  296.   byte *pos,*record_end;
  297.   my_off_t  next_delete_block;
  298.   uchar temp[MI_SPLIT_LENGTH+MI_DYN_DELETE_BLOCK_HEADER];
  299.   DBUG_ENTER("_mi_write_part_record");
  300.   next_delete_block=HA_OFFSET_ERROR;
  301.   res_length=extra_length=0;
  302.   if (length > *reclength + MI_SPLIT_LENGTH)
  303.   { /* Splitt big block */
  304.     res_length=MY_ALIGN(length- *reclength - MI_EXTEND_BLOCK_LENGTH,
  305. MI_DYN_ALIGN_SIZE);
  306.     length-= res_length; /* Use this for first part */
  307.   }
  308.   long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
  309.   if (length == *reclength+ 3 + long_block)
  310.   {
  311.     /* Block is exactly of the right length */
  312.     temp[0]=(uchar) (1+ *flag)+(uchar) long_block; /* Flag is 0 or 6 */
  313.     if (long_block)
  314.     {
  315.       mi_int3store(temp+1,*reclength);
  316.       head_length=4;
  317.     }
  318.     else
  319.     {
  320.       mi_int2store(temp+1,*reclength);
  321.       head_length=3;
  322.     }
  323.   }
  324.   else if (length-long_block < *reclength+4)
  325.   { /* To short block */
  326.     if (next_filepos == HA_OFFSET_ERROR)
  327.       next_filepos=info->s->state.dellink != HA_OFFSET_ERROR ?
  328. info->s->state.dellink : info->state->data_file_length;
  329.     if (*flag == 0) /* First block */
  330.     {
  331.       head_length=5+8+long_block*2;
  332.       temp[0]=5+(uchar) long_block;
  333.       if (long_block)
  334.       {
  335. mi_int3store(temp+1,*reclength);
  336. mi_int3store(temp+4,length-head_length);
  337. mi_sizestore((byte*) temp+7,next_filepos);
  338.       }
  339.       else
  340.       {
  341. mi_int2store(temp+1,*reclength);
  342. mi_int2store(temp+3,length-head_length);
  343. mi_sizestore((byte*) temp+5,next_filepos);
  344.       }
  345.     }
  346.     else
  347.     {
  348.       head_length=3+8+long_block;
  349.       temp[0]=11+(uchar) long_block;
  350.       if (long_block)
  351.       {
  352. mi_int3store(temp+1,length-head_length);
  353. mi_sizestore((byte*) temp+4,next_filepos);
  354.       }
  355.       else
  356.       {
  357. mi_int2store(temp+1,length-head_length);
  358. mi_sizestore((byte*) temp+3,next_filepos);
  359.       }
  360.     }
  361.   }
  362.   else
  363.   { /* Block with empty info last */
  364.     head_length=4+long_block;
  365.     extra_length= length- *reclength-head_length;
  366.     temp[0]= (uchar) (3+ *flag)+(uchar) long_block; /* 3,4 or 9,10 */
  367.     if (long_block)
  368.     {
  369.       mi_int3store(temp+1,*reclength);
  370.       temp[4]= (uchar) (extra_length);
  371.     }
  372.     else
  373.     {
  374.       mi_int2store(temp+1,*reclength);
  375.       temp[3]= (uchar) (extra_length);
  376.     }
  377.     length=   *reclength+head_length; /* Write only what is needed */
  378.   }
  379.   DBUG_DUMP("header",(byte*) temp,head_length);
  380. /* Make a long block for one write */
  381.   record_end= *record+length-head_length;
  382.   del_length=(res_length ? MI_DYN_DELETE_BLOCK_HEADER : 0);
  383.   bmove((byte*) (*record-head_length),(byte*) temp,head_length);
  384.   memcpy(temp,record_end,(size_t) (extra_length+del_length));
  385.   bzero((byte*) record_end,extra_length);
  386.   if (res_length)
  387.   {
  388.     /* Check first if we can join this block with the next one */
  389.     MI_BLOCK_INFO del_block;
  390.     my_off_t next_block=filepos+length+extra_length+res_length;
  391.     del_block.second_read=0;
  392.     if (next_block < info->state->data_file_length &&
  393. info->s->state.dellink != HA_OFFSET_ERROR)
  394.     {
  395.       if ((_mi_get_block_info(&del_block,info->dfile,next_block)
  396.    & BLOCK_DELETED) &&
  397.   res_length + del_block.block_len < MI_DYN_MAX_BLOCK_LENGTH)
  398.       {
  399. if (unlink_deleted_block(info,&del_block))
  400.   goto err;
  401. res_length+=del_block.block_len;
  402.       }
  403.     }
  404.     /* Create a delete link of the last part of the block */
  405.     pos=record_end+extra_length;
  406.     pos[0]= '';
  407.     mi_int3store(pos+1,res_length);
  408.     mi_sizestore(pos+4,info->s->state.dellink);
  409.     bfill(pos+12,8,255); /* End link */
  410.     next_delete_block=info->s->state.dellink;
  411.     info->s->state.dellink= filepos+length+extra_length;
  412.     info->state->del++;
  413.     info->state->empty+=res_length;
  414.     info->s->state.split++;
  415.   }
  416.   if (info->opt_flag & WRITE_CACHE_USED &&
  417.       info->update & HA_STATE_WRITE_AT_END)
  418.   {
  419.     if (info->update & HA_STATE_EXTEND_BLOCK)
  420.     {
  421.       info->update&= ~HA_STATE_EXTEND_BLOCK;
  422.       if (my_block_write(&info->rec_cache,(byte*) *record-head_length,
  423.        length+extra_length+del_length,filepos))
  424.       goto err;
  425.     }
  426.     else if (my_b_write(&info->rec_cache,(byte*) *record-head_length,
  427. length+extra_length+del_length))
  428.       goto err;
  429.   }
  430.   else
  431.   {
  432.     info->rec_cache.seek_not_done=1;
  433.     if (my_pwrite(info->dfile,(byte*) *record-head_length,length+extra_length+
  434.   del_length,filepos,info->s->write_flag))
  435.       goto err;
  436.   }
  437.   memcpy(record_end,temp,(size_t) (extra_length+del_length));
  438.   *record=record_end;
  439.   *reclength-=(length-head_length);
  440.   *flag=6;
  441.   if (del_length && next_delete_block != HA_OFFSET_ERROR)
  442.   {
  443.     /* link the next delete block to this */
  444.     MI_BLOCK_INFO del_block;
  445.     del_block.second_read=0;
  446.     if (!(_mi_get_block_info(&del_block,info->dfile,next_delete_block)
  447.   & BLOCK_DELETED))
  448.     {
  449.       my_errno=HA_ERR_WRONG_IN_RECORD;
  450.       goto err;
  451.     }
  452.     mi_sizestore(del_block.header+12,info->s->state.dellink);
  453.     if (my_pwrite(info->dfile,(char*) del_block.header+12,8,
  454.   next_delete_block+12,
  455.   MYF(MY_NABP)))
  456.       goto err;
  457.   }
  458.   DBUG_RETURN(0);
  459. err:
  460.   DBUG_PRINT("exit",("errno: %d",my_errno));
  461.   DBUG_RETURN(1);
  462. } /*_mi_write_part_record */
  463. /* update record from datafile */
  464. static int update_dynamic_record(MI_INFO *info, my_off_t filepos, byte *record,
  465.  ulong reclength)
  466. {
  467.   int flag;
  468.   uint error;
  469.   ulong length;
  470.   MI_BLOCK_INFO block_info;
  471.   DBUG_ENTER("update_dynamic_record");
  472.   flag=block_info.second_read=0;
  473.   while (reclength > 0)
  474.   {
  475.     if (filepos != info->s->state.dellink)
  476.     {
  477.       block_info.next_filepos= HA_OFFSET_ERROR;
  478.       if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
  479.   & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  480.      BLOCK_FATAL_ERROR))
  481.       {
  482. DBUG_PRINT("error",("Got wrong block info"));
  483. if (!(error & BLOCK_FATAL_ERROR))
  484.   my_errno=HA_ERR_WRONG_IN_RECORD;
  485. goto err;
  486.       }
  487.       length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
  488.       if (length < reclength)
  489.       {
  490. uint tmp=MY_ALIGN(reclength - length + 3 +
  491.   test(reclength >= 65520L),MI_DYN_ALIGN_SIZE);
  492. /* Check if we can extend this block */
  493. if (block_info.filepos + block_info.block_len ==
  494.     info->state->data_file_length &&
  495.     info->state->data_file_length <
  496.     info->s->base.max_data_file_length-tmp)
  497. {
  498.   /* extend file */
  499.   DBUG_PRINT("info",("Extending file with %d bytes",tmp));
  500.   if (info->nextpos == info->state->data_file_length)
  501.     info->nextpos+= tmp;
  502.   info->state->data_file_length+= tmp;
  503.   info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
  504.   length+=tmp;
  505. }
  506. else
  507. {
  508.   /* Check if next block is a deleted block */
  509.   MI_BLOCK_INFO del_block;
  510.   del_block.second_read=0;
  511.   if (_mi_get_block_info(&del_block,info->dfile,
  512.  block_info.filepos + block_info.block_len) &
  513.       BLOCK_DELETED)
  514.   {
  515.     /* Use; Unlink it and extend the current block */
  516.     DBUG_PRINT("info",("Extending current block"));
  517.     if (unlink_deleted_block(info,&del_block))
  518.       goto err;
  519.     length+=del_block.block_len;
  520.   }
  521. }
  522.       }
  523.     }
  524.     else
  525.     {
  526.       if (_mi_find_writepos(info,reclength,&filepos,&length))
  527. goto err;
  528.     }
  529.     if (_mi_write_part_record(info,filepos,length,block_info.next_filepos,
  530.       &record,&reclength,&flag))
  531.       goto err;
  532.     if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
  533.       filepos=info->s->state.dellink;
  534.   }
  535.   if (block_info.next_filepos != HA_OFFSET_ERROR)
  536.     if (delete_dynamic_record(info,block_info.next_filepos,1))
  537.       goto err;
  538.   DBUG_RETURN(0);
  539. err:
  540.   DBUG_RETURN(1);
  541. }
  542. /* Pack a record. Return new reclength */
  543. uint _mi_rec_pack(MI_INFO *info, register byte *to, register const byte *from)
  544. {
  545.   uint length,new_length,flag,bit,i;
  546.   char *pos,*end,*startpos,*packpos;
  547.   enum en_fieldtype type;
  548.   reg3 MI_COLUMNDEF *rec;
  549.   MI_BLOB *blob;
  550.   DBUG_ENTER("_mi_rec_pack");
  551.   flag=0 ; bit=1;
  552.   startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
  553.   rec=info->s->rec;
  554.   for (i=info->s->base.fields ; i-- > 0; from+= length,rec++)
  555.   {
  556.     length=(uint) rec->length;
  557.     if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
  558.     {
  559.       if (type == FIELD_BLOB)
  560.       {
  561. if (!blob->length)
  562.   flag|=bit;
  563. else
  564. {
  565.   char *temp_pos;
  566.   size_t tmp_length=length-mi_portable_sizeof_char_ptr;
  567.   memcpy((byte*) to,from,tmp_length);
  568.   memcpy_fixed(&temp_pos,from+tmp_length,sizeof(char*));
  569.   memcpy(to+tmp_length,temp_pos,(size_t) blob->length);
  570.   to+=tmp_length+blob->length;
  571. }
  572. blob++;
  573.       }
  574.       else if (type == FIELD_SKIPP_ZERO)
  575.       {
  576. if (memcmp((byte*) from,zero_string,length) == 0)
  577.   flag|=bit;
  578. else
  579. {
  580.   memcpy((byte*) to,from,(size_t) length); to+=length;
  581. }
  582.       }
  583.       else if (type == FIELD_SKIPP_ENDSPACE ||
  584.        type == FIELD_SKIPP_PRESPACE)
  585.       {
  586. pos= (byte*) from; end= (byte*) from + length;
  587. if (type == FIELD_SKIPP_ENDSPACE)
  588. { /* Pack trailing spaces */
  589.   while (end > from && *(end-1) == ' ')
  590.     end--;
  591. }
  592. else
  593. { /* Pack pref-spaces */
  594.   while (pos < end && *pos == ' ')
  595.     pos++;
  596. }
  597. new_length=(uint) (end-pos);
  598. if (new_length +1 + test(rec->length > 255 && new_length > 127)
  599.     < length)
  600. {
  601.   if (rec->length > 255 && new_length > 127)
  602.   {
  603.     to[0]=(char) ((new_length & 127)+128);
  604.     to[1]=(char) (new_length >> 7);
  605.     to+=2;
  606.   }
  607.   else
  608.     *to++= (char) new_length;
  609.   memcpy((byte*) to,pos,(size_t) new_length); to+=new_length;
  610.   flag|=bit;
  611. }
  612. else
  613. {
  614.   memcpy(to,from,(size_t) length); to+=length;
  615. }
  616.       }
  617.       else if (type == FIELD_VARCHAR)
  618.       {
  619. uint tmp_length=uint2korr(from);
  620. store_key_length_inc(to,tmp_length);
  621. memcpy(to,from+2,tmp_length);
  622. to+=tmp_length;
  623. continue;
  624.       }
  625.       else
  626.       {
  627. memcpy(to,from,(size_t) length); to+=length;
  628. continue; /* Normal field */
  629.       }
  630.       if ((bit= bit << 1) >= 256)
  631.       {
  632. *packpos++ = (char) (uchar) flag;
  633. bit=1; flag=0;
  634.       }
  635.     }
  636.     else
  637.     {
  638.       memcpy(to,from,(size_t) length); to+=length;
  639.     }
  640.   }
  641.   if (bit != 1)
  642.     *packpos= (char) (uchar) flag;
  643.   if (info->s->calc_checksum)
  644.     *to++=(char) info->checksum;
  645.   DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
  646.   DBUG_RETURN((uint) (to-startpos));
  647. } /* _mi_rec_pack */
  648. /*
  649. ** Check if a record was correctly packed. Used only by isamchk
  650. ** Returns 0 if record is ok.
  651. */
  652. my_bool _mi_rec_check(MI_INFO *info,const char *record)
  653. {
  654.   uint length,new_length,flag,bit,i;
  655.   char *pos,*end,*packpos,*to;
  656.   enum en_fieldtype type;
  657.   reg3 MI_COLUMNDEF *rec;
  658.   DBUG_ENTER("_mi_rec_check");
  659.   packpos=info->rec_buff; to= info->rec_buff+info->s->base.pack_bits;
  660.   rec=info->s->rec;
  661.   flag= *packpos; bit=1;
  662.   for (i=info->s->base.fields ; i-- > 0; record+= length, rec++)
  663.   {
  664.     length=(uint) rec->length;
  665.     if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL)
  666.     {
  667.       if (type == FIELD_BLOB)
  668.       {
  669. uint blob_length=
  670.   _mi_calc_blob_length(length-mi_portable_sizeof_char_ptr,record);
  671. if (!blob_length && !(flag & bit))
  672.   goto err;
  673. if (blob_length)
  674.   to+=length - mi_portable_sizeof_char_ptr+ blob_length;
  675.       }
  676.       else if (type == FIELD_SKIPP_ZERO)
  677.       {
  678. if (memcmp((byte*) record,zero_string,length) == 0)
  679. {
  680.   if (!(flag & bit))
  681.     goto err;
  682. }
  683. else
  684.   to+=length;
  685.       }
  686.       else if (type == FIELD_SKIPP_ENDSPACE ||
  687.        type == FIELD_SKIPP_PRESPACE)
  688.       {
  689. pos= (byte*) record; end= (byte*) record + length;
  690. if (type == FIELD_SKIPP_ENDSPACE)
  691. { /* Pack trailing spaces */
  692.   while (end > record && *(end-1) == ' ')
  693.     end--;
  694. }
  695. else
  696. { /* Pack pre-spaces */
  697.   while (pos < end && *pos == ' ')
  698.     pos++;
  699. }
  700. new_length=(uint) (end-pos);
  701. if (new_length +1 + test(rec->length > 255 && new_length > 127)
  702.     < length)
  703. {
  704.   if (!(flag & bit))
  705.     goto err;
  706.   if (rec->length > 255 && new_length > 127)
  707.   {
  708.     if (to[0] != (char) ((new_length & 127)+128) ||
  709. to[1] != (char) (new_length >> 7))
  710.       goto err;
  711.     to+=2;
  712.   }
  713.   else if (*to++ != (char) new_length)
  714.     goto err;
  715.   to+=new_length;
  716. }
  717. else
  718.   to+=length;
  719.       }
  720.       else if (type == FIELD_VARCHAR)
  721.       {
  722. uint tmp_length=uint2korr(record);
  723. to+=get_pack_length(tmp_length)+tmp_length;
  724. continue;
  725.       }
  726.       else
  727.       {
  728. to+=length;
  729. continue; /* Normal field */
  730.       }
  731.       if ((bit= bit << 1) >= 256)
  732.       {
  733. flag= *++packpos;
  734. bit=1;
  735.       }
  736.     }
  737.     else
  738.     {
  739.       to+=length;
  740.     }
  741.   }
  742.   if (info->packed_length != (uint) (to - info->rec_buff)
  743.       + test(info->s->calc_checksum) ||
  744.       (bit != 1 && (flag & ~(bit - 1))))
  745.     goto err;
  746.   if (info->s->calc_checksum)
  747.   {
  748.     if ((uchar) info->checksum != (uchar) *to)
  749.     {
  750.       DBUG_PRINT("error",("wrong checksum for row"));
  751.       goto err;
  752.     }
  753.   }
  754.   DBUG_RETURN(0);
  755.  err:
  756.   DBUG_RETURN(1);
  757. }
  758. /* Unpacks a record */
  759. /* Returns -1 and my_errno =HA_ERR_RECORD_DELETED if reclength isn't */
  760. /* right. Returns reclength (>0) if ok */
  761. ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
  762.      ulong found_length)
  763. {
  764.   uint flag,bit,length,rec_length,min_pack_length;
  765.   enum en_fieldtype type;
  766.   byte *from_end,*to_end,*packpos;
  767.   reg3 MI_COLUMNDEF *rec,*end_field;
  768.   DBUG_ENTER("_mi_rec_unpack");
  769.   to_end=to + info->s->base.reclength;
  770.   from_end=from+found_length;
  771.   flag= (uchar) *from; bit=1; packpos=from;
  772.   if (found_length < info->s->base.min_pack_length)
  773.     goto err;
  774.   from+= info->s->base.pack_bits;
  775.   min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
  776.   for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
  777.        rec < end_field ; to+= rec_length, rec++)
  778.   {
  779.     rec_length=rec->length;
  780.     if ((type = (enum en_fieldtype) rec->type) != FIELD_NORMAL &&
  781. (type != FIELD_CHECK))
  782.     {
  783.       if (type == FIELD_VARCHAR)
  784.       {
  785. get_key_length(length,from);
  786. if (length > rec_length-2)
  787.   goto err;
  788. int2store(to,length);
  789. memcpy(to+2,from,length);
  790. from+=length;
  791. continue;
  792.       }
  793.       if (flag & bit)
  794.       {
  795. if (type == FIELD_BLOB || type == FIELD_SKIPP_ZERO)
  796.   bzero((byte*) to,rec_length);
  797. else if (type == FIELD_SKIPP_ENDSPACE ||
  798.  type == FIELD_SKIPP_PRESPACE)
  799. {
  800.   if (rec->length > 255 && *from & 128)
  801.   {
  802.     if (from + 1 >= from_end)
  803.       goto err;
  804.     length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
  805.   }
  806.   else
  807.   {
  808.     if (from == from_end)
  809.       goto err;
  810.     length= (uchar) *from++;
  811.   }
  812.   min_pack_length--;
  813.   if (length >= rec_length ||
  814.       min_pack_length + length > (uint) (from_end - from))
  815.     goto err;
  816.   if (type == FIELD_SKIPP_ENDSPACE)
  817.   {
  818.     memcpy(to,(byte*) from,(size_t) length);
  819.     bfill((byte*) to+length,rec_length-length,' ');
  820.   }
  821.   else
  822.   {
  823.     bfill((byte*) to,rec_length-length,' ');
  824.     memcpy(to+rec_length-length,(byte*) from,(size_t) length);
  825.   }
  826.   from+=length;
  827. }
  828.       }
  829.       else if (type == FIELD_BLOB)
  830.       {
  831. uint size_length=rec_length- mi_portable_sizeof_char_ptr;
  832. ulong blob_length=_mi_calc_blob_length(size_length,from);
  833. if ((ulong) (from_end-from) - size_length < blob_length ||
  834.     min_pack_length > (uint) (from_end -(from+size_length+blob_length)))
  835.   goto err;
  836. memcpy((byte*) to,(byte*) from,(size_t) size_length);
  837. from+=size_length;
  838. memcpy_fixed((byte*) to+size_length,(byte*) &from,sizeof(char*));
  839. from+=blob_length;
  840.       }
  841.       else
  842.       {
  843. if (type == FIELD_SKIPP_ENDSPACE || type == FIELD_SKIPP_PRESPACE)
  844.   min_pack_length--;
  845. if (min_pack_length + rec_length > (uint) (from_end - from))
  846.   goto err;
  847. memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
  848.       }
  849.       if ((bit= bit << 1) >= 256)
  850.       {
  851. flag= (uchar) *++packpos; bit=1;
  852.       }
  853.     }
  854.     else
  855.     {
  856.       if (min_pack_length > (uint) (from_end - from))
  857. goto err;
  858.       min_pack_length-=rec_length;
  859.       memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
  860.     }
  861.   }
  862.   if (info->s->calc_checksum)
  863.     from++;
  864.   if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
  865.     DBUG_RETURN((info->packed_length=found_length));
  866.  err:
  867.   my_errno=HA_ERR_RECORD_DELETED;
  868.   DBUG_PRINT("error",("to_end: %lx -> %lx  from_end: %lx -> %lx",
  869.       to,to_end,from,from_end));
  870.   DBUG_DUMP("from",(byte*) info->rec_buff,info->s->base.min_pack_length);
  871.   DBUG_RETURN(MY_FILE_ERROR);
  872. } /* _mi_rec_unpack */
  873. /* Calc length of blob. Update info in blobs->length */
  874. ulong _my_calc_total_blob_length(MI_INFO *info, const byte *record)
  875. {
  876.   ulong length;
  877.   MI_BLOB *blob,*end;
  878.   for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
  879.        blob != end;
  880.        blob++)
  881.   {
  882.     blob->length=_mi_calc_blob_length(blob->pack_length,record + blob->offset);
  883.     length+=blob->length;
  884.   }
  885.   return length;
  886. }
  887. ulong _mi_calc_blob_length(uint length, const byte *pos)
  888. {
  889.   switch (length) {
  890.   case 1:
  891.     return (uint) (uchar) *pos;
  892.   case 2:
  893.     return (uint) uint2korr(pos);
  894.   case 3:
  895.     return uint3korr(pos);
  896.   case 4:
  897.     return uint4korr(pos);
  898.   default:
  899.     break;
  900.   }
  901.   return 0; /* Impossible */
  902. }
  903. void _my_store_blob_length(byte *pos,uint pack_length,uint length)
  904. {
  905.   switch (pack_length) {
  906.   case 1:
  907.     *pos= (uchar) length;
  908.     break;
  909.   case 2:
  910.     int2store(pos,length);
  911.     break;
  912.   case 3:
  913.     int3store(pos,length);
  914.     break;
  915.   case 4:
  916.     int4store(pos,length);
  917.   default:
  918.     break;
  919.   }
  920.   return;
  921. }
  922. /* Read record from datafile */
  923. /* Returns 0 if ok, -1 if error */
  924. int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf)
  925. {
  926.   int flag;
  927.   uint b_type,left_length;
  928.   byte *to;
  929.   MI_BLOCK_INFO block_info;
  930.   File file;
  931.   DBUG_ENTER("mi_read_dynamic_record");
  932.   if (filepos != HA_OFFSET_ERROR)
  933.   {
  934.     LINT_INIT(to);
  935.     LINT_INIT(left_length);
  936.     file=info->dfile;
  937.     block_info.next_filepos=filepos; /* for easyer loop */
  938.     flag=block_info.second_read=0;
  939.     do
  940.     {
  941.       if (info->opt_flag & WRITE_CACHE_USED &&
  942.   info->rec_cache.pos_in_file <= block_info.next_filepos &&
  943.   flush_io_cache(&info->rec_cache))
  944. goto err;
  945.       info->rec_cache.seek_not_done=1;
  946.       if ((b_type=_mi_get_block_info(&block_info,file,
  947.      block_info.next_filepos))
  948.   & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  949.      BLOCK_FATAL_ERROR))
  950.       {
  951. if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
  952.   my_errno=HA_ERR_RECORD_DELETED;
  953. goto err;
  954.       }
  955.       if (flag == 0) /* First block */
  956.       {
  957. flag=1;
  958. if (block_info.rec_len > (uint) info->s->base.max_pack_length)
  959.   goto panic;
  960. if (info->s->base.blobs)
  961. {
  962.   if (!(to=mi_fix_rec_buff_for_blob(info,block_info.rec_len)))
  963.     goto err;
  964. }
  965. else
  966.   to= info->rec_buff;
  967. left_length=block_info.rec_len;
  968.       }
  969.       if (left_length < block_info.data_len || ! block_info.data_len)
  970. goto panic; /* Wrong linked record */
  971.       if (my_pread(file,(byte*) to,block_info.data_len,block_info.filepos,
  972.    MYF(MY_NABP)))
  973. goto panic;
  974.       left_length-=block_info.data_len;
  975.       to+=block_info.data_len;
  976.     } while (left_length);
  977.     info->update|= HA_STATE_AKTIV; /* We have a aktive record */
  978.     VOID(_mi_writeinfo(info,0));
  979.     DBUG_RETURN(_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
  980. MY_FILE_ERROR ? 0 : -1);
  981.   }
  982.   VOID(_mi_writeinfo(info,0));
  983.   DBUG_RETURN(-1); /* Wrong data to read */
  984. panic:
  985.   my_errno=HA_ERR_WRONG_IN_RECORD;
  986. err:
  987.   VOID(_mi_writeinfo(info,0));
  988.   DBUG_RETURN(-1);
  989. }
  990. byte *mi_fix_rec_buff_for_blob(MI_INFO *info, ulong length)
  991. {
  992.   uint extra;
  993.   if (! info->rec_buff || length > info->alloced_rec_buff_length)
  994.   {
  995.     byte *newptr;
  996.     extra=ALIGN_SIZE(MI_MAX_DYN_BLOCK_HEADER)+MI_SPLIT_LENGTH+
  997.       MI_DYN_DELETE_BLOCK_HEADER;
  998.     if (!(newptr=(byte*) my_realloc((gptr) info->rec_alloc,length+extra,
  999.     MYF(MY_ALLOW_ZERO_PTR))))
  1000.       return newptr;
  1001.     info->rec_alloc=newptr;
  1002.     info->rec_buff=newptr+ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER);
  1003.     info->alloced_rec_buff_length=length;
  1004.   }
  1005.   return info->rec_buff;
  1006. }
  1007. /* compare unique constraint between stored rows */
  1008. int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def,
  1009.    const byte *record, my_off_t pos)
  1010. {
  1011.   byte *rec_buff,*rec_alloc,*old_record;
  1012.   uint alloced_rec_buff_length;
  1013.   int error;
  1014.   DBUG_ENTER("_mi_cmp_dynamic_unique");
  1015.   if (!(old_record=my_alloca(info->s->base.reclength)))
  1016.     DBUG_RETURN(1);
  1017.   /* Don't let the compare destroy blobs that may be in use */
  1018.   rec_buff=info->rec_buff;
  1019.   rec_alloc=info->rec_alloc;
  1020.   alloced_rec_buff_length=info->alloced_rec_buff_length;
  1021.   if (info->s->base.blobs)
  1022.   {
  1023.     info->rec_buff=0;
  1024.     info->rec_alloc=0;
  1025.     info->alloced_rec_buff_length=0;
  1026.   }
  1027.   error=_mi_read_dynamic_record(info,pos,old_record);
  1028.   if (!error)
  1029.     error=mi_unique_comp(def, record, old_record, def->null_are_equal);
  1030.   if (info->s->base.blobs)
  1031.   {
  1032.     my_free(info->rec_alloc,MYF(MY_ALLOW_ZERO_PTR));
  1033.     info->rec_buff=rec_buff;
  1034.     info->rec_alloc=rec_alloc;
  1035.     info->alloced_rec_buff_length=alloced_rec_buff_length;
  1036.   }
  1037.   my_afree(old_record);
  1038.   DBUG_RETURN(error);
  1039. }
  1040. /* Compare of record one disk with packed record in memory */
  1041. int _mi_cmp_dynamic_record(register MI_INFO *info, register const byte *record)
  1042. {
  1043.   uint flag,reclength,b_type;
  1044.   my_off_t filepos;
  1045.   byte *buffer;
  1046.   MI_BLOCK_INFO block_info;
  1047.   DBUG_ENTER("_mi_cmp_dynamic_record");
  1048. /* We are going to do changes; dont let anybody disturb */
  1049.   dont_break(); /* Dont allow SIGHUP or SIGINT */
  1050.   if (info->opt_flag & WRITE_CACHE_USED)
  1051.   {
  1052.     info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
  1053.     if (flush_io_cache(&info->rec_cache))
  1054.       DBUG_RETURN(-1);
  1055.   }
  1056.   info->rec_cache.seek_not_done=1;
  1057. /* If nobody have touched the database we don't have to test rec */
  1058.   buffer=info->rec_buff;
  1059.   if ((info->opt_flag & READ_CHECK_USED))
  1060.   { /* If check isn't disabled  */
  1061.     if (info->s->base.blobs)
  1062.     {
  1063.       if (!(buffer=(byte*) my_alloca(info->s->base.pack_reclength+
  1064.      _my_calc_total_blob_length(info,record))))
  1065. DBUG_RETURN(-1);
  1066.     }
  1067.     reclength=_mi_rec_pack(info,buffer,record);
  1068.     record= buffer;
  1069.     filepos=info->lastpos;
  1070.     flag=block_info.second_read=0;
  1071.     block_info.next_filepos=filepos;
  1072.     while (reclength > 0)
  1073.     {
  1074.       if ((b_type=_mi_get_block_info(&block_info,info->dfile,
  1075.     block_info.next_filepos))
  1076.   & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  1077.      BLOCK_FATAL_ERROR))
  1078.       {
  1079. if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
  1080.   my_errno=HA_ERR_RECORD_CHANGED;
  1081. goto err;
  1082.       }
  1083.       if (flag == 0) /* First block */
  1084.       {
  1085. flag=1;
  1086. if (reclength != block_info.rec_len)
  1087. {
  1088.   my_errno=HA_ERR_RECORD_CHANGED;
  1089.   goto err;
  1090. }
  1091.       } else if (reclength < block_info.data_len)
  1092.       {
  1093. my_errno=HA_ERR_WRONG_IN_RECORD;
  1094. goto err;
  1095.       }
  1096.       reclength-=block_info.data_len;
  1097.       if (_mi_cmp_buffer(info->dfile,record,block_info.filepos,
  1098.  block_info.data_len))
  1099.       {
  1100. my_errno=HA_ERR_RECORD_CHANGED;
  1101. goto err;
  1102.       }
  1103.       flag=1;
  1104.       record+=block_info.data_len;
  1105.     }
  1106.   }
  1107.   my_errno=0;
  1108.  err:
  1109.   if (buffer != info->rec_buff)
  1110.     my_afree((gptr) buffer);
  1111.   DBUG_RETURN(my_errno);
  1112. }
  1113. /* Compare file to buffert */
  1114. static int _mi_cmp_buffer(File file, const byte *buff, my_off_t filepos,
  1115.   uint length)
  1116. {
  1117.   uint next_length;
  1118.   char temp_buff[IO_SIZE*2];
  1119.   DBUG_ENTER("_mi_cmp_buffer");
  1120.   VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
  1121.   next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
  1122.   while (length > IO_SIZE*2)
  1123.   {
  1124.     if (my_read(file,temp_buff,next_length,MYF(MY_NABP)))
  1125.       goto err;
  1126.     if (memcmp((byte*) buff,temp_buff,IO_SIZE))
  1127.       DBUG_RETURN(1);
  1128.     buff+=next_length;
  1129.     length-= next_length;
  1130.     next_length=IO_SIZE*2;
  1131.   }
  1132.   if (my_read(file,temp_buff,length,MYF(MY_NABP)))
  1133.     goto err;
  1134.   DBUG_RETURN(memcmp((byte*) buff,temp_buff,length));
  1135. err:
  1136.   DBUG_RETURN(1);
  1137. }
  1138. int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf,
  1139. register my_off_t filepos,
  1140. my_bool skipp_deleted_blocks)
  1141. {
  1142.   int flag,info_read,save_errno;
  1143.   uint left_len,b_type;
  1144.   byte *to;
  1145.   MI_BLOCK_INFO block_info;
  1146.   MYISAM_SHARE *share=info->s;
  1147.   DBUG_ENTER("_mi_read_rnd_dynamic_record");
  1148.   info_read=0;
  1149.   LINT_INIT(to);
  1150.   if (info->lock_type == F_UNLCK)
  1151.   {
  1152. #ifndef UNSAFE_LOCKING
  1153.     if (share->r_locks == 0 && share->w_locks == 0)
  1154.     {
  1155.       if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
  1156.   MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
  1157. DBUG_RETURN(my_errno);
  1158.     }
  1159. #else
  1160.     info->tmp_lock_type=F_RDLCK;
  1161. #endif
  1162.   }
  1163.   else
  1164.     info_read=1; /* memory-keyinfoblock is ok */
  1165.   flag=block_info.second_read=0;
  1166.   left_len=1;
  1167.   do
  1168.   {
  1169.     if (filepos >= info->state->data_file_length)
  1170.     {
  1171.       if (!info_read)
  1172.       { /* Check if changed */
  1173. info_read=1;
  1174. info->rec_cache.seek_not_done=1;
  1175. if (mi_state_info_read_dsk(share->kfile,&share->state,1))
  1176.   goto panic;
  1177.       }
  1178.       if (filepos >= info->state->data_file_length)
  1179.       {
  1180. my_errno= HA_ERR_END_OF_FILE;
  1181. goto err;
  1182.       }
  1183.     }
  1184.     if (info->opt_flag & READ_CACHE_USED)
  1185.     {
  1186.       if (_mi_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
  1187.  sizeof(block_info.header),
  1188.  (!flag && skipp_deleted_blocks ? READING_NEXT : 0) |
  1189.  READING_HEADER))
  1190. goto panic;
  1191.       b_type=_mi_get_block_info(&block_info,-1,filepos);
  1192.     }
  1193.     else
  1194.     {
  1195.       if (info->opt_flag & WRITE_CACHE_USED &&
  1196.   info->rec_cache.pos_in_file <= filepos &&
  1197.   flush_io_cache(&info->rec_cache))
  1198. DBUG_RETURN(my_errno);
  1199.       info->rec_cache.seek_not_done=1;
  1200.       b_type=_mi_get_block_info(&block_info,info->dfile,filepos);
  1201.     }
  1202.     if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  1203.   BLOCK_FATAL_ERROR))
  1204.     {
  1205.       if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
  1206.   && skipp_deleted_blocks)
  1207.       {
  1208. filepos=block_info.filepos+block_info.block_len;
  1209. block_info.second_read=0;
  1210. continue; /* Search after next_record */
  1211.       }
  1212.       if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
  1213.       {
  1214. my_errno=HA_ERR_RECORD_DELETED;
  1215. info->lastpos=block_info.filepos;
  1216. info->nextpos=block_info.filepos+block_info.block_len;
  1217.       }
  1218.       goto err;
  1219.     }
  1220.     if (flag == 0) /* First block */
  1221.     {
  1222.       if (block_info.rec_len > (uint) share->base.max_pack_length)
  1223. goto panic;
  1224.       info->lastpos=filepos;
  1225.       if (share->base.blobs)
  1226.       {
  1227. if (!(to=mi_fix_rec_buff_for_blob(info,block_info.rec_len)))
  1228.   goto err;
  1229.       }
  1230.       else
  1231. to= info->rec_buff;
  1232.       left_len=block_info.rec_len;
  1233.     }
  1234.     if (left_len < block_info.data_len)
  1235.       goto panic; /* Wrong linked record */
  1236.     /* copy information that is already read */
  1237.     {
  1238.       uint offset=(uint) (block_info.filepos - filepos);
  1239.       uint tmp_length= (sizeof(block_info.header) - offset);
  1240.       filepos=block_info.filepos;
  1241.       if (tmp_length > block_info.data_len)
  1242. tmp_length= block_info.data_len;
  1243.       if (tmp_length)
  1244.       {
  1245. memcpy((byte*) to, block_info.header+offset,tmp_length);
  1246. block_info.data_len-=tmp_length;
  1247. left_len-=tmp_length;
  1248. to+=tmp_length;
  1249. filepos+=tmp_length;
  1250.      }
  1251.     }
  1252.     /* read rest of record from file */
  1253.     if (block_info.data_len)
  1254.     {
  1255.       if (info->opt_flag & READ_CACHE_USED)
  1256.       {
  1257. if (_mi_read_cache(&info->rec_cache,(byte*) to,filepos,
  1258.    block_info.data_len,
  1259.    (!flag && skipp_deleted_blocks) ? READING_NEXT :0))
  1260.   goto panic;
  1261.       }
  1262.       else
  1263.       {
  1264. /* VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); */
  1265. if (my_read(info->dfile,(byte*) to,block_info.data_len,MYF(MY_NABP)))
  1266. {
  1267.   if (my_errno == -1)
  1268.     my_errno= HA_ERR_WRONG_IN_RECORD; /* Unexpected end of file */
  1269.   goto err;
  1270. }
  1271.       }
  1272.     }
  1273.     if (flag++ == 0)
  1274.     {
  1275.       info->nextpos=block_info.filepos+block_info.block_len;
  1276.       skipp_deleted_blocks=0;
  1277.     }
  1278.     left_len-=block_info.data_len;
  1279.     to+=block_info.data_len;
  1280.     filepos=block_info.next_filepos;
  1281.   } while (left_len);
  1282.   info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
  1283.   if (share->r_locks == 0 && share->w_locks == 0)
  1284.     VOID(_mi_writeinfo(info,0));
  1285.   if (_mi_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
  1286.       MY_FILE_ERROR)
  1287.     DBUG_RETURN(0);
  1288.   DBUG_RETURN(my_errno); /* Wrong record */
  1289. panic:
  1290.   my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
  1291. err:
  1292.   save_errno=my_errno;
  1293.   VOID(_mi_writeinfo(info,0));
  1294.   DBUG_RETURN(my_errno=save_errno);
  1295. }
  1296. /* Read and process header from a dynamic-record-file */
  1297. uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos)
  1298. {
  1299.   uint return_val=0;
  1300.   uchar *header=info->header;
  1301.   if (file >= 0)
  1302.   {
  1303.     VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
  1304.     if (my_read(file,(char*) header,sizeof(info->header),MYF(0)) !=
  1305. sizeof(info->header))
  1306.     {
  1307.       my_errno=HA_ERR_WRONG_IN_RECORD;
  1308.       return BLOCK_FATAL_ERROR;
  1309.     }
  1310.   }
  1311.   DBUG_DUMP("header",(byte*) header,MI_BLOCK_INFO_HEADER_LENGTH);
  1312.   if (info->second_read)
  1313.   {
  1314.     if (info->header[0] <= 6)
  1315.       return_val=BLOCK_SYNC_ERROR;
  1316.   }
  1317.   else
  1318.   {
  1319.     if (info->header[0] > 6)
  1320.       return_val=BLOCK_SYNC_ERROR;
  1321.   }
  1322.   info->next_filepos= HA_OFFSET_ERROR; /* Dummy ifall no next block */
  1323.   switch (info->header[0]) {
  1324.   case 0:
  1325.     if ((info->block_len=(uint) mi_uint3korr(header+1)) <
  1326. MI_MIN_BLOCK_LENGTH ||
  1327. (info->block_len & (MI_DYN_ALIGN_SIZE -1)))
  1328.     {
  1329.       my_errno=HA_ERR_WRONG_IN_RECORD;
  1330.       return BLOCK_ERROR;
  1331.     }
  1332.     info->filepos=filepos;
  1333.     info->next_filepos=mi_sizekorr(header+4);
  1334.     info->prev_filepos=mi_sizekorr(header+12);
  1335. #if SIZEOF_OFF_T == 4
  1336.     if ((mi_uint4korr(header+4) != 0 &&
  1337.  (mi_uint4korr(header+4) != (ulong) ~0 ||
  1338.   info->next_filepos != (ulong) ~0)) ||
  1339. (mi_uint4korr(header+12) != 0 &&
  1340.  (mi_uint4korr(header+12) != (ulong) ~0 ||
  1341.   info->prev_filepos != (ulong) ~0)))
  1342.       return BLOCK_FATAL_ERROR;
  1343. #endif
  1344.     return return_val | BLOCK_DELETED; /* Deleted block */
  1345.   case 1:
  1346.     info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
  1347.     info->filepos=filepos+3;
  1348.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1349.   case 2:
  1350.     info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
  1351.     info->filepos=filepos+4;
  1352.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1353.   case 3:
  1354.     info->rec_len=info->data_len=mi_uint2korr(header+1);
  1355.     info->block_len=info->rec_len+ (uint) header[3];
  1356.     info->filepos=filepos+4;
  1357.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1358.   case 4:
  1359.     info->rec_len=info->data_len=mi_uint3korr(header+1);
  1360.     info->block_len=info->rec_len+ (uint) header[4];
  1361.     info->filepos=filepos+5;
  1362.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1363.   case 5:
  1364.     info->rec_len=mi_uint2korr(header+1);
  1365.     info->block_len=info->data_len=mi_uint2korr(header+3);
  1366.     info->next_filepos=mi_sizekorr(header+5);
  1367.     info->second_read=1;
  1368.     info->filepos=filepos+13;
  1369.     return return_val | BLOCK_FIRST;
  1370.   case 6:
  1371.     info->rec_len=mi_uint3korr(header+1);
  1372.     info->block_len=info->data_len=mi_uint3korr(header+4);
  1373.     info->next_filepos=mi_sizekorr(header+7);
  1374.     info->second_read=1;
  1375.     info->filepos=filepos+15;
  1376.     return return_val | BLOCK_FIRST;
  1377.     /* The following blocks are identical to 1-6 without rec_len */
  1378.   case 7:
  1379.     info->data_len=info->block_len=mi_uint2korr(header+1);
  1380.     info->filepos=filepos+3;
  1381.     return return_val | BLOCK_LAST;
  1382.   case 8:
  1383.     info->data_len=info->block_len=mi_uint3korr(header+1);
  1384.     info->filepos=filepos+4;
  1385.     return return_val | BLOCK_LAST;
  1386.   case 9:
  1387.     info->data_len=mi_uint2korr(header+1);
  1388.     info->block_len=info->data_len+ (uint) header[3];
  1389.     info->filepos=filepos+4;
  1390.     return return_val | BLOCK_LAST;
  1391.   case 10:
  1392.     info->data_len=mi_uint3korr(header+1);
  1393.     info->block_len=info->data_len+ (uint) header[4];
  1394.     info->filepos=filepos+5;
  1395.     return return_val | BLOCK_LAST;
  1396.   case 11:
  1397.     info->data_len=info->block_len=mi_uint2korr(header+1);
  1398.     info->next_filepos=mi_sizekorr(header+3);
  1399.     info->second_read=1;
  1400.     info->filepos=filepos+11;
  1401.     return return_val;
  1402.   case 12:
  1403.     info->data_len=info->block_len=mi_uint3korr(header+1);
  1404.     info->next_filepos=mi_sizekorr(header+4);
  1405.     info->second_read=1;
  1406.     info->filepos=filepos+12;
  1407.     return return_val;
  1408.   default:
  1409.     my_errno=HA_ERR_WRONG_IN_RECORD;  /* Garbage */
  1410.     return BLOCK_ERROR;
  1411.   }
  1412. }