Fixed bug lp:917689 "Archive table corruption crashing MariaDB signal 11"

Added 'from_end' as extra parameter to Field::unpack() to detect wrong from data.
Change ha_archive::unpack_row() to detect wrong field lengths.
Replication code changed to detect wrong field information in events.


mysql-test/r/archive.result:
  dded test case for lp:917689
sql/field.cc:
  Added 'from_end' as extra parameter to Field::unpack() to detect wrong from data.
  Removed not used 'unpack_key' functions.
sql/field.h:
  Added 'from_end' as extra parameter to Field::unpack() to detect wrong from data.
  Removed not used 'unpack_key' functions.
  Removed some not needed unpack() functions.
sql/filesort.cc:
  Added buffer end parameter to unpack_addon_fields()
sql/log_event.h:
  Added end of buffer argument to unpack_row()
sql/log_event_old.cc:
  Added end of buffer argument to unpack_row()
sql/log_event_old.h:
  Added end of buffer argument to unpack_row()
sql/records.cc:
  Added buffer end parameter to unpack_addon_fields()
sql/rpl_record.cc:
  Added end of buffer argument to unpack_row()
  Added detection of wrong field information in events
sql/rpl_record.h:
  Added end of buffer argument to unpack_row()
sql/rpl_record_old.cc:
  Added end of buffer argument to unpack_row()
  Added detection of wrong field information in events
sql/rpl_record_old.h:
  Added end of buffer argument to unpack_row()
sql/table.h:
  Added buffer end parameter to unpack()
storage/archive/ha_archive.cc:
  Change ha_archive::unpack_row() to detect wrong field lengths.
  This fixes lp:917689
This commit is contained in:
Michael Widenius 2012-03-13 16:38:43 +02:00
parent 223483aedf
commit 6f06cef02b
18 changed files with 203 additions and 81 deletions

View file

@ -12801,3 +12801,14 @@ OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 optimize status OK test.t1 optimize status OK
DROP TABLE t1; DROP TABLE t1;
#
# BUG#917689 Using wrong archive table causes crash
#
create table t1 (a int, b char(50)) engine=archive;
select * from t1;
ERROR HY000: Table 't1' is marked as crashed and should be repaired
show warnings;
Level Code Message
Error 127 Got error 127 when reading table `test`.`t1`
Error 1194 Table 't1' is marked as crashed and should be repaired
drop table t1;

Binary file not shown.

View file

@ -1727,3 +1727,14 @@ CHECKSUM TABLE t1 EXTENDED;
FLUSH TABLE t1; FLUSH TABLE t1;
OPTIMIZE TABLE t1; OPTIMIZE TABLE t1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # BUG#917689 Using wrong archive table causes crash
--echo #
create table t1 (a int, b char(50)) engine=archive;
--remove_file $MYSQLD_DATADIR/test/t1.ARZ
copy_file std_data/t917689.ARZ $MYSQLD_DATADIR/test/t1.ARZ;
--error 1194
select * from t1;
show warnings;
drop table t1;

View file

@ -194,12 +194,15 @@ begin
insert into test.t1 values (x, z); insert into test.t1 values (x, z);
end| end|
let $start_value= `SELECT @@max_join_size`|
call mixset("mixset", 19)| call mixset("mixset", 19)|
show variables like 'max_join_size'| show variables like 'max_join_size'|
select id,data,@z from t1| select id,data,@z from t1|
delete from t1| delete from t1|
drop procedure mixset| drop procedure mixset|
--disable_query_log
eval SET @@max_join_size= $start_value|
--enable_query_log
# Multiple CALL statements, one with OUT parameter. # Multiple CALL statements, one with OUT parameter.
--disable_warnings --disable_warnings

View file

@ -1472,11 +1472,13 @@ Field::pack(uchar *to, const uchar *from, uint max_length)
data data
@return New pointer into memory based on from + length of the data @return New pointer into memory based on from + length of the data
@return 0 if wrong data
*/ */
const uchar * const uchar *
Field::unpack(uchar* to, const uchar *from, uint param_data) Field::unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data)
{ {
uint length=pack_length(); uint length=pack_length(), len;
int from_type= 0; int from_type= 0;
/* /*
If from length is > 255, it has encoded data in the upper bits. Need If from length is > 255, it has encoded data in the upper bits. Need
@ -1492,14 +1494,19 @@ Field::unpack(uchar* to, const uchar *from, uint param_data)
(length == param_data) || (length == param_data) ||
(from_type != real_type())) (from_type != real_type()))
{ {
if (from + length > from_end)
return 0; // Error in data
memcpy(to, from, length); memcpy(to, from, length);
return from+length; return from+length;
} }
uint len= (param_data && (param_data < length)) ? len= (param_data && (param_data < length)) ? param_data : length;
param_data : length;
memcpy(to, from, param_data > length ? length : len); if (from + len > from_end)
return 0; // Error in data
memcpy(to, from, len);
return from+len; return from+len;
} }
@ -2916,10 +2923,11 @@ uint Field_new_decimal::is_equal(Create_field *new_field)
@return New pointer into memory based on from + length of the data @return New pointer into memory based on from + length of the data
*/ */
const uchar * const uchar *
Field_new_decimal::unpack(uchar* to, const uchar *from, uint param_data) Field_new_decimal::unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data)
{ {
if (param_data == 0) if (param_data == 0)
return Field::unpack(to, from, param_data); return Field::unpack(to, from, from_end, param_data);
uint from_precision= (param_data & 0xff00) >> 8U; uint from_precision= (param_data & 0xff00) >> 8U;
uint from_decimal= param_data & 0x00ff; uint from_decimal= param_data & 0x00ff;
@ -2949,7 +2957,11 @@ Field_new_decimal::unpack(uchar* to, const uchar *from, uint param_data)
decimal2bin(&dec_val, to, precision, decimals()); decimal2bin(&dec_val, to, precision, decimals());
} }
else else
{
if (from + len > from_end)
return 0; // Wrong data
memcpy(to, from, len); // Sizes are the same, just copy the data. memcpy(to, from, len); // Sizes are the same, just copy the data.
}
return from+len; return from+len;
} }
@ -6542,7 +6554,8 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
@return New pointer into memory based on from + length of the data @return New pointer into memory based on from + length of the data
*/ */
const uchar * const uchar *
Field_string::unpack(uchar *to, const uchar *from, uint param_data) Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data)
{ {
uint from_length, length; uint from_length, length;
@ -6564,11 +6577,19 @@ Field_string::unpack(uchar *to, const uchar *from, uint param_data)
*/ */
if (from_length > 255) if (from_length > 255)
{ {
if (from + 2 > from_end)
return 0;
length= uint2korr(from); length= uint2korr(from);
from+= 2; from+= 2;
} }
else else
{
if (from + 1 > from_end)
return 0;
length= (uint) *from++; length= (uint) *from++;
}
if (from + length > from_end || length > field_length)
return 0;
memcpy(to, from, length); memcpy(to, from, length);
// Pad the string with the pad character of the fields charset // Pad the string with the pad character of the fields charset
@ -7060,6 +7081,7 @@ Field_varstring::pack_key(uchar *to, const uchar *key, uint max_length)
Pointer to end of 'key' (To the next key part if multi-segment key) Pointer to end of 'key' (To the next key part if multi-segment key)
*/ */
#ifdef NOT_USED
const uchar * const uchar *
Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length) Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length)
{ {
@ -7076,6 +7098,7 @@ Field_varstring::unpack_key(uchar *to, const uchar *key, uint max_length)
memcpy(ptr + length_bytes, key, length); memcpy(ptr + length_bytes, key, length);
return key + length; return key + length;
} }
#endif
/** /**
Create a packed key that will be used for storage in the index tree. Create a packed key that will be used for storage in the index tree.
@ -7120,11 +7143,16 @@ uchar * Field_varstring::pack_key_from_key_image(uchar *to, const uchar *from,
@return New pointer into memory based on from + length of the data @return New pointer into memory based on from + length of the data
*/ */
const uchar * const uchar *
Field_varstring::unpack(uchar *to, const uchar *from, uint param_data) Field_varstring::unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data)
{ {
uint length; uint length;
uint l_bytes= (param_data && (param_data < field_length)) ? uint l_bytes= (param_data && (param_data < field_length)) ?
(param_data <= 255) ? 1 : 2 : length_bytes; (param_data <= 255) ? 1 : 2 : length_bytes;
if (from + l_bytes > from_end)
return 0; // Error in data
if (l_bytes == 1) if (l_bytes == 1)
{ {
to[0]= *from++; to[0]= *from++;
@ -7139,7 +7167,11 @@ Field_varstring::unpack(uchar *to, const uchar *from, uint param_data)
to[1]= *from++; to[1]= *from++;
} }
if (length) if (length)
{
if (from + length > from_end || length > field_length)
return 0; // Error in data
memcpy(to+ length_bytes, from, length); memcpy(to+ length_bytes, from, length);
}
return from+length; return from+length;
} }
@ -7771,16 +7803,21 @@ uchar *Field_blob::pack(uchar *to, const uchar *from, uint max_length)
@return New pointer into memory based on from + length of the data @return New pointer into memory based on from + length of the data
*/ */
const uchar *Field_blob::unpack(uchar *to, const uchar *from, uint param_data) const uchar *Field_blob::unpack(uchar *to, const uchar *from,
const uchar *from_end, uint param_data)
{ {
DBUG_ENTER("Field_blob::unpack"); DBUG_ENTER("Field_blob::unpack");
DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx; param_data: %u", DBUG_PRINT("enter", ("to: 0x%lx; from: 0x%lx; param_data: %u",
(ulong) to, (ulong) from, param_data)); (ulong) to, (ulong) from, param_data));
uint const master_packlength= uint const master_packlength=
param_data > 0 ? param_data & 0xFF : packlength; param_data > 0 ? param_data & 0xFF : packlength;
if (from + master_packlength > from_end)
DBUG_RETURN(0); // Error in data
uint32 const length= get_length(from, master_packlength); uint32 const length= get_length(from, master_packlength);
DBUG_DUMP("packed", from, length + master_packlength); DBUG_DUMP("packed", from, length + master_packlength);
bitmap_set_bit(table->write_set, field_index); bitmap_set_bit(table->write_set, field_index);
if (from + master_packlength + length > from_end)
DBUG_RETURN(0);
store(reinterpret_cast<const char*>(from) + master_packlength, store(reinterpret_cast<const char*>(from) + master_packlength,
length, field_charset); length, field_charset);
DBUG_DUMP("record", to, table->s->reclength); DBUG_DUMP("record", to, table->s->reclength);
@ -7878,6 +7915,7 @@ Field_blob::pack_key(uchar *to, const uchar *from, uint max_length)
Pointer into 'from' past the last byte copied from packed key. Pointer into 'from' past the last byte copied from packed key.
*/ */
#ifdef NOT_USED
const uchar * const uchar *
Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length) Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length)
{ {
@ -7898,7 +7936,7 @@ Field_blob::unpack_key(uchar *to, const uchar *from, uint max_length)
/* point to first byte of next field in 'from' */ /* point to first byte of next field in 'from' */
return from + length; return from + length;
} }
#endif
/** Create a packed key that will be used for storage from a MySQL key. */ /** Create a packed key that will be used for storage from a MySQL key. */
@ -8940,7 +8978,8 @@ Field_bit::pack(uchar *to, const uchar *from, uint max_length)
@return New pointer into memory based on from + length of the data @return New pointer into memory based on from + length of the data
*/ */
const uchar * const uchar *
Field_bit::unpack(uchar *to, const uchar *from, uint param_data) Field_bit::unpack(uchar *to, const uchar *from, const uchar *from_end,
uint param_data)
{ {
uint const from_len= (param_data >> 8U) & 0x00ff; uint const from_len= (param_data >> 8U) & 0x00ff;
uint const from_bit_len= param_data & 0x00ff; uint const from_bit_len= param_data & 0x00ff;
@ -8951,6 +8990,9 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data)
if (param_data == 0 || if (param_data == 0 ||
((from_bit_len == bit_len) && (from_len == bytes_in_rec))) ((from_bit_len == bit_len) && (from_len == bytes_in_rec)))
{ {
if (from + bytes_in_rec + test(bit_len) > from_end)
return 0; // Error in data
if (bit_len > 0) if (bit_len > 0)
{ {
/* /*
@ -8975,10 +9017,16 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data)
Lastly the odd bits need to be masked out if the bytes_in_rec > 0. Lastly the odd bits need to be masked out if the bytes_in_rec > 0.
Otherwise stray bits can cause spurious values. Otherwise stray bits can cause spurious values.
*/ */
uint len= from_len + ((from_bit_len > 0) ? 1 : 0);
uint new_len= (field_length + 7) / 8; uint new_len= (field_length + 7) / 8;
if (from + len > from_end || new_len < len)
return 0; // Error in data
char *value= (char *)my_alloca(new_len); char *value= (char *)my_alloca(new_len);
bzero(value, new_len); bzero(value, new_len);
uint len= from_len + ((from_bit_len > 0) ? 1 : 0);
memcpy(value + (new_len - len), from, len); memcpy(value + (new_len - len), from, len);
/* /*
Mask out the unused bits in the partial byte. Mask out the unused bits in the partial byte.

View file

@ -483,17 +483,8 @@ public:
DBUG_RETURN(result); DBUG_RETURN(result);
} }
virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); virtual const uchar *unpack(uchar* to, const uchar *from,
/** const uchar *from_end, uint param_data=0);
@overload Field::unpack(uchar*, const uchar*, uint, bool)
*/
const uchar *unpack(uchar* to, const uchar *from)
{
DBUG_ENTER("Field::unpack");
const uchar *result= unpack(to, from, 0);
DBUG_RETURN(result);
}
virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length) virtual uchar *pack_key(uchar* to, const uchar *from, uint max_length)
{ {
return pack(to, from, max_length); return pack(to, from, max_length);
@ -502,10 +493,12 @@ public:
{ {
return pack(to, from, max_length); return pack(to, from, max_length);
} }
#ifdef NOT_USED
virtual const uchar *unpack_key(uchar* to, const uchar *from, uint max_length) virtual const uchar *unpack_key(uchar* to, const uchar *from, uint max_length)
{ {
return unpack(to, from, max_length); return unpack(to, from, from + max_length+2, max_length);
} }
#endif
virtual uint packed_col_length(const uchar *to, uint length) virtual uint packed_col_length(const uchar *to, uint length)
{ return length;} { return length;}
virtual uint max_packed_col_length(uint max_length) virtual uint max_packed_col_length(uint max_length)
@ -786,10 +779,6 @@ public:
void overflow(bool negative); void overflow(bool negative);
bool zero_pack() const { return 0; } bool zero_pack() const { return 0; }
void sql_type(String &str) const; void sql_type(String &str) const;
virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data)
{
return Field::unpack(to, from, param_data);
}
virtual uchar *pack(uchar* to, const uchar *from, uint max_length) virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
{ {
return Field::pack(to, from, max_length); return Field::pack(to, from, max_length);
@ -845,7 +834,7 @@ public:
int compatible_field_size(uint field_metadata, int compatible_field_size(uint field_metadata,
const Relay_log_info *rli, uint16 mflags); const Relay_log_info *rli, uint16 mflags);
uint is_equal(Create_field *new_field); uint is_equal(Create_field *new_field);
virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data);
static Field *create_from_item (Item *); static Field *create_from_item (Item *);
}; };
@ -883,8 +872,11 @@ public:
return to + 1; return to + 1;
} }
virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) virtual const uchar *unpack(uchar* to, const uchar *from,
const uchar *from_end, uint param_data)
{ {
if (from == from_end)
return 0;
*to= *from; *to= *from;
return from + 1; return from + 1;
} }
@ -928,15 +920,19 @@ public:
int16 val; int16 val;
val = sint2korr(from); val = sint2korr(from);
int2store(to, val); int2store(to, val);
return to + sizeof(val); return to + 2;
} }
virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data) virtual const uchar *unpack(uchar* to, const uchar *from,
const uchar *from_end, uint param_data)
{ {
int16 val; int16 val;
if (from +2 > from_end)
return 0;
val = sint2korr(from); val = sint2korr(from);
int2store(to, val); int2store(to, val);
return from + sizeof(val); return from + 2;
} }
}; };
@ -971,11 +967,6 @@ public:
{ {
return Field::pack(to, from, max_length); return Field::pack(to, from, max_length);
} }
virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data)
{
return Field::unpack(to, from, param_data);
}
}; };
@ -1016,8 +1007,11 @@ public:
return pack_int32(to, from); return pack_int32(to, from);
} }
virtual const uchar *unpack(uchar* to, const uchar *from, virtual const uchar *unpack(uchar* to, const uchar *from,
const uchar *from_end,
uint param_data __attribute__((unused))) uint param_data __attribute__((unused)))
{ {
if (from + 4 > from_end)
return 0;
return unpack_int32(to, from); return unpack_int32(to, from);
} }
}; };
@ -1064,9 +1058,11 @@ public:
{ {
return pack_int64(to, from); return pack_int64(to, from);
} }
virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data __attribute__((unused))) uint param_data __attribute__((unused)))
{ {
if (from + 8 > from_end)
return 0;
return unpack_int64(to, from); return unpack_int64(to, from);
} }
}; };
@ -1230,9 +1226,11 @@ public:
{ {
return pack_int32(to, from); return pack_int32(to, from);
} }
const uchar *unpack(uchar* to, const uchar *from, const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data __attribute__((unused))) uint param_data __attribute__((unused)))
{ {
if (from + 4 > from_end)
return 0;
return unpack_int32(to, from); return unpack_int32(to, from);
} }
}; };
@ -1269,8 +1267,9 @@ public:
uint32 pack_length() const; uint32 pack_length() const;
uchar *pack(uchar *to, const uchar *from, uint max_length) uchar *pack(uchar *to, const uchar *from, uint max_length)
{ return Field::pack(to, from, max_length); } { return Field::pack(to, from, max_length); }
const uchar *unpack(uchar* to, const uchar *from, uint param_data) const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
{ return Field::unpack(to, from, param_data); } uint param_data)
{ return Field::unpack(to, from, from_end, param_data); }
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
bool eq_def(Field *field) bool eq_def(Field *field)
{ return Field_str::eq_def(field) && dec == field->decimals(); } { return Field_str::eq_def(field) && dec == field->decimals(); }
@ -1353,9 +1352,11 @@ public:
{ {
return pack_int32(to, from); return pack_int32(to, from);
} }
const uchar *unpack(uchar* to, const uchar *from, const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data __attribute__((unused))) uint param_data __attribute__((unused)))
{ {
if (from + 4 > from_end)
return 0;
return unpack_int32(to, from); return unpack_int32(to, from);
} }
}; };
@ -1482,9 +1483,11 @@ public:
{ {
return pack_int64(to, from); return pack_int64(to, from);
} }
const uchar *unpack(uchar* to, const uchar *from, const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
uint param_data __attribute__((unused))) uint param_data __attribute__((unused)))
{ {
if (from + 8 > from_end)
return 0;
return unpack_int64(to, from); return unpack_int64(to, from);
} }
}; };
@ -1520,8 +1523,9 @@ public:
bool get_date(MYSQL_TIME *ltime,uint fuzzydate); bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
uchar *pack(uchar *to, const uchar *from, uint max_length) uchar *pack(uchar *to, const uchar *from, uint max_length)
{ return Field::pack(to, from, max_length); } { return Field::pack(to, from, max_length); }
const uchar *unpack(uchar* to, const uchar *from, uint param_data) const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end,
{ return Field::unpack(to, from, param_data); } uint param_data)
{ return Field::unpack(to, from, from_end, param_data); }
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
}; };
@ -1612,7 +1616,8 @@ public:
void sql_type(String &str) const; void sql_type(String &str) const;
virtual uchar *pack(uchar *to, const uchar *from, virtual uchar *pack(uchar *to, const uchar *from,
uint max_length); uint max_length);
virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); virtual const uchar *unpack(uchar* to, const uchar *from,
const uchar *from_end,uint param_data);
uint pack_length_from_metadata(uint field_metadata) uint pack_length_from_metadata(uint field_metadata)
{ {
DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata)); DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata));
@ -1700,8 +1705,11 @@ public:
virtual uchar *pack(uchar *to, const uchar *from, uint max_length); virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
uchar *pack_key(uchar *to, const uchar *from, uint max_length); uchar *pack_key(uchar *to, const uchar *from, uint max_length);
uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length); uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length);
virtual const uchar *unpack(uchar* to, const uchar *from, uint param_data); virtual const uchar *unpack(uchar* to, const uchar *from,
const uchar *from_end, uint param_data);
#ifdef NOT_USED
const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); const uchar *unpack_key(uchar* to, const uchar *from, uint max_length);
#endif
int pack_cmp(const uchar *a, const uchar *b, uint key_length, int pack_cmp(const uchar *a, const uchar *b, uint key_length,
bool insert_or_update); bool insert_or_update);
int pack_cmp(const uchar *b, uint key_length,bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,bool insert_or_update);
@ -1873,8 +1881,11 @@ public:
virtual uchar *pack(uchar *to, const uchar *from, uint max_length); virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
uchar *pack_key(uchar *to, const uchar *from, uint max_length); uchar *pack_key(uchar *to, const uchar *from, uint max_length);
uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length); uchar *pack_key_from_key_image(uchar* to, const uchar *from, uint max_length);
virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); virtual const uchar *unpack(uchar *to, const uchar *from,
const uchar *from_end, uint param_data);
#ifdef NOT_USED
const uchar *unpack_key(uchar* to, const uchar *from, uint max_length); const uchar *unpack_key(uchar* to, const uchar *from, uint max_length);
#endif
int pack_cmp(const uchar *a, const uchar *b, uint key_length, int pack_cmp(const uchar *a, const uchar *b, uint key_length,
bool insert_or_update); bool insert_or_update);
int pack_cmp(const uchar *b, uint key_length,bool insert_or_update); int pack_cmp(const uchar *b, uint key_length,bool insert_or_update);
@ -2077,7 +2088,8 @@ public:
const Relay_log_info *rli, uint16 mflags); const Relay_log_info *rli, uint16 mflags);
void sql_type(String &str) const; void sql_type(String &str) const;
virtual uchar *pack(uchar *to, const uchar *from, uint max_length); virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
virtual const uchar *unpack(uchar *to, const uchar *from, uint param_data); virtual const uchar *unpack(uchar *to, const uchar *from,
const uchar *from_end, uint param_data);
virtual void set_default(); virtual void set_default();
Field *new_key_field(MEM_ROOT *root, struct st_table *new_table, Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,

View file

@ -60,7 +60,7 @@ static uint sortlength(THD *thd, SORT_FIELD *sortorder, uint s_length,
static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield, static SORT_ADDON_FIELD *get_addon_fields(THD *thd, Field **ptabfield,
uint sortlength, uint *plength); uint sortlength, uint *plength);
static void unpack_addon_fields(struct st_sort_addon_field *addon_field, static void unpack_addon_fields(struct st_sort_addon_field *addon_field,
uchar *buff); uchar *buff, uchar *buff_end);
/** /**
Sort a table. Sort a table.
Creates a set of pointers that can be used to read the rows Creates a set of pointers that can be used to read the rows
@ -1732,7 +1732,8 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
*/ */
static void static void
unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff) unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff,
uchar *buff_end)
{ {
Field *field; Field *field;
SORT_ADDON_FIELD *addonf= addon_field; SORT_ADDON_FIELD *addonf= addon_field;
@ -1745,7 +1746,7 @@ unpack_addon_fields(struct st_sort_addon_field *addon_field, uchar *buff)
continue; continue;
} }
field->set_notnull(); field->set_notnull();
field->unpack(field->ptr, buff + addonf->offset); field->unpack(field->ptr, buff + addonf->offset, buff_end, 0);
} }
} }

View file

@ -3752,7 +3752,8 @@ protected:
DBUG_ASSERT(m_table); DBUG_ASSERT(m_table);
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, int const result= ::unpack_row(rli, m_table, m_width, m_curr_row,
m_rows_end, &m_cols,
&m_curr_row_end, &m_master_reclength); &m_curr_row_end, &m_master_reclength);
if (m_curr_row_end > m_rows_end) if (m_curr_row_end > m_rows_end)
my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0)); my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0));

View file

@ -998,7 +998,8 @@ Write_rows_log_event_old::do_prepare_row(THD *thd_arg,
int error; int error;
error= unpack_row_old(const_cast<Relay_log_info*>(rli), error= unpack_row_old(const_cast<Relay_log_info*>(rli),
table, m_width, table->record[0], table, m_width, table->record[0],
row_start, &m_cols, row_end, &m_master_reclength, row_start, m_rows_end,
&m_cols, row_end, &m_master_reclength,
table->write_set, PRE_GA_WRITE_ROWS_EVENT); table->write_set, PRE_GA_WRITE_ROWS_EVENT);
bitmap_copy(table->read_set, table->write_set); bitmap_copy(table->read_set, table->write_set);
return error; return error;
@ -1085,7 +1086,8 @@ Delete_rows_log_event_old::do_prepare_row(THD *thd_arg,
error= unpack_row_old(const_cast<Relay_log_info*>(rli), error= unpack_row_old(const_cast<Relay_log_info*>(rli),
table, m_width, table->record[0], table, m_width, table->record[0],
row_start, &m_cols, row_end, &m_master_reclength, row_start, m_rows_end,
&m_cols, row_end, &m_master_reclength,
table->read_set, PRE_GA_DELETE_ROWS_EVENT); table->read_set, PRE_GA_DELETE_ROWS_EVENT);
/* /*
If we will access rows using the random access method, m_key will If we will access rows using the random access method, m_key will
@ -1184,13 +1186,15 @@ int Update_rows_log_event_old::do_prepare_row(THD *thd_arg,
/* record[0] is the before image for the update */ /* record[0] is the before image for the update */
error= unpack_row_old(const_cast<Relay_log_info*>(rli), error= unpack_row_old(const_cast<Relay_log_info*>(rli),
table, m_width, table->record[0], table, m_width, table->record[0],
row_start, &m_cols, row_end, &m_master_reclength, row_start, m_rows_end,
&m_cols, row_end, &m_master_reclength,
table->read_set, PRE_GA_UPDATE_ROWS_EVENT); table->read_set, PRE_GA_UPDATE_ROWS_EVENT);
row_start = *row_end; row_start = *row_end;
/* m_after_image is the after image for the update */ /* m_after_image is the after image for the update */
error= unpack_row_old(const_cast<Relay_log_info*>(rli), error= unpack_row_old(const_cast<Relay_log_info*>(rli),
table, m_width, m_after_image, table, m_width, m_after_image,
row_start, &m_cols, row_end, &m_master_reclength, row_start, m_rows_end,
&m_cols, row_end, &m_master_reclength,
table->write_set, PRE_GA_UPDATE_ROWS_EVENT); table->write_set, PRE_GA_UPDATE_ROWS_EVENT);
DBUG_DUMP("record[0]", table->record[0], table->s->reclength); DBUG_DUMP("record[0]", table->record[0], table->s->reclength);

View file

@ -203,7 +203,8 @@ protected:
{ {
DBUG_ASSERT(m_table); DBUG_ASSERT(m_table);
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, int const result= ::unpack_row(rli, m_table, m_width, m_curr_row,
m_rows_end, &m_cols,
&m_curr_row_end, &m_master_reclength); &m_curr_row_end, &m_master_reclength);
ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
return result; return result;

View file

@ -447,7 +447,8 @@ static int rr_unpack_from_tempfile(READ_RECORD *info)
if (my_b_read(info->io_cache, info->rec_buf, info->ref_length)) if (my_b_read(info->io_cache, info->rec_buf, info->ref_length))
return -1; return -1;
TABLE *table= info->table; TABLE *table= info->table;
(*table->sort.unpack)(table->sort.addon_field, info->rec_buf); (*table->sort.unpack)(table->sort.addon_field, info->rec_buf,
info->rec_buf + info->ref_length);
return 0; return 0;
} }
@ -498,7 +499,8 @@ static int rr_unpack_from_buffer(READ_RECORD *info)
if (info->cache_pos == info->cache_end) if (info->cache_pos == info->cache_end)
return -1; /* End of buffer */ return -1; /* End of buffer */
TABLE *table= info->table; TABLE *table= info->table;
(*table->sort.unpack)(table->sort.addon_field, info->cache_pos); (*table->sort.unpack)(table->sort.addon_field, info->cache_pos,
info->cache_end);
info->cache_pos+= info->ref_length; info->cache_pos+= info->ref_length;
return 0; return 0;

View file

@ -176,13 +176,15 @@ pack_row(TABLE *table, MY_BITMAP const* cols,
@retval ER_NO_DEFAULT_FOR_FIELD @retval ER_NO_DEFAULT_FOR_FIELD
Returned if one of the fields existing on the slave but not on the Returned if one of the fields existing on the slave but not on the
master does not have a default value (and isn't nullable) master does not have a default value (and isn't nullable)
@retval ER_SLAVE_CORRUPT_EVENT
Found error when trying to unpack fields.
*/ */
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
int int
unpack_row(Relay_log_info const *rli, unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt, TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols, uchar const *const row_data, uchar const *const row_buffer_end,
MY_BITMAP const *cols,
uchar const **const row_end, ulong *const master_reclength) uchar const **const row_end, ulong *const master_reclength)
{ {
DBUG_ENTER("unpack_row"); DBUG_ENTER("unpack_row");
@ -224,9 +226,6 @@ unpack_row(Relay_log_info const *rli,
DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set DBUG_ASSERT(null_mask & 0xFF); // One of the 8 LSB should be set
/* Field...::unpack() cannot return 0 */
DBUG_ASSERT(pack_ptr != NULL);
if (null_bits & null_mask) if (null_bits & null_mask)
{ {
if (f->maybe_null()) if (f->maybe_null())
@ -272,14 +271,21 @@ unpack_row(Relay_log_info const *rli,
#ifndef DBUG_OFF #ifndef DBUG_OFF
uchar const *const old_pack_ptr= pack_ptr; uchar const *const old_pack_ptr= pack_ptr;
#endif #endif
pack_ptr= f->unpack(f->ptr, pack_ptr, metadata); pack_ptr= f->unpack(f->ptr, pack_ptr, row_buffer_end, metadata);
DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;" DBUG_PRINT("debug", ("field: %s; metadata: 0x%x;"
" pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d", " pack_ptr: 0x%lx; pack_ptr': 0x%lx; bytes: %d",
f->field_name, metadata, f->field_name, metadata,
(ulong) old_pack_ptr, (ulong) pack_ptr, (ulong) old_pack_ptr, (ulong) pack_ptr,
(int) (pack_ptr - old_pack_ptr))); (int) (pack_ptr - old_pack_ptr)));
if (!pack_ptr)
{
rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT,
"Could not read field `%s` of table `%s`.`%s`",
f->field_name, table->s->db.str,
table->s->table_name.str);
DBUG_RETURN(ER_SLAVE_CORRUPT_EVENT);
}
} }
null_mask <<= 1; null_mask <<= 1;
} }
i++; i++;

View file

@ -29,7 +29,8 @@ size_t pack_row(TABLE* table, MY_BITMAP const* cols,
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
int unpack_row(Relay_log_info const *rli, int unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt, TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols, uchar const *const row_data, uchar const *row_buffer_end,
MY_BITMAP const *cols,
uchar const **const row_end, ulong *const master_reclength); uchar const **const row_end, ulong *const master_reclength);
// Fill table's record[0] with default values. // Fill table's record[0] with default values.

View file

@ -82,12 +82,15 @@ pack_row_old(TABLE *table, MY_BITMAP const* cols,
ER_NO_DEFAULT_FOR_FIELD ER_NO_DEFAULT_FOR_FIELD
Returned if one of the fields existing on the slave but not on Returned if one of the fields existing on the slave but not on
the master does not have a default value (and isn't nullable) the master does not have a default value (and isn't nullable)
ER_SLAVE_CORRUPT_EVENT
Wrong data for field found.
*/ */
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
int int
unpack_row_old(Relay_log_info *rli, unpack_row_old(Relay_log_info *rli,
TABLE *table, uint const colcnt, uchar *record, TABLE *table, uint const colcnt, uchar *record,
uchar const *row, MY_BITMAP const *cols, uchar const *row, const uchar *row_buffer_end,
MY_BITMAP const *cols,
uchar const **row_end, ulong *master_reclength, uchar const **row_end, ulong *master_reclength,
MY_BITMAP* const rw_set, Log_event_type const event_type) MY_BITMAP* const rw_set, Log_event_type const event_type)
{ {
@ -133,10 +136,16 @@ unpack_row_old(Relay_log_info *rli,
if (bitmap_is_set(cols, field_ptr - begin_ptr)) if (bitmap_is_set(cols, field_ptr - begin_ptr))
{ {
f->move_field_offset(offset); f->move_field_offset(offset);
ptr= f->unpack(f->ptr, ptr); ptr= f->unpack(f->ptr, ptr, row_buffer_end, 0);
f->move_field_offset(-offset); f->move_field_offset(-offset);
/* Field...::unpack() cannot return 0 */ if (!ptr)
DBUG_ASSERT(ptr != NULL); {
rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT,
"Could not read field `%s` of table `%s`.`%s`",
f->field_name, table->s->db.str,
table->s->table_name.str);
return(ER_SLAVE_CORRUPT_EVENT);
}
} }
else else
bitmap_clear_bit(rw_set, field_ptr - begin_ptr); bitmap_clear_bit(rw_set, field_ptr - begin_ptr);

View file

@ -23,7 +23,8 @@ size_t pack_row_old(TABLE *table, MY_BITMAP const* cols,
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
int unpack_row_old(Relay_log_info *rli, int unpack_row_old(Relay_log_info *rli,
TABLE *table, uint const colcnt, uchar *record, TABLE *table, uint const colcnt, uchar *record,
uchar const *row, MY_BITMAP const *cols, uchar const *row, uchar const *row_buffer_end,
MY_BITMAP const *cols,
uchar const **row_end, ulong *master_reclength, uchar const **row_end, ulong *master_reclength,
MY_BITMAP* const rw_set, MY_BITMAP* const rw_set,
Log_event_type const event_type); Log_event_type const event_type);

View file

@ -15763,8 +15763,13 @@ int report_error(TABLE *table, int error)
print them to the .err log print them to the .err log
*/ */
if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT)
{
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_ERROR, error,
"Got error %d when reading table `%s`.`%s`",
error, table->s->db.str, table->s->table_name.str);
sql_print_error("Got error %d when reading table '%s'", sql_print_error("Got error %d when reading table '%s'",
error, table->s->path.str); error, table->s->path.str);
}
table->file->print_error(error,MYF(0)); table->file->print_error(error,MYF(0));
return 1; return 1;
} }

View file

@ -166,7 +166,7 @@ typedef struct st_filesort_info
uchar *addon_buf; /* Pointer to a buffer if sorted with fields */ uchar *addon_buf; /* Pointer to a buffer if sorted with fields */
size_t addon_length; /* Length of the buffer */ size_t addon_length; /* Length of the buffer */
struct st_sort_addon_field *addon_field; /* Pointer to the fields info */ struct st_sort_addon_field *addon_field; /* Pointer to the fields info */
void (*unpack)(struct st_sort_addon_field *, uchar *); /* To unpack back */ void (*unpack)(struct st_sort_addon_field *, uchar *, uchar *); /* To unpack back */
uchar *record_pointers; /* If sorted in memory */ uchar *record_pointers; /* If sorted in memory */
ha_rows found_records; /* How many records in sort */ ha_rows found_records; /* How many records in sort */
} FILESORT_INFO; } FILESORT_INFO;

View file

@ -1120,20 +1120,26 @@ int ha_archive::unpack_row(azio_stream *file_to_read, uchar *record)
if (read != row_len || error) if (read != row_len || error)
{ {
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); DBUG_RETURN(error ? HA_ERR_CRASHED_ON_USAGE : HA_ERR_WRONG_IN_RECORD);
} }
/* Copy null bits */ /* Copy null bits */
const uchar *ptr= record_buffer->buffer; const uchar *ptr= record_buffer->buffer, *end= ptr+ row_len;
memcpy(record, ptr, table->s->null_bytes); memcpy(record, ptr, table->s->null_bytes);
ptr+= table->s->null_bytes; ptr+= table->s->null_bytes;
if (ptr > end)
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
for (Field **field=table->field ; *field ; field++) for (Field **field=table->field ; *field ; field++)
{ {
if (!((*field)->is_null_in_record(record))) if (!((*field)->is_null_in_record(record)))
{ {
ptr= (*field)->unpack(record + (*field)->offset(table->record[0]), ptr); if (!(ptr= (*field)->unpack(record + (*field)->offset(table->record[0]),
ptr, end)))
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
} }
} }
if (ptr != end)
DBUG_RETURN(HA_ERR_WRONG_IN_RECORD);
DBUG_RETURN(0); DBUG_RETURN(0);
} }