summaryrefslogtreecommitdiff
path: root/sql/field.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/field.cc')
-rw-r--r--sql/field.cc272
1 files changed, 271 insertions, 1 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 37cdf452652..b1b89d16bbb 100644
--- a/sql/field.cc
+++ b/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;
@@ -7563,6 +7726,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 +
@@ -8151,6 +8331,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)
{
@@ -8687,6 +8886,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();