LTP GCOV extension - code coverage report
Current view: directory - storage/maria - ma_dynrec.c
Test: mtr_and_unit.info
Date: 2009-03-05 Instrumented lines: 865
Code covered: 76.9 % Executed lines: 665

       1                 : /* Copyright (C) 2006 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; version 2 of the License.
       6                 : 
       7                 :    This program is distributed in the hope that it will be useful,
       8                 :    but WITHOUT ANY WARRANTY; without even the implied warranty of
       9                 :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      10                 :    GNU General Public License for more details.
      11                 : 
      12                 :    You should have received a copy of the GNU General Public License
      13                 :    along with this program; if not, write to the Free Software
      14                 :    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
      15                 : 
      16                 : /*
      17                 :   Functions to handle space-packed-records and blobs
      18                 : 
      19                 :   A row may be stored in one or more linked blocks.
      20                 :   The block size is between MARIA_MIN_BLOCK_LENGTH and MARIA_MAX_BLOCK_LENGTH.
      21                 :   Each block is aligned on MARIA_DYN_ALIGN_SIZE.
      22                 :   The reson for the max block size is to not have too many different types
      23                 :   of blocks.  For the differnet block types, look at _ma_get_block_info()
      24                 : */
      25                 : 
      26                 : #include "maria_def.h"
      27                 : 
      28                 : static my_bool write_dynamic_record(MARIA_HA *info,const uchar *record,
      29                 :                                     ulong reclength);
      30                 : static int _ma_find_writepos(MARIA_HA *info,ulong reclength,my_off_t *filepos,
      31                 :                              ulong *length);
      32                 : static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
      33                 :                                      uchar *record, ulong reclength);
      34                 : static my_bool delete_dynamic_record(MARIA_HA *info,MARIA_RECORD_POS filepos,
      35                 :                                      uint second_read);
      36                 : static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
      37                 :                               uint length);
      38                 : 
      39                 : #ifdef THREAD
      40                 : /* Play it safe; We have a small stack when using threads */
      41                 : #undef my_alloca
      42                 : #undef my_afree
      43                 : #define my_alloca(A) my_malloc((A),MYF(0))
      44                 : #define my_afree(A) my_free((A),MYF(0))
      45                 : #endif
      46                 : 
      47                 :         /* Interface function from MARIA_HA */
      48                 : 
      49                 : #ifdef HAVE_MMAP
      50                 : 
      51                 : /*
      52                 :   Create mmaped area for MARIA handler
      53                 : 
      54                 :   SYNOPSIS
      55                 :     _ma_dynmap_file()
      56                 :     info                MARIA handler
      57                 : 
      58                 :   RETURN
      59                 :     0  ok
      60                 :     1  error.
      61                 : */
      62                 : 
      63                 : my_bool _ma_dynmap_file(MARIA_HA *info, my_off_t size)
      64               0 : {
      65               0 :   DBUG_ENTER("_ma_dynmap_file");
      66               0 :   if (size > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
      67                 :   {
      68               0 :     DBUG_PRINT("warning", ("File is too large for mmap"));
      69               0 :     DBUG_RETURN(1);
      70                 :   }
      71                 :   /*
      72                 :     Ingo wonders if it is good to use MAP_NORESERVE. From the Linux man page:
      73                 :     MAP_NORESERVE
      74                 :       Do not reserve swap space for this mapping. When swap space is
      75                 :       reserved, one has the guarantee that it is possible to modify the
      76                 :       mapping. When swap space is not reserved one might get SIGSEGV
      77                 :       upon a write if no physical memory is available.
      78                 :   */
      79               0 :   info->s->file_map= (uchar*)
      80                 :                   my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN),
      81                 :                           info->s->mode==O_RDONLY ? PROT_READ :
      82                 :                           PROT_READ | PROT_WRITE,
      83                 :                           MAP_SHARED | MAP_NORESERVE,
      84                 :                           info->dfile.file, 0L);
      85               0 :   if (info->s->file_map == (uchar*) MAP_FAILED)
      86                 :   {
      87               0 :     info->s->file_map= NULL;
      88               0 :     DBUG_RETURN(1);
      89                 :   }
      90                 : #if defined(HAVE_MADVISE)
      91               0 :   madvise((char*) info->s->file_map, size, MADV_RANDOM);
      92                 : #endif
      93               0 :   info->s->mmaped_length= size;
      94               0 :   DBUG_RETURN(0);
      95                 : }
      96                 : 
      97                 : 
      98                 : /*
      99                 :   Resize mmaped area for MARIA handler
     100                 : 
     101                 :   SYNOPSIS
     102                 :     _ma_remap_file()
     103                 :     info                MARIA handler
     104                 : 
     105                 :   RETURN
     106                 : */
     107                 : 
     108                 : void _ma_remap_file(MARIA_HA *info, my_off_t size)
     109               0 : {
     110               0 :   if (info->s->file_map)
     111                 :   {
     112               0 :     VOID(my_munmap((char*) info->s->file_map,
     113                 :                    (size_t) info->s->mmaped_length + MEMMAP_EXTRA_MARGIN));
     114               0 :     _ma_dynmap_file(info, size);
     115                 :   }
     116                 : }
     117                 : #endif
     118                 : 
     119                 : 
     120                 : /*
     121                 :   Read bytes from MySAM handler, using mmap or pread
     122                 : 
     123                 :   SYNOPSIS
     124                 :     _ma_mmap_pread()
     125                 :     info                MARIA handler
     126                 :     Buffer              Input buffer
     127                 :     Count               Count of bytes for read
     128                 :     offset              Start position
     129                 :     MyFlags
     130                 : 
     131                 :   RETURN
     132                 :     0  ok
     133                 : */
     134                 : 
     135                 : size_t _ma_mmap_pread(MARIA_HA *info, uchar *Buffer,
     136                 :                       size_t Count, my_off_t offset, myf MyFlags)
     137               0 : {
     138               0 :   DBUG_PRINT("info", ("maria_read with mmap %d\n", info->dfile.file));
     139               0 :   if (info->s->lock_key_trees)
     140               0 :     rw_rdlock(&info->s->mmap_lock);
     141                 : 
     142                 :   /*
     143                 :     The following test may fail in the following cases:
     144                 :     - We failed to remap a memory area (fragmented memory?)
     145                 :     - This thread has done some writes, but not yet extended the
     146                 :     memory mapped area.
     147                 :   */
     148                 : 
     149               0 :   if (info->s->mmaped_length >= offset + Count)
     150                 :   {
     151               0 :     memcpy(Buffer, info->s->file_map + offset, Count);
     152               0 :     if (info->s->lock_key_trees)
     153               0 :       rw_unlock(&info->s->mmap_lock);
     154               0 :     return 0;
     155                 :   }
     156                 :   else
     157                 :   {
     158               0 :     if (info->s->lock_key_trees)
     159               0 :       rw_unlock(&info->s->mmap_lock);
     160               0 :     return my_pread(info->dfile.file, Buffer, Count, offset, MyFlags);
     161                 :   }
     162                 : }
     163                 : 
     164                 : 
     165                 :         /* wrapper for my_pread in case if mmap isn't used */
     166                 : 
     167                 : size_t _ma_nommap_pread(MARIA_HA *info, uchar *Buffer,
     168                 :                         size_t Count, my_off_t offset, myf MyFlags)
     169          185146 : {
     170          185146 :   return my_pread(info->dfile.file, Buffer, Count, offset, MyFlags);
     171                 : }
     172                 : 
     173                 : 
     174                 : /*
     175                 :   Write bytes to MySAM handler, using mmap or pwrite
     176                 : 
     177                 :   SYNOPSIS
     178                 :     _ma_mmap_pwrite()
     179                 :     info                MARIA handler
     180                 :     Buffer              Output buffer
     181                 :     Count               Count of bytes for write
     182                 :     offset              Start position
     183                 :     MyFlags
     184                 : 
     185                 :   RETURN
     186                 :     0  ok
     187                 :     !=0  error.  In this case return error from pwrite
     188                 : */
     189                 : 
     190                 : size_t _ma_mmap_pwrite(MARIA_HA *info, const uchar *Buffer,
     191                 :                        size_t Count, my_off_t offset, myf MyFlags)
     192               0 : {
     193               0 :   DBUG_PRINT("info", ("maria_write with mmap %d\n", info->dfile.file));
     194               0 :   if (info->s->lock_key_trees)
     195               0 :     rw_rdlock(&info->s->mmap_lock);
     196                 : 
     197                 :   /*
     198                 :     The following test may fail in the following cases:
     199                 :     - We failed to remap a memory area (fragmented memory?)
     200                 :     - This thread has done some writes, but not yet extended the
     201                 :     memory mapped area.
     202                 :   */
     203                 : 
     204               0 :   if (info->s->mmaped_length >= offset + Count)
     205                 :   {
     206               0 :     memcpy(info->s->file_map + offset, Buffer, Count);
     207               0 :     if (info->s->lock_key_trees)
     208               0 :       rw_unlock(&info->s->mmap_lock);
     209               0 :     return 0;
     210                 :   }
     211                 :   else
     212                 :   {
     213               0 :     info->s->nonmmaped_inserts++;
     214               0 :     if (info->s->lock_key_trees)
     215               0 :       rw_unlock(&info->s->mmap_lock);
     216               0 :     return my_pwrite(info->dfile.file, Buffer, Count, offset, MyFlags);
     217                 :   }
     218                 : 
     219                 : }
     220                 : 
     221                 : 
     222                 :         /* wrapper for my_pwrite in case if mmap isn't used */
     223                 : 
     224                 : size_t _ma_nommap_pwrite(MARIA_HA *info, const uchar *Buffer,
     225                 :                          size_t Count, my_off_t offset, myf MyFlags)
     226          116680 : {
     227          116680 :   return my_pwrite(info->dfile.file, Buffer, Count, offset, MyFlags);
     228                 : }
     229                 : 
     230                 : 
     231                 : my_bool _ma_write_dynamic_record(MARIA_HA *info, const uchar *record)
     232           21142 : {
     233                 :   ulong reclength= _ma_rec_pack(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
     234           21142 :                                 record);
     235           21142 :   return (write_dynamic_record(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
     236                 :                                reclength));
     237                 : }
     238                 : 
     239                 : my_bool _ma_update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS pos,
     240                 :                                   const uchar *oldrec __attribute__ ((unused)),
     241                 :                                   const uchar *record)
     242            2348 : {
     243                 :   uint length= _ma_rec_pack(info, info->rec_buff + MARIA_REC_BUFF_OFFSET,
     244            2348 :                             record);
     245            2348 :   return (update_dynamic_record(info, pos,
     246                 :                                 info->rec_buff + MARIA_REC_BUFF_OFFSET,
     247                 :                                 length));
     248                 : }
     249                 : 
     250                 : 
     251                 : my_bool _ma_write_blob_record(MARIA_HA *info, const uchar *record)
     252            3811 : {
     253                 :   uchar *rec_buff;
     254                 :   int error;
     255                 :   ulong reclength,reclength2,extra;
     256                 : 
     257            3811 :   extra= (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
     258                 :           MARIA_DYN_DELETE_BLOCK_HEADER+1);
     259            3811 :   reclength= (info->s->base.pack_reclength +
     260                 :               _ma_calc_total_blob_length(info,record)+ extra);
     261            3811 :   if (!(rec_buff=(uchar*) my_alloca(reclength)))
     262                 :   {
     263               0 :     my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
     264               0 :     return(1);
     265                 :   }
     266            3811 :   reclength2= _ma_rec_pack(info,
     267                 :                            rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
     268                 :                            record);
     269            3811 :   DBUG_PRINT("info",("reclength: %lu  reclength2: %lu",
     270                 :                      reclength, reclength2));
     271            3811 :   DBUG_ASSERT(reclength2 <= reclength);
     272            3811 :   error= write_dynamic_record(info,
     273                 :                               rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
     274                 :                               reclength2);
     275            3811 :   my_afree(rec_buff);
     276            3811 :   return(error != 0);
     277                 : }
     278                 : 
     279                 : 
     280                 : my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
     281                 :                                const uchar *oldrec __attribute__ ((unused)),
     282                 :                                const uchar *record)
     283             427 : {
     284                 :   uchar *rec_buff;
     285                 :   int error;
     286                 :   ulong reclength,extra;
     287                 : 
     288             427 :   extra= (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
     289                 :           MARIA_DYN_DELETE_BLOCK_HEADER);
     290             427 :   reclength= (info->s->base.pack_reclength+
     291                 :               _ma_calc_total_blob_length(info,record)+ extra);
     292                 : #ifdef NOT_USED                                 /* We now support big rows */
     293                 :   if (reclength > MARIA_DYN_MAX_ROW_LENGTH)
     294                 :   {
     295                 :     my_errno=HA_ERR_TO_BIG_ROW;
     296                 :     return 1;
     297                 :   }
     298                 : #endif
     299             427 :   if (!(rec_buff=(uchar*) my_alloca(reclength)))
     300                 :   {
     301               0 :     my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
     302               0 :     return(1);
     303                 :   }
     304             427 :   reclength= _ma_rec_pack(info,rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
     305                 :                          record);
     306             427 :   error=update_dynamic_record(info,pos,
     307                 :                               rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
     308                 :                               reclength);
     309             427 :   my_afree(rec_buff);
     310             427 :   return(error != 0);
     311                 : }
     312                 : 
     313                 : 
     314                 : my_bool _ma_delete_dynamic_record(MARIA_HA *info,
     315                 :                                   const uchar *record __attribute__ ((unused)))
     316           20765 : {
     317           20765 :   return delete_dynamic_record(info, info->cur_row.lastpos, 0);
     318                 : }
     319                 : 
     320                 : 
     321                 : /**
     322                 :   Write record to data-file.
     323                 : 
     324                 :   @todo it's cheating: it casts "const uchar*" to uchar*.
     325                 : */
     326                 : 
     327                 : static my_bool write_dynamic_record(MARIA_HA *info, const uchar *record,
     328                 :                                     ulong reclength)
     329           24953 : {
     330                 :   int flag;
     331                 :   ulong length;
     332                 :   my_off_t filepos;
     333           24953 :   DBUG_ENTER("write_dynamic_record");
     334                 : 
     335           24953 :   flag=0;
     336                 : 
     337                 :   /*
     338                 :     Check if we have enough room for the new record.
     339                 :     First we do simplified check to make usual case faster.
     340                 :     Then we do more precise check for the space left.
     341                 :     Though it still is not absolutely precise, as
     342                 :     we always use MARIA_MAX_DYN_BLOCK_HEADER while it can be
     343                 :     less in the most of the cases.
     344                 :   */
     345                 : 
     346           24953 :   if (unlikely(info->s->base.max_data_file_length -
     347                 :                info->state->data_file_length <
     348                 :                reclength + MARIA_MAX_DYN_BLOCK_HEADER))
     349                 :   {
     350               1 :     if (info->s->base.max_data_file_length - info->state->data_file_length +
     351                 :         info->state->empty - info->state->del * MARIA_MAX_DYN_BLOCK_HEADER <
     352                 :         reclength + MARIA_MAX_DYN_BLOCK_HEADER)
     353                 :     {
     354               1 :       my_errno=HA_ERR_RECORD_FILE_FULL;
     355               1 :       DBUG_RETURN(1);
     356                 :     }
     357                 :   }
     358                 : 
     359                 :   do
     360                 :   {
     361           24952 :     if (_ma_find_writepos(info,reclength,&filepos,&length))
     362           24952 :       goto err;
     363           24952 :     if (_ma_write_part_record(info,filepos,length,
     364                 :                               (info->append_insert_at_end ?
     365                 :                                HA_OFFSET_ERROR : info->s->state.dellink),
     366                 :                               (uchar**) &record,&reclength,&flag))
     367           24952 :       goto err;
     368           24952 :   } while (reclength);
     369                 : 
     370           24952 :   DBUG_RETURN(0);
     371               0 : err:
     372               0 :   DBUG_RETURN(1);
     373                 : }
     374                 : 
     375                 : 
     376                 :         /* Get a block for data ; The given data-area must be used !! */
     377                 : 
     378                 : static int _ma_find_writepos(MARIA_HA *info,
     379                 :                              ulong reclength, /* record length */
     380                 :                              my_off_t *filepos, /* Return file pos */
     381                 :                              ulong *length)   /* length of block at filepos */
     382           26878 : {
     383                 :   MARIA_BLOCK_INFO block_info;
     384                 :   ulong tmp;
     385           26878 :   DBUG_ENTER("_ma_find_writepos");
     386                 : 
     387           27890 :   if (info->s->state.dellink != HA_OFFSET_ERROR &&
     388                 :       !info->append_insert_at_end)
     389                 :   {
     390                 :     /* Deleted blocks exists;  Get last used block */
     391            1012 :     *filepos=info->s->state.dellink;
     392            1012 :     block_info.second_read=0;
     393            1012 :     info->rec_cache.seek_not_done=1;
     394            1012 :     if (!(_ma_get_block_info(&block_info, info->dfile.file,
     395                 :                              info->s->state.dellink) &
     396                 :            BLOCK_DELETED))
     397                 :     {
     398               0 :       DBUG_PRINT("error",("Delete link crashed"));
     399               0 :       my_errno=HA_ERR_WRONG_IN_RECORD;
     400               0 :       DBUG_RETURN(-1);
     401                 :     }
     402            1012 :     info->s->state.dellink=block_info.next_filepos;
     403            1012 :     info->state->del--;
     404            1012 :     info->state->empty-= block_info.block_len;
     405            1012 :     *length= block_info.block_len;
     406                 :   }
     407                 :   else
     408                 :   {
     409                 :     /* No deleted blocks;  Allocate a new block */
     410           25866 :     *filepos=info->state->data_file_length;
     411           25866 :     if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
     412                 :         info->s->base.min_block_length)
     413              87 :       tmp= info->s->base.min_block_length;
     414                 :     else
     415           25779 :       tmp= ((tmp+MARIA_DYN_ALIGN_SIZE-1) &
     416                 :             (~ (ulong) (MARIA_DYN_ALIGN_SIZE-1)));
     417           25866 :     if (info->state->data_file_length >
     418                 :         (info->s->base.max_data_file_length - tmp))
     419                 :     {
     420               0 :       my_errno=HA_ERR_RECORD_FILE_FULL;
     421               0 :       DBUG_RETURN(-1);
     422                 :     }
     423           25866 :     if (tmp > MARIA_MAX_BLOCK_LENGTH)
     424               0 :       tmp=MARIA_MAX_BLOCK_LENGTH;
     425           25866 :     *length= tmp;
     426           25866 :     info->state->data_file_length+= tmp;
     427           25866 :     info->s->state.split++;
     428           25866 :     info->update|=HA_STATE_WRITE_AT_END;
     429                 :   }
     430           26878 :   DBUG_RETURN(0);
     431                 : } /* _ma_find_writepos */
     432                 : 
     433                 : 
     434                 : 
     435                 : /*
     436                 :   Unlink a deleted block from the deleted list.
     437                 :   This block will be combined with the preceding or next block to form
     438                 :   a big block.
     439                 : */
     440                 : 
     441                 : static my_bool unlink_deleted_block(MARIA_HA *info,
     442                 :                                     MARIA_BLOCK_INFO *block_info)
     443            4295 : {
     444            4295 :   DBUG_ENTER("unlink_deleted_block");
     445            4295 :   if (block_info->filepos == info->s->state.dellink)
     446                 :   {
     447                 :     /* First deleted block;  We can just use this ! */
     448               1 :     info->s->state.dellink=block_info->next_filepos;
     449                 :   }
     450                 :   else
     451                 :   {
     452                 :     MARIA_BLOCK_INFO tmp;
     453            4294 :     tmp.second_read=0;
     454                 :     /* Unlink block from the previous block */
     455            4294 :     if (!(_ma_get_block_info(&tmp, info->dfile.file, block_info->prev_filepos)
     456                 :           & BLOCK_DELETED))
     457               0 :       DBUG_RETURN(1);                           /* Something is wrong */
     458            4294 :     mi_sizestore(tmp.header+4,block_info->next_filepos);
     459            4294 :     if (info->s->file_write(info, tmp.header+4,8,
     460                 :                   block_info->prev_filepos+4, MYF(MY_NABP)))
     461               0 :       DBUG_RETURN(1);
     462                 :     /* Unlink block from next block */
     463            4294 :     if (block_info->next_filepos != HA_OFFSET_ERROR)
     464                 :     {
     465            3654 :       if (!(_ma_get_block_info(&tmp, info->dfile.file,
     466                 :                                block_info->next_filepos)
     467                 :             & BLOCK_DELETED))
     468               0 :         DBUG_RETURN(1);                         /* Something is wrong */
     469            3654 :       mi_sizestore(tmp.header+12,block_info->prev_filepos);
     470            3654 :       if (info->s->file_write(info, tmp.header+12,8,
     471                 :                     block_info->next_filepos+12,
     472                 :                     MYF(MY_NABP)))
     473               0 :         DBUG_RETURN(1);
     474                 :     }
     475                 :   }
     476                 :   /* We now have one less deleted block */
     477            4295 :   info->state->del--;
     478            4295 :   info->state->empty-= block_info->block_len;
     479            4295 :   info->s->state.split--;
     480                 : 
     481                 :   /*
     482                 :     If this was a block that we where accessing through table scan
     483                 :     (maria_rrnd() or maria_scan(), then ensure that we skip over this block
     484                 :     when doing next maria_rrnd() or maria_scan().
     485                 :   */
     486            4295 :   if (info->cur_row.nextpos == block_info->filepos)
     487            2322 :     info->cur_row.nextpos+= block_info->block_len;
     488            4295 :   DBUG_RETURN(0);
     489                 : }
     490                 : 
     491                 : 
     492                 : /*
     493                 :   Add a backward link to delete block
     494                 : 
     495                 :   SYNOPSIS
     496                 :     update_backward_delete_link()
     497                 :     info                MARIA handler
     498                 :     delete_block        Position to delete block to update.
     499                 :                         If this is 'HA_OFFSET_ERROR', nothing will be done
     500                 :     filepos             Position to block that 'delete_block' should point to
     501                 : 
     502                 :   RETURN
     503                 :     0  ok
     504                 :     1  error.  In this case my_error is set.
     505                 : */
     506                 : 
     507                 : static my_bool update_backward_delete_link(MARIA_HA *info,
     508                 :                                            my_off_t delete_block,
     509                 :                                            MARIA_RECORD_POS filepos)
     510           21336 : {
     511                 :   MARIA_BLOCK_INFO block_info;
     512           21336 :   DBUG_ENTER("update_backward_delete_link");
     513                 : 
     514           21336 :   if (delete_block != HA_OFFSET_ERROR)
     515                 :   {
     516           21284 :     block_info.second_read=0;
     517           21284 :     if (_ma_get_block_info(&block_info, info->dfile.file, delete_block)
     518                 :         & BLOCK_DELETED)
     519                 :     {
     520                 :       uchar buff[8];
     521           21284 :       mi_sizestore(buff,filepos);
     522           21284 :       if (info->s->file_write(info,buff, 8, delete_block+12, MYF(MY_NABP)))
     523               0 :         DBUG_RETURN(1);                         /* Error on write */
     524                 :     }
     525                 :     else
     526                 :     {
     527               0 :       my_errno=HA_ERR_WRONG_IN_RECORD;
     528               0 :       DBUG_RETURN(1);                           /* Wrong delete link */
     529                 :     }
     530                 :   }
     531           21336 :   DBUG_RETURN(0);
     532                 : }
     533                 : 
     534                 : /* Delete datarecord from database */
     535                 : /* info->rec_cache.seek_not_done is updated in cmp_record */
     536                 : 
     537                 : static my_bool delete_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
     538                 :                                      uint second_read)
     539           20780 : {
     540                 :   uint length,b_type;
     541                 :   MARIA_BLOCK_INFO block_info,del_block;
     542                 :   int error;
     543                 :   my_bool remove_next_block;
     544           20780 :   DBUG_ENTER("delete_dynamic_record");
     545                 : 
     546                 :   /* First add a link from the last block to the new one */
     547           20780 :   error= update_backward_delete_link(info, info->s->state.dellink, filepos);
     548                 : 
     549           20780 :   block_info.second_read=second_read;
     550                 :   do
     551                 :   {
     552                 :     /* Remove block at 'filepos' */
     553           22004 :     if ((b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos))
     554                 :         & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
     555                 :            BLOCK_FATAL_ERROR) ||
     556                 :         (length=(uint) (block_info.filepos-filepos) +block_info.block_len) <
     557                 :         MARIA_MIN_BLOCK_LENGTH)
     558                 :     {
     559               0 :       my_errno=HA_ERR_WRONG_IN_RECORD;
     560               0 :       DBUG_RETURN(1);
     561                 :     }
     562                 :     /* Check if next block is a delete block */
     563           22004 :     del_block.second_read=0;
     564           22004 :     remove_next_block=0;
     565           22004 :     if (_ma_get_block_info(&del_block, info->dfile.file, filepos + length) &
     566                 :         BLOCK_DELETED && del_block.block_len+length <
     567                 :         MARIA_DYN_MAX_BLOCK_LENGTH)
     568                 :     {
     569                 :       /* We can't remove this yet as this block may be the head block */
     570            4026 :       remove_next_block=1;
     571            4026 :       length+=del_block.block_len;
     572                 :     }
     573                 : 
     574           22004 :     block_info.header[0]=0;
     575           22004 :     mi_int3store(block_info.header+1,length);
     576           22004 :     mi_sizestore(block_info.header+4,info->s->state.dellink);
     577           22004 :     if (b_type & BLOCK_LAST)
     578           20780 :       bfill(block_info.header+12,8,255);
     579                 :     else
     580            1224 :       mi_sizestore(block_info.header+12,block_info.next_filepos);
     581           22004 :     if (info->s->file_write(info, block_info.header, 20, filepos,
     582                 :                   MYF(MY_NABP)))
     583               0 :       DBUG_RETURN(1);
     584           22004 :     info->s->state.dellink = filepos;
     585           22004 :     info->state->del++;
     586           22004 :     info->state->empty+=length;
     587           22004 :     filepos=block_info.next_filepos;
     588                 : 
     589                 :     /* Now it's safe to unlink the deleted block directly after this one */
     590           22004 :     if (remove_next_block && unlink_deleted_block(info,&del_block))
     591               0 :       error=1;
     592           22004 :   } while (!(b_type & BLOCK_LAST));
     593                 : 
     594           20780 :   DBUG_RETURN(error);
     595                 : }
     596                 : 
     597                 : 
     598                 :         /* Write a block to datafile */
     599                 : 
     600                 : int _ma_write_part_record(MARIA_HA *info,
     601                 :                           my_off_t filepos,     /* points at empty block */
     602                 :                           ulong length,         /* length of block */
     603                 :                           my_off_t next_filepos,/* Next empty block */
     604                 :                           uchar **record,       /* pointer to record ptr */
     605                 :                           ulong *reclength,     /* length of *record */
     606                 :                           int *flag)            /* *flag == 0 if header */
     607           33399 : {
     608                 :   ulong head_length,res_length,extra_length,long_block,del_length;
     609                 :   uchar *pos,*record_end;
     610                 :   my_off_t  next_delete_block;
     611                 :   uchar temp[MARIA_SPLIT_LENGTH+MARIA_DYN_DELETE_BLOCK_HEADER];
     612           33399 :   DBUG_ENTER("_ma_write_part_record");
     613                 : 
     614           33399 :   next_delete_block=HA_OFFSET_ERROR;
     615                 : 
     616           33399 :   res_length=extra_length=0;
     617           33399 :   if (length > *reclength + MARIA_SPLIT_LENGTH)
     618                 :   {                                             /* Splitt big block */
     619             556 :     res_length=MY_ALIGN(length- *reclength - MARIA_EXTEND_BLOCK_LENGTH,
     620                 :                         MARIA_DYN_ALIGN_SIZE);
     621             556 :     length-= res_length;                        /* Use this for first part */
     622                 :   }
     623           33399 :   long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
     624           33399 :   if (length == *reclength+ 3 + long_block)
     625                 :   {
     626                 :     /* Block is exactly of the right length */
     627            7571 :     temp[0]=(uchar) (1+ *flag)+(uchar) long_block;      /* Flag is 0 or 6 */
     628            7571 :     if (long_block)
     629                 :     {
     630               1 :       mi_int3store(temp+1,*reclength);
     631               1 :       head_length=4;
     632                 :     }
     633                 :     else
     634                 :     {
     635            7570 :       mi_int2store(temp+1,*reclength);
     636            7570 :       head_length=3;
     637                 :     }
     638                 :   }
     639           25828 :   else if (length-long_block < *reclength+4)
     640                 :   {                                             /* To short block */
     641            1942 :     if (next_filepos == HA_OFFSET_ERROR)
     642            1926 :       next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR &&
     643                 :                      !info->append_insert_at_end ?
     644                 :                      info->s->state.dellink : info->state->data_file_length);
     645            1942 :     if (*flag == 0)                             /* First block */
     646                 :     {
     647            1524 :       if (*reclength > MARIA_MAX_BLOCK_LENGTH)
     648                 :       {
     649               0 :         head_length= 16;
     650               0 :         temp[0]=13;
     651               0 :         mi_int4store(temp+1,*reclength);
     652               0 :         mi_int3store(temp+5,length-head_length);
     653               0 :         mi_sizestore(temp+8,next_filepos);
     654                 :       }
     655                 :       else
     656                 :       {
     657            1524 :         head_length=5+8+long_block*2;
     658            1524 :         temp[0]=5+(uchar) long_block;
     659            1524 :         if (long_block)
     660                 :         {
     661               0 :           mi_int3store(temp+1,*reclength);
     662               0 :           mi_int3store(temp+4,length-head_length);
     663               0 :           mi_sizestore(temp+7,next_filepos);
     664                 :         }
     665                 :         else
     666                 :         {
     667            1524 :           mi_int2store(temp+1,*reclength);
     668            1524 :           mi_int2store(temp+3,length-head_length);
     669            1524 :           mi_sizestore(temp+5,next_filepos);
     670                 :         }
     671                 :       }
     672                 :     }
     673                 :     else
     674                 :     {
     675             418 :       head_length=3+8+long_block;
     676             418 :       temp[0]=11+(uchar) long_block;
     677             418 :       if (long_block)
     678                 :       {
     679               0 :         mi_int3store(temp+1,length-head_length);
     680               0 :         mi_sizestore(temp+4,next_filepos);
     681                 :       }
     682                 :       else
     683                 :       {
     684             418 :         mi_int2store(temp+1,length-head_length);
     685             418 :         mi_sizestore(temp+3,next_filepos);
     686                 :       }
     687                 :     }
     688                 :   }
     689                 :   else
     690                 :   {                                     /* Block with empty info last */
     691           23886 :     head_length=4+long_block;
     692           23886 :     extra_length= length- *reclength-head_length;
     693           23886 :     temp[0]= (uchar) (3+ *flag)+(uchar) long_block; /* 3,4 or 9,10 */
     694           23886 :     if (long_block)
     695                 :     {
     696               2 :       mi_int3store(temp+1,*reclength);
     697               2 :       temp[4]= (uchar) (extra_length);
     698                 :     }
     699                 :     else
     700                 :     {
     701           23884 :       mi_int2store(temp+1,*reclength);
     702           23884 :       temp[3]= (uchar) (extra_length);
     703                 :     }
     704           23886 :     length= *reclength+head_length;     /* Write only what is needed */
     705                 :   }
     706           33399 :   DBUG_DUMP("header", temp, head_length);
     707                 : 
     708                 :         /* Make a long block for one write */
     709           33399 :   record_end= *record+length-head_length;
     710           33399 :   del_length=(res_length ? MARIA_DYN_DELETE_BLOCK_HEADER : 0);
     711           33399 :   bmove((*record-head_length), temp, head_length);
     712           33399 :   memcpy(temp,record_end,(size_t) (extra_length+del_length));
     713           33399 :   bzero(record_end, extra_length);
     714                 : 
     715           33399 :   if (res_length)
     716                 :   {
     717                 :     /* Check first if we can join this block with the next one */
     718                 :     MARIA_BLOCK_INFO del_block;
     719             556 :     my_off_t next_block=filepos+length+extra_length+res_length;
     720                 : 
     721             556 :     del_block.second_read=0;
     722             556 :     if (next_block < info->state->data_file_length &&
     723                 :         info->s->state.dellink != HA_OFFSET_ERROR)
     724                 :     {
     725             556 :       if ((_ma_get_block_info(&del_block, info->dfile.file, next_block)
     726                 :            & BLOCK_DELETED) &&
     727                 :           res_length + del_block.block_len < MARIA_DYN_MAX_BLOCK_LENGTH)
     728                 :       {
     729              67 :         if (unlink_deleted_block(info,&del_block))
     730              67 :           goto err;
     731              67 :         res_length+=del_block.block_len;
     732                 :       }
     733                 :     }
     734                 : 
     735                 :     /* Create a delete link of the last part of the block */
     736             556 :     pos=record_end+extra_length;
     737             556 :     pos[0]= '\0';
     738             556 :     mi_int3store(pos+1,res_length);
     739             556 :     mi_sizestore(pos+4,info->s->state.dellink);
     740             556 :     bfill(pos+12,8,255);                        /* End link */
     741             556 :     next_delete_block=info->s->state.dellink;
     742             556 :     info->s->state.dellink= filepos+length+extra_length;
     743             556 :     info->state->del++;
     744             556 :     info->state->empty+=res_length;
     745             556 :     info->s->state.split++;
     746                 :   }
     747           33399 :   if (info->opt_flag & WRITE_CACHE_USED &&
     748                 :       info->update & HA_STATE_WRITE_AT_END)
     749                 :   {
     750            7368 :     if (info->update & HA_STATE_EXTEND_BLOCK)
     751                 :     {
     752               0 :       info->update&= ~HA_STATE_EXTEND_BLOCK;
     753               0 :       if (my_block_write(&info->rec_cache, *record-head_length,
     754                 :                          length+extra_length+del_length,filepos))
     755                 :       goto err;
     756                 :     }
     757            7368 :     else if (my_b_write(&info->rec_cache, *record-head_length,
     758                 :                         length+extra_length+del_length))
     759                 :       goto err;
     760                 :   }
     761                 :   else
     762                 :   {
     763           26031 :     info->rec_cache.seek_not_done=1;
     764           26031 :     if (info->s->file_write(info, *record-head_length,
     765                 :                             length+extra_length+
     766                 :                             del_length,filepos,info->s->write_flag))
     767           33399 :       goto err;
     768                 :   }
     769           33399 :   memcpy(record_end,temp,(size_t) (extra_length+del_length));
     770           33399 :   *record=record_end;
     771           33399 :   *reclength-=(length-head_length);
     772           33399 :   *flag=6;
     773                 : 
     774           33399 :   if (del_length)
     775                 :   {
     776                 :     /* link the next delete block to this */
     777             556 :     if (update_backward_delete_link(info, next_delete_block,
     778                 :                                     info->s->state.dellink))
     779           33399 :       goto err;
     780                 :   }
     781                 : 
     782           33399 :   DBUG_RETURN(0);
     783               0 : err:
     784               0 :   DBUG_PRINT("exit",("errno: %d",my_errno));
     785               0 :   DBUG_RETURN(1);
     786                 : } /* _ma_write_part_record */
     787                 : 
     788                 : 
     789                 :         /* update record from datafile */
     790                 : 
     791                 : static my_bool update_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos,
     792                 :                                      uchar *record, ulong reclength)
     793            2775 : {
     794                 :   int flag;
     795                 :   uint error;
     796                 :   ulong length;
     797                 :   MARIA_BLOCK_INFO block_info;
     798            2775 :   DBUG_ENTER("update_dynamic_record");
     799                 : 
     800            2775 :   flag=block_info.second_read=0;
     801                 :   /*
     802                 :     Check if we have enough room for the record.
     803                 :     First we do simplified check to make usual case faster.
     804                 :     Then we do more precise check for the space left.
     805                 :     Though it still is not absolutely precise, as
     806                 :     we always use MARIA_MAX_DYN_BLOCK_HEADER while it can be
     807                 :     less in the most of the cases.
     808                 :   */
     809                 : 
     810                 :   /*
     811                 :     compare with just the reclength as we're going
     812                 :     to get some space from the old replaced record
     813                 :   */
     814            2775 :   if (unlikely(info->s->base.max_data_file_length -
     815                 :         info->state->data_file_length < reclength))
     816                 :   {
     817                 :     /* If new record isn't longer, we can go on safely */
     818               0 :     if (info->cur_row.total_length < reclength)
     819                 :     {
     820               0 :       if (info->s->base.max_data_file_length - info->state->data_file_length +
     821                 :           info->state->empty - info->state->del * MARIA_MAX_DYN_BLOCK_HEADER <
     822                 :           reclength - info->cur_row.total_length + MARIA_MAX_DYN_BLOCK_HEADER)
     823                 :       {
     824               0 :         my_errno=HA_ERR_RECORD_FILE_FULL;
     825               0 :         goto err;
     826                 :       }
     827                 :     }
     828                 :   }
     829                 :   /* Remember length for updated row if it's updated again */
     830            2775 :   info->cur_row.total_length= reclength;
     831                 : 
     832           10267 :   while (reclength > 0)
     833                 :   {
     834            4717 :     if (filepos != info->s->state.dellink)
     835                 :     {
     836            2791 :       block_info.next_filepos= HA_OFFSET_ERROR;
     837            2791 :       if ((error= _ma_get_block_info(&block_info, info->dfile.file, filepos))
     838                 :           & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
     839                 :              BLOCK_FATAL_ERROR))
     840                 :       {
     841               0 :         DBUG_PRINT("error",("Got wrong block info"));
     842               0 :         if (!(error & BLOCK_FATAL_ERROR))
     843               0 :           my_errno=HA_ERR_WRONG_IN_RECORD;
     844                 :         goto err;
     845                 :       }
     846            2791 :       length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
     847            2791 :       if (length < reclength)
     848                 :       {
     849            1718 :         uint tmp=MY_ALIGN(reclength - length + 3 +
     850                 :                           test(reclength >= 65520L),MARIA_DYN_ALIGN_SIZE);
     851                 :         /* Don't create a block bigger than MARIA_MAX_BLOCK_LENGTH */
     852            1718 :         tmp= min(length+tmp, MARIA_MAX_BLOCK_LENGTH)-length;
     853                 :         /* Check if we can extend this block */
     854            1755 :         if (block_info.filepos + block_info.block_len ==
     855                 :             info->state->data_file_length &&
     856                 :             info->state->data_file_length <
     857                 :             info->s->base.max_data_file_length-tmp)
     858                 :         {
     859                 :           /* extend file */
     860              37 :           DBUG_PRINT("info",("Extending file with %d bytes",tmp));
     861              37 :           if (info->cur_row.nextpos == info->state->data_file_length)
     862               0 :             info->cur_row.nextpos+= tmp;
     863              37 :           info->state->data_file_length+= tmp;
     864              37 :           info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
     865              37 :           length+=tmp;
     866                 :         }
     867            1681 :         else if (length < MARIA_MAX_BLOCK_LENGTH - MARIA_MIN_BLOCK_LENGTH)
     868                 :         {
     869                 :           /*
     870                 :             Check if next block is a deleted block
     871                 :             Above we have MARIA_MIN_BLOCK_LENGTH to avoid the problem where
     872                 :             the next block is so small it can't be splited which could
     873                 :             casue problems
     874                 :           */
     875                 : 
     876                 :           MARIA_BLOCK_INFO del_block;
     877            1681 :           del_block.second_read=0;
     878            1681 :           if (_ma_get_block_info(&del_block, info->dfile.file,
     879                 :                                  block_info.filepos + block_info.block_len) &
     880                 :               BLOCK_DELETED)
     881                 :           {
     882                 :             /* Use; Unlink it and extend the current block */
     883             202 :             DBUG_PRINT("info",("Extending current block"));
     884             202 :             if (unlink_deleted_block(info,&del_block))
     885             202 :               goto err;
     886             202 :             if ((length+=del_block.block_len) > MARIA_MAX_BLOCK_LENGTH)
     887                 :             {
     888                 :               /*
     889                 :                 New block was too big, link overflow part back to
     890                 :                 delete list
     891                 :               */
     892                 :               my_off_t next_pos;
     893               0 :               ulong rest_length= length-MARIA_MAX_BLOCK_LENGTH;
     894               0 :               set_if_bigger(rest_length, MARIA_MIN_BLOCK_LENGTH);
     895               0 :               next_pos= del_block.filepos+ del_block.block_len - rest_length;
     896                 : 
     897               0 :               if (update_backward_delete_link(info, info->s->state.dellink,
     898                 :                                               next_pos))
     899               0 :                 DBUG_RETURN(1);
     900                 : 
     901                 :               /* create delete link for data that didn't fit into the page */
     902               0 :               del_block.header[0]=0;
     903               0 :               mi_int3store(del_block.header+1, rest_length);
     904               0 :               mi_sizestore(del_block.header+4,info->s->state.dellink);
     905               0 :               bfill(del_block.header+12,8,255);
     906               0 :               if (info->s->file_write(info, del_block.header, 20,
     907                 :                                       next_pos, MYF(MY_NABP)))
     908               0 :                 DBUG_RETURN(1);
     909               0 :               info->s->state.dellink= next_pos;
     910               0 :               info->s->state.split++;
     911               0 :               info->state->del++;
     912               0 :               info->state->empty+= rest_length;
     913               0 :               length-= rest_length;
     914                 :             }
     915                 :           }
     916                 :         }
     917                 :       }
     918                 :     }
     919                 :     else
     920                 :     {
     921            1926 :       if (_ma_find_writepos(info,reclength,&filepos,&length))
     922            4717 :         goto err;
     923                 :     }
     924            4717 :     if (_ma_write_part_record(info,filepos,length,block_info.next_filepos,
     925                 :                               &record,&reclength,&flag))
     926            4717 :       goto err;
     927            4717 :     if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
     928                 :     {
     929                 :       /* Start writing data on deleted blocks */
     930            4686 :       filepos=info->s->state.dellink;
     931                 :     }
     932                 :   }
     933                 : 
     934            2775 :   if (block_info.next_filepos != HA_OFFSET_ERROR)
     935              15 :     if (delete_dynamic_record(info,block_info.next_filepos,1))
     936            2775 :       goto err;
     937                 : 
     938            2775 :   DBUG_RETURN(0);
     939               0 : err:
     940               0 :   DBUG_RETURN(1);
     941                 : }
     942                 : 
     943                 : 
     944                 :         /* Pack a record. Return new reclength */
     945                 : 
     946                 : uint _ma_rec_pack(MARIA_HA *info, register uchar *to,
     947                 :                   register const uchar *from)
     948           57110 : {
     949                 :   uint          length,new_length,flag,bit,i;
     950                 :   const uchar   *pos,*end;
     951                 :   uchar         *startpos,*packpos;
     952                 :   enum en_fieldtype type;
     953                 :   reg3 MARIA_COLUMNDEF *column;
     954                 :   MARIA_BLOB    *blob;
     955           57110 :   DBUG_ENTER("_ma_rec_pack");
     956                 : 
     957           57110 :   flag= 0;
     958           57110 :   bit= 1;
     959           57110 :   startpos= packpos=to;
     960           57110 :   to+= info->s->base.pack_bytes;
     961           57110 :   blob= info->blobs;
     962           57110 :   column= info->s->columndef;
     963           57110 :   if (info->s->base.null_bytes)
     964                 :   {
     965            3386 :     memcpy(to, from, info->s->base.null_bytes);
     966            3386 :     from+= info->s->base.null_bytes;
     967            3386 :     to+=   info->s->base.null_bytes;
     968                 :   }
     969                 : 
     970          394260 :   for (i=info->s->base.fields ; i-- > 0; from+= length, column++)
     971                 :   {
     972          337150 :     length=(uint) column->length;
     973          337150 :     if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL)
     974                 :     {
     975          283426 :       if (type == FIELD_BLOB)
     976                 :       {
     977            8048 :         if (!blob->length)
     978            6522 :           flag|=bit;
     979                 :         else
     980                 :         {
     981                 :           char *temp_pos;
     982            1526 :           size_t tmp_length=length-portable_sizeof_char_ptr;
     983            1526 :           memcpy(to,from,tmp_length);
     984            1526 :           memcpy_fixed(&temp_pos,from+tmp_length,sizeof(char*));
     985            1526 :           memcpy(to+tmp_length,temp_pos,(size_t) blob->length);
     986            1526 :           to+=tmp_length+blob->length;
     987                 :         }
     988            8048 :         blob++;
     989                 :       }
     990          275378 :       else if (type == FIELD_SKIP_ZERO)
     991                 :       {
     992           53724 :         if (memcmp(from, maria_zero_string, length) == 0)
     993              58 :           flag|=bit;
     994                 :         else
     995                 :         {
     996           53666 :           memcpy(to, from, (size_t) length);
     997           53666 :           to+=length;
     998                 :         }
     999                 :       }
    1000          221654 :       else if (type == FIELD_SKIP_ENDSPACE ||
    1001                 :                type == FIELD_SKIP_PRESPACE)
    1002                 :       {
    1003          220234 :         pos= from; end= from + length;
    1004          220234 :         if (type == FIELD_SKIP_ENDSPACE)
    1005                 :         {                                       /* Pack trailing spaces */
    1006         1719861 :           while (end > from && *(end-1) == ' ')
    1007         1663468 :             end--;
    1008                 :         }
    1009                 :         else
    1010                 :         {                                       /* Pack pref-spaces */
    1011          674750 :           while (pos < end && *pos == ' ')
    1012          510909 :             pos++;
    1013                 :         }
    1014          220234 :         new_length=(uint) (end-pos);
    1015          220234 :         if (new_length +1 + test(column->length > 255 && new_length > 127)
    1016                 :             < length)
    1017                 :         {
    1018          216614 :           if (column->length > 255 && new_length > 127)
    1019                 :           {
    1020               0 :             to[0]= (uchar) ((new_length & 127) + 128);
    1021               0 :             to[1]= (uchar) (new_length >> 7);
    1022               0 :             to+=2;
    1023                 :           }
    1024                 :           else
    1025          216614 :             *to++= (uchar) new_length;
    1026          216614 :           memcpy(to, pos, (size_t) new_length); to+=new_length;
    1027          216614 :           flag|=bit;
    1028                 :         }
    1029                 :         else
    1030                 :         {
    1031            3620 :           memcpy(to,from,(size_t) length); to+=length;
    1032                 :         }
    1033                 :       }
    1034            1420 :       else if (type == FIELD_VARCHAR)
    1035                 :       {
    1036             710 :         uint pack_length= HA_VARCHAR_PACKLENGTH(column->length -1);
    1037                 :         uint tmp_length;
    1038             710 :         if (pack_length == 1)
    1039                 :         {
    1040             529 :           tmp_length= (uint) *from;
    1041             529 :           *to++= *from;
    1042                 :         }
    1043                 :         else
    1044                 :         {
    1045             181 :           tmp_length= uint2korr(from);
    1046             181 :           store_key_length_inc(to,tmp_length);
    1047                 :         }
    1048             710 :         memcpy(to, from+pack_length,tmp_length);
    1049             710 :         to+= tmp_length;
    1050             710 :         continue;
    1051                 :       }
    1052                 :       else
    1053                 :       {
    1054             710 :         memcpy(to,from,(size_t) length); to+=length;
    1055             710 :         continue;                               /* Normal field */
    1056                 :       }
    1057          282006 :       if ((bit= bit << 1) >= 256)
    1058                 :       {
    1059               0 :         *packpos++ = (uchar) flag;
    1060               0 :         bit=1; flag=0;
    1061                 :       }
    1062                 :     }
    1063                 :     else
    1064                 :     {
    1065           53724 :       memcpy(to,from,(size_t) length); to+=length;
    1066                 :     }
    1067                 :   }
    1068           57110 :   if (bit != 1)
    1069           56755 :     *packpos= (uchar) flag;
    1070           57110 :   if (info->s->calc_checksum)
    1071           13806 :     *to++= (uchar) info->cur_row.checksum;
    1072           57110 :   DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
    1073           57110 :   DBUG_RETURN((uint) (to-startpos));
    1074                 : } /* _ma_rec_pack */
    1075                 : 
    1076                 : 
    1077                 : 
    1078                 : /*
    1079                 :   Check if a record was correctly packed. Used only by maria_chk
    1080                 :   Returns 0 if record is ok.
    1081                 : */
    1082                 : 
    1083                 : my_bool _ma_rec_check(MARIA_HA *info,const uchar *record, uchar *rec_buff,
    1084                 :                       ulong packed_length, my_bool with_checksum,
    1085                 :                       ha_checksum checksum)
    1086           34600 : {
    1087                 :   uint          length,new_length,flag,bit,i;
    1088                 :   const uchar   *pos,*end;
    1089                 :   uchar         *packpos,*to;
    1090                 :   enum en_fieldtype type;
    1091                 :   reg3 MARIA_COLUMNDEF *column;
    1092           34600 :   DBUG_ENTER("_ma_rec_check");
    1093                 : 
    1094           34187 :   packpos=rec_buff; to= rec_buff+info->s->base.pack_bytes;
    1095           34187 :   column= info->s->columndef;
    1096           34187 :   flag= *packpos; bit=1;
    1097           34187 :   record+= info->s->base.null_bytes;
    1098           34187 :   to+= info->s->base.null_bytes;
    1099                 : 
    1100          238511 :   for (i=info->s->base.fields ; i-- > 0; record+= length, column++)
    1101                 :   {
    1102          203910 :     length=(uint) column->length;
    1103          203910 :     if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL)
    1104                 :     {
    1105          170082 :       if (type == FIELD_BLOB)
    1106                 :       {
    1107                 :         uint blob_length=
    1108               0 :           _ma_calc_blob_length(length-portable_sizeof_char_ptr,record);
    1109             124 :         if (!blob_length && !(flag & bit))
    1110               0 :           goto err;
    1111               0 :         if (blob_length)
    1112             124 :           to+=length - portable_sizeof_char_ptr+ blob_length;
    1113                 :       }
    1114          170550 :       else if (type == FIELD_SKIP_ZERO)
    1115                 :       {
    1116           33827 :         if (memcmp(record, maria_zero_string, length) == 0)
    1117                 :         {
    1118              37 :           if (!(flag & bit))
    1119                 :             goto err;
    1120                 :         }
    1121                 :         else
    1122           33790 :           to+=length;
    1123                 :       }
    1124          136723 :       else if (type == FIELD_SKIP_ENDSPACE ||
    1125                 :                type == FIELD_SKIP_PRESPACE)
    1126                 :       {
    1127          136479 :         pos= record; end= record + length;
    1128          136479 :         if (type == FIELD_SKIP_ENDSPACE)
    1129                 :         {                                       /* Pack trailing spaces */
    1130         1080361 :           while (end > record && *(end-1) == ' ')
    1131         1045991 :             end--;
    1132                 :         }
    1133                 :         else
    1134                 :         {                                       /* Pack pre-spaces */
    1135          422479 :           while (pos < end && *pos == ' ')
    1136          320370 :             pos++;
    1137                 :         }
    1138          136479 :         new_length=(uint) (end-pos);
    1139          136479 :         if (new_length +1 + test(column->length > 255 && new_length > 127)
    1140                 :             < length)
    1141                 :         {
    1142          134994 :           if (!(flag & bit))
    1143          135025 :             goto err;
    1144          135025 :           if (column->length > 255 && new_length > 127)
    1145                 :           {
    1146                 :             /* purecov: begin inspected */
    1147               0 :             if (to[0] != (uchar) ((new_length & 127) + 128) ||
    1148                 :                 to[1] != (uchar) (new_length >> 7))
    1149                 :               goto err;
    1150               0 :             to+=2;
    1151                 :             /* purecov: end */
    1152                 :           }
    1153          135025 :           else if (*to++ != (uchar) new_length)
    1154          135052 :             goto err;
    1155          135052 :           to+=new_length;
    1156                 :         }
    1157                 :         else
    1158            1485 :           to+=length;
    1159                 :       }
    1160             244 :       else if (type == FIELD_VARCHAR)
    1161                 :       {
    1162             122 :         uint pack_length= HA_VARCHAR_PACKLENGTH(column->length -1);
    1163                 :         uint tmp_length;
    1164             122 :         if (pack_length == 1)
    1165                 :         {
    1166              91 :           tmp_length= (uint) *record;
    1167              91 :           to+= 1+ tmp_length;
    1168              91 :           continue;
    1169                 :         }
    1170                 :         else
    1171                 :         {
    1172              31 :           tmp_length= uint2korr(record);
    1173              31 :           to+= get_pack_length(tmp_length)+tmp_length;
    1174                 :         }
    1175              31 :         continue;
    1176                 :       }
    1177                 :       else
    1178                 :       {
    1179             122 :         to+=length;
    1180             122 :         continue;                               /* Normal field */
    1181                 :       }
    1182          170252 :       if ((bit= bit << 1) >= 256)
    1183                 :       {
    1184               0 :         flag= *++packpos;
    1185               0 :         bit=1;
    1186                 :       }
    1187                 :     }
    1188                 :     else
    1189           33828 :       to+= length;
    1190                 :   }
    1191           34601 :   if (packed_length != (uint) (to - rec_buff) +
    1192                 :       test(info->s->calc_checksum) || (bit != 1 && (flag & ~(bit - 1))))
    1193                 :     goto err;
    1194           34603 :   if (with_checksum && ((uchar) checksum != (uchar) *to))
    1195                 :   {
    1196               0 :     DBUG_PRINT("error",("wrong checksum for row"));
    1197               0 :     goto err;
    1198                 :   }
    1199           34603 :   DBUG_RETURN(0);
    1200                 : 
    1201             176 : err:
    1202             176 :   DBUG_RETURN(1);
    1203                 : }
    1204                 : 
    1205                 : 
    1206                 : /*
    1207                 :   @brief Unpacks a record
    1208                 : 
    1209                 :   @return Recordlength
    1210                 :   @retval >0  ok
    1211                 :   @retval MY_FILE_ERROR (== -1)  Error.
    1212                 :           my_errno is set to HA_ERR_WRONG_IN_RECORD
    1213                 : */
    1214                 : 
    1215                 : ulong _ma_rec_unpack(register MARIA_HA *info, register uchar *to, uchar *from,
    1216                 :                      ulong found_length)
    1217          157028 : {
    1218                 :   uint flag,bit,length,min_pack_length, column_length;
    1219                 :   enum en_fieldtype type;
    1220                 :   uchar *from_end,*to_end,*packpos;
    1221                 :   reg3 MARIA_COLUMNDEF *column, *end_column;
    1222          157028 :   DBUG_ENTER("_ma_rec_unpack");
    1223                 : 
    1224          157017 :   to_end=to + info->s->base.reclength;
    1225          157017 :   from_end=from+found_length;
    1226          157017 :   flag= (uchar) *from; bit=1; packpos=from;
    1227          157017 :   if (found_length < info->s->base.min_pack_length)
    1228          156703 :     goto err;
    1229          156703 :   from+= info->s->base.pack_bytes;
    1230          156703 :   min_pack_length= info->s->base.min_pack_length - info->s->base.pack_bytes;
    1231                 : 
    1232          156703 :   if ((length= info->s->base.null_bytes))
    1233                 :   {
    1234            3435 :     memcpy(to, from, length);
    1235            3435 :     from+= length;
    1236            3435 :     to+= length;
    1237            3435 :     min_pack_length-= length;
    1238                 :   }
    1239                 : 
    1240          156703 :   for (column= info->s->columndef, end_column= column + info->s->base.fields;
    1241         1102398 :        column < end_column ; to+= column_length, column++)
    1242                 :   {
    1243          945373 :     column_length= column->length;
    1244          945373 :     if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL &&
    1245                 :         (type != FIELD_CHECK))
    1246                 :     {
    1247          791964 :       if (type == FIELD_VARCHAR)
    1248                 :       {
    1249             662 :         uint pack_length= HA_VARCHAR_PACKLENGTH(column_length-1);
    1250             662 :         if (pack_length == 1)
    1251                 :         {
    1252             494 :           length= (uint) *(uchar*) from;
    1253             494 :           if (length > column_length-1)
    1254             494 :             goto err;
    1255             494 :           *to= *from++;
    1256                 :         }
    1257                 :         else
    1258                 :         {
    1259             168 :           get_key_length(length, from);
    1260             168 :           if (length > column_length-2)
    1261             168 :             goto err;
    1262             168 :           int2store(to,length);
    1263                 :         }
    1264             662 :         if (from+length > from_end)
    1265             662 :           goto err;
    1266             662 :         memcpy(to+pack_length, from, length);
    1267             662 :         from+= length;
    1268             662 :         min_pack_length--;
    1269             662 :         continue;
    1270                 :       }
    1271          791302 :       if (flag & bit)
    1272                 :       {
    1273          645104 :         if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
    1274           15760 :           bzero(to, column_length);
    1275          613584 :         else if (type == FIELD_SKIP_ENDSPACE ||
    1276                 :                  type == FIELD_SKIP_PRESPACE)
    1277                 :         {
    1278          614165 :           if (column->length > 255 && *from & 128)
    1279                 :           {
    1280               0 :             if (from + 1 >= from_end)
    1281               0 :               goto err;
    1282               0 :             length= (*from & 127)+ ((uint) (uchar) *(from+1) << 7); from+=2;
    1283                 :           }
    1284                 :           else
    1285                 :           {
    1286          614165 :             if (from == from_end)
    1287          613626 :               goto err;
    1288          613626 :             length= (uchar) *from++;
    1289                 :           }
    1290          613626 :           min_pack_length--;
    1291          613626 :           if (length >= column_length ||
    1292                 :               min_pack_length + length > (uint) (from_end - from))
    1293                 :             goto err;
    1294          613858 :           if (type == FIELD_SKIP_ENDSPACE)
    1295                 :           {
    1296          151974 :             memcpy(to, from, (size_t) length);
    1297          151974 :             bfill(to+length, column_length-length, ' ');
    1298                 :           }
    1299                 :           else
    1300                 :           {
    1301          461884 :             bfill(to, column_length-length, ' ');
    1302          461927 :             memcpy(to+column_length-length, from, (size_t) length);
    1303                 :           }
    1304          613642 :           from+=length;
    1305                 :         }
    1306                 :       }
    1307          161958 :       else if (type == FIELD_BLOB)
    1308                 :       {
    1309            2595 :         uint size_length=column_length- portable_sizeof_char_ptr;
    1310            2595 :         ulong blob_length= _ma_calc_blob_length(size_length,from);
    1311            2595 :         ulong from_left= (ulong) (from_end - from);
    1312            2595 :         if (from_left < size_length ||
    1313                 :             from_left - size_length < blob_length ||
    1314                 :             from_left - size_length - blob_length < min_pack_length)
    1315                 :           goto err;
    1316            2595 :         memcpy(to, from, (size_t) size_length);
    1317            2595 :         from+=size_length;
    1318            2595 :         memcpy_fixed(to+size_length,(uchar*) &from,sizeof(char*));
    1319            2595 :         from+=blob_length;
    1320                 :       }
    1321                 :       else
    1322                 :       {
    1323          159363 :         if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
    1324            5911 :           min_pack_length--;
    1325          159363 :         if (min_pack_length + column_length > (uint) (from_end - from))
    1326          159351 :           goto err;
    1327          159351 :         memcpy(to, from, (size_t) column_length); from+=column_length;
    1328                 :       }
    1329          790767 :       if ((bit= bit << 1) >= 256)
    1330                 :       {
    1331               0 :         flag= (uchar) *++packpos; bit=1;
    1332                 :       }
    1333                 :     }
    1334                 :     else
    1335                 :     {
    1336          153409 :       if (min_pack_length > (uint) (from_end - from))
    1337          154266 :         goto err;
    1338          154266 :       min_pack_length-=column_length;
    1339          154266 :       memcpy(to, from, (size_t) column_length);
    1340          154266 :       from+=column_length;
    1341                 :     }
    1342                 :   }
    1343          157025 :   if (info->s->calc_checksum)
    1344           50506 :     info->cur_row.checksum= (uint) (uchar) *from++;
    1345          157025 :   if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
    1346          157025 :     DBUG_RETURN(found_length);
    1347                 : 
    1348               0 : err:
    1349               0 :   my_errno= HA_ERR_WRONG_IN_RECORD;
    1350               0 :   DBUG_PRINT("error",("to_end: 0x%lx -> 0x%lx  from_end: 0x%lx -> 0x%lx",
    1351                 :                       (long) to, (long) to_end, (long) from, (long) from_end));
    1352               0 :   DBUG_DUMP("from", info->rec_buff, info->s->base.min_pack_length);
    1353               0 :   DBUG_RETURN(MY_FILE_ERROR);
    1354                 : } /* _ma_rec_unpack */
    1355                 : 
    1356                 : 
    1357                 :         /* Calc length of blob. Update info in blobs->length */
    1358                 : 
    1359                 : ulong _ma_calc_total_blob_length(MARIA_HA *info, const uchar *record)
    1360           11416 : {
    1361                 :   ulong length;
    1362                 :   MARIA_BLOB *blob,*end;
    1363                 : 
    1364           11416 :   for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
    1365           30880 :        blob != end;
    1366            8048 :        blob++)
    1367                 :   {
    1368            8048 :     blob->length= _ma_calc_blob_length(blob->pack_length,
    1369                 :                                        record + blob->offset);
    1370            8048 :     length+=blob->length;
    1371                 :   }
    1372           11416 :   return length;
    1373                 : }
    1374                 : 
    1375                 : 
    1376                 : ulong _ma_calc_blob_length(uint length, const uchar *pos)
    1377          598365 : {
    1378          598365 :   switch (length) {
    1379                 :   case 1:
    1380               0 :     return (uint) (uchar) *pos;
    1381                 :   case 2:
    1382          270256 :     return (uint) uint2korr(pos);
    1383                 :   case 3:
    1384               0 :     return uint3korr(pos);
    1385                 :   case 4:
    1386          328109 :     return uint4korr(pos);
    1387                 :   default:
    1388                 :     break;
    1389                 :   }
    1390               0 :   return 0; /* Impossible */
    1391                 : }
    1392                 : 
    1393                 : 
    1394                 : void _ma_store_blob_length(uchar *pos,uint pack_length,uint length)
    1395             339 : {
    1396             339 :   switch (pack_length) {
    1397                 :   case 1:
    1398               0 :     *pos= (uchar) length;
    1399               0 :     break;
    1400                 :   case 2:
    1401               0 :     int2store(pos,length);
    1402               0 :     break;
    1403                 :   case 3:
    1404               0 :     int3store(pos,length);
    1405               0 :     break;
    1406                 :   case 4:
    1407             339 :     int4store(pos,length);
    1408                 :   default:
    1409                 :     break;
    1410                 :   }
    1411                 :   return;
    1412                 : }
    1413                 : 
    1414                 : 
    1415                 : /*
    1416                 :   Read record from datafile.
    1417                 : 
    1418                 :   SYNOPSIS
    1419                 :     _ma_read_dynamic_record()
    1420                 :       info                      MARIA_HA pointer to table.
    1421                 :       filepos                   From where to read the record.
    1422                 :       buf                       Destination for record.
    1423                 : 
    1424                 :   NOTE
    1425                 :     If a write buffer is active, it needs to be flushed if its contents
    1426                 :     intersects with the record to read. We always check if the position
    1427                 :     of the first uchar of the write buffer is lower than the position
    1428                 :     past the last uchar to read. In theory this is also true if the write
    1429                 :     buffer is completely below the read segment. That is, if there is no
    1430                 :     intersection. But this case is unusual. We flush anyway. Only if the
    1431                 :     first uchar in the write buffer is above the last uchar to read, we do
    1432                 :     not flush.
    1433                 : 
    1434                 :     A dynamic record may need several reads. So this check must be done
    1435                 :     before every read. Reading a dynamic record starts with reading the
    1436                 :     block header. If the record does not fit into the free space of the
    1437                 :     header, the block may be longer than the header. In this case a
    1438                 :     second read is necessary. These one or two reads repeat for every
    1439                 :     part of the record.
    1440                 : 
    1441                 :   RETURN
    1442                 :     0          OK
    1443                 :     #          Error number
    1444                 : */
    1445                 : 
    1446                 : int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf,
    1447                 :                             MARIA_RECORD_POS filepos)
    1448           54995 : {
    1449                 :   int block_of_record;
    1450                 :   uint b_type;
    1451                 :   MARIA_BLOCK_INFO block_info;
    1452                 :   File file;
    1453                 :   uchar *to;
    1454                 :   uint left_length;
    1455           54995 :   DBUG_ENTER("_ma_read_dynamic_record");
    1456                 : 
    1457           54995 :   if (filepos == HA_OFFSET_ERROR)
    1458           54995 :     goto err;
    1459                 : 
    1460           54995 :   LINT_INIT(to);
    1461           54995 :   LINT_INIT(left_length);
    1462           54995 :   file= info->dfile.file;
    1463           54995 :   block_of_record= 0;   /* First block of record is numbered as zero. */
    1464           54995 :   block_info.second_read= 0;
    1465                 :   do
    1466                 :   {
    1467                 :     /* A corrupted table can have wrong pointers. (Bug# 19835) */
    1468           58205 :     if (filepos == HA_OFFSET_ERROR)
    1469           58205 :       goto panic;
    1470           58205 :     if (info->opt_flag & WRITE_CACHE_USED &&
    1471                 :         (info->rec_cache.pos_in_file < filepos +
    1472                 :          MARIA_BLOCK_INFO_HEADER_LENGTH) &&
    1473                 :         flush_io_cache(&info->rec_cache))
    1474           58205 :       goto err;
    1475           58205 :     info->rec_cache.seek_not_done=1;
    1476           58205 :     if ((b_type= _ma_get_block_info(&block_info, file, filepos)) &
    1477                 :         (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
    1478                 :          BLOCK_FATAL_ERROR))
    1479                 :     {
    1480               0 :       if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
    1481               0 :         my_errno=HA_ERR_RECORD_DELETED;
    1482                 :       goto err;
    1483                 :     }
    1484           58205 :     if (block_of_record++ == 0)                 /* First block */
    1485                 :     {
    1486           54995 :       info->cur_row.total_length= block_info.rec_len;
    1487           54995 :       if (block_info.rec_len > (uint) info->s->base.max_pack_length)
    1488           54995 :         goto panic;
    1489           54995 :       if (info->s->base.blobs)
    1490                 :       {
    1491            7720 :         if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
    1492                 :                              block_info.rec_len +
    1493                 :                              info->s->base.extra_rec_buff_size))
    1494           54995 :           goto err;
    1495                 :       }
    1496           54995 :       to= info->rec_buff;
    1497           54995 :       left_length=block_info.rec_len;
    1498                 :     }
    1499           58205 :     if (left_length < block_info.data_len || ! block_info.data_len)
    1500                 :       goto panic;                       /* Wrong linked record */
    1501                 :     /* copy information that is already read */
    1502                 :     {
    1503           58205 :       uint offset= (uint) (block_info.filepos - filepos);
    1504           58205 :       uint prefetch_len= (sizeof(block_info.header) - offset);
    1505           58205 :       filepos+= sizeof(block_info.header);
    1506                 : 
    1507           58205 :       if (prefetch_len > block_info.data_len)
    1508             281 :         prefetch_len= block_info.data_len;
    1509           58205 :       if (prefetch_len)
    1510                 :       {
    1511           58205 :         memcpy(to, block_info.header + offset, prefetch_len);
    1512           58205 :         block_info.data_len-= prefetch_len;
    1513           58205 :         left_length-= prefetch_len;
    1514           58205 :         to+= prefetch_len;
    1515                 :       }
    1516                 :     }
    1517                 :     /* read rest of record from file */
    1518           58205 :     if (block_info.data_len)
    1519                 :     {
    1520           57725 :       if (info->opt_flag & WRITE_CACHE_USED &&
    1521                 :           info->rec_cache.pos_in_file < filepos + block_info.data_len &&
    1522                 :           flush_io_cache(&info->rec_cache))
    1523           57725 :         goto err;
    1524                 :       /*
    1525                 :         What a pity that this method is not called 'file_pread' and that
    1526                 :         there is no equivalent without seeking. We are at the right
    1527                 :         position already. :(
    1528                 :       */
    1529           57725 :       if (info->s->file_read(info, to, block_info.data_len,
    1530                 :                              filepos, MYF(MY_NABP)))
    1531           57725 :         goto panic;
    1532           57725 :       left_length-=block_info.data_len;
    1533           57725 :       to+=block_info.data_len;
    1534                 :     }
    1535           58205 :     filepos= block_info.next_filepos;
    1536           58205 :   } while (left_length);
    1537                 : 
    1538           54995 :   info->update|= HA_STATE_AKTIV;     /* We have a aktive record */
    1539           54995 :   fast_ma_writeinfo(info);
    1540           54995 :   DBUG_RETURN(_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
    1541                 :               MY_FILE_ERROR ? 0 : my_errno);
    1542                 : 
    1543               0 : err:
    1544               0 :   fast_ma_writeinfo(info);
    1545               0 :   DBUG_RETURN(my_errno);
    1546                 : 
    1547               0 : panic:
    1548               0 :   my_errno=HA_ERR_WRONG_IN_RECORD;
    1549               0 :   goto err;
    1550                 : }
    1551                 : 
    1552                 :         /* compare unique constraint between stored rows */
    1553                 : 
    1554                 : my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def,
    1555                 :                                const uchar *record, MARIA_RECORD_POS pos)
    1556              12 : {
    1557                 :   uchar *old_rec_buff,*old_record;
    1558                 :   size_t old_rec_buff_size;
    1559                 :   my_bool error;
    1560              12 :   DBUG_ENTER("_ma_cmp_dynamic_unique");
    1561                 : 
    1562              12 :   if (!(old_record=my_alloca(info->s->base.reclength)))
    1563               0 :     DBUG_RETURN(1);
    1564                 : 
    1565                 :   /* Don't let the compare destroy blobs that may be in use */
    1566              12 :   old_rec_buff=      info->rec_buff;
    1567              12 :   old_rec_buff_size= info->rec_buff_size;
    1568                 : 
    1569              12 :   if (info->s->base.blobs)
    1570                 :   {
    1571               0 :     info->rec_buff= 0;
    1572               0 :     info->rec_buff_size= 0;
    1573                 :   }
    1574              12 :   error= _ma_read_dynamic_record(info, old_record, pos) != 0;
    1575              12 :   if (!error)
    1576              12 :     error=_ma_unique_comp(def, record, old_record, def->null_are_equal) != 0;
    1577              12 :   if (info->s->base.blobs)
    1578                 :   {
    1579               0 :     my_free(info->rec_buff, MYF(MY_ALLOW_ZERO_PTR));
    1580               0 :     info->rec_buff=      old_rec_buff;
    1581               0 :     info->rec_buff_size= old_rec_buff_size;
    1582                 :   }
    1583              12 :   my_afree(old_record);
    1584              12 :   DBUG_RETURN(error);
    1585                 : }
    1586                 : 
    1587                 : 
    1588                 :         /* Compare of record on disk with packed record in memory */
    1589                 : 
    1590                 : my_bool _ma_cmp_dynamic_record(register MARIA_HA *info,
    1591                 :                                register const uchar *record)
    1592           25652 : {
    1593                 :   uint flag, reclength, b_type,cmp_length;
    1594                 :   my_off_t filepos;
    1595                 :   uchar *buffer;
    1596                 :   MARIA_BLOCK_INFO block_info;
    1597           25652 :   my_bool error= 1;
    1598           25652 :   DBUG_ENTER("_ma_cmp_dynamic_record");
    1599                 : 
    1600                 :         /* We are going to do changes; dont let anybody disturb */
    1601                 :   dont_break();                         /* Dont allow SIGHUP or SIGINT */
    1602                 : 
    1603           25652 :   if (info->opt_flag & WRITE_CACHE_USED)
    1604                 :   {
    1605               0 :     info->update&= ~(HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK);
    1606               0 :     if (flush_io_cache(&info->rec_cache))
    1607               0 :       DBUG_RETURN(1);
    1608                 :   }
    1609           25652 :   info->rec_cache.seek_not_done=1;
    1610                 : 
    1611                 :         /* If nobody have touched the database we don't have to test rec */
    1612                 : 
    1613           25652 :   buffer=info->rec_buff;
    1614           25652 :   if ((info->opt_flag & READ_CHECK_USED))
    1615                 :   {                                             /* If check isn't disabled  */
    1616           25652 :     if (info->s->base.blobs)
    1617                 :     {
    1618            3448 :       if (!(buffer=(uchar*) my_alloca(info->s->base.pack_reclength+
    1619                 :                                      _ma_calc_total_blob_length(info,record))))
    1620               0 :         DBUG_RETURN(1);
    1621                 :     }
    1622           25652 :     reclength= _ma_rec_pack(info,buffer,record);
    1623           25652 :     record= buffer;
    1624                 : 
    1625           25652 :     filepos= info->cur_row.lastpos;
    1626           25652 :     flag=block_info.second_read=0;
    1627           25652 :     block_info.next_filepos=filepos;
    1628           78278 :     while (reclength > 0)
    1629                 :     {
    1630           26974 :       if ((b_type= _ma_get_block_info(&block_info, info->dfile.file,
    1631                 :                                     block_info.next_filepos))
    1632                 :           & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
    1633                 :              BLOCK_FATAL_ERROR))
    1634                 :       {
    1635               0 :         if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED))
    1636               0 :           my_errno=HA_ERR_RECORD_CHANGED;
    1637                 :         goto err;
    1638                 :       }
    1639           26974 :       if (flag == 0)                            /* First block */
    1640                 :       {
    1641           25652 :         flag=1;
    1642           25652 :         if (reclength != block_info.rec_len)
    1643                 :         {
    1644               0 :           my_errno=HA_ERR_RECORD_CHANGED;
    1645               0 :           goto err;
    1646                 :         }
    1647            1322 :       } else if (reclength < block_info.data_len)
    1648                 :       {
    1649               0 :         my_errno=HA_ERR_WRONG_IN_RECORD;
    1650               0 :         goto err;
    1651                 :       }
    1652           26974 :       reclength-= block_info.data_len;
    1653           26974 :       cmp_length= block_info.data_len;
    1654           26974 :       if (!reclength && info->s->calc_checksum)
    1655            3670 :         cmp_length--;        /* 'record' may not contain checksum */
    1656                 : 
    1657           26974 :       if (_ma_cmp_buffer(info->dfile.file, record, block_info.filepos,
    1658                 :                          cmp_length))
    1659                 :       {
    1660               0 :         my_errno=HA_ERR_RECORD_CHANGED;
    1661               0 :         goto err;
    1662                 :       }
    1663           26974 :       flag=1;
    1664           26974 :       record+=block_info.data_len;
    1665                 :     }
    1666                 :   }
    1667           25652 :   my_errno=0;
    1668           25652 :   error= 0;
    1669           25652 : err:
    1670           25652 :   if (buffer != info->rec_buff)
    1671            3448 :     my_afree(buffer);
    1672           25652 :   DBUG_PRINT("exit", ("result: %d", error));
    1673           25652 :   DBUG_RETURN(error);
    1674                 : }
    1675                 : 
    1676                 : 
    1677                 :         /* Compare file to buffert */
    1678                 : 
    1679                 : static my_bool _ma_cmp_buffer(File file, const uchar *buff, my_off_t filepos,
    1680                 :                               uint length)
    1681           26974 : {
    1682                 :   uint next_length;
    1683                 :   uchar temp_buff[IO_SIZE*2];
    1684           26974 :   DBUG_ENTER("_ma_cmp_buffer");
    1685                 : 
    1686           26974 :   next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
    1687                 : 
    1688           55123 :   while (length > IO_SIZE*2)
    1689                 :   {
    1690            1175 :     if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
    1691                 :         memcmp(buff, temp_buff, next_length))
    1692                 :       goto err;
    1693            1175 :     filepos+=next_length;
    1694            1175 :     buff+=next_length;
    1695            1175 :     length-= next_length;
    1696            1175 :     next_length=IO_SIZE*2;
    1697                 :   }
    1698           26974 :   if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
    1699           26974 :     goto err;
    1700           26974 :   DBUG_RETURN(memcmp(buff, temp_buff, length) != 0);
    1701               0 : err:
    1702               0 :   DBUG_RETURN(1);
    1703                 : }
    1704                 : 
    1705                 : 
    1706                 : /*
    1707                 :   Read next record from datafile during table scan.
    1708                 : 
    1709                 :   SYNOPSIS
    1710                 :     _ma_read_rnd_dynamic_record()
    1711                 :       info                      MARIA_HA pointer to table.
    1712                 :       buf                       Destination for record.
    1713                 :       filepos                   From where to read the record.
    1714                 :       skip_deleted_blocks       If to repeat reading until a non-deleted
    1715                 :                                 record is found.
    1716                 : 
    1717                 :   NOTE
    1718                 :     This is identical to _ma_read_dynamic_record(), except the following
    1719                 :     cases:
    1720                 : 
    1721                 :     - If there is no active row at 'filepos', continue scanning for
    1722                 :       an active row. (This is becasue the previous
    1723                 :       _ma_read_rnd_dynamic_record() call stored the next block position
    1724                 :       in filepos, but this position may not be a start block for a row
    1725                 :     - We may have READ_CACHING enabled, in which case we use the cache
    1726                 :       to read rows.
    1727                 : 
    1728                 :    For other comments, check _ma_read_dynamic_record()
    1729                 : 
    1730                 :   RETURN
    1731                 :     0           OK
    1732                 :     != 0        Error number
    1733                 : */
    1734                 : 
    1735                 : int _ma_read_rnd_dynamic_record(MARIA_HA *info,
    1736                 :                                 uchar *buf,
    1737                 :                                 MARIA_RECORD_POS filepos,
    1738                 :                                 my_bool skip_deleted_blocks)
    1739           71380 : {
    1740                 :   int block_of_record, info_read;
    1741                 :   uint left_len,b_type;
    1742                 :   uchar *to;
    1743                 :   MARIA_BLOCK_INFO block_info;
    1744           71380 :   MARIA_SHARE *share= info->s;
    1745           71380 :   DBUG_ENTER("_ma_read_rnd_dynamic_record");
    1746                 : 
    1747           71380 :   info_read=0;
    1748           71380 :   LINT_INIT(to);
    1749                 : 
    1750           71380 :   if (info->lock_type == F_UNLCK)
    1751                 :   {
    1752                 : #ifndef UNSAFE_LOCKING
    1753                 : #else
    1754                 :     info->tmp_lock_type=F_RDLCK;
    1755                 : #endif
    1756                 :   }
    1757                 :   else
    1758           31240 :     info_read=1;                                /* memory-keyinfoblock is ok */
    1759                 : 
    1760           71380 :   block_of_record= 0;   /* First block of record is numbered as zero. */
    1761           71380 :   block_info.second_read= 0;
    1762           71380 :   left_len=1;
    1763                 :   do
    1764                 :   {
    1765           88828 :     if (filepos >= info->state->data_file_length)
    1766                 :     {
    1767            3951 :       if (!info_read)
    1768                 :       {                                         /* Check if changed */
    1769            2403 :         info_read=1;
    1770            2403 :         info->rec_cache.seek_not_done=1;
    1771            2403 :         if (_ma_state_info_read_dsk(share->kfile.file, &share->state))
    1772            3951 :           goto panic;
    1773                 :       }
    1774            3951 :       if (filepos >= info->state->data_file_length)
    1775                 :       {
    1776            3951 :         my_errno= HA_ERR_END_OF_FILE;
    1777            3951 :         goto err;
    1778                 :       }
    1779                 :     }
    1780           84877 :     if (info->opt_flag & READ_CACHE_USED)
    1781                 :     {
    1782            9657 :       if (_ma_read_cache(&info->rec_cache, block_info.header, filepos,
    1783                 :                          sizeof(block_info.header),
    1784                 :                          (!block_of_record && skip_deleted_blocks ?
    1785                 :                           READING_NEXT : 0) | READING_HEADER))
    1786            9657 :         goto panic;
    1787            9657 :       b_type= _ma_get_block_info(&block_info,-1,filepos);
    1788                 :     }
    1789                 :     else
    1790                 :     {
    1791           75220 :       if (info->opt_flag & WRITE_CACHE_USED &&
    1792                 :           info->rec_cache.pos_in_file < filepos + MARIA_BLOCK_INFO_HEADER_LENGTH &&
    1793                 :           flush_io_cache(&info->rec_cache))
    1794               0 :         DBUG_RETURN(my_errno);
    1795           75220 :       info->rec_cache.seek_not_done=1;
    1796           75220 :       b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos);
    1797                 :     }
    1798                 : 
    1799           84877 :     if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
    1800                 :                   BLOCK_FATAL_ERROR))
    1801                 :     {
    1802           13303 :       if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
    1803                 :           && skip_deleted_blocks)
    1804                 :       {
    1805           13303 :         filepos=block_info.filepos+block_info.block_len;
    1806           13303 :         block_info.second_read=0;
    1807           13303 :         continue;               /* Search after next_record */
    1808                 :       }
    1809               0 :       if (b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
    1810                 :       {
    1811               0 :         my_errno= HA_ERR_RECORD_DELETED;
    1812               0 :         info->cur_row.lastpos= block_info.filepos;
    1813               0 :         info->cur_row.nextpos= block_info.filepos+block_info.block_len;
    1814                 :       }
    1815                 :       goto err;
    1816                 :     }
    1817           71574 :     if (block_of_record == 0)                           /* First block */
    1818                 :     {
    1819           67429 :       info->cur_row.total_length= block_info.rec_len;
    1820           67429 :       if (block_info.rec_len > (uint) share->base.max_pack_length)
    1821           67429 :         goto panic;
    1822           67429 :       info->cur_row.lastpos= filepos;
    1823           67429 :       if (share->base.blobs)
    1824                 :       {
    1825           10102 :         if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size,
    1826                 :                              block_info.rec_len +
    1827                 :                              info->s->base.extra_rec_buff_size))
    1828           67429 :           goto err;
    1829                 :       }
    1830           67429 :       to= info->rec_buff;
    1831           67429 :       left_len=block_info.rec_len;
    1832                 :     }
    1833           71574 :     if (left_len < block_info.data_len)
    1834           71574 :       goto panic;                               /* Wrong linked record */
    1835                 : 
    1836                 :     /* copy information that is already read */
    1837                 :     {
    1838           71574 :       uint offset=(uint) (block_info.filepos - filepos);
    1839           71574 :       uint tmp_length= (sizeof(block_info.header) - offset);
    1840           71574 :       filepos=block_info.filepos;
    1841                 : 
    1842           71574 :       if (tmp_length > block_info.data_len)
    1843             490 :         tmp_length= block_info.data_len;
    1844           71574 :       if (tmp_length)
    1845                 :       {
    1846           71574 :         memcpy(to, block_info.header+offset, tmp_length);
    1847           71574 :         block_info.data_len-=tmp_length;
    1848           71574 :         left_len-=tmp_length;
    1849           71574 :         to+=tmp_length;
    1850           71574 :         filepos+=tmp_length;
    1851                 :      }
    1852                 :     }
    1853                 :     /* read rest of record from file */
    1854           71574 :     if (block_info.data_len)
    1855                 :     {
    1856           70771 :       if (info->opt_flag & READ_CACHE_USED)
    1857                 :       {
    1858            7983 :         if (_ma_read_cache(&info->rec_cache, to,filepos,
    1859                 :                            block_info.data_len,
    1860                 :                            (!block_of_record && skip_deleted_blocks) ?
    1861                 :                            READING_NEXT : 0))
    1862                 :           goto panic;
    1863                 :       }
    1864                 :       else
    1865                 :       {
    1866           62788 :         if (info->opt_flag & WRITE_CACHE_USED &&
    1867                 :             info->rec_cache.pos_in_file <
    1868                 :             block_info.filepos + block_info.data_len &&
    1869                 :             flush_io_cache(&info->rec_cache))
    1870           62788 :           goto err;
    1871                 :         /* VOID(my_seek(info->dfile.file, filepos, MY_SEEK_SET, MYF(0))); */
    1872           62788 :         if (my_read(info->dfile.file, to, block_info.data_len, MYF(MY_NABP)))
    1873                 :         {
    1874               0 :           if (my_errno == HA_ERR_FILE_TOO_SHORT)
    1875               0 :             my_errno= HA_ERR_WRONG_IN_RECORD;   /* Unexpected end of file */
    1876                 :           goto err;
    1877                 :         }
    1878                 :       }
    1879                 :     }
    1880                 :     /*
    1881                 :       Increment block-of-record counter. If it was the first block,
    1882                 :       remember the position behind the block for the next call.
    1883                 :     */
    1884           71574 :     if (block_of_record++ == 0)
    1885                 :     {
    1886           67429 :       info->cur_row.nextpos= block_info.filepos+block_info.block_len;
    1887           67429 :       skip_deleted_blocks=0;
    1888                 :     }
    1889           71574 :     left_len-=block_info.data_len;
    1890           71574 :     to+=block_info.data_len;
    1891           71574 :     filepos=block_info.next_filepos;
    1892           84877 :   } while (left_len);
    1893                 : 
    1894           67429 :   info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
    1895           67429 :   fast_ma_writeinfo(info);
    1896           67429 :   if (_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
    1897                 :       MY_FILE_ERROR)
    1898           67429 :     DBUG_RETURN(0);
    1899               0 :   DBUG_RETURN(my_errno);                        /* Wrong record */
    1900                 : 
    1901               0 : panic:
    1902               0 :   my_errno=HA_ERR_WRONG_IN_RECORD;              /* Something is fatal wrong */
    1903            3951 : err:
    1904            3951 :   fast_ma_writeinfo(info);
    1905            3951 :   DBUG_RETURN(my_errno);
    1906                 : }
    1907                 : 
    1908                 : 
    1909                 :         /* Read and process header from a dynamic-record-file */
    1910                 : 
    1911                 : uint _ma_get_block_info(MARIA_BLOCK_INFO *info, File file, my_off_t filepos)
    1912          303117 : {
    1913          303117 :   uint return_val=0;
    1914          303117 :   uchar *header=info->header;
    1915                 : 
    1916          303117 :   if (file >= 0)
    1917                 :   {
    1918                 :     /*
    1919                 :       We do not use my_pread() here because we want to have the file
    1920                 :       pointer set to the end of the header after this function.
    1921                 :       my_pread() may leave the file pointer untouched.
    1922                 :     */
    1923          239679 :     VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
    1924          239679 :     if (my_read(file, header, sizeof(info->header),MYF(0)) !=
    1925                 :         sizeof(info->header))
    1926          303071 :       goto err;
    1927                 :   }
    1928          303071 :   DBUG_DUMP("header",header,MARIA_BLOCK_INFO_HEADER_LENGTH);
    1929          303075 :   if (info->second_read)
    1930                 :   {
    1931           10459 :     if (info->header[0] <= 6 || info->header[0] == 13)
    1932               0 :       return_val=BLOCK_SYNC_ERROR;
    1933                 :   }
    1934                 :   else
    1935                 :   {
    1936          292616 :     if (info->header[0] > 6 && info->header[0] != 13)
    1937            5837 :       return_val=BLOCK_SYNC_ERROR;
    1938                 :   }
    1939          303075 :   info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
    1940                 : 
    1941          303075 :   switch (info->header[0]) {
    1942                 :   case 0:
    1943           61216 :     if ((info->block_len=(uint) mi_uint3korr(header+1)) <
    1944                 :         MARIA_MIN_BLOCK_LENGTH ||
    1945                 :         (info->block_len & (MARIA_DYN_ALIGN_SIZE -1)))
    1946                 :       goto err;
    1947           61213 :     info->filepos=filepos;
    1948           61213 :     info->next_filepos=mi_sizekorr(header+4);
    1949           61213 :     info->prev_filepos=mi_sizekorr(header+12);
    1950                 : #if SIZEOF_OFF_T == 4
    1951                 :     if ((mi_uint4korr(header+4) != 0 &&
    1952                 :          (mi_uint4korr(header+4) != (ulong) ~0 ||
    1953                 :           info->next_filepos != (ulong) ~0)) ||
    1954                 :         (mi_uint4korr(header+12) != 0 &&
    1955                 :          (mi_uint4korr(header+12) != (ulong) ~0 ||
    1956                 :           info->prev_filepos != (ulong) ~0)))
    1957                 :       goto err;
    1958                 : #endif
    1959           61213 :     return return_val | BLOCK_DELETED;          /* Deleted block */
    1960                 : 
    1961                 :   case 1:
    1962           52823 :     info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
    1963           52823 :     info->filepos=filepos+3;
    1964           52823 :     return return_val | BLOCK_FIRST | BLOCK_LAST;
    1965                 :   case 2:
    1966               4 :     info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
    1967               4 :     info->filepos=filepos+4;
    1968               4 :     return return_val | BLOCK_FIRST | BLOCK_LAST;
    1969                 : 
    1970                 :   case 13:
    1971               0 :     info->rec_len=mi_uint4korr(header+1);
    1972               0 :     info->block_len=info->data_len=mi_uint3korr(header+5);
    1973               0 :     info->next_filepos=mi_sizekorr(header+8);
    1974               0 :     info->second_read=1;
    1975               0 :     info->filepos=filepos+16;
    1976               0 :     return return_val | BLOCK_FIRST;
    1977                 : 
    1978                 :   case 3:
    1979          164622 :     info->rec_len=info->data_len=mi_uint2korr(header+1);
    1980          164622 :     info->block_len=info->rec_len+ (uint) header[3];
    1981          164622 :     info->filepos=filepos+4;
    1982          164622 :     return return_val | BLOCK_FIRST | BLOCK_LAST;
    1983                 :   case 4:
    1984              13 :     info->rec_len=info->data_len=mi_uint3korr(header+1);
    1985              13 :     info->block_len=info->rec_len+ (uint) header[4];
    1986              13 :     info->filepos=filepos+5;
    1987              13 :     return return_val | BLOCK_FIRST | BLOCK_LAST;
    1988                 : 
    1989                 :   case 5:
    1990            8100 :     info->rec_len=mi_uint2korr(header+1);
    1991            8100 :     info->block_len=info->data_len=mi_uint2korr(header+3);
    1992            8100 :     info->next_filepos=mi_sizekorr(header+5);
    1993            8100 :     info->second_read=1;
    1994            8100 :     info->filepos=filepos+13;
    1995            8100 :     return return_val | BLOCK_FIRST;
    1996                 :   case 6:
    1997               0 :     info->rec_len=mi_uint3korr(header+1);
    1998               0 :     info->block_len=info->data_len=mi_uint3korr(header+4);
    1999               0 :     info->next_filepos=mi_sizekorr(header+7);
    2000               0 :     info->second_read=1;
    2001               0 :     info->filepos=filepos+15;
    2002               0 :     return return_val | BLOCK_FIRST;
    2003                 : 
    2004                 :     /* The following blocks are identical to 1-6 without rec_len */
    2005                 :   case 7:
    2006            1150 :     info->data_len=info->block_len=mi_uint2korr(header+1);
    2007            1150 :     info->filepos=filepos+3;
    2008            1150 :     return return_val | BLOCK_LAST;
    2009                 :   case 8:
    2010               0 :     info->data_len=info->block_len=mi_uint3korr(header+1);
    2011               0 :     info->filepos=filepos+4;
    2012               0 :     return return_val | BLOCK_LAST;
    2013                 : 
    2014                 :   case 9:
    2015           10896 :     info->data_len=mi_uint2korr(header+1);
    2016           10896 :     info->block_len=info->data_len+ (uint) header[3];
    2017           10896 :     info->filepos=filepos+4;
    2018           10896 :     return return_val | BLOCK_LAST;
    2019                 :   case 10:
    2020               0 :     info->data_len=mi_uint3korr(header+1);
    2021               0 :     info->block_len=info->data_len+ (uint) header[4];
    2022               0 :     info->filepos=filepos+5;
    2023               0 :     return return_val | BLOCK_LAST;
    2024                 : 
    2025                 :   case 11:
    2026            4197 :     info->data_len=info->block_len=mi_uint2korr(header+1);
    2027            4197 :     info->next_filepos=mi_sizekorr(header+3);
    2028            4197 :     info->second_read=1;
    2029            4197 :     info->filepos=filepos+11;
    2030            4197 :     return return_val;
    2031                 :   case 12:
    2032               0 :     info->data_len=info->block_len=mi_uint3korr(header+1);
    2033               0 :     info->next_filepos=mi_sizekorr(header+4);
    2034               0 :     info->second_read=1;
    2035               0 :     info->filepos=filepos+12;
    2036               0 :     return return_val;
    2037                 :   }
    2038                 : 
    2039             103 : err:
    2040             103 :   my_errno=HA_ERR_WRONG_IN_RECORD;       /* Garbage */
    2041             103 :   return BLOCK_ERROR;
    2042                 : }

Generated by: LTP GCOV extension version 1.4