1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

BUG#22086 : Extra Slave Col: Char(5) on slave and Char(10) on master cause mysqld crash

This patch adds functionality to row-based replication to ensure the
slave's column sizes are >= to that of the master.

It also includes some refactoring for the code from WL#3228.
This commit is contained in:
cbell/Chuck@mysql_cab_desk.
2007-08-10 12:48:01 -04:00
parent ac1767df09
commit e8ea4b84c0
13 changed files with 1697 additions and 269 deletions

View File

@ -1360,6 +1360,27 @@ bool Field::send_binary(Protocol *protocol)
}
/**
Check to see if field size is compatible with destination.
This method is used in row-based replication to verify that the slave's
field size is less than or equal to the master's field size. The
encoded field metadata (from the master or source) is decoded and compared
to the size of this field (the slave or destination).
@param field_metadata Encoded size in field metadata
@retval 0 if this field's size is < the source field's size
@retval 1 if this field's size is >= the source field's size
*/
int Field::compatible_field_size(uint field_metadata)
{
uint const source_size= pack_length_from_metadata(field_metadata);
uint const destination_size= row_pack_length();
return (source_size <= destination_size);
}
int Field::store(const char *to, uint length, CHARSET_INFO *cs,
enum_check_fields check_level)
{
@ -2690,6 +2711,76 @@ void Field_new_decimal::sql_type(String &str) const
}
/**
Save the field metadata for new decimal fields.
Saves the precision in the first byte and decimals() in the second
byte of the field metadata array at index of *metadata_ptr and
*(metadata_ptr + 1).
@param metadata_ptr First byte of field metadata
@returns number of bytes written to metadata_ptr
*/
int Field_new_decimal::do_save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= precision;
*(metadata_ptr + 1)= decimals();
return 2;
}
/**
Returns the number of bytes field uses in row-based replication
row packed size.
This method is used in row-based replication to determine the number
of bytes that the field consumes in the row record format. This is
used to skip fields in the master that do not exist on the slave.
@param field_metadata Encoded size in field metadata
@returns The size of the field based on the field metadata.
*/
uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
{
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
uint const source_decimal= field_metadata & 0x00ff;
uint const source_size= my_decimal_get_binary_size(source_precision,
source_decimal);
return (source_size);
}
/**
Check to see if field size is compatible with destination.
This method is used in row-based replication to verify that the slave's
field size is less than or equal to the master's field size. The
encoded field metadata (from the master or source) is decoded and compared
to the size of this field (the slave or destination).
@param field_metadata Encoded size in field metadata
@retval 0 if this field's size is < the source field's size
@retval 1 if this field's size is >= the source field's size
*/
int Field_new_decimal::compatible_field_size(uint field_metadata)
{
int compatible= 0;
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
uint const source_decimal= field_metadata & 0x00ff;
uint const source_size= my_decimal_get_binary_size(source_precision,
source_decimal);
uint const destination_size= row_pack_length();
compatible= (source_size <= destination_size);
if (compatible)
compatible= (source_precision <= precision) &&
(source_decimal <= decimals());
return (compatible);
}
uint Field_new_decimal::is_equal(Create_field *new_field)
{
return ((new_field->sql_type == real_type()) &&
@ -2724,7 +2815,9 @@ const uchar *Field_new_decimal::unpack(uchar* to,
uint from_pack_len= my_decimal_get_binary_size(from_precision, from_decimal);
uint len= (param_data && (from_pack_len < length)) ?
from_pack_len : length;
if (from_pack_len && (from_pack_len < length))
if ((from_pack_len && (from_pack_len < length)) ||
(from_precision < precision) ||
(from_decimal < decimals()))
{
/*
If the master's data is smaller than the slave, we need to convert
@ -4087,6 +4180,22 @@ bool Field_float::send_binary(Protocol *protocol)
}
/**
Save the field metadata for float fields.
Saves the pack length in the first byte.
@param metadata_ptr First byte of field metadata
@returns number of bytes written to metadata_ptr
*/
int Field_float::do_save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= pack_length();
return 1;
}
void Field_float::sql_type(String &res) const
{
if (dec == NOT_FIXED_DEC)
@ -4404,6 +4513,23 @@ void Field_double::sort_string(uchar *to,uint length __attribute__((unused)))
}
/**
Save the field metadata for double fields.
Saves the pack length in the first byte of the field metadata array
at index of *metadata_ptr.
@param metadata_ptr First byte of field metadata
@returns number of bytes written to metadata_ptr
*/
int Field_double::do_save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= pack_length();
return 1;
}
void Field_double::sql_type(String &res) const
{
CHARSET_INFO *cs=res.charset();
@ -6445,6 +6571,25 @@ const uchar *Field_string::unpack(uchar *to, const uchar *from)
}
/**
Save the field metadata for string fields.
Saves the real type in the first byte and the field length in the
second byte of the field metadata array at index of *metadata_ptr and
*(metadata_ptr + 1).
@param metadata_ptr First byte of field metadata
@returns number of bytes written to metadata_ptr
*/
int Field_string::do_save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= real_type();
*(metadata_ptr + 1)= field_length;
return 2;
}
/*
Compare two packed keys
@ -6597,6 +6742,24 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
const uint Field_varstring::MAX_SIZE= UINT_MAX16;
/**
Save the field metadata for varstring fields.
Saves the field length in the first byte. Note: may consume
2 bytes. Caller must ensure second byte is contiguous with
first byte (e.g. array index 0,1).
@param metadata_ptr First byte of field metadata
@returns number of bytes written to metadata_ptr
*/
int Field_varstring::do_save_field_metadata(uchar *metadata_ptr)
{
char *ptr= (char *)metadata_ptr;
int2store(ptr, field_length);
return 2;
}
int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
@ -7560,6 +7723,23 @@ int Field_blob::key_cmp(const uchar *a,const uchar *b)
}
/**
Save the field metadata for blob fields.
Saves the pack length in the first byte of the field metadata array
at index of *metadata_ptr.
@param metadata_ptr First byte of field metadata
@returns number of bytes written to metadata_ptr
*/
int Field_blob::do_save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= pack_length_no_ptr();
return 1;
}
uint32 Field_blob::sort_length() const
{
return (uint32) (current_thd->variables.max_sort_length +
@ -8145,6 +8325,25 @@ longlong Field_enum::val_int(void)
}
/**
Save the field metadata for enum fields.
Saves the real type in the first byte and the pack length in the
second byte of the field metadata array at index of *metadata_ptr and
*(metadata_ptr + 1).
@param metadata_ptr First byte of field metadata
@returns number of bytes written to metadata_ptr
*/
int Field_enum::do_save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= real_type();
*(metadata_ptr + 1)= pack_length();
return 2;
}
String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
@ -8681,6 +8880,77 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
}
/**
Save the field metadata for bit fields.
Saves the bit length in the first byte and bytes in record in the
second byte of the field metadata array at index of *metadata_ptr and
*(metadata_ptr + 1).
@param metadata_ptr First byte of field metadata
@returns number of bytes written to metadata_ptr
*/
int Field_bit::do_save_field_metadata(uchar *metadata_ptr)
{
*metadata_ptr= bit_len;
*(metadata_ptr + 1)= bytes_in_rec;
return 2;
}
/**
Returns the number of bytes field uses in row-based replication
row packed size.
This method is used in row-based replication to determine the number
of bytes that the field consumes in the row record format. This is
used to skip fields in the master that do not exist on the slave.
@param field_metadata Encoded size in field metadata
@returns The size of the field based on the field metadata.
*/
uint Field_bit::pack_length_from_metadata(uint field_metadata)
{
uint const from_len= (field_metadata >> 8U) & 0x00ff;
uint const from_bit_len= field_metadata & 0x00ff;
uint const source_size= from_len + ((from_bit_len > 0) ? 1 : 0);
return (source_size);
}
/**
Check to see if field size is compatible with destination.
This method is used in row-based replication to verify that the slave's
field size is less than or equal to the master's field size. The
encoded field metadata (from the master or source) is decoded and compared
to the size of this field (the slave or destination).
@param field_metadata Encoded size in field metadata
@retval 0 if this field's size is < the source field's size
@retval 1 if this field's size is >= the source field's size
*/
int Field_bit::compatible_field_size(uint field_metadata)
{
int compatible= 0;
uint const source_size= pack_length_from_metadata(field_metadata);
uint const destination_size= row_pack_length();
uint const from_bit_len= field_metadata & 0x00ff;
uint const from_len= (field_metadata >> 8U) & 0x00ff;
if ((bit_len == 0) || (from_bit_len == 0))
compatible= (source_size <= destination_size);
else if (from_bit_len > bit_len)
compatible= (from_len < bytes_in_rec);
else
compatible= ((from_bit_len <= bit_len) && (from_len <= bytes_in_rec));
return (compatible);
}
void Field_bit::sql_type(String &res) const
{
CHARSET_INFO *cs= res.charset();