Commit 943f8335 authored by unknown's avatar unknown
Browse files

a fix (bug #4214: Table corruption with myisampack and large BLOB objects).


myisam/mi_check.c:
  a fix (bug #4214: Table corruption with myisampack and large BLOB objects).
  - pass version to the save_pack_length().
myisam/mi_packrec.c:
  a fix (bug #4214: Table corruption with myisampack and large BLOB objects).
  - code cleanup: read_pack_length() and calc_pack_length() introduced, 
                  save_pack_length() modified: now the behavior depends on packing version
  - save packing version in the share->pack.version
  - pass it to the read_pack_length()
myisam/mi_static.c:
  a fix (bug #4214: Table corruption with myisampack and large BLOB objects).
  - packing version set to 2
myisam/myisamdef.h:
  a fix (bug #4214: Table corruption with myisampack and large BLOB objects).
  - packing version slot introduced (see MI_PACK)
myisam/myisampack.c:
  a fix (bug #4214: Table corruption with myisampack and large BLOB objects).
  - code cleanup
  - pass version to the calc_pack_length() and save_pack_length()
parent 9e796abb
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -3189,9 +3189,11 @@ int sort_write_record(MI_SORT_PARAM *sort_param)
      break;
    case COMPRESSED_RECORD:
      reclength=info->packed_length;
      length=save_pack_length(block_buff,reclength);
      length= save_pack_length((uint) share->pack.version, block_buff,
                               reclength);
      if (info->s->base.blobs)
	length+=save_pack_length(block_buff+length,info->blob_length);
	length+= save_pack_length((uint) share->pack.version,
	                          block_buff + length, info->blob_length);
      if (my_b_write(&info->rec_cache,block_buff,length) ||
	  my_b_write(&info->rec_cache,(byte*) sort_param->rec_buff,reclength))
      {
+53 −60
Original line number Diff line number Diff line
@@ -149,11 +149,12 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys)
      my_errno=HA_ERR_END_OF_FILE;
    goto err0;
  }
  if (memcmp((byte*) header,(byte*) myisam_pack_file_magic,4))
  if (memcmp((byte*) header, (byte*) myisam_pack_file_magic, 3))
  {
    my_errno=HA_ERR_WRONG_IN_RECORD;
    goto err0;
  }
  share->pack.version= header[3];
  share->pack.header_length=	uint4korr(header+4);
  share->min_pack_length=(uint) uint4korr(header+8);
  share->max_pack_length=(uint) uint4korr(header+12);
@@ -1040,38 +1041,12 @@ uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file,
      return BLOCK_FATAL_ERROR;
    DBUG_DUMP("header",(byte*) header,ref_length);
  }
  if (header[0] < 254)
  {
    info->rec_len=header[0];
    head_length=1;
  }
  else if (header[0] == 254)
  {
    info->rec_len=uint2korr(header+1);
    head_length=3;
  }
  else
  {
    info->rec_len=uint3korr(header+1);
    head_length=4;
  }
  head_length= read_pack_length((uint) myisam->s->pack.version, header,
                                &info->rec_len);
  if (myisam->s->base.blobs)
  {
    if (header[head_length] < 254)
    {
      info->blob_len=header[head_length];
      head_length++;
    }
    else if (header[head_length] == 254)
    {
      info->blob_len=uint2korr(header+head_length+1);
      head_length+=3;
    }
    else
    {
      info->blob_len=uint3korr(header+head_length+1);
      head_length+=4;
    }
    head_length+= read_pack_length((uint) myisam->s->pack.version,
                                   header + head_length, &info->blob_len);
    if (!(mi_alloc_rec_buff(myisam,info->rec_len + info->blob_len,
			    &myisam->rec_buff)))
      return BLOCK_FATAL_ERROR;			/* not enough memory */
@@ -1220,34 +1195,12 @@ void _mi_unmap_file(MI_INFO *info)
static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info,
					 uchar *header)
{
  if (header[0] < 254)
    info->rec_len= *header++;
  else if (header[0] == 254)
  {
    info->rec_len=uint2korr(header+1);
    header+=3;
  }
  else
  {
    info->rec_len=uint3korr(header+1);
    header+=4;
  }
  header+= read_pack_length((uint) myisam->s->pack.version, header,
                            &info->rec_len);
  if (myisam->s->base.blobs)
  {
    if (header[0] < 254)
    {
      info->blob_len= *header++;
    }
    else if (header[0] == 254)
    {
      info->blob_len=uint2korr(header+1);
      header+=3;
    }
    else
    {
      info->blob_len=uint3korr(header+1);
      header+=4;
    }
    header+= read_pack_length((uint) myisam->s->pack.version, header,
                              &info->blob_len);
    /* mi_alloc_rec_buff sets my_errno on error */
    if (!(mi_alloc_rec_buff(myisam, info->blob_len,
			    &myisam->rec_buff)))
@@ -1319,7 +1272,7 @@ static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf,

	/* Save length of row */

uint save_pack_length(byte *block_buff,ulong length)
uint save_pack_length(uint version, byte *block_buff, ulong length)
{
  if (length < 254)
  {
@@ -1333,6 +1286,46 @@ uint save_pack_length(byte *block_buff,ulong length)
    return 3;
  }
  *(uchar*) block_buff=255;
  if (version == 1) /* old format */
  {
    DBUG_ASSERT(length <= 0xFFFFFF);
    int3store(block_buff + 1, (ulong) length);
    return 4;
  }
  else
  {
    int4store(block_buff + 1, (ulong) length);
    return 5;
  }
}


uint read_pack_length(uint version, const uchar *buf, ulong *length)
{
  if (buf[0] < 254)
  {
    *length= buf[0];
    return 1;
  }
  else if (buf[0] == 254)
  {
    *length= uint2korr(buf + 1);
    return 3;
  }
  if (version == 1) /* old format */
  {
    *length= uint3korr(buf + 1);
    return 4;
  }
  else
  {
    *length= uint4korr(buf + 1);
    return 5;
  }
}


uint calc_pack_length(uint version, ulong length)
{
  return (length < 254) ? 1 : (length < 65536) ? 3 : (version == 1) ? 4 : 5;
}
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ LIST *myisam_open_list=0;
uchar	NEAR myisam_file_magic[]=
{ (uchar) 254, (uchar) 254,'\007', '\001', };
uchar	NEAR myisam_pack_file_magic[]=
{ (uchar) 254, (uchar) 254,'\010', '\001', };
{ (uchar) 254, (uchar) 254,'\010', '\002', };
my_string myisam_log_filename=(char*) "myisam.log";
File	myisam_log_file= -1;
uint	myisam_quick_table_bits=9;
+4 −1
Original line number Diff line number Diff line
@@ -149,6 +149,7 @@ typedef struct st_mi_blob /* Info of record */
typedef struct st_mi_isam_pack {
  ulong header_length;
  uint ref_length;
  uchar version;
} MI_PACK;


@@ -669,7 +670,9 @@ extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info,
			      int result);
extern my_bool _mi_memmap_file(MI_INFO *info);
extern void _mi_unmap_file(MI_INFO *info);
extern uint save_pack_length(byte *block_buff,ulong length);
extern uint save_pack_length(uint version, byte *block_buff, ulong length);
extern uint read_pack_length(uint version, const uchar *buf, ulong *length);
extern uint calc_pack_length(uint version, ulong length);

uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite);
char *mi_state_info_read(char *ptr, MI_STATE_INFO *state);
+7 −18
Original line number Diff line number Diff line
@@ -1666,6 +1666,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
  HUFF_COUNTS *count,*end_count;
  HUFF_TREE *tree;
  MI_INFO *isam_file=mrg->file[0];
  uint pack_version= (uint) isam_file->s->pack.version;
  DBUG_ENTER("compress_isam_file");

  if (!(record=(byte*) my_alloca(isam_file->s->base.reclength)))
@@ -1693,23 +1694,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
	  huff_counts[i].tree->height+huff_counts[i].length_bits;
  }
  max_calc_length/=8;
  if (max_calc_length < 254)
    pack_ref_length=1;
  else if (max_calc_length <= 65535)
    pack_ref_length=3;
  else
    pack_ref_length=4;
  pack_ref_length= calc_pack_length(pack_version, max_calc_length);
  record_count=0;
  pack_blob_length=0;
  if (isam_file->s->base.blobs)
  {
    if (mrg->max_blob_length < 254)
      pack_blob_length=1;
    else if (mrg->max_blob_length <= 65535)
      pack_blob_length=3;
    else
      pack_blob_length=4;
  }
  pack_blob_length= isam_file->s->base.blobs ?
                    calc_pack_length(pack_version, mrg->max_blob_length) : 0;
  max_pack_length=pack_ref_length+pack_blob_length;

  mrg_reset(mrg);
@@ -1865,9 +1853,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
      }
      flush_bits();
      length=(ulong) (file_buffer.pos-record_pos)-max_pack_length;
      pack_length=save_pack_length(record_pos,length);
      pack_length= save_pack_length(pack_version, record_pos, length);
      if (pack_blob_length)
	pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length);
	pack_length+= save_pack_length(pack_version, record_pos + pack_length,
	                               tot_blob_length);

      /* Correct file buffer if the header was smaller */
      if (pack_length != max_pack_length)