diff options
author | Alexander Barkov <bar@mariadb.org> | 2015-12-04 16:38:42 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2015-12-04 16:38:42 +0400 |
commit | aee068085ddb13f700780eeb61fce29c1e37df63 (patch) | |
tree | 54097c8df3e15812add5f0b35f28a650f4501817 /sql/rpl_utility.cc | |
parent | 10408782335b3578fbbbfa3645a1be781e0867d7 (diff) | |
download | mariadb-git-aee068085ddb13f700780eeb61fce29c1e37df63.tar.gz |
MDEV-9238 Wrap create_virtual_tmp_table() into a class, split into different steps
Diffstat (limited to 'sql/rpl_utility.cc')
-rw-r--r-- | sql/rpl_utility.cc | 156 |
1 files changed, 67 insertions, 89 deletions
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 1c48d6bc937..244363e43ac 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -922,6 +922,51 @@ table_def::compatible_with(THD *thd, rpl_group_info *rgi, 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); + 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, + tmp->field_length, tmp->decimals(), TRUE, + tmp->flags, tmp->pack_length())); + return false; + } +}; + + /** Create a conversion table. @@ -937,8 +982,7 @@ TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi, { DBUG_ENTER("table_def::create_conversion_table"); - List<Column_definition> field_list; - TABLE *conv_table= NULL; + Virtual_conversion_table *conv_table; Relay_log_info *rli= rgi->rli; /* At slave, columns may differ. So we should create @@ -946,101 +990,35 @@ TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi, 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) { - Column_definition *field_def= - (Create_field*) alloc_root(thd->mem_root, sizeof(Create_field)); - bool unsigned_flag= 0; - if (field_list.push_back(field_def, thd->mem_root)) - DBUG_RETURN(NULL); - - uint decimals= 0; - TYPELIB* interval= NULL; - uint pack_length= 0; - uint32 max_length= - max_display_length_for_field(type(col), field_metadata(col)); - - switch(type(col)) { - int precision; - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - interval= static_cast<Field_enum*>(target_table->field[col])->typelib; - pack_length= field_metadata(col) & 0x00ff; - break; - - case MYSQL_TYPE_NEWDECIMAL: - /* - The display length of a DECIMAL type is not the same as the - length that should be supplied to make_field, so we correct - the length here. - */ - precision= field_metadata(col) >> 8; - decimals= field_metadata(col) & 0x00ff; - max_length= - my_decimal_precision_to_length(precision, decimals, FALSE); - break; - - case MYSQL_TYPE_DECIMAL: - sql_print_error("In RBR mode, Slave received incompatible DECIMAL field " - "(old-style decimal field) from Master while creating " - "conversion table. Please consider changing datatype on " - "Master to new style decimal by executing ALTER command for" - " column Name: %s.%s.%s.", - target_table->s->db.str, - target_table->s->table_name.str, - target_table->field[col]->field_name); + 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)); goto err; - - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_GEOMETRY: - pack_length= field_metadata(col) & 0x00ff; - break; - - case MYSQL_TYPE_TINY: - case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_LONGLONG: - /* - As we don't know if the integer was signed or not on the master, - assume we have same sign on master and slave. This is true when not - using conversions so it should be true also when using conversions. - */ - unsigned_flag= ((Field_num*) target_table->field[col])->unsigned_flag; - break; - default: - break; } - - DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d," - " maybe_null: %d, unsigned_flag: %d, pack_length: %u", - binlog_type(col), target_table->field[col]->field_name, - max_length, decimals, TRUE, unsigned_flag, - pack_length)); - field_def->init_for_tmp_table(type(col), - max_length, - decimals, - TRUE, // maybe_null - unsigned_flag, - pack_length); - field_def->charset= target_table->field[col]->charset(); - field_def->interval= interval; } - conv_table= create_virtual_tmp_table(thd, field_list); + if (conv_table->open()) + goto err; // Could not allocate record buffer? -err: - if (conv_table == NULL) - { - 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(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 */ |