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:
272
sql/field.cc
272
sql/field.cc
@ -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();
|
||||
|
Reference in New Issue
Block a user