diff options
Diffstat (limited to 'sql/rpl_utility.cc')
-rw-r--r-- | sql/rpl_utility.cc | 986 |
1 files changed, 0 insertions, 986 deletions
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 437d58d772f..1e4b59844b8 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -19,185 +19,7 @@ #include "rpl_utility.h" #include "log_event.h" -#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) -#include "rpl_rli.h" -#include "sql_select.h" -/** - Calculate display length for MySQL56 temporal data types from their metadata. - It contains fractional precision in the low 16-bit word. -*/ -static uint32 -max_display_length_for_temporal2_field(uint32 int_display_length, - unsigned int metadata) -{ - metadata&= 0x00ff; - return int_display_length + metadata + (metadata ? 1 : 0); -} - - -/** - Compute the maximum display length of a field. - - @param sql_type Type of the field - @param metadata The metadata from the master for the field. - @return Maximum length of the field in bytes. - - The precise values calculated by field->max_display_length() and - calculated by max_display_length_for_field() can differ (by +1 or -1) - for integer data types (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT). - This slight difference is not important here, because we call - this function only for two *different* integer data types. - */ -static uint32 -max_display_length_for_field(enum_field_types sql_type, unsigned int metadata) -{ - DBUG_PRINT("debug", ("sql_type: %d, metadata: 0x%x", sql_type, metadata)); - DBUG_ASSERT(metadata >> 16 == 0); - - switch (sql_type) { - case MYSQL_TYPE_NEWDECIMAL: - return metadata >> 8; - - case MYSQL_TYPE_FLOAT: - return 12; - - case MYSQL_TYPE_DOUBLE: - return 22; - - case MYSQL_TYPE_SET: - case MYSQL_TYPE_ENUM: - return metadata & 0x00ff; - - case MYSQL_TYPE_STRING: - { - uchar type= metadata >> 8; - if (type == MYSQL_TYPE_SET || type == MYSQL_TYPE_ENUM) - return metadata & 0xff; - else - /* This is taken from Field_string::unpack. */ - return (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff); - } - - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_TINY: - return 4; - - case MYSQL_TYPE_SHORT: - return 6; - - case MYSQL_TYPE_INT24: - return 9; - - case MYSQL_TYPE_LONG: - return 11; - -#ifdef HAVE_LONG_LONG - case MYSQL_TYPE_LONGLONG: - return 20; - -#endif - case MYSQL_TYPE_NULL: - return 0; - - case MYSQL_TYPE_NEWDATE: - return 3; - - case MYSQL_TYPE_DATE: - return 3; - - case MYSQL_TYPE_TIME: - return MIN_TIME_WIDTH; - - case MYSQL_TYPE_TIME2: - return max_display_length_for_temporal2_field(MIN_TIME_WIDTH, metadata); - - case MYSQL_TYPE_TIMESTAMP: - return MAX_DATETIME_WIDTH; - - case MYSQL_TYPE_TIMESTAMP2: - return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata); - - case MYSQL_TYPE_DATETIME: - return MAX_DATETIME_WIDTH; - - case MYSQL_TYPE_DATETIME2: - return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata); - - case MYSQL_TYPE_BIT: - /* - Decode the size of the bit field from the master. - */ - DBUG_ASSERT((metadata & 0xff) <= 7); - return 8 * (metadata >> 8U) + (metadata & 0x00ff); - - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_VARCHAR: - return metadata; - case MYSQL_TYPE_VARCHAR_COMPRESSED: - return metadata - 1; - - /* - The actual length for these types does not really matter since - they are used to calc_pack_length, which ignores the given - length for these types. - - Since we want this to be accurate for other uses, we return the - maximum size in bytes of these BLOBs. - */ - - case MYSQL_TYPE_TINY_BLOB: - return (uint32)my_set_bits(1 * 8); - - case MYSQL_TYPE_MEDIUM_BLOB: - return (uint32)my_set_bits(3 * 8); - - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_BLOB_COMPRESSED: - /* - For the blob type, Field::real_type() lies and say that all - blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look - at the length instead to decide what the max display size is. - */ - return (uint32)my_set_bits(metadata * 8); - - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_GEOMETRY: - return (uint32)my_set_bits(4 * 8); - - default: - return ~(uint32) 0; - } -} - - -/* - Compare the pack lengths of a source field (on the master) and a - target field (on the slave). - - @param field Target field. - @param type Source field type. - @param metadata Source field metadata. - - @retval -1 The length of the source field is smaller than the target field. - @retval 0 The length of the source and target fields are the same. - @retval 1 The length of the source field is greater than the target field. - */ -int compare_lengths(Field *field, enum_field_types source_type, uint16 metadata) -{ - DBUG_ENTER("compare_lengths"); - size_t const source_length= - max_display_length_for_field(source_type, metadata); - size_t const target_length= field->max_display_length(); - DBUG_PRINT("debug", ("source_length: %lu, source_type: %u," - " target_length: %lu, target_type: %u", - (unsigned long) source_length, source_type, - (unsigned long) target_length, field->real_type())); - int result= source_length < target_length ? -1 : source_length > target_length; - DBUG_PRINT("result", ("%d", result)); - DBUG_RETURN(result); -} -#endif //MYSQL_CLIENT /********************************************************************* * table_def member definitions * *********************************************************************/ @@ -349,750 +171,6 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const return length; } -#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) -/** - */ -void show_sql_type(enum_field_types type, uint16 metadata, String *str, - bool char_with_octets) -{ - DBUG_ENTER("show_sql_type"); - DBUG_PRINT("enter", ("type: %d, metadata: 0x%x", type, metadata)); - - switch (type) - { - case MYSQL_TYPE_TINY: - str->set_ascii(STRING_WITH_LEN("tinyint")); - break; - - case MYSQL_TYPE_SHORT: - str->set_ascii(STRING_WITH_LEN("smallint")); - break; - - case MYSQL_TYPE_LONG: - str->set_ascii(STRING_WITH_LEN("int")); - break; - - case MYSQL_TYPE_FLOAT: - str->set_ascii(STRING_WITH_LEN("float")); - break; - - case MYSQL_TYPE_DOUBLE: - str->set_ascii(STRING_WITH_LEN("double")); - break; - - case MYSQL_TYPE_NULL: - str->set_ascii(STRING_WITH_LEN("null")); - break; - - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_TIMESTAMP2: - str->set_ascii(STRING_WITH_LEN("timestamp")); - break; - - case MYSQL_TYPE_LONGLONG: - str->set_ascii(STRING_WITH_LEN("bigint")); - break; - - case MYSQL_TYPE_INT24: - str->set_ascii(STRING_WITH_LEN("mediumint")); - break; - - case MYSQL_TYPE_NEWDATE: - case MYSQL_TYPE_DATE: - str->set_ascii(STRING_WITH_LEN("date")); - break; - - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_TIME2: - str->set_ascii(STRING_WITH_LEN("time")); - break; - - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_DATETIME2: - str->set_ascii(STRING_WITH_LEN("datetime")); - break; - - case MYSQL_TYPE_YEAR: - str->set_ascii(STRING_WITH_LEN("year")); - break; - - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_VARCHAR_COMPRESSED: - { - CHARSET_INFO *cs= str->charset(); - size_t length=0; - if (char_with_octets) - length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "varchar(%u octets)", metadata); - else - length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "varbinary(%u)", metadata); - str->length(length); - } - break; - - case MYSQL_TYPE_BIT: - { - CHARSET_INFO *cs= str->charset(); - int bit_length= 8 * (metadata >> 8) + (metadata & 0xFF); - size_t length= - cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "bit(%d)", bit_length); - str->length(length); - } - break; - - case MYSQL_TYPE_DECIMAL: - { - CHARSET_INFO *cs= str->charset(); - size_t length= - cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "decimal(%d,?)/*old*/", metadata); - str->length(length); - } - break; - - case MYSQL_TYPE_NEWDECIMAL: - { - CHARSET_INFO *cs= str->charset(); - size_t length= - cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "decimal(%d,%d)", metadata >> 8, metadata & 0xff); - str->length(length); - } - break; - - case MYSQL_TYPE_ENUM: - str->set_ascii(STRING_WITH_LEN("enum")); - break; - - case MYSQL_TYPE_SET: - str->set_ascii(STRING_WITH_LEN("set")); - break; - - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_BLOB_COMPRESSED: - /* - Field::real_type() lies regarding the actual type of a BLOB, so - it is necessary to check the pack length to figure out what kind - of blob it really is. - */ - switch (metadata) - { - case 1: - str->set_ascii(STRING_WITH_LEN("tinyblob")); - break; - - case 2: - str->set_ascii(STRING_WITH_LEN("blob")); - break; - - case 3: - str->set_ascii(STRING_WITH_LEN("mediumblob")); - break; - - case 4: - str->set_ascii(STRING_WITH_LEN("longblob")); - break; - - default: - DBUG_ASSERT(0); - break; - } - - if (type == MYSQL_TYPE_BLOB_COMPRESSED) - str->append(STRING_WITH_LEN(" compressed")); - break; - - case MYSQL_TYPE_STRING: - { - /* - This is taken from Field_string::unpack. - */ - CHARSET_INFO *cs= str->charset(); - uint bytes= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff); - size_t length=0; - if (char_with_octets) - length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "char(%u octets)", bytes); - else - length= cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), - "binary(%u)", bytes); - str->length(length); - } - break; - - case MYSQL_TYPE_GEOMETRY: - str->set_ascii(STRING_WITH_LEN("geometry")); - break; - - default: - str->set_ascii(STRING_WITH_LEN("<unknown type>")); - } - DBUG_VOID_RETURN; -} - - -/** - Check the order variable and print errors if the order is not - acceptable according to the current settings. - - @param order The computed order of the conversion needed. - @param rli The relay log info data structure: for error reporting. - */ -bool is_conversion_ok(int order, Relay_log_info *rli) -{ - DBUG_ENTER("is_conversion_ok"); - bool allow_non_lossy, allow_lossy; - - allow_non_lossy = slave_type_conversions_options & - (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY); - allow_lossy= slave_type_conversions_options & - (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_LOSSY); - - DBUG_PRINT("enter", ("order: %d, flags:%s%s", order, - allow_non_lossy ? " ALL_NON_LOSSY" : "", - allow_lossy ? " ALL_LOSSY" : "")); - if (order < 0 && !allow_non_lossy) - { - /* !!! Add error message saying that non-lossy conversions need to be allowed. */ - DBUG_RETURN(false); - } - - if (order > 0 && !allow_lossy) - { - /* !!! Add error message saying that lossy conversions need to be allowed. */ - DBUG_RETURN(false); - } - - DBUG_RETURN(true); -} - - -/** - Can a type potentially be converted to another type? - - This function check if the types are convertible and what - conversion is required. - - If conversion is not possible, and error is printed. - - If conversion is possible: - - - *order will be set to -1 if source type is smaller than target - type and a non-lossy conversion can be required. This includes - the case where the field types are different but types could - actually be converted in either direction. - - - *order will be set to 0 if no conversion is required. - - - *order will be set to 1 if the source type is strictly larger - than the target type and that conversion is potentially lossy. - - @param[in] field Target field - @param[in] type Source field type - @param[in] metadata Source field metadata - @param[in] rli Relay log info (for error reporting) - @param[in] mflags Flags from the table map event - @param[out] order Order between source field and target field - - @return @c true if conversion is possible according to the current - settings, @c false if conversion is not possible according to the - current setting. - */ -static bool -can_convert_field_to(Field *field, - enum_field_types source_type, uint16 metadata, - Relay_log_info *rli, uint16 mflags, - int *order_var) -{ - DBUG_ENTER("can_convert_field_to"); - bool same_type; -#ifndef DBUG_OFF - char field_type_buf[MAX_FIELD_WIDTH]; - String field_type(field_type_buf, sizeof(field_type_buf), &my_charset_latin1); - field->sql_type(field_type); - DBUG_PRINT("enter", ("field_type: %s, target_type: %d, source_type: %d, source_metadata: 0x%x", - field_type.c_ptr_safe(), field->real_type(), source_type, metadata)); -#endif - /** - @todo - Implement Field_varstring_cmopressed::real_type() and - Field_blob_compressed::real_type() properly. All occurencies - of Field::real_type() have to be inspected and adjusted if needed. - - Until it is not ready we have to compare source_type against - binlog_type() when replicating from or to compressed data types. - - @sa Comment for Field::binlog_type() - */ - if (source_type == MYSQL_TYPE_VARCHAR_COMPRESSED || - source_type == MYSQL_TYPE_BLOB_COMPRESSED || - field->binlog_type() == MYSQL_TYPE_VARCHAR_COMPRESSED || - field->binlog_type() == MYSQL_TYPE_BLOB_COMPRESSED) - same_type= field->binlog_type() == source_type; - else - same_type= field->real_type() == source_type; - - /* - If the real type is the same, we need to check the metadata to - decide if conversions are allowed. - */ - if (same_type) - { - if (metadata == 0) // Metadata can only be zero if no metadata was provided - { - /* - If there is no metadata, we either have an old event where no - metadata were supplied, or a type that does not require any - metadata. In either case, conversion can be done but no - conversion table is necessary. - */ - DBUG_PRINT("debug", ("Base types are identical, but there is no metadata")); - *order_var= 0; - DBUG_RETURN(true); - } - - DBUG_PRINT("debug", ("Base types are identical, doing field size comparison")); - if (field->compatible_field_size(metadata, rli, mflags, order_var)) - DBUG_RETURN(is_conversion_ok(*order_var, rli)); - else - DBUG_RETURN(false); - } - else if ( - /* - Conversion from MariaDB TIMESTAMP(0), TIME(0), DATETIME(0) - to the corresponding MySQL56 types is non-lossy. - */ - (metadata == 0 && - ((field->real_type() == MYSQL_TYPE_TIMESTAMP2 && - source_type == MYSQL_TYPE_TIMESTAMP) || - (field->real_type() == MYSQL_TYPE_TIME2 && - source_type == MYSQL_TYPE_TIME) || - (field->real_type() == MYSQL_TYPE_DATETIME2 && - source_type == MYSQL_TYPE_DATETIME))) || - /* - Conversion from MySQL56 TIMESTAMP(N), TIME(N), DATETIME(N) - to the corresponding MariaDB or MySQL55 types is non-lossy. - */ - (metadata == field->decimals() && - ((field->real_type() == MYSQL_TYPE_TIMESTAMP && - source_type == MYSQL_TYPE_TIMESTAMP2) || - (field->real_type() == MYSQL_TYPE_TIME && - source_type == MYSQL_TYPE_TIME2) || - (field->real_type() == MYSQL_TYPE_DATETIME && - source_type == MYSQL_TYPE_DATETIME2)))) - { - /* - TS-TODO: conversion from FSP1>FSP2. - */ - *order_var= -1; - DBUG_RETURN(true); - } - else if (!slave_type_conversions_options) - DBUG_RETURN(false); - - /* - Here, from and to will always be different. Since the types are - different, we cannot use the compatible_field_size() function, but - have to rely on hard-coded max-sizes for fields. - */ - - DBUG_PRINT("debug", ("Base types are different, checking conversion")); - switch (source_type) // Source type (on master) - { - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - switch (field->real_type()) - { - case MYSQL_TYPE_NEWDECIMAL: - /* - Then the other type is either FLOAT, DOUBLE, or old style - DECIMAL, so we require lossy conversion. - */ - *order_var= 1; - DBUG_RETURN(is_conversion_ok(*order_var, rli)); - - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_FLOAT: - case MYSQL_TYPE_DOUBLE: - { - if (source_type == MYSQL_TYPE_NEWDECIMAL || - source_type == MYSQL_TYPE_DECIMAL) - *order_var = 1; // Always require lossy conversions - else - *order_var= compare_lengths(field, source_type, metadata); - DBUG_ASSERT(*order_var != 0); - DBUG_RETURN(is_conversion_ok(*order_var, rli)); - } - - default: - DBUG_RETURN(false); - } - break; - - /* - The length comparison check will do the correct job of comparing - the field lengths (in bytes) of two integer types. - */ - case MYSQL_TYPE_TINY: - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_LONGLONG: - switch (field->real_type()) - { - case MYSQL_TYPE_TINY: - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_LONGLONG: - /* - max_display_length_for_field() is not fully precise for the integer - data types. So its result cannot be compared to the result of - field->max_dispay_length() when the table field and the binlog field - are of the same type. - This code should eventually be rewritten not to use - compare_lengths(), to detect subtype/supetype relations - just using the type codes. - */ - DBUG_ASSERT(source_type != field->real_type()); - *order_var= compare_lengths(field, source_type, metadata); - DBUG_ASSERT(*order_var != 0); - DBUG_RETURN(is_conversion_ok(*order_var, rli)); - - default: - DBUG_RETURN(false); - } - break; - - /* - Since source and target type is different, and it is not possible - to convert bit types to anything else, this will return false. - */ - case MYSQL_TYPE_BIT: - DBUG_RETURN(false); - - /* - If all conversions are disabled, it is not allowed to convert - between these types. Since the TEXT vs. BINARY is distinguished by - the charset, and the charset is not replicated, we cannot - currently distinguish between , e.g., TEXT and BLOB. - */ - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_BLOB_COMPRESSED: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_VARCHAR_COMPRESSED: - switch (field->real_type()) - { - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_BLOB_COMPRESSED: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_VAR_STRING: - case MYSQL_TYPE_VARCHAR: - case MYSQL_TYPE_VARCHAR_COMPRESSED: - *order_var= compare_lengths(field, source_type, metadata); - /* - Here we know that the types are different, so if the order - gives that they do not require any conversion, we still need - to have non-lossy conversion enabled to allow conversion - between different (string) types of the same length. - */ - if (*order_var == 0) - *order_var= -1; - DBUG_RETURN(is_conversion_ok(*order_var, rli)); - - default: - DBUG_RETURN(false); - } - break; - - case MYSQL_TYPE_GEOMETRY: - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_NULL: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_TIMESTAMP2: - case MYSQL_TYPE_TIME2: - DBUG_RETURN(false); - case MYSQL_TYPE_NEWDATE: - { - if (field->real_type() == MYSQL_TYPE_DATETIME2 || - field->real_type() == MYSQL_TYPE_DATETIME) - { - *order_var= -1; - DBUG_RETURN(is_conversion_ok(*order_var, rli)); - } - else - { - DBUG_RETURN(false); - } - } - break; - - //case MYSQL_TYPE_DATETIME: TODO: fix MDEV-17394 and uncomment. - // - //The "old" type does not specify the fraction part size which is required - //for correct conversion. - case MYSQL_TYPE_DATETIME2: - { - if (field->real_type() == MYSQL_TYPE_NEWDATE) - { - *order_var= 1; - DBUG_RETURN(is_conversion_ok(*order_var, rli)); - } - else - { - DBUG_RETURN(false); - } - } - break; - } - DBUG_RETURN(false); // To keep GCC happy -} - - -/** - Is the definition compatible with a table? - - This function will compare the master table with an existing table - on the slave and see if they are compatible with respect to the - current settings of @c SLAVE_TYPE_CONVERSIONS. - - If the tables are compatible and conversions are required, @c - *tmp_table_var will be set to a virtual temporary table with field - pointers for the fields that require conversions. This allow simple - checking of whether a conversion are to be applied or not. - - If tables are compatible, but no conversions are necessary, @c - *tmp_table_var will be set to NULL. - - @param rli_arg[in] - Relay log info, for error reporting. - - @param table[in] - Table to compare with - - @param tmp_table_var[out] - Virtual temporary table for performing conversions, if necessary. - - @retval true Master table is compatible with slave table. - @retval false Master table is not compatible with slave table. -*/ -bool -table_def::compatible_with(THD *thd, rpl_group_info *rgi, - TABLE *table, TABLE **conv_table_var) - const -{ - /* - We only check the initial columns for the tables. - */ - uint const cols_to_check= MY_MIN(table->s->fields, size()); - Relay_log_info *rli= rgi->rli; - TABLE *tmp_table= NULL; - - for (uint col= 0 ; col < cols_to_check ; ++col) - { - Field *const field= table->field[col]; - int order; - if (can_convert_field_to(field, type(col), field_metadata(col), rli, m_flags, &order)) - { - DBUG_PRINT("debug", ("Checking column %d -" - " field '%s' can be converted - order: %d", - col, field->field_name.str, order)); - DBUG_ASSERT(order >= -1 && order <= 1); - - /* - If order is not 0, a conversion is required, so we need to set - up the conversion table. - */ - if (order != 0 && tmp_table == NULL) - { - /* - This will create the full table with all fields. This is - necessary to ge the correct field lengths for the record. - */ - tmp_table= create_conversion_table(thd, rgi, table); - if (tmp_table == NULL) - return false; - /* - Clear all fields up to, but not including, this column. - */ - for (unsigned int i= 0; i < col; ++i) - tmp_table->field[i]= NULL; - } - - if (order == 0 && tmp_table != NULL) - tmp_table->field[col]= NULL; - } - else - { - DBUG_PRINT("debug", ("Checking column %d -" - " field '%s' can not be converted", - col, field->field_name.str)); - DBUG_ASSERT(col < size() && col < table->s->fields); - DBUG_ASSERT(table->s->db.str && table->s->table_name.str); - DBUG_ASSERT(table->in_use); - const char *db_name= table->s->db.str; - const char *tbl_name= table->s->table_name.str; - char source_buf[MAX_FIELD_WIDTH]; - char target_buf[MAX_FIELD_WIDTH]; - String source_type(source_buf, sizeof(source_buf), &my_charset_latin1); - String target_type(target_buf, sizeof(target_buf), &my_charset_latin1); - THD *thd= table->in_use; - bool char_with_octets= field->cmp_type() == STRING_RESULT ? - field->has_charset() : true; - - show_sql_type(type(col), field_metadata(col), &source_type, - char_with_octets); - field->sql_rpl_type(&target_type); - - rli->report(ERROR_LEVEL, ER_SLAVE_CONVERSION_FAILED, rgi->gtid_info(), - ER_THD(thd, ER_SLAVE_CONVERSION_FAILED), - col, db_name, tbl_name, - source_type.c_ptr_safe(), target_type.c_ptr_safe()); - return false; - } - } - -#ifndef DBUG_OFF - if (tmp_table) - { - for (unsigned int col= 0; col < tmp_table->s->fields; ++col) - if (tmp_table->field[col]) - { - char source_buf[MAX_FIELD_WIDTH]; - char target_buf[MAX_FIELD_WIDTH]; - String source_type(source_buf, sizeof(source_buf), &my_charset_latin1); - String target_type(target_buf, sizeof(target_buf), &my_charset_latin1); - tmp_table->field[col]->sql_type(source_type); - table->field[col]->sql_type(target_type); - DBUG_PRINT("debug", ("Field %s - conversion required." - " Source type: '%s', Target type: '%s'", - tmp_table->field[col]->field_name.str, - source_type.c_ptr_safe(), target_type.c_ptr_safe())); - } - } -#endif - - *conv_table_var= tmp_table; - return true; -} - - -/** - A wrapper to Virtual_tmp_table, to get access to its constructor, - which is protected for safety purposes (against illegal use on stack). -*/ -class Virtual_conversion_table: public Virtual_tmp_table -{ -public: - Virtual_conversion_table(THD *thd) :Virtual_tmp_table(thd) { } - /** - Add a new field into the virtual table. - @param sql_type - The real_type of the field. - @param metadata - The RBR binary log metadata for this field. - @param target_field - The field from the target table, to get extra - attributes from (e.g. typelib in case of ENUM). - */ - bool add(enum_field_types sql_type, - uint16 metadata, const Field *target_field) - { - const Type_handler *handler= Type_handler::get_handler_by_real_type(sql_type); - if (!handler) - { - sql_print_error("In RBR mode, Slave received unknown field type field %d " - " for column Name: %s.%s.%s.", - (int) sql_type, - target_field->table->s->db.str, - target_field->table->s->table_name.str, - target_field->field_name.str); - return true; - } - Field *tmp= handler->make_conversion_table_field(this, metadata, - target_field); - if (!tmp) - return true; - Virtual_tmp_table::add(tmp); - DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d," - " maybe_null: %d, unsigned_flag: %d, pack_length: %u", - sql_type, target_field->field_name.str, - tmp->field_length, tmp->decimals(), TRUE, - tmp->flags, tmp->pack_length())); - return false; - } -}; - - -/** - Create a conversion table. - - If the function is unable to create the conversion table, an error - will be printed and NULL will be returned. - - @return Pointer to conversion table, or NULL if unable to create - conversion table. - */ - -TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi, - TABLE *target_table) const -{ - DBUG_ENTER("table_def::create_conversion_table"); - - Virtual_conversion_table *conv_table; - Relay_log_info *rli= rgi->rli; - /* - At slave, columns may differ. So we should create - MY_MIN(columns@master, columns@slave) columns in the - conversion table. - */ - uint const cols_to_create= MY_MIN(target_table->s->fields, size()); - if (!(conv_table= new(thd) Virtual_conversion_table(thd)) || - conv_table->init(cols_to_create)) - goto err; - for (uint col= 0 ; col < cols_to_create; ++col) - { - if (conv_table->add(type(col), field_metadata(col), - target_table->field[col])) - { - DBUG_PRINT("debug", ("binlog_type: %d, metadata: %04X, target_field: '%s'" - " make_conversion_table_field() failed", - binlog_type(col), field_metadata(col), - target_table->field[col]->field_name.str)); - goto err; - } - } - - if (conv_table->open()) - goto err; // Could not allocate record buffer? - - DBUG_RETURN(conv_table); - -err: - if (conv_table) - delete conv_table; - rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION, rgi->gtid_info(), - ER_THD(thd, ER_SLAVE_CANT_CREATE_CONVERSION), - target_table->s->db.str, - target_table->s->table_name.str); - DBUG_RETURN(NULL); -} -#endif /* MYSQL_CLIENT */ table_def::table_def(unsigned char *types, ulong size, uchar *field_metadata, int metadata_size, @@ -1256,67 +334,3 @@ bool event_checksum_test(uchar *event_buf, ulong event_len, enum enum_binlog_che } return res; } - -#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) - -Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL) -{ - my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16, MYF(0)); -} - -Deferred_log_events::~Deferred_log_events() -{ - delete_dynamic(&array); -} - -int Deferred_log_events::add(Log_event *ev) -{ - last_added= ev; - insert_dynamic(&array, (uchar*) &ev); - return 0; -} - -bool Deferred_log_events::is_empty() -{ - return array.elements == 0; -} - -bool Deferred_log_events::execute(rpl_group_info *rgi) -{ - bool res= false; - DBUG_ENTER("Deferred_log_events::execute"); - DBUG_ASSERT(rgi->deferred_events_collecting); - - rgi->deferred_events_collecting= false; - for (uint i= 0; !res && i < array.elements; i++) - { - Log_event *ev= (* (Log_event **) - dynamic_array_ptr(&array, i)); - res= ev->apply_event(rgi); - } - rgi->deferred_events_collecting= true; - DBUG_RETURN(res); -} - -void Deferred_log_events::rewind() -{ - /* - Reset preceding Query log event events which execution was - deferred because of slave side filtering. - */ - if (!is_empty()) - { - for (uint i= 0; i < array.elements; i++) - { - Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i); - delete ev; - } - last_added= NULL; - if (array.elements > array.max_element) - freeze_size(&array); - reset_dynamic(&array); - } - last_added= NULL; -} - -#endif |