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

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. /* Functions to handle space-packed-records and blobs */
  14. #include "isamdef.h"
  15. /* Enough for comparing if number is zero */
  16. static char zero_string[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  17. static int write_dynamic_record(N_INFO *info,const byte *record,
  18. uint reclength);
  19. static int _nisam_find_writepos(N_INFO *info,uint reclength,ulong *filepos,
  20.      uint *length);
  21. static int update_dynamic_record(N_INFO *info,ulong filepos,byte *record,
  22.  uint reclength);
  23. static int delete_dynamic_record(N_INFO *info,ulong filepos,
  24.  uint second_read);
  25. static int _nisam_cmp_buffer(File file, const byte *buff, ulong filepos,
  26.   uint length);
  27. #ifdef THREAD
  28. /* Play it safe; We have a small stack when using threads */
  29. #undef my_alloca
  30. #undef my_afree
  31. #define my_alloca(A) my_malloc((A),MYF(0))
  32. #define my_afree(A) my_free((A),MYF(0))
  33. #endif
  34. /* Interface function from N_INFO */
  35. int _nisam_write_dynamic_record(N_INFO *info, const byte *record)
  36. {
  37.   uint reclength=_nisam_rec_pack(info,info->rec_buff,record);
  38.   return (write_dynamic_record(info,info->rec_buff,reclength));
  39. }
  40. int _nisam_update_dynamic_record(N_INFO *info, ulong pos, const byte *record)
  41. {
  42.   uint length=_nisam_rec_pack(info,info->rec_buff,record);
  43.   return (update_dynamic_record(info,pos,info->rec_buff,length));
  44. }
  45. int _nisam_write_blob_record(N_INFO *info, const byte *record)
  46. {
  47.   byte *rec_buff;
  48.   int error;
  49.   uint reclength,extra;
  50.   extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
  51.     DYN_DELETE_BLOCK_HEADER;
  52.   if (!(rec_buff=(byte*) my_alloca(info->s->base.pack_reclength+
  53.    _calc_total_blob_length(info,record)+
  54.    extra)))
  55.     return(-1);
  56.   reclength=_nisam_rec_pack(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
  57.  record);
  58.   error=write_dynamic_record(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
  59.      reclength);
  60.   my_afree(rec_buff);
  61.   return(error);
  62. }
  63. int _nisam_update_blob_record(N_INFO *info, ulong pos, const byte *record)
  64. {
  65.   byte *rec_buff;
  66.   int error;
  67.   uint reclength,extra;
  68.   extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
  69.     DYN_DELETE_BLOCK_HEADER;
  70.   if (!(rec_buff=(byte*) my_alloca(info->s->base.pack_reclength+
  71.    _calc_total_blob_length(info,record)+
  72.    extra)))
  73.     return(-1);
  74.   reclength=_nisam_rec_pack(info,rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
  75.  record);
  76.   error=update_dynamic_record(info,pos,
  77.       rec_buff+ALIGN_SIZE(MAX_DYN_BLOCK_HEADER),
  78.       reclength);
  79.   my_afree(rec_buff);
  80.   return(error);
  81. }
  82. int _nisam_delete_dynamic_record(N_INFO *info)
  83. {
  84.   return delete_dynamic_record(info,info->lastpos,0);
  85. }
  86. /* Write record to data-file */
  87. static int write_dynamic_record(N_INFO *info, const byte *record,
  88. uint reclength)
  89. {
  90.   int flag;
  91.   uint length;
  92.   ulong filepos;
  93.   DBUG_ENTER("write_dynamic_record");
  94.   flag=0;
  95.   while (reclength)
  96.   {
  97.     if (_nisam_find_writepos(info,reclength,&filepos,&length))
  98.       goto err;
  99.     if (_nisam_write_part_record(info,filepos,length,info->s->state.dellink,
  100.       (byte**) &record,&reclength,&flag))
  101.       goto err;
  102.   }
  103.   DBUG_RETURN(0);
  104.  err:
  105.   DBUG_RETURN(1);
  106. }
  107. /* Get a block for data ; The given data-area must be used !! */
  108. static int _nisam_find_writepos(N_INFO *info,
  109.      uint reclength, /* record length */
  110.      ulong *filepos, /* Return file pos */
  111.      uint *length)   /* length of block at filepos */
  112. {
  113.   BLOCK_INFO block_info;
  114.   DBUG_ENTER("_nisam_find_writepos");
  115.   if (info->s->state.dellink != NI_POS_ERROR)
  116.   {
  117.     *filepos=info->s->state.dellink;
  118.     block_info.second_read=0;
  119.     info->rec_cache.seek_not_done=1;
  120.     if (!(_nisam_get_block_info(&block_info,info->dfile,
  121. info->s->state.dellink) & BLOCK_DELETED))
  122.     {
  123.       my_errno=HA_ERR_WRONG_IN_RECORD;
  124.       DBUG_RETURN(-1);
  125.     }
  126.     info->s->state.dellink=block_info.next_filepos;
  127.     info->s->state.del--;
  128.     info->s->state.empty-= block_info.block_len;
  129.     *length= block_info.block_len;
  130.   }
  131.   else
  132.   {
  133.     if (info->s->state.data_file_length > info->s->base.max_data_file_length)
  134.     {
  135.       my_errno=HA_ERR_RECORD_FILE_FULL;
  136.       DBUG_RETURN(-1);
  137.     }
  138.     *filepos=info->s->state.data_file_length; /* New block last */
  139.     if ((*length=reclength+3 + test(reclength > 65532)) <
  140. info->s->base.min_block_length)
  141.       *length=info->s->base.min_block_length;
  142.     info->s->state.data_file_length+= *length;
  143.     info->s->state.splitt++;
  144.     info->update|=HA_STATE_WRITE_AT_END;
  145.   }
  146.   DBUG_RETURN(0);
  147. } /* _nisam_find_writepos */
  148. /* Write a block to datafile */
  149. int _nisam_write_part_record(N_INFO *info,
  150.   ulong filepos, /* points at empty block */
  151.   uint length, /* length of block */
  152.   ulong next_filepos, /* Next empty block */
  153.   byte **record, /* pointer to record ptr */
  154.   uint *reclength, /* length of *record */
  155.   int *flag) /* *flag == 0 if header */
  156. {
  157.   uint head_length,res_length,extra_length,long_block,del_length;
  158.   byte *pos,*record_end;
  159.   uchar temp[N_SPLITT_LENGTH+DYN_DELETE_BLOCK_HEADER];
  160.   DBUG_ENTER("_nisam_write_part_record");
  161.   res_length=extra_length=0;
  162.   if (length > *reclength + N_SPLITT_LENGTH)
  163.   { /* Splitt big block */
  164.     res_length=length- *reclength - 3 - N_EXTEND_BLOCK_LENGTH;
  165.     length-= res_length; /* Use this for first part */
  166.   }
  167.   long_block= (length < 65535L && *reclength < 65535L) ? 0 : 1;
  168.   if (length-long_block == *reclength+3 || length == *reclength + 4)
  169.   { /* Exact what we need */
  170.     temp[0]=(uchar) (1+ *flag); /* 1, or 9 */
  171.     if (long_block)
  172.     {
  173.       int3store(temp+1,*reclength);
  174.     }
  175.     else
  176.     {
  177.       int2store(temp+1,*reclength);
  178.     }
  179.     head_length=3+long_block;
  180.     if (length-long_block == *reclength+4)
  181.     {
  182.       length--;
  183.       temp[0]++; /* 2 or 10 */
  184.       extra_length++; /* One empty */
  185.     }
  186.   }
  187.   else if (length-long_block*2 < *reclength+5)
  188.   { /* To short block */
  189.     if (next_filepos == NI_POS_ERROR)
  190.       next_filepos=info->s->state.dellink != NI_POS_ERROR ?
  191. info->s->state.dellink : info->s->state.data_file_length;
  192.     if (*flag == 0) /* First block */
  193.     {
  194.       head_length=5+4+long_block*2;
  195.       temp[0]=4;
  196.       if (long_block)
  197.       {
  198. int3store(temp+1,*reclength);
  199. int3store(temp+4,length-head_length);
  200. int4store((byte*) temp+7,next_filepos);
  201.       }
  202.       else
  203.       {
  204. int2store(temp+1,*reclength);
  205. int2store(temp+3,length-head_length);
  206. int4store((byte*) temp+5,next_filepos);
  207.       }
  208.     }
  209.     else
  210.     {
  211.       head_length=3+4+long_block;
  212.       temp[0]=12;
  213.       if (long_block)
  214.       {
  215. int3store(temp+1,length-head_length);
  216. int4store((byte*) temp+4,next_filepos);
  217.       }
  218.       else
  219.       {
  220. int2store(temp+1,length-head_length);
  221. int4store((byte*) temp+3,next_filepos);
  222.       }
  223.     }
  224.   }
  225.   else
  226.   { /* Block with empty info last */
  227.     head_length=5+long_block*2;
  228.     temp[0]= (uchar) (3+ *flag); /* 3 or 11 */
  229.     if (long_block)
  230.     {
  231.       int3store(temp+1,*reclength);
  232.       int3store(temp+4,length-7);
  233.     }
  234.     else
  235.     {
  236.       int2store(temp+1,*reclength);
  237.       int2store(temp+3,length-5);
  238.     }
  239.     extra_length= length- *reclength-head_length;
  240.     length=   *reclength+head_length; /* Write only what is needed */
  241.   }
  242.   temp[0]+=(uchar) (long_block*4);
  243.   DBUG_DUMP("header",(byte*) temp,head_length);
  244. /* Make a long block for one write */
  245.   record_end= *record+length-head_length;
  246.   del_length=(res_length ? DYN_DELETE_BLOCK_HEADER : 0);
  247.   bmove((byte*) (*record-head_length),(byte*) temp,head_length);
  248.   memcpy(temp,record_end,(size_t) (extra_length+del_length));
  249.   bzero((byte*) record_end,extra_length);
  250.   if (res_length)
  251.   {
  252.     pos=record_end+extra_length;
  253.     pos[0]= '';
  254.     int3store(pos+1,res_length);
  255.     int4store(pos+4,info->s->state.dellink);
  256.     info->s->state.dellink= filepos+length+extra_length;
  257.     info->s->state.del++;
  258.     info->s->state.empty+=res_length;
  259.     info->s->state.splitt++;
  260.   }
  261.   if (info->opt_flag & WRITE_CACHE_USED && info->update & HA_STATE_WRITE_AT_END)
  262.   {
  263.     if (my_b_write(&info->rec_cache,(byte*) *record-head_length,
  264.    length+extra_length+del_length))
  265.       goto err;
  266.   }
  267.   else
  268.   {
  269.     info->rec_cache.seek_not_done=1;
  270.     if (my_pwrite(info->dfile,(byte*) *record-head_length,length+extra_length+
  271.   del_length,filepos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
  272.       goto err;
  273.   }
  274.   memcpy(record_end,temp,(size_t) (extra_length+del_length));
  275.   *record=record_end;
  276.   *reclength-=(length-head_length);
  277.   *flag=8;
  278.   DBUG_RETURN(0);
  279. err:
  280.   DBUG_PRINT("exit",("errno: %d",my_errno));
  281.   DBUG_RETURN(1);
  282. } /*_nisam_write_part_record */
  283. /* update record from datafile */
  284. static int update_dynamic_record(N_INFO *info, ulong filepos, byte *record, uint reclength)
  285. {
  286.   int flag;
  287.   uint error,length;
  288.   BLOCK_INFO block_info;
  289.   DBUG_ENTER("update_dynamic_record");
  290.   flag=block_info.second_read=0;
  291.   while (reclength > 0)
  292.   {
  293.     if (filepos != info->s->state.dellink)
  294.     {
  295.       block_info.next_filepos= NI_POS_ERROR;
  296.       if ((error=_nisam_get_block_info(&block_info,info->dfile,filepos))
  297.   & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  298.      BLOCK_FATAL_ERROR))
  299.       {
  300. if (!(error & BLOCK_FATAL_ERROR))
  301.   my_errno=HA_ERR_WRONG_IN_RECORD;
  302. goto err;
  303.       }
  304.       length=(uint) (block_info.filepos-filepos) + block_info.block_len;
  305.     }
  306.     else
  307.     {
  308.       if (_nisam_find_writepos(info,reclength,&filepos,&length))
  309. goto err;
  310.     }
  311.     if (_nisam_write_part_record(info,filepos,length,block_info.next_filepos,
  312.       &record,&reclength,&flag))
  313.       goto err;
  314.     if ((filepos=block_info.next_filepos) == NI_POS_ERROR)
  315.       filepos=info->s->state.dellink;
  316.   }
  317.   if (block_info.next_filepos != NI_POS_ERROR)
  318.     if (delete_dynamic_record(info,block_info.next_filepos,1))
  319.       goto err;
  320.   DBUG_RETURN(0);
  321. err:
  322.   DBUG_RETURN(1);
  323. }
  324. /* Delete datarecord from database */
  325. /* info->rec_cache.seek_not_done is updated in cmp_record */
  326. static int delete_dynamic_record(N_INFO *info, ulong filepos, uint second_read)
  327. {
  328.   uint length,b_type;
  329.   BLOCK_INFO block_info;
  330.   DBUG_ENTER("delete_dynamic_record");
  331.   block_info.second_read=second_read;
  332.   do
  333.   {
  334.     if ((b_type=_nisam_get_block_info(&block_info,info->dfile,filepos))
  335. & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  336.    BLOCK_FATAL_ERROR) ||
  337. (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
  338. N_MIN_BLOCK_LENGTH)
  339.     {
  340.       my_errno=HA_ERR_WRONG_IN_RECORD;
  341.       DBUG_RETURN(1);
  342.     }
  343.     block_info.header[0]=0;
  344.     length=(uint) (block_info.filepos-filepos) +block_info.block_len;
  345.     int3store(block_info.header+1,length);
  346.     int4store(block_info.header+4,info->s->state.dellink);
  347.     if (my_pwrite(info->dfile,(byte*) block_info.header,8,filepos,
  348.   MYF(MY_NABP)))
  349.       DBUG_RETURN(1);
  350.     info->s->state.dellink = filepos;
  351.     info->s->state.del++;
  352.     info->s->state.empty+=length;
  353.     filepos=block_info.next_filepos;
  354.   } while (!(b_type & BLOCK_LAST));
  355.   DBUG_RETURN(0);
  356. }
  357. /* Pack a record. Return new reclength */
  358. uint _nisam_rec_pack(N_INFO *info, register byte *to, register const byte *from)
  359. {
  360.   uint length,new_length,flag,bit,i;
  361.   char *pos,*end,*startpos,*packpos;
  362.   enum en_fieldtype type;
  363.   reg3 N_RECINFO *rec;
  364.   N_BLOB *blob;
  365.   DBUG_ENTER("_nisam_rec_pack");
  366.   flag=0 ; bit=1;
  367.   startpos=packpos=to; to+= info->s->base.pack_bits; blob=info->blobs;
  368.   rec=info->s->rec;
  369.   for (i=info->s->base.fields ; i-- > 0; from+= (rec++)->base.length)
  370.   {
  371.     length=(uint) rec->base.length;
  372.     if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
  373.     {
  374.       if (type == FIELD_BLOB)
  375.       {
  376. if (!blob->length)
  377.   flag|=bit;
  378. else
  379. {
  380.   char *temp_pos;
  381.   memcpy((byte*) to,from,(size_t) length);
  382.   memcpy_fixed(&temp_pos,from+length,sizeof(char*));
  383.   memcpy(to+length,temp_pos,(size_t) blob->length);
  384.   to+=length+blob->length;
  385. }
  386. blob++;
  387. from+=sizeof(char*); /* Skipp blob-pointer */
  388.       }
  389.       else if (type == FIELD_SKIPP_ZERO)
  390.       {
  391. if (memcmp((byte*) from,zero_string,length) == 0)
  392.   flag|=bit;
  393. else
  394. {
  395.   memcpy((byte*) to,from,(size_t) length); to+=length;
  396. }
  397.       }
  398.       else if (type == FIELD_SKIPP_ENDSPACE ||
  399.        type == FIELD_SKIPP_PRESPACE)
  400.       {
  401. pos= (byte*) from; end= (byte*) from + length;
  402. if (type == FIELD_SKIPP_ENDSPACE)
  403. { /* Pack trailing spaces */
  404.   while (end > from && *(end-1) == ' ')
  405.     end--;
  406. }
  407. else
  408. { /* Pack pref-spaces */
  409.   while (pos < end && *pos == ' ')
  410.     pos++;
  411. }
  412. new_length=(uint) (end-pos);
  413. if (new_length +1 + test(rec->base.length > 255 && new_length > 127)
  414.     < length)
  415. {
  416.   if (rec->base.length > 255 && new_length > 127)
  417.   {
  418.     to[0]=(char) ((new_length & 127)+128);
  419.     to[1]=(char) (new_length >> 7);
  420.     to+=2;
  421.   }
  422.   else
  423.     *to++= (char) new_length;
  424.   memcpy((byte*) to,pos,(size_t) new_length); to+=new_length;
  425.   flag|=bit;
  426. }
  427. else
  428. {
  429.   memcpy(to,from,(size_t) length); to+=length;
  430. }
  431.       }
  432.       else if (type == FIELD_ZERO)
  433. continue; /* Don't store this */
  434.       else
  435.       {
  436. memcpy(to,from,(size_t) length); to+=length;
  437. continue; /* Normal field */
  438.       }
  439.       if ((bit= bit << 1) >= 256)
  440.       {
  441. *packpos++ = (char) (uchar) flag;
  442. bit=1; flag=0;
  443.       }
  444.     }
  445.     else
  446.     {
  447.       memcpy(to,from,(size_t) length); to+=length;
  448.     }
  449.   }
  450.   if (bit != 1)
  451.     *packpos= (char) (uchar) flag;
  452.   DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
  453.   DBUG_RETURN((uint) (to-startpos));
  454. } /* _nisam_rec_pack */
  455. /*
  456. ** Check if a record was correctly packed. Used only by isamchk
  457. ** Returns 0 if record is ok.
  458. */
  459. my_bool _nisam_rec_check(N_INFO *info,const char *from)
  460. {
  461.   uint length,new_length,flag,bit,i;
  462.   char *pos,*end,*packpos,*to;
  463.   enum en_fieldtype type;
  464.   reg3 N_RECINFO *rec;
  465.   DBUG_ENTER("_nisam_rec_check");
  466.   packpos=info->rec_buff; to= info->rec_buff+info->s->base.pack_bits;
  467.   rec=info->s->rec;
  468.   flag= *packpos; bit=1;
  469.   for (i=info->s->base.fields ; i-- > 0; from+= (rec++)->base.length)
  470.   {
  471.     length=(uint) rec->base.length;
  472.     if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
  473.     {
  474.       if (type == FIELD_BLOB)
  475.       {
  476. uint blob_length= _calc_blob_length(length,from);
  477. if (!blob_length && !(flag & bit))
  478.   goto err;
  479. if (blob_length)
  480.   to+=length+ blob_length;
  481. from+=sizeof(char*);
  482.       }
  483.       else if (type == FIELD_SKIPP_ZERO)
  484.       {
  485. if (memcmp((byte*) from,zero_string,length) == 0)
  486. {
  487.   if (!(flag & bit))
  488.     goto err;
  489. }
  490. else
  491.   to+=length;
  492.       }
  493.       else if (type == FIELD_SKIPP_ENDSPACE ||
  494.        type == FIELD_SKIPP_PRESPACE)
  495.       {
  496. pos= (byte*) from; end= (byte*) from + length;
  497. if (type == FIELD_SKIPP_ENDSPACE)
  498. { /* Pack trailing spaces */
  499.   while (end > from && *(end-1) == ' ')
  500.     end--;
  501. }
  502. else
  503. { /* Pack pre-spaces */
  504.   while (pos < end && *pos == ' ')
  505.     pos++;
  506. }
  507. new_length=(uint) (end-pos);
  508. if (new_length +1 + test(rec->base.length > 255 && new_length > 127)
  509.     < length)
  510. {
  511.   if (!(flag & bit))
  512.     goto err;
  513.   if (rec->base.length > 255 && new_length > 127)
  514.   {
  515.     if (to[0] != (char) ((new_length & 127)+128) ||
  516. to[1] != (char) (new_length >> 7))
  517.       goto err;
  518.     to+=2;
  519.   }
  520.   else if (*to++ != (char) new_length)
  521.     goto err;
  522.   to+=new_length;
  523. }
  524. else
  525.   to+=length;
  526.       }
  527.       else
  528.       {
  529. if (type != FIELD_ZERO)
  530.   to+=length; /* Not packed field */
  531. continue;
  532.       }
  533.       if ((bit= bit << 1) >= 256)
  534.       {
  535. flag= *++packpos;
  536. bit=1;
  537.       }
  538.     }
  539.     else
  540.     {
  541.       to+=length;
  542.     }
  543.   }
  544.   if (bit != 1)
  545.     *packpos= (char) (uchar) flag;
  546.   if (info->packed_length == (uint) (to - info->rec_buff) &&
  547.       (bit == 1 || !(flag & ~(bit - 1))))
  548.     DBUG_RETURN(0);
  549.  err:
  550.   DBUG_RETURN(1);
  551. }
  552. /* Unpacks a record */
  553. /* Returns -1 and my_errno =HA_ERR_RECORD_DELETED if reclength isn't */
  554. /* right. Returns reclength (>0) if ok */
  555. uint _nisam_rec_unpack(register N_INFO *info, register byte *to, byte *from,
  556.     uint found_length)
  557. {
  558.   uint flag,bit,length,rec_length,min_pack_length;
  559.   enum en_fieldtype type;
  560.   byte *from_end,*to_end,*packpos;
  561.   reg3 N_RECINFO *rec,*end_field;
  562.   DBUG_ENTER("_nisam_rec_unpack");
  563.   to_end=to + info->s->base.reclength;
  564.   from_end=from+found_length;
  565.   flag= (uchar) *from; bit=1; packpos=from;
  566.   if (found_length < info->s->base.min_pack_length)
  567.     goto err;
  568.   from+= info->s->base.pack_bits;
  569.   min_pack_length=info->s->base.min_pack_length - info->s->base.pack_bits;
  570.   for (rec=info->s->rec , end_field=rec+info->s->base.fields ;
  571.        rec < end_field ; to+= rec_length, rec++)
  572.   {
  573.     rec_length=rec->base.length;
  574.     if ((type = (enum en_fieldtype) rec->base.type) != FIELD_NORMAL)
  575.     {
  576.       if (type == FIELD_ZERO)
  577. continue; /* Skipp this */
  578.       if (flag & bit)
  579.       {
  580. if (type == FIELD_BLOB)
  581. {
  582.   bzero((byte*) to,rec_length+sizeof(char*));
  583.   to+=sizeof(char*);
  584. }
  585. else if (type == FIELD_SKIPP_ZERO)
  586.   bzero((byte*) to,rec_length);
  587. else if (type == FIELD_SKIPP_ENDSPACE ||
  588.  type == FIELD_SKIPP_PRESPACE)
  589. {
  590.   if (rec->base.length > 255 && *from & 128)
  591.   {
  592.     if (from + 1 >= from_end)
  593.       goto err;
  594.     length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
  595.   }
  596.   else
  597.   {
  598.     if (from == from_end)
  599.       goto err;
  600.     length= (uchar) *from++;
  601.   }
  602.   min_pack_length--;
  603.   if (length >= rec_length ||
  604.       min_pack_length + length > (uint) (from_end - from))
  605.     goto err;
  606.   if (type == FIELD_SKIPP_ENDSPACE)
  607.   {
  608.     memcpy(to,(byte*) from,(size_t) length);
  609.     bfill((byte*) to+length,rec_length-length,' ');
  610.   }
  611.   else
  612.   {
  613.     bfill((byte*) to,rec_length-length,' ');
  614.     memcpy(to+rec_length-length,(byte*) from,(size_t) length);
  615.   }
  616.   from+=length;
  617. }
  618.       }
  619.       else if (type == FIELD_BLOB)
  620.       {
  621. ulong blob_length=_calc_blob_length(rec_length,from);
  622. if ((ulong) (from_end-from) - rec_length < blob_length ||
  623.     min_pack_length > (uint) (from_end -(from+rec_length+blob_length)))
  624.   goto err;
  625. memcpy((byte*) to,(byte*) from,(size_t) rec_length);
  626. from+=rec_length;
  627. /* memcpy crasches alpha egcs 1.1.2 */
  628. bmove((byte*) to+rec_length,(byte*) &from,sizeof(char*));
  629. from+=blob_length;
  630. to+=sizeof(char*);
  631.       }
  632.       else
  633.       {
  634. if (type == FIELD_SKIPP_ENDSPACE || type == FIELD_SKIPP_PRESPACE)
  635.   min_pack_length--;
  636. if (min_pack_length + rec_length > (uint) (from_end - from))
  637.   goto err;
  638. memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
  639.       }
  640.       if ((bit= bit << 1) >= 256)
  641.       {
  642. flag= (uchar) *++packpos; bit=1;
  643.       }
  644.     }
  645.     else
  646.     {
  647.       if (min_pack_length > (uint) (from_end - from))
  648. goto err;
  649.       min_pack_length-=rec_length;
  650.       memcpy(to,(byte*) from,(size_t) rec_length); from+=rec_length;
  651.     }
  652.   }
  653.   if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
  654.     DBUG_RETURN((info->packed_length=found_length));
  655.  err:
  656.   my_errno=HA_ERR_RECORD_DELETED;
  657.   DBUG_PRINT("error",("to_end: %lx -> %lx  from_end: %lx -> %lx",
  658.       to,to_end,from,from_end));
  659.   DBUG_DUMP("from",(byte*) info->rec_buff,info->s->base.min_pack_length);
  660.   DBUG_RETURN(MY_FILE_ERROR);
  661. } /* _nisam_rec_unpack */
  662. /* Calc length of blob. Update info in blobs->length */
  663. uint _calc_total_blob_length(N_INFO *info, const byte *record)
  664. {
  665.   uint i,length;
  666.   N_BLOB *blob;
  667.   for (i=length=0, blob= info->blobs; i++ < info->s->base.blobs ; blob++)
  668.   {
  669.     blob->length=_calc_blob_length(blob->pack_length,record + blob->offset);
  670.     length+=blob->length;
  671.   }
  672.   return length;
  673. }
  674. uint _calc_blob_length(uint length, const byte *pos)
  675. {
  676.   switch (length) {
  677.   case 1:
  678.     return (uint) (uchar) *pos;
  679.   case 2:
  680.     {
  681.       short j; shortget(j,pos);
  682.       return (uint) (unsigned short) j;
  683.     }
  684. #ifdef MSDOS
  685.     break; /* skipp microsoft warning */
  686. #endif
  687.   case 3:
  688.     return uint3korr(pos);
  689.   case 4:
  690.     {
  691.       long j; longget(j,pos);
  692.       return (uint) j;
  693.     }
  694. #ifdef MSDOS
  695.     break;
  696. #endif
  697.   default:
  698.     break;
  699.   }
  700.   return 0; /* Impossible */
  701. }
  702. /* Read record from datafile */
  703. /* Returns 0 if ok, -1 if error */
  704. int _nisam_read_dynamic_record(N_INFO *info, ulong filepos, byte *buf)
  705. {
  706.   int flag;
  707.   uint b_type,left_length;
  708.   byte *to;
  709.   BLOCK_INFO block_info;
  710.   File file;
  711.   DBUG_ENTER("ni_read_dynamic_record");
  712.   if (filepos != NI_POS_ERROR)
  713.   {
  714.     LINT_INIT(to);
  715.     LINT_INIT(left_length);
  716.     file=info->dfile;
  717.     block_info.next_filepos=filepos; /* for easyer loop */
  718.     flag=block_info.second_read=0;
  719.     do
  720.     {
  721.       if (info->opt_flag & WRITE_CACHE_USED &&
  722.   info->rec_cache.pos_in_file <= block_info.next_filepos &&
  723.   flush_io_cache(&info->rec_cache))
  724. goto err;
  725.       info->rec_cache.seek_not_done=1;
  726.       if ((b_type=_nisam_get_block_info(&block_info,file,
  727.      block_info.next_filepos))
  728.   & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  729.      BLOCK_FATAL_ERROR))
  730.       {
  731. if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
  732.   my_errno=HA_ERR_RECORD_DELETED;
  733. goto err;
  734.       }
  735.       if (flag == 0) /* First block */
  736.       {
  737. flag=1;
  738. if (block_info.rec_len > (uint) info->s->base.max_pack_length)
  739.   goto panic;
  740. if (info->s->base.blobs)
  741. {
  742.   if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
  743.     goto err;
  744. }
  745. else
  746.   to= info->rec_buff;
  747. left_length=block_info.rec_len;
  748.       }
  749.       if (left_length < block_info.data_len || ! block_info.data_len)
  750. goto panic; /* Wrong linked record */
  751.       if (my_pread(file,(byte*) to,block_info.data_len,block_info.filepos,
  752.    MYF(MY_NABP)))
  753. goto panic;
  754.       left_length-=block_info.data_len;
  755.       to+=block_info.data_len;
  756.     } while (left_length);
  757.     info->update|= HA_STATE_AKTIV; /* We have a aktive record */
  758.     VOID(_nisam_writeinfo(info,0));
  759.     DBUG_RETURN(_nisam_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
  760. MY_FILE_ERROR ? 0 : -1);
  761.   }
  762.   VOID(_nisam_writeinfo(info,0));
  763.   DBUG_RETURN(-1); /* Wrong data to read */
  764. panic:
  765.   my_errno=HA_ERR_WRONG_IN_RECORD;
  766. err:
  767.   VOID(_nisam_writeinfo(info,0));
  768.   DBUG_RETURN(-1);
  769. }
  770. byte *fix_rec_buff_for_blob(N_INFO *info, uint length)
  771. {
  772.   uint extra;
  773.   if (! info->rec_buff || length > info->alloced_rec_buff_length)
  774.   {
  775.     byte *newptr;
  776.     extra=ALIGN_SIZE(MAX_DYN_BLOCK_HEADER)+N_SPLITT_LENGTH+
  777.       DYN_DELETE_BLOCK_HEADER;
  778.     if (!(newptr=(byte*) my_realloc((gptr) info->rec_alloc,length+extra,
  779.     MYF(MY_ALLOW_ZERO_PTR))))
  780.       return newptr;
  781.     info->rec_alloc=newptr;
  782.     info->rec_buff=newptr+ALIGN_SIZE(DYN_DELETE_BLOCK_HEADER);
  783.     info->alloced_rec_buff_length=length;
  784.   }
  785.   return info->rec_buff;
  786. }
  787. /* Compare of record one disk with packed record in memory */
  788. int _nisam_cmp_dynamic_record(register N_INFO *info, register const byte *record)
  789. {
  790.   uint flag,reclength,b_type;
  791.   ulong filepos;
  792.   byte *buffer;
  793.   BLOCK_INFO block_info;
  794.   DBUG_ENTER("_nisam_cmp_dynamic_record");
  795. /* We are going to do changes; dont let anybody disturb */
  796.   dont_break(); /* Dont allow SIGHUP or SIGINT */
  797.   if (info->opt_flag & WRITE_CACHE_USED)
  798.   {
  799.     info->update&= ~HA_STATE_WRITE_AT_END;
  800.     if (flush_io_cache(&info->rec_cache))
  801.       DBUG_RETURN(-1);
  802.   }
  803.   info->rec_cache.seek_not_done=1;
  804. /* If nobody have touched the database we don't have to test rec */
  805.   buffer=info->rec_buff;
  806.   if ((info->opt_flag & READ_CHECK_USED))
  807.   { /* If check isn't disabled  */
  808.     if (info->s->base.blobs)
  809.     {
  810.       if (!(buffer=(byte*) my_alloca(info->s->base.pack_reclength+
  811.      _calc_total_blob_length(info,record))))
  812. DBUG_RETURN(-1);
  813.     }
  814.     reclength=_nisam_rec_pack(info,buffer,record);
  815.     record= buffer;
  816.     filepos=info->lastpos;
  817.     flag=block_info.second_read=0;
  818.     block_info.next_filepos=filepos;
  819.     while (reclength > 0)
  820.     {
  821.       if ((b_type=_nisam_get_block_info(&block_info,info->dfile,
  822.     block_info.next_filepos))
  823.   & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  824.      BLOCK_FATAL_ERROR))
  825.       {
  826. if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
  827.   my_errno=HA_ERR_RECORD_CHANGED;
  828. goto err;
  829.       }
  830.       if (flag == 0) /* First block */
  831.       {
  832. flag=1;
  833. if (reclength != block_info.rec_len)
  834. {
  835.   my_errno=HA_ERR_RECORD_CHANGED;
  836.   goto err;
  837. }
  838.       } else if (reclength < block_info.data_len)
  839.       {
  840. my_errno=HA_ERR_WRONG_IN_RECORD;
  841. goto err;
  842.       }
  843.       reclength-=block_info.data_len;
  844.       if (_nisam_cmp_buffer(info->dfile,record,block_info.filepos,
  845.  block_info.data_len))
  846.       {
  847. my_errno=HA_ERR_RECORD_CHANGED;
  848. goto err;
  849.       }
  850.       flag=1;
  851.       record+=block_info.data_len;
  852.     }
  853.   }
  854.   my_errno=0;
  855.  err:
  856.   if (buffer != info->rec_buff)
  857.     my_afree((gptr) buffer);
  858.   DBUG_RETURN(my_errno);
  859. }
  860. /* Compare file to buffert */
  861. static int _nisam_cmp_buffer(File file, const byte *buff, ulong filepos, uint length)
  862. {
  863.   uint next_length;
  864.   char temp_buff[IO_SIZE*2];
  865.   DBUG_ENTER("_nisam_cmp_buffer");
  866.   VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
  867.   next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
  868.   while (length > IO_SIZE*2)
  869.   {
  870.     if (my_read(file,temp_buff,next_length,MYF(MY_NABP)))
  871.       goto err;
  872.     if (memcmp((byte*) buff,temp_buff,IO_SIZE))
  873.       DBUG_RETURN(1);
  874.     buff+=next_length;
  875.     length-= next_length;
  876.     next_length=IO_SIZE*2;
  877.   }
  878.   if (my_read(file,temp_buff,length,MYF(MY_NABP)))
  879.     goto err;
  880.   DBUG_RETURN(memcmp((byte*) buff,temp_buff,length));
  881. err:
  882.   DBUG_RETURN(1);
  883. }
  884. int _nisam_read_rnd_dynamic_record(N_INFO *info, byte *buf, register ulong filepos, int skipp_deleted_blocks)
  885. {
  886.   int flag,info_read,fatal_errcode;
  887.   uint left_len,b_type;
  888.   byte *to;
  889.   BLOCK_INFO block_info;
  890.   ISAM_SHARE *share=info->s;
  891.   DBUG_ENTER("_nisam_read_rnd_dynamic_record");
  892.   info_read=0;
  893.   fatal_errcode= -1;
  894.   LINT_INIT(to);
  895. #ifndef NO_LOCKING
  896.   if (info->lock_type == F_UNLCK)
  897.   {
  898. #ifndef UNSAFE_LOCKING
  899.     if (share->r_locks == 0 && share->w_locks == 0)
  900.     {
  901.       if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
  902.   MYF(MY_SEEK_NOT_DONE) | info->lock_wait))
  903. DBUG_RETURN(fatal_errcode);
  904.     }
  905. #else
  906.     info->tmp_lock_type=F_RDLCK;
  907. #endif
  908.   }
  909.   else
  910.     info_read=1; /* memory-keyinfoblock is ok */
  911. #endif /* !NO_LOCKING */
  912.   flag=block_info.second_read=0;
  913.   left_len=1;
  914.   do
  915.   {
  916.     if (filepos >= share->state.data_file_length)
  917.     {
  918. #ifndef NO_LOCKING
  919.       if (!info_read)
  920.       { /* Check if changed */
  921. info_read=1;
  922. info->rec_cache.seek_not_done=1;
  923. if (my_pread(share->kfile,(char*) &share->state.header,
  924.      share->state_length, 0L,MYF(MY_NABP)))
  925.   goto err;
  926.       }
  927.       if (filepos >= share->state.data_file_length)
  928. #endif
  929.       {
  930. my_errno= HA_ERR_END_OF_FILE;
  931. goto err;
  932.       }
  933.     }
  934.     if (info->opt_flag & READ_CACHE_USED)
  935.     {
  936.       if (_nisam_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
  937. sizeof(block_info.header),
  938. test(!flag && skipp_deleted_blocks) | 2))
  939. goto err;
  940.       b_type=_nisam_get_block_info(&block_info,-1,filepos);
  941.     }
  942.     else
  943.     {
  944.       if (info->opt_flag & WRITE_CACHE_USED &&
  945.   info->rec_cache.pos_in_file <= filepos &&
  946.   flush_io_cache(&info->rec_cache))
  947. DBUG_RETURN(-1);
  948.       info->rec_cache.seek_not_done=1;
  949.       b_type=_nisam_get_block_info(&block_info,info->dfile,filepos);
  950.     }
  951.     if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
  952.   BLOCK_FATAL_ERROR))
  953.     {
  954.       if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
  955.   && skipp_deleted_blocks)
  956.       {
  957. filepos=block_info.filepos+block_info.block_len;
  958. block_info.second_read=0;
  959. continue; /* Search after next_record */
  960.       }
  961.       if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
  962.       {
  963. my_errno=HA_ERR_RECORD_DELETED;
  964. info->lastpos=block_info.filepos;
  965. info->nextpos=block_info.filepos+block_info.block_len;
  966. fatal_errcode=1;
  967.       }
  968.       goto err;
  969.     }
  970.     if (flag == 0) /* First block */
  971.     {
  972.       if (block_info.rec_len > (uint) share->base.max_pack_length)
  973. goto panic;
  974.       info->lastpos=filepos;
  975.       if (share->base.blobs)
  976.       {
  977. if (!(to=fix_rec_buff_for_blob(info,block_info.rec_len)))
  978.   goto err;
  979.       }
  980.       else
  981. to= info->rec_buff;
  982.       left_len=block_info.rec_len;
  983.     }
  984.     if (left_len < block_info.data_len)
  985.       goto panic; /* Wrong linked record */
  986.     if (info->opt_flag & READ_CACHE_USED)
  987.     {
  988.       if (_nisam_read_cache(&info->rec_cache,(byte*) to,block_info.filepos,
  989. block_info.data_len,
  990. test(!flag && skipp_deleted_blocks)))
  991. goto err;
  992.     }
  993.     else
  994.     {
  995.       VOID(my_seek(info->dfile,block_info.filepos,MY_SEEK_SET,MYF(0)));
  996.       if (my_read(info->dfile,(byte*) to,block_info.data_len,MYF(MY_NABP)))
  997. goto err;
  998.     }
  999.     if (flag++ == 0)
  1000.     {
  1001.       info->nextpos=block_info.filepos+block_info.block_len;
  1002.       skipp_deleted_blocks=0;
  1003.     }
  1004.     left_len-=block_info.data_len;
  1005.     to+=block_info.data_len;
  1006.     filepos=block_info.next_filepos;
  1007.   } while (left_len);
  1008.   info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
  1009.   VOID(_nisam_writeinfo(info,0));
  1010.   if (_nisam_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
  1011.       MY_FILE_ERROR)
  1012.     DBUG_RETURN(0);
  1013.   DBUG_RETURN(fatal_errcode); /* Wrong record */
  1014. panic:
  1015.   my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */
  1016. err:
  1017.   VOID(_nisam_writeinfo(info,0));
  1018.   DBUG_RETURN(fatal_errcode);
  1019. }
  1020. /* Read and process header from a dynamic-record-file */
  1021. uint _nisam_get_block_info(BLOCK_INFO *info, File file, ulong filepos)
  1022. {
  1023.   uint return_val=0,length;
  1024.   uchar *header=info->header;
  1025.   if (file >= 0)
  1026.   {
  1027.     VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
  1028.     if ((length=my_read(file,(char*) header,BLOCK_INFO_HEADER_LENGTH,MYF(0)))
  1029. == MY_FILE_ERROR)
  1030.       return BLOCK_FATAL_ERROR;
  1031.     if (length != BLOCK_INFO_HEADER_LENGTH)
  1032.     { /* Test if short block */
  1033.       if (length < 3)
  1034.       {
  1035. my_errno=HA_ERR_WRONG_IN_RECORD;  /* Garbage */
  1036. return BLOCK_FATAL_ERROR;
  1037.       }
  1038.       bzero((byte*) header+length,BLOCK_INFO_HEADER_LENGTH-length);
  1039.     }
  1040.   }
  1041.   DBUG_DUMP("header",(byte*) header,BLOCK_INFO_HEADER_LENGTH);
  1042.   if (info->second_read)
  1043.   {
  1044.     if (info->header[0] <= 8)
  1045.       return_val=BLOCK_SYNC_ERROR;
  1046.   }
  1047.   else
  1048.   {
  1049.     if (info->header[0] > 8)
  1050.       return_val=BLOCK_SYNC_ERROR;
  1051.   }
  1052.   info->next_filepos= (ulong) NI_POS_ERROR; /* Dummy ifall no next block */
  1053.   switch (info->header[0]) {
  1054.   case 0:
  1055.     if ((info->block_len=(uint) uint3korr(header+1)) < N_MIN_BLOCK_LENGTH)
  1056.       return BLOCK_FATAL_ERROR;
  1057.     info->filepos=filepos;
  1058.     info->next_filepos=uint4korr(header+4);
  1059.     if (info->next_filepos == (uint32) ~0) /* Fix for 64 bit long */
  1060.       info->next_filepos=NI_POS_ERROR;
  1061.     return return_val | BLOCK_DELETED; /* Deleted block */
  1062.   case 1:
  1063.     info->rec_len=info->data_len=info->block_len=uint2korr(header+1);
  1064.     info->filepos=filepos+3;
  1065.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1066.   case 2:
  1067.     info->block_len=(info->rec_len=info->data_len=uint2korr(header+1))+1;
  1068.     info->filepos=filepos+3;
  1069.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1070.   case 3:
  1071.     info->rec_len=info->data_len=uint2korr(header+1);
  1072.     info->block_len=uint2korr(header+3);
  1073.     info->filepos=filepos+5;
  1074.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1075.   case 4:
  1076.     info->rec_len=uint2korr(header+1);
  1077.     info->block_len=info->data_len=uint2korr(header+3);
  1078.     info->next_filepos=uint4korr(header+5);
  1079.     info->second_read=1;
  1080.     info->filepos=filepos+9;
  1081.     return return_val | BLOCK_FIRST;
  1082. #if defined(_MSC_VER) || !defined(__WIN__)
  1083.   case 5:
  1084.     info->rec_len=info->data_len=info->block_len=uint3korr(header+1);
  1085.     info->filepos=filepos+4;
  1086.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1087.   case 6:
  1088.     info->block_len=(info->rec_len=info->data_len=uint3korr(header+1))+1;
  1089.     info->filepos=filepos+4;
  1090.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1091.   case 7:
  1092.     info->rec_len=info->data_len=uint3korr(header+1);
  1093.     info->block_len=uint3korr(header+4);
  1094.     info->filepos=filepos+7;
  1095.     return return_val | BLOCK_FIRST | BLOCK_LAST;
  1096.   case 8:
  1097.     info->rec_len=uint3korr(header+1);
  1098.     info->block_len=info->data_len=uint3korr(header+4);
  1099.     info->next_filepos=uint4korr(header+7);
  1100.     info->second_read=1;
  1101.     info->filepos=filepos+11;
  1102.     return return_val | BLOCK_FIRST;
  1103. #endif
  1104.   case 9:
  1105.     info->data_len=info->block_len=uint2korr(header+1);
  1106.     info->filepos=filepos+3;
  1107.     return return_val | BLOCK_LAST;
  1108.   case 10:
  1109.     info->block_len=(info->data_len=uint2korr(header+1))+1;
  1110.     info->filepos=filepos+3;
  1111.     return return_val | BLOCK_LAST;
  1112.   case 11:
  1113.     info->data_len=uint2korr(header+1);
  1114.     info->block_len=uint2korr(header+3);
  1115.     info->filepos=filepos+5;
  1116.     return return_val | BLOCK_LAST;
  1117.   case 12:
  1118.     info->data_len=info->block_len=uint2korr(header+1);
  1119.     info->next_filepos=uint4korr(header+3);
  1120.     info->second_read=1;
  1121.     info->filepos=filepos+7;
  1122.     return return_val;
  1123. #if defined(_MSC_VER) || !defined(__WIN__)
  1124.   case 13:
  1125.     info->data_len=info->block_len=uint3korr(header+1);
  1126.     info->filepos=filepos+4;
  1127.     return return_val | BLOCK_LAST;
  1128.   case 14:
  1129.     info->block_len=(info->data_len=uint3korr(header+1))+1;
  1130.     info->filepos=filepos+4;
  1131.     return return_val | BLOCK_LAST;
  1132.   case 15:
  1133.     info->data_len=uint3korr(header+1);
  1134.     info->block_len=uint3korr(header+4);
  1135.     info->filepos=filepos+7;
  1136.     return return_val | BLOCK_LAST;
  1137.   case 16:
  1138.     info->data_len=info->block_len=uint3korr(header+1);
  1139.     info->next_filepos=uint4korr(header+4);
  1140.     info->second_read=1;
  1141.     info->filepos=filepos+8;
  1142.     return return_val;
  1143. #endif
  1144.   default:
  1145.     my_errno=HA_ERR_WRONG_IN_RECORD;  /* Garbage */
  1146.     return BLOCK_ERROR;
  1147.   }
  1148. }