LTP GCOV extension - code coverage report
Current view: directory - storage/maria - ma_dynrec.c
Test: maria-mtr.html
Date: 2009-03-04 Instrumented lines: 865
Code covered: 0.3 % Executed lines: 3

       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               0 : {
     170               0 :   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               0 : {
     227               0 :   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               0 : {
     233                 :   ulong reclength= _ma_rec_pack(info,info->rec_buff + MARIA_REC_BUFF_OFFSET,
     234               0 :                                 record);
     235               0 :   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               0 : {
     243                 :   uint length= _ma_rec_pack(info, info->rec_buff + MARIA_REC_BUFF_OFFSET,
     244               0 :                             record);
     245               0 :   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               0 : {
     253                 :   uchar *rec_buff;
     254                 :   int error;
     255                 :   ulong reclength,reclength2,extra;
     256                 : 
     257               0 :   extra= (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
     258                 :           MARIA_DYN_DELETE_BLOCK_HEADER+1);
     259               0 :   reclength= (info->s->base.pack_reclength +
     260                 :               _ma_calc_total_blob_length(info,record)+ extra);
     261               0 :   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               0 :   reclength2= _ma_rec_pack(info,
     267                 :                            rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
     268                 :                            record);
     269               0 :   DBUG_PRINT("info",("reclength: %lu  reclength2: %lu",
     270                 :                      reclength, reclength2));
     271               0 :   DBUG_ASSERT(reclength2 <= reclength);
     272               0 :   error= write_dynamic_record(info,
     273                 :                               rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
     274                 :                               reclength2);
     275               0 :   my_afree(rec_buff);
     276               0 :   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               0 : {
     284                 :   uchar *rec_buff;
     285                 :   int error;
     286                 :   ulong reclength,extra;
     287                 : 
     288               0 :   extra= (ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER)+MARIA_SPLIT_LENGTH+
     289                 :           MARIA_DYN_DELETE_BLOCK_HEADER);
     290               0 :   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               0 :   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               0 :   reclength= _ma_rec_pack(info,rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
     305                 :                          record);
     306               0 :   error=update_dynamic_record(info,pos,
     307                 :                               rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
     308                 :                               reclength);
     309               0 :   my_afree(rec_buff);
     310               0 :   return(error != 0);
     311                 : }
     312                 : 
     313                 : 
     314                 : my_bool _ma_delete_dynamic_record(MARIA_HA *info,
     315                 :                                   const uchar *record __attribute__ ((unused)))
     316               0 : {
     317               0 :   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               0 : {
     330                 :   int flag;
     331                 :   ulong length;
     332                 :   my_off_t filepos;
     333               0 :   DBUG_ENTER("write_dynamic_record");
     334                 : 
     335               0 :   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               0 :   if (unlikely(info->s->base.max_data_file_length -
     347                 :                info->state->data_file_length <
     348                 :                reclength + MARIA_MAX_DYN_BLOCK_HEADER))
     349                 :   {
     350               0 :     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               0 :       my_errno=HA_ERR_RECORD_FILE_FULL;
     355               0 :       DBUG_RETURN(1);
     356                 :     }
     357                 :   }
     358                 : 
     359                 :   do
     360                 :   {
     361               0 :     if (_ma_find_writepos(info,reclength,&filepos,&length))
     362               0 :       goto err;
     363               0 :     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               0 :       goto err;
     368               0 :   } while (reclength);
     369                 : 
     370               0 :   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               0 : {
     383                 :   MARIA_BLOCK_INFO block_info;
     384                 :   ulong tmp;
     385               0 :   DBUG_ENTER("_ma_find_writepos");
     386                 : 
     387               0 :   if (info->s->state.dellink != HA_OFFSET_ERROR &&
     388                 :       !info->append_insert_at_end)
     389                 :   {
     390                 :     /* Deleted blocks exists;  Get last used block */
     391               0 :     *filepos=info->s->state.dellink;
     392               0 :     block_info.second_read=0;
     393               0 :     info->rec_cache.seek_not_done=1;
     394               0 :     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               0 :     info->s->state.dellink=block_info.next_filepos;
     403               0 :     info->state->del--;
     404               0 :     info->state->empty-= block_info.block_len;
     405               0 :     *length= block_info.block_len;
     406                 :   }
     407                 :   else
     408                 :   {
     409                 :     /* No deleted blocks;  Allocate a new block */
     410               0 :     *filepos=info->state->data_file_length;
     411               0 :     if ((tmp=reclength+3 + test(reclength >= (65520-3))) <
     412                 :         info->s->base.min_block_length)
     413               0 :       tmp= info->s->base.min_block_length;
     414                 :     else
     415               0 :       tmp= ((tmp+MARIA_DYN_ALIGN_SIZE-1) &
     416                 :             (~ (ulong) (MARIA_DYN_ALIGN_SIZE-1)));
     417               0 :     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               0 :     if (tmp > MARIA_MAX_BLOCK_LENGTH)
     424               0 :       tmp=MARIA_MAX_BLOCK_LENGTH;
     425               0 :     *length= tmp;
     426               0 :     info->state->data_file_length+= tmp;
     427               0 :     info->s->state.split++;
     428               0 :     info->update|=HA_STATE_WRITE_AT_END;
     429                 :   }
     430               0 :   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               0 : {
     444               0 :   DBUG_ENTER("unlink_deleted_block");
     445               0 :   if (block_info->filepos == info->s->state.dellink)
     446                 :   {
     447                 :     /* First deleted block;  We can just use this ! */
     448               0 :     info->s->state.dellink=block_info->next_filepos;
     449                 :   }
     450                 :   else
     451                 :   {
     452                 :     MARIA_BLOCK_INFO tmp;
     453               0 :     tmp.second_read=0;
     454                 :     /* Unlink block from the previous block */
     455               0 :     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               0 :     mi_sizestore(tmp.header+4,block_info->next_filepos);
     459               0 :     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               0 :     if (block_info->next_filepos != HA_OFFSET_ERROR)
     464                 :     {
     465               0 :       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               0 :       mi_sizestore(tmp.header+12,block_info->prev_filepos);
     470               0 :       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               0 :   info->state->del--;
     478               0 :   info->state->empty-= block_info->block_len;
     479               0 :   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               0 :   if (info->cur_row.nextpos == block_info->filepos)
     487               0 :     info->cur_row.nextpos+= block_info->block_len;
     488               0 :   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               0 : {
     511                 :   MARIA_BLOCK_INFO block_info;
     512               0 :   DBUG_ENTER("update_backward_delete_link");
     513                 : 
     514               0 :   if (delete_block != HA_OFFSET_ERROR)
     515                 :   {
     516               0 :     block_info.second_read=0;
     517               0 :     if (_ma_get_block_info(&block_info, info->dfile.file, delete_block)
     518                 :         & BLOCK_DELETED)
     519                 :     {
     520                 :       uchar buff[8];
     521               0 :       mi_sizestore(buff,filepos);
     522               0 :       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               0 :   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               0 : {
     540                 :   uint length,b_type;
     541                 :   MARIA_BLOCK_INFO block_info,del_block;
     542                 :   int error;
     543                 :   my_bool remove_next_block;
     544               0 :   DBUG_ENTER("delete_dynamic_record");
     545                 : 
     546                 :   /* First add a link from the last block to the new one */
     547               0 :   error= update_backward_delete_link(info, info->s->state.dellink, filepos);
     548                 : 
     549               0 :   block_info.second_read=second_read;
     550                 :   do
     551                 :   {
     552                 :     /* Remove block at 'filepos' */
     553               0 :     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               0 :     del_block.second_read=0;
     564               0 :     remove_next_block=0;
     565               0 :     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               0 :       remove_next_block=1;
     571               0 :       length+=del_block.block_len;
     572                 :     }
     573                 : 
     574               0 :     block_info.header[0]=0;
     575               0 :     mi_int3store(block_info.header+1,length);
     576               0 :     mi_sizestore(block_info.header+4,info->s->state.dellink);
     577               0 :     if (b_type & BLOCK_LAST)
     578               0 :       bfill(block_info.header+12,8,255);
     579                 :     else
     580               0 :       mi_sizestore(block_info.header+12,block_info.next_filepos);
     581               0 :     if (info->s->file_write(info, block_info.header, 20, filepos,
     582                 :                   MYF(MY_NABP)))
     583               0 :       DBUG_RETURN(1);
     584               0 :     info->s->state.dellink = filepos;
     585               0 :     info->state->del++;
     586               0 :     info->state->empty+=length;
     587               0 :     filepos=block_info.next_filepos;
     588                 : 
     589                 :     /* Now it's safe to unlink the deleted block directly after this one */
     590               0 :     if (remove_next_block && unlink_deleted_block(info,&del_block))
     591               0 :       error=1;
     592               0 :   } while (!(b_type & BLOCK_LAST));
     593                 : 
     594               0 :   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               0 : {
     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               0 :   DBUG_ENTER("_ma_write_part_record");
     613                 : 
     614               0 :   next_delete_block=HA_OFFSET_ERROR;
     615                 : 
     616               0 :   res_length=extra_length=0;
     617               0 :   if (length > *reclength + MARIA_SPLIT_LENGTH)
     618                 :   {                                             /* Splitt big block */
     619               0 :     res_length=MY_ALIGN(length- *reclength - MARIA_EXTEND_BLOCK_LENGTH,
     620                 :                         MARIA_DYN_ALIGN_SIZE);
     621               0 :     length-= res_length;                        /* Use this for first part */
     622                 :   }
     623               0 :   long_block= (length < 65520L && *reclength < 65520L) ? 0 : 1;
     624               0 :   if (length == *reclength+ 3 + long_block)
     625                 :   {
     626                 :     /* Block is exactly of the right length */
     627               0 :     temp[0]=(uchar) (1+ *flag)+(uchar) long_block;      /* Flag is 0 or 6 */
     628               0 :     if (long_block)
     629                 :     {
     630               0 :       mi_int3store(temp+1,*reclength);
     631               0 :       head_length=4;
     632                 :     }
     633                 :     else
     634                 :     {
     635               0 :       mi_int2store(temp+1,*reclength);
     636               0 :       head_length=3;
     637                 :     }
     638                 :   }
     639               0 :   else if (length-long_block < *reclength+4)
     640                 :   {                                             /* To short block */
     641               0 :     if (next_filepos == HA_OFFSET_ERROR)
     642               0 :       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               0 :     if (*flag == 0)                             /* First block */
     646                 :     {
     647               0 :       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               0 :         head_length=5+8+long_block*2;
     658               0 :         temp[0]=5+(uchar) long_block;
     659               0 :         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               0 :           mi_int2store(temp+1,*reclength);
     668               0 :           mi_int2store(temp+3,length-head_length);
     669               0 :           mi_sizestore(temp+5,next_filepos);
     670                 :         }
     671                 :       }
     672                 :     }
     673                 :     else
     674                 :     {
     675               0 :       head_length=3+8+long_block;
     676               0 :       temp[0]=11+(uchar) long_block;
     677               0 :       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               0 :         mi_int2store(temp+1,length-head_length);
     685               0 :         mi_sizestore(temp+3,next_filepos);
     686                 :       }
     687                 :     }
     688                 :   }
     689                 :   else
     690                 :   {                                     /* Block with empty info last */
     691               0 :     head_length=4+long_block;
     692               0 :     extra_length= length- *reclength-head_length;
     693               0 :     temp[0]= (uchar) (3+ *flag)+(uchar) long_block; /* 3,4 or 9,10 */
     694               0 :     if (long_block)
     695                 :     {
     696               0 :       mi_int3store(temp+1,*reclength);
     697               0 :       temp[4]= (uchar) (extra_length);
     698                 :     }
     699                 :     else
     700                 :     {
     701               0 :       mi_int2store(temp+1,*reclength);
     702               0 :       temp[3]= (uchar) (extra_length);
     703                 :     }
     704               0 :     length= *reclength+head_length;     /* Write only what is needed */
     705                 :   }
     706               0 :   DBUG_DUMP("header", temp, head_length);
     707                 : 
     708                 :         /* Make a long block for one write */
     709               0 :   record_end= *record+length-head_length;
     710               0 :   del_length=(res_length ? MARIA_DYN_DELETE_BLOCK_HEADER : 0);
     711               0 :   bmove((*record-head_length), temp, head_length);
     712               0 :   memcpy(temp,record_end,(size_t) (extra_length+del_length));
     713               0 :   bzero(record_end, extra_length);
     714                 : 
     715               0 :   if (res_length)
     716                 :   {
     717                 :     /* Check first if we can join this block with the next one */
     718                 :     MARIA_BLOCK_INFO del_block;
     719               0 :     my_off_t next_block=filepos+length+extra_length+res_length;
     720                 : 
     721               0 :     del_block.second_read=0;
     722               0 :     if (next_block < info->state->data_file_length &&
     723                 :         info->s->state.dellink != HA_OFFSET_ERROR)
     724                 :     {
     725               0 :       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               0 :         if (unlink_deleted_block(info,&del_block))
     730               0 :           goto err;
     731               0 :         res_length+=del_block.block_len;
     732                 :       }
     733                 :     }
     734                 : 
     735                 :     /* Create a delete link of the last part of the block */
     736               0 :     pos=record_end+extra_length;
     737               0 :     pos[0]= '\0';
     738               0 :     mi_int3store(pos+1,res_length);
     739               0 :     mi_sizestore(pos+4,info->s->state.dellink);
     740               0 :     bfill(pos+12,8,255);                        /* End link */
     741               0 :     next_delete_block=info->s->state.dellink;
     742               0 :     info->s->state.dellink= filepos+length+extra_length;
     743               0 :     info->state->del++;
     744               0 :     info->state->empty+=res_length;
     745               0 :     info->s->state.split++;
     746                 :   }
     747               0 :   if (info->opt_flag & WRITE_CACHE_USED &&
     748                 :       info->update & HA_STATE_WRITE_AT_END)
     749                 :   {
     750               0 :     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               0 :     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               0 :     info->rec_cache.seek_not_done=1;
     764               0 :     if (info->s->file_write(info, *record-head_length,
     765                 :                             length+extra_length+
     766                 :                             del_length,filepos,info->s->write_flag))
     767               0 :       goto err;
     768                 :   }
     769               0 :   memcpy(record_end,temp,(size_t) (extra_length+del_length));
     770               0 :   *record=record_end;
     771               0 :   *reclength-=(length-head_length);
     772               0 :   *flag=6;
     773                 : 
     774               0 :   if (del_length)
     775                 :   {
     776                 :     /* link the next delete block to this */
     777               0 :     if (update_backward_delete_link(info, next_delete_block,
     778                 :                                     info->s->state.dellink))
     779               0 :       goto err;
     780                 :   }
     781                 : 
     782               0 :   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               0 : {
     794                 :   int flag;
     795                 :   uint error;
     796                 :   ulong length;
     797                 :   MARIA_BLOCK_INFO block_info;
     798               0 :   DBUG_ENTER("update_dynamic_record");
     799                 : 
     800               0 :   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               0 :   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               0 :   info->cur_row.total_length= reclength;
     831                 : 
     832               0 :   while (reclength > 0)
     833                 :   {
     834               0 :     if (filepos != info->s->state.dellink)
     835                 :     {
     836               0 :       block_info.next_filepos= HA_OFFSET_ERROR;
     837               0 :       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               0 :       length=(ulong) (block_info.filepos-filepos) + block_info.block_len;
     847               0 :       if (length < reclength)
     848                 :       {
     849               0 :         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               0 :         tmp= min(length+tmp, MARIA_MAX_BLOCK_LENGTH)-length;
     853                 :         /* Check if we can extend this block */
     854               0 :         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               0 :           DBUG_PRINT("info",("Extending file with %d bytes",tmp));
     861               0 :           if (info->cur_row.nextpos == info->state->data_file_length)
     862               0 :             info->cur_row.nextpos+= tmp;
     863               0 :           info->state->data_file_length+= tmp;
     864               0 :           info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK;
     865               0 :           length+=tmp;
     866                 :         }
     867               0 :         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               0 :           del_block.second_read=0;
     878               0 :           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               0 :             DBUG_PRINT("info",("Extending current block"));
     884               0 :             if (unlink_deleted_block(info,&del_block))
     885               0 :               goto err;
     886               0 :             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               0 :       if (_ma_find_writepos(info,reclength,&filepos,&length))
     922               0 :         goto err;
     923                 :     }
     924               0 :     if (_ma_write_part_record(info,filepos,length,block_info.next_filepos,
     925                 :                               &record,&reclength,&flag))
     926               0 :       goto err;
     927               0 :     if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR)
     928                 :     {
     929                 :       /* Start writing data on deleted blocks */
     930               0 :       filepos=info->s->state.dellink;
     931                 :     }
     932                 :   }
     933                 : 
     934               0 :   if (block_info.next_filepos != HA_OFFSET_ERROR)
     935               0 :     if (delete_dynamic_record(info,block_info.next_filepos,1))
     936               0 :       goto err;
     937                 : 
     938               0 :   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               0 : {
     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               0 :   DBUG_ENTER("_ma_rec_pack");
     956                 : 
     957               0 :   flag= 0;
     958               0 :   bit= 1;
     959               0 :   startpos= packpos=to;
     960               0 :   to+= info->s->base.pack_bytes;
     961               0 :   blob= info->blobs;
     962               0 :   column= info->s->columndef;
     963               0 :   if (info->s->base.null_bytes)
     964                 :   {
     965               0 :     memcpy(to, from, info->s->base.null_bytes);
     966               0 :     from+= info->s->base.null_bytes;
     967               0 :     to+=   info->s->base.null_bytes;
     968                 :   }
     969                 : 
     970               0 :   for (i=info->s->base.fields ; i-- > 0; from+= length, column++)
     971                 :   {
     972               0 :     length=(uint) column->length;
     973               0 :     if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL)
     974                 :     {
     975               0 :       if (type == FIELD_BLOB)
     976                 :       {
     977               0 :         if (!blob->length)
     978               0 :           flag|=bit;
     979                 :         else
     980                 :         {
     981                 :           char *temp_pos;
     982               0 :           size_t tmp_length=length-portable_sizeof_char_ptr;
     983               0 :           memcpy(to,from,tmp_length);
     984               0 :           memcpy_fixed(&temp_pos,from+tmp_length,sizeof(char*));
     985               0 :           memcpy(to+tmp_length,temp_pos,(size_t) blob->length);
     986               0 :           to+=tmp_length+blob->length;
     987                 :         }
     988               0 :         blob++;
     989                 :       }
     990               0 :       else if (type == FIELD_SKIP_ZERO)
     991                 :       {
     992               0 :         if (memcmp(from, maria_zero_string, length) == 0)
     993               0 :           flag|=bit;
     994                 :         else
     995                 :         {
     996               0 :           memcpy(to, from, (size_t) length);
     997               0 :           to+=length;
     998                 :         }
     999                 :       }
    1000               0 :       else if (type == FIELD_SKIP_ENDSPACE ||
    1001                 :                type == FIELD_SKIP_PRESPACE)
    1002                 :       {
    1003               0 :         pos= from; end= from + length;
    1004               0 :         if (type == FIELD_SKIP_ENDSPACE)
    1005                 :         {                                       /* Pack trailing spaces */
    1006               0 :           while (end > from && *(end-1) == ' ')
    1007               0 :             end--;
    1008                 :         }
    1009                 :         else
    1010                 :         {                                       /* Pack pref-spaces */
    1011               0 :           while (pos < end && *pos == ' ')
    1012               0 :             pos++;
    1013                 :         }
    1014               0 :         new_length=(uint) (end-pos);
    1015               0 :         if (new_length +1 + test(column->length > 255 && new_length > 127)
    1016                 :             < length)
    1017                 :         {
    1018               0 :           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               0 :             *to++= (uchar) new_length;
    1026               0 :           memcpy(to, pos, (size_t) new_length); to+=new_length;
    1027               0 :           flag|=bit;
    1028                 :         }
    1029                 :         else
    1030                 :         {
    1031               0 :           memcpy(to,from,(size_t) length); to+=length;
    1032                 :         }
    1033                 :       }
    1034               0 :       else if (type == FIELD_VARCHAR)
    1035                 :       {
    1036               0 :         uint pack_length= HA_VARCHAR_PACKLENGTH(column->length -1);
    1037                 :         uint tmp_length;
    1038               0 :         if (pack_length == 1)
    1039                 :         {
    1040               0 :           tmp_length= (uint) *from;
    1041               0 :           *to++= *from;
    1042                 :         }
    1043                 :         else
    1044                 :         {
    1045               0 :           tmp_length= uint2korr(from);
    1046               0 :           store_key_length_inc(to,tmp_length);
    1047                 :         }
    1048               0 :         memcpy(to, from+pack_length,tmp_length);
    1049               0 :         to+= tmp_length;
    1050               0 :         continue;
    1051                 :       }
    1052                 :       else
    1053                 :       {
    1054               0 :         memcpy(to,from,(size_t) length); to+=length;
    1055               0 :         continue;                               /* Normal field */
    1056                 :       }
    1057               0 :       if ((bit= bit << 1) >= 256)
    1058                 :       {
    1059               0 :         *packpos++ = (uchar) flag;
    1060               0 :         bit=1; flag=0;
    1061                 :       }
    1062                 :     }
    1063                 :     else
    1064                 :     {
    1065               0 :       memcpy(to,from,(size_t) length); to+=length;
    1066                 :     }
    1067                 :   }
    1068               0 :   if (bit != 1)
    1069               0 :     *packpos= (uchar) flag;
    1070               0 :   if (info->s->calc_checksum)
    1071               0 :     *to++= (uchar) info->cur_row.checksum;
    1072               0 :   DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos)));
    1073               0 :   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               0 : {
    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               0 :   DBUG_ENTER("_ma_rec_check");
    1093                 : 
    1094               0 :   packpos=rec_buff; to= rec_buff+info->s->base.pack_bytes;
    1095               0 :   column= info->s->columndef;
    1096               0 :   flag= *packpos; bit=1;
    1097               0 :   record+= info->s->base.null_bytes;
    1098               0 :   to+= info->s->base.null_bytes;
    1099                 : 
    1100               0 :   for (i=info->s->base.fields ; i-- > 0; record+= length, column++)
    1101                 :   {
    1102               0 :     length=(uint) column->length;
    1103               0 :     if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL)
    1104                 :     {
    1105               0 :       if (type == FIELD_BLOB)
    1106                 :       {
    1107                 :         uint blob_length=
    1108               0 :           _ma_calc_blob_length(length-portable_sizeof_char_ptr,record);
    1109               0 :         if (!blob_length && !(flag & bit))
    1110               0 :           goto err;
    1111               0 :         if (blob_length)
    1112               0 :           to+=length - portable_sizeof_char_ptr+ blob_length;
    1113                 :       }
    1114               0 :       else if (type == FIELD_SKIP_ZERO)
    1115                 :       {
    1116               0 :         if (memcmp(record, maria_zero_string, length) == 0)
    1117                 :         {
    1118               0 :           if (!(flag & bit))
    1119                 :             goto err;
    1120                 :         }
    1121                 :         else
    1122               0 :           to+=length;
    1123                 :       }
    1124               0 :       else if (type == FIELD_SKIP_ENDSPACE ||
    1125                 :                type == FIELD_SKIP_PRESPACE)
    1126                 :       {
    1127               0 :         pos= record; end= record + length;
    1128               0 :         if (type == FIELD_SKIP_ENDSPACE)
    1129                 :         {                                       /* Pack trailing spaces */
    1130               0 :           while (end > record && *(end-1) == ' ')
    1131               0 :             end--;
    1132                 :         }
    1133                 :         else
    1134                 :         {                                       /* Pack pre-spaces */
    1135               0 :           while (pos < end && *pos == ' ')
    1136               0 :             pos++;
    1137                 :         }
    1138               0 :         new_length=(uint) (end-pos);
    1139               0 :         if (new_length +1 + test(column->length > 255 && new_length > 127)
    1140                 :             < length)
    1141                 :         {
    1142               0 :           if (!(flag & bit))
    1143               0 :             goto err;
    1144               0 :           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               0 :           else if (*to++ != (uchar) new_length)
    1154               0 :             goto err;
    1155               0 :           to+=new_length;
    1156                 :         }
    1157                 :         else
    1158               0 :           to+=length;
    1159                 :       }
    1160               0 :       else if (type == FIELD_VARCHAR)
    1161                 :       {
    1162               0 :         uint pack_length= HA_VARCHAR_PACKLENGTH(column->length -1);
    1163                 :         uint tmp_length;
    1164               0 :         if (pack_length == 1)
    1165                 :         {
    1166               0 :           tmp_length= (uint) *record;
    1167               0 :           to+= 1+ tmp_length;
    1168               0 :           continue;
    1169                 :         }
    1170                 :         else
    1171                 :         {
    1172               0 :           tmp_length= uint2korr(record);
    1173               0 :           to+= get_pack_length(tmp_length)+tmp_length;
    1174                 :         }
    1175               0 :         continue;
    1176                 :       }
    1177                 :       else
    1178                 :       {
    1179               0 :         to+=length;
    1180               0 :         continue;                               /* Normal field */
    1181                 :       }
    1182               0 :       if ((bit= bit << 1) >= 256)
    1183                 :       {
    1184               0 :         flag= *++packpos;
    1185               0 :         bit=1;
    1186                 :       }
    1187                 :     }
    1188                 :     else
    1189               0 :       to+= length;
    1190                 :   }
    1191               0 :   if (packed_length != (uint) (to - rec_buff) +
    1192                 :       test(info->s->calc_checksum) || (bit != 1 && (flag & ~(bit - 1))))
    1193                 :     goto err;
    1194               0 :   if (with_checksum && ((uchar) checksum != (uchar) *to))
    1195                 :   {
    1196               0 :     DBUG_PRINT("error",("wrong checksum for row"));
    1197               0 :     goto err;
    1198                 :   }
    1199               0 :   DBUG_RETURN(0);
    1200                 : 
    1201               0 : err:
    1202               0 :   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               0 : {
    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               0 :   DBUG_ENTER("_ma_rec_unpack");
    1223                 : 
    1224               0 :   to_end=to + info->s->base.reclength;
    1225               0 :   from_end=from+found_length;
    1226               0 :   flag= (uchar) *from; bit=1; packpos=from;
    1227               0 :   if (found_length < info->s->base.min_pack_length)
    1228               0 :     goto err;
    1229               0 :   from+= info->s->base.pack_bytes;
    1230               0 :   min_pack_length= info->s->base.min_pack_length - info->s->base.pack_bytes;
    1231                 : 
    1232               0 :   if ((length= info->s->base.null_bytes))
    1233                 :   {
    1234               0 :     memcpy(to, from, length);
    1235               0 :     from+= length;
    1236               0 :     to+= length;
    1237               0 :     min_pack_length-= length;
    1238                 :   }
    1239                 : 
    1240               0 :   for (column= info->s->columndef, end_column= column + info->s->base.fields;
    1241               0 :        column < end_column ; to+= column_length, column++)
    1242                 :   {
    1243               0 :     column_length= column->length;
    1244               0 :     if ((type = (enum en_fieldtype) column->type) != FIELD_NORMAL &&
    1245                 :         (type != FIELD_CHECK))
    1246                 :     {
    1247               0 :       if (type == FIELD_VARCHAR)
    1248                 :       {
    1249               0 :         uint pack_length= HA_VARCHAR_PACKLENGTH(column_length-1);
    1250               0 :         if (pack_length == 1)
    1251                 :         {
    1252               0 :           length= (uint) *(uchar*) from;
    1253               0 :           if (length > column_length-1)
    1254               0 :             goto err;
    1255               0 :           *to= *from++;
    1256                 :         }
    1257                 :         else
    1258                 :         {
    1259               0 :           get_key_length(length, from);
    1260               0 :           if (length > column_length-2)
    1261               0 :             goto err;
    1262               0 :           int2store(to,length);
    1263                 :         }
    1264               0 :         if (from+length > from_end)
    1265               0 :           goto err;
    1266               0 :         memcpy(to+pack_length, from, length);
    1267               0 :         from+= length;
    1268               0 :         min_pack_length--;
    1269               0 :         continue;
    1270                 :       }
    1271               0 :       if (flag & bit)
    1272                 :       {
    1273               0 :         if (type == FIELD_BLOB || type == FIELD_SKIP_ZERO)
    1274               0 :           bzero(to, column_length);
    1275               0 :         else if (type == FIELD_SKIP_ENDSPACE ||
    1276                 :                  type == FIELD_SKIP_PRESPACE)
    1277                 :         {
    1278               0 :           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               0 :             if (from == from_end)
    1287               0 :               goto err;
    1288               0 :             length= (uchar) *from++;
    1289                 :           }
    1290               0 :           min_pack_length--;
    1291               0 :           if (length >= column_length ||
    1292                 :               min_pack_length + length > (uint) (from_end - from))
    1293                 :             goto err;
    1294               0 :           if (type == FIELD_SKIP_ENDSPACE)
    1295                 :           {
    1296               0 :             memcpy(to, from, (size_t) length);
    1297               0 :             bfill(to+length, column_length-length, ' ');
    1298                 :           }
    1299                 :           else
    1300                 :           {
    1301               0 :             bfill(to, column_length-length, ' ');
    1302               0 :             memcpy(to+column_length-length, from, (size_t) length);
    1303                 :           }
    1304               0 :           from+=length;
    1305                 :         }
    1306                 :       }
    1307               0 :       else if (type == FIELD_BLOB)
    1308                 :       {
    1309               0 :         uint size_length=column_length- portable_sizeof_char_ptr;
    1310               0 :         ulong blob_length= _ma_calc_blob_length(size_length,from);
    1311               0 :         ulong from_left= (ulong) (from_end - from);
    1312               0 :         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               0 :         memcpy(to, from, (size_t) size_length);
    1317               0 :         from+=size_length;
    1318               0 :         memcpy_fixed(to+size_length,(uchar*) &from,sizeof(char*));
    1319               0 :         from+=blob_length;
    1320                 :       }
    1321                 :       else
    1322                 :       {
    1323               0 :         if (type == FIELD_SKIP_ENDSPACE || type == FIELD_SKIP_PRESPACE)
    1324               0 :           min_pack_length--;
    1325               0 :         if (min_pack_length + column_length > (uint) (from_end - from))
    1326               0 :           goto err;
    1327               0 :         memcpy(to, from, (size_t) column_length); from+=column_length;
    1328                 :       }
    1329               0 :       if ((bit= bit << 1) >= 256)
    1330                 :       {
    1331               0 :         flag= (uchar) *++packpos; bit=1;
    1332                 :       }
    1333                 :     }
    1334                 :     else
    1335                 :     {
    1336               0 :       if (min_pack_length > (uint) (from_end - from))
    1337               0 :         goto err;
    1338               0 :       min_pack_length-=column_length;
    1339               0 :       memcpy(to, from, (size_t) column_length);
    1340               0 :       from+=column_length;
    1341                 :     }
    1342                 :   }
    1343               0 :   if (info->s->calc_checksum)
    1344               0 :     info->cur_row.checksum= (uint) (uchar) *from++;
    1345               0 :   if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1))))
    1346               0 :     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               0 : {
    1361                 :   ulong length;
    1362                 :   MARIA_BLOB *blob,*end;
    1363                 : 
    1364               0 :   for (length=0, blob= info->blobs, end=blob+info->s->base.blobs ;
    1365               0 :        blob != end;
    1366               0 :        blob++)
    1367                 :   {
    1368               0 :     blob->length= _ma_calc_blob_length(blob->pack_length,
    1369                 :                                        record + blob->offset);
    1370               0 :     length+=blob->length;
    1371                 :   }
    1372               0 :   return length;
    1373                 : }
    1374                 : 
    1375                 : 
    1376                 : ulong _ma_calc_blob_length(uint length, const uchar *pos)
    1377           10969 : {
    1378           10969 :   switch (length) {
    1379                 :   case 1:
    1380               0 :     return (uint) (uchar) *pos;
    1381                 :   case 2:
    1382               0 :     return (uint) uint2korr(pos);
    1383                 :   case 3:
    1384               0 :     return uint3korr(pos);
    1385                 :   case 4:
    1386           10969 :     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               0 : {
    1396               0 :   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               0 :     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               0 : {
    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               0 :   DBUG_ENTER("_ma_read_dynamic_record");
    1456                 : 
    1457               0 :   if (filepos == HA_OFFSET_ERROR)
    1458               0 :     goto err;
    1459                 : 
    1460               0 :   LINT_INIT(to);
    1461               0 :   LINT_INIT(left_length);
    1462               0 :   file= info->dfile.file;
    1463               0 :   block_of_record= 0;   /* First block of record is numbered as zero. */
    1464               0 :   block_info.second_read= 0;
    1465                 :   do
    1466                 :   {
    1467                 :     /* A corrupted table can have wrong pointers. (Bug# 19835) */
    1468               0 :     if (filepos == HA_OFFSET_ERROR)
    1469               0 :       goto panic;
    1470               0 :     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               0 :       goto err;
    1475               0 :     info->rec_cache.seek_not_done=1;
    1476               0 :     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               0 :     if (block_of_record++ == 0)                 /* First block */
    1485                 :     {
    1486               0 :       info->cur_row.total_length= block_info.rec_len;
    1487               0 :       if (block_info.rec_len > (uint) info->s->base.max_pack_length)
    1488               0 :         goto panic;
    1489               0 :       if (info->s->base.blobs)
    1490                 :       {
    1491               0 :         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               0 :           goto err;
    1495                 :       }
    1496               0 :       to= info->rec_buff;
    1497               0 :       left_length=block_info.rec_len;
    1498                 :     }
    1499               0 :     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               0 :       uint offset= (uint) (block_info.filepos - filepos);
    1504               0 :       uint prefetch_len= (sizeof(block_info.header) - offset);
    1505               0 :       filepos+= sizeof(block_info.header);
    1506                 : 
    1507               0 :       if (prefetch_len > block_info.data_len)
    1508               0 :         prefetch_len= block_info.data_len;
    1509               0 :       if (prefetch_len)
    1510                 :       {
    1511               0 :         memcpy(to, block_info.header + offset, prefetch_len);
    1512               0 :         block_info.data_len-= prefetch_len;
    1513               0 :         left_length-= prefetch_len;
    1514               0 :         to+= prefetch_len;
    1515                 :       }
    1516                 :     }
    1517                 :     /* read rest of record from file */
    1518               0 :     if (block_info.data_len)
    1519                 :     {
    1520               0 :       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               0 :         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               0 :       if (info->s->file_read(info, to, block_info.data_len,
    1530                 :                              filepos, MYF(MY_NABP)))
    1531               0 :         goto panic;
    1532               0 :       left_length-=block_info.data_len;
    1533               0 :       to+=block_info.data_len;
    1534                 :     }
    1535               0 :     filepos= block_info.next_filepos;
    1536               0 :   } while (left_length);
    1537                 : 
    1538               0 :   info->update|= HA_STATE_AKTIV;     /* We have a aktive record */
    1539               0 :   fast_ma_writeinfo(info);
    1540               0 :   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               0 : {
    1557                 :   uchar *old_rec_buff,*old_record;
    1558                 :   size_t old_rec_buff_size;
    1559                 :   my_bool error;
    1560               0 :   DBUG_ENTER("_ma_cmp_dynamic_unique");
    1561                 : 
    1562               0 :   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               0 :   old_rec_buff=      info->rec_buff;
    1567               0 :   old_rec_buff_size= info->rec_buff_size;
    1568                 : 
    1569               0 :   if (info->s->base.blobs)
    1570                 :   {
    1571               0 :     info->rec_buff= 0;
    1572               0 :     info->rec_buff_size= 0;
    1573                 :   }
    1574               0 :   error= _ma_read_dynamic_record(info, old_record, pos) != 0;
    1575               0 :   if (!error)
    1576               0 :     error=_ma_unique_comp(def, record, old_record, def->null_are_equal) != 0;
    1577               0 :   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               0 :   my_afree(old_record);
    1584               0 :   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               0 : {
    1593                 :   uint flag, reclength, b_type,cmp_length;
    1594                 :   my_off_t filepos;
    1595                 :   uchar *buffer;
    1596                 :   MARIA_BLOCK_INFO block_info;
    1597               0 :   my_bool error= 1;
    1598               0 :   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               0 :   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               0 :   info->rec_cache.seek_not_done=1;
    1610                 : 
    1611                 :         /* If nobody have touched the database we don't have to test rec */
    1612                 : 
    1613               0 :   buffer=info->rec_buff;
    1614               0 :   if ((info->opt_flag & READ_CHECK_USED))
    1615                 :   {                                             /* If check isn't disabled  */
    1616               0 :     if (info->s->base.blobs)
    1617                 :     {
    1618               0 :       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               0 :     reclength= _ma_rec_pack(info,buffer,record);
    1623               0 :     record= buffer;
    1624                 : 
    1625               0 :     filepos= info->cur_row.lastpos;
    1626               0 :     flag=block_info.second_read=0;
    1627               0 :     block_info.next_filepos=filepos;
    1628               0 :     while (reclength > 0)
    1629                 :     {
    1630               0 :       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               0 :       if (flag == 0)                            /* First block */
    1640                 :       {
    1641               0 :         flag=1;
    1642               0 :         if (reclength != block_info.rec_len)
    1643                 :         {
    1644               0 :           my_errno=HA_ERR_RECORD_CHANGED;
    1645               0 :           goto err;
    1646                 :         }
    1647               0 :       } else if (reclength < block_info.data_len)
    1648                 :       {
    1649               0 :         my_errno=HA_ERR_WRONG_IN_RECORD;
    1650               0 :         goto err;
    1651                 :       }
    1652               0 :       reclength-= block_info.data_len;
    1653               0 :       cmp_length= block_info.data_len;
    1654               0 :       if (!reclength && info->s->calc_checksum)
    1655               0 :         cmp_length--;        /* 'record' may not contain checksum */
    1656                 : 
    1657               0 :       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               0 :       flag=1;
    1664               0 :       record+=block_info.data_len;
    1665                 :     }
    1666                 :   }
    1667               0 :   my_errno=0;
    1668               0 :   error= 0;
    1669               0 : err:
    1670               0 :   if (buffer != info->rec_buff)
    1671               0 :     my_afree(buffer);
    1672               0 :   DBUG_PRINT("exit", ("result: %d", error));
    1673               0 :   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               0 : {
    1682                 :   uint next_length;
    1683                 :   uchar temp_buff[IO_SIZE*2];
    1684               0 :   DBUG_ENTER("_ma_cmp_buffer");
    1685                 : 
    1686               0 :   next_length= IO_SIZE*2 - (uint) (filepos & (IO_SIZE-1));
    1687                 : 
    1688               0 :   while (length > IO_SIZE*2)
    1689                 :   {
    1690               0 :     if (my_pread(file,temp_buff,next_length,filepos, MYF(MY_NABP)) ||
    1691                 :         memcmp(buff, temp_buff, next_length))
    1692                 :       goto err;
    1693               0 :     filepos+=next_length;
    1694               0 :     buff+=next_length;
    1695               0 :     length-= next_length;
    1696               0 :     next_length=IO_SIZE*2;
    1697                 :   }
    1698               0 :   if (my_pread(file,temp_buff,length,filepos,MYF(MY_NABP)))
    1699               0 :     goto err;
    1700               0 :   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               0 : {
    1740                 :   int block_of_record, info_read;
    1741                 :   uint left_len,b_type;
    1742                 :   uchar *to;
    1743                 :   MARIA_BLOCK_INFO block_info;
    1744               0 :   MARIA_SHARE *share= info->s;
    1745               0 :   DBUG_ENTER("_ma_read_rnd_dynamic_record");
    1746                 : 
    1747               0 :   info_read=0;
    1748               0 :   LINT_INIT(to);
    1749                 : 
    1750               0 :   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               0 :     info_read=1;                                /* memory-keyinfoblock is ok */
    1759                 : 
    1760               0 :   block_of_record= 0;   /* First block of record is numbered as zero. */
    1761               0 :   block_info.second_read= 0;
    1762               0 :   left_len=1;
    1763                 :   do
    1764                 :   {
    1765               0 :     if (filepos >= info->state->data_file_length)
    1766                 :     {
    1767               0 :       if (!info_read)
    1768                 :       {                                         /* Check if changed */
    1769               0 :         info_read=1;
    1770               0 :         info->rec_cache.seek_not_done=1;
    1771               0 :         if (_ma_state_info_read_dsk(share->kfile.file, &share->state))
    1772               0 :           goto panic;
    1773                 :       }
    1774               0 :       if (filepos >= info->state->data_file_length)
    1775                 :       {
    1776               0 :         my_errno= HA_ERR_END_OF_FILE;
    1777               0 :         goto err;
    1778                 :       }
    1779                 :     }
    1780               0 :     if (info->opt_flag & READ_CACHE_USED)
    1781                 :     {
    1782               0 :       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               0 :         goto panic;
    1787               0 :       b_type= _ma_get_block_info(&block_info,-1,filepos);
    1788                 :     }
    1789                 :     else
    1790                 :     {
    1791               0 :       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               0 :       info->rec_cache.seek_not_done=1;
    1796               0 :       b_type= _ma_get_block_info(&block_info, info->dfile.file, filepos);
    1797                 :     }
    1798                 : 
    1799               0 :     if (b_type & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR |
    1800                 :                   BLOCK_FATAL_ERROR))
    1801                 :     {
    1802               0 :       if ((b_type & (BLOCK_DELETED | BLOCK_SYNC_ERROR))
    1803                 :           && skip_deleted_blocks)
    1804                 :       {
    1805               0 :         filepos=block_info.filepos+block_info.block_len;
    1806               0 :         block_info.second_read=0;
    1807               0 :         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               0 :     if (block_of_record == 0)                           /* First block */
    1818                 :     {
    1819               0 :       info->cur_row.total_length= block_info.rec_len;
    1820               0 :       if (block_info.rec_len > (uint) share->base.max_pack_length)
    1821               0 :         goto panic;
    1822               0 :       info->cur_row.lastpos= filepos;
    1823               0 :       if (share->base.blobs)
    1824                 :       {
    1825               0 :         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               0 :           goto err;
    1829                 :       }
    1830               0 :       to= info->rec_buff;
    1831               0 :       left_len=block_info.rec_len;
    1832                 :     }
    1833               0 :     if (left_len < block_info.data_len)
    1834               0 :       goto panic;                               /* Wrong linked record */
    1835                 : 
    1836                 :     /* copy information that is already read */
    1837                 :     {
    1838               0 :       uint offset=(uint) (block_info.filepos - filepos);
    1839               0 :       uint tmp_length= (sizeof(block_info.header) - offset);
    1840               0 :       filepos=block_info.filepos;
    1841                 : 
    1842               0 :       if (tmp_length > block_info.data_len)
    1843               0 :         tmp_length= block_info.data_len;
    1844               0 :       if (tmp_length)
    1845                 :       {
    1846               0 :         memcpy(to, block_info.header+offset, tmp_length);
    1847               0 :         block_info.data_len-=tmp_length;
    1848               0 :         left_len-=tmp_length;
    1849               0 :         to+=tmp_length;
    1850               0 :         filepos+=tmp_length;
    1851                 :      }
    1852                 :     }
    1853                 :     /* read rest of record from file */
    1854               0 :     if (block_info.data_len)
    1855                 :     {
    1856               0 :       if (info->opt_flag & READ_CACHE_USED)
    1857                 :       {
    1858               0 :         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               0 :         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               0 :           goto err;
    1871                 :         /* VOID(my_seek(info->dfile.file, filepos, MY_SEEK_SET, MYF(0))); */
    1872               0 :         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               0 :     if (block_of_record++ == 0)
    1885                 :     {
    1886               0 :       info->cur_row.nextpos= block_info.filepos+block_info.block_len;
    1887               0 :       skip_deleted_blocks=0;
    1888                 :     }
    1889               0 :     left_len-=block_info.data_len;
    1890               0 :     to+=block_info.data_len;
    1891               0 :     filepos=block_info.next_filepos;
    1892               0 :   } while (left_len);
    1893                 : 
    1894               0 :   info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
    1895               0 :   fast_ma_writeinfo(info);
    1896               0 :   if (_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) !=
    1897                 :       MY_FILE_ERROR)
    1898               0 :     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               0 : err:
    1904               0 :   fast_ma_writeinfo(info);
    1905               0 :   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               0 : {
    1913               0 :   uint return_val=0;
    1914               0 :   uchar *header=info->header;
    1915                 : 
    1916               0 :   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               0 :     VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
    1924               0 :     if (my_read(file, header, sizeof(info->header),MYF(0)) !=
    1925                 :         sizeof(info->header))
    1926               0 :       goto err;
    1927                 :   }
    1928               0 :   DBUG_DUMP("header",header,MARIA_BLOCK_INFO_HEADER_LENGTH);
    1929               0 :   if (info->second_read)
    1930                 :   {
    1931               0 :     if (info->header[0] <= 6 || info->header[0] == 13)
    1932               0 :       return_val=BLOCK_SYNC_ERROR;
    1933                 :   }
    1934                 :   else
    1935                 :   {
    1936               0 :     if (info->header[0] > 6 && info->header[0] != 13)
    1937               0 :       return_val=BLOCK_SYNC_ERROR;
    1938                 :   }
    1939               0 :   info->next_filepos= HA_OFFSET_ERROR; /* Dummy if no next block */
    1940                 : 
    1941               0 :   switch (info->header[0]) {
    1942                 :   case 0:
    1943               0 :     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               0 :     info->filepos=filepos;
    1948               0 :     info->next_filepos=mi_sizekorr(header+4);
    1949               0 :     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               0 :     return return_val | BLOCK_DELETED;          /* Deleted block */
    1960                 : 
    1961                 :   case 1:
    1962               0 :     info->rec_len=info->data_len=info->block_len=mi_uint2korr(header+1);
    1963               0 :     info->filepos=filepos+3;
    1964               0 :     return return_val | BLOCK_FIRST | BLOCK_LAST;
    1965                 :   case 2:
    1966               0 :     info->rec_len=info->data_len=info->block_len=mi_uint3korr(header+1);
    1967               0 :     info->filepos=filepos+4;
    1968               0 :     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               0 :     info->rec_len=info->data_len=mi_uint2korr(header+1);
    1980               0 :     info->block_len=info->rec_len+ (uint) header[3];
    1981               0 :     info->filepos=filepos+4;
    1982               0 :     return return_val | BLOCK_FIRST | BLOCK_LAST;
    1983                 :   case 4:
    1984               0 :     info->rec_len=info->data_len=mi_uint3korr(header+1);
    1985               0 :     info->block_len=info->rec_len+ (uint) header[4];
    1986               0 :     info->filepos=filepos+5;
    1987               0 :     return return_val | BLOCK_FIRST | BLOCK_LAST;
    1988                 : 
    1989                 :   case 5:
    1990               0 :     info->rec_len=mi_uint2korr(header+1);
    1991               0 :     info->block_len=info->data_len=mi_uint2korr(header+3);
    1992               0 :     info->next_filepos=mi_sizekorr(header+5);
    1993               0 :     info->second_read=1;
    1994               0 :     info->filepos=filepos+13;
    1995               0 :     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               0 :     info->data_len=info->block_len=mi_uint2korr(header+1);
    2007               0 :     info->filepos=filepos+3;
    2008               0 :     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               0 :     info->data_len=mi_uint2korr(header+1);
    2016               0 :     info->block_len=info->data_len+ (uint) header[3];
    2017               0 :     info->filepos=filepos+4;
    2018               0 :     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               0 :     info->data_len=info->block_len=mi_uint2korr(header+1);
    2027               0 :     info->next_filepos=mi_sizekorr(header+3);
    2028               0 :     info->second_read=1;
    2029               0 :     info->filepos=filepos+11;
    2030               0 :     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               0 : err:
    2040               0 :   my_errno=HA_ERR_WRONG_IN_RECORD;       /* Garbage */
    2041               0 :   return BLOCK_ERROR;
    2042                 : }

Generated by: LTP GCOV extension version 1.4