mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-33442 REPAIR TABLE corrupts UUIDs
Problem: REPAIR TABLE executed for a pre-MDEV-29959 table (with the old UUID format) updated the server version in the FRM file without rewriting the data, so it created a new FRM for old UUIDs. After that MariaDB could not read UUIDs correctly. Fix: - Adding a new virtual method in class Type_handler: virtual bool type_handler_for_implicit_upgrade() const; * For the up-to-date data types it returns "this". * For the data types which need to be implicitly upgraded during REPAIR TABLE or ALTER TABLE, it returns a pointer to a new replacement data type handler. Old VARCHAR and old UUID type handlers override this method. See more comments below. - Changing the semantics of the method Type_handler::Column_definition_implicit_upgrade(Column_definition *c) to the opposite, so now: * c->type_handler() references the old data type (to upgrade from) * "this" references the new data type (to upgrade to). Before this change Column_definition_implicit_upgrade() was supposed to be called with the old data type handler (to upgrade from). Renaming the method to Column_definition_implicit_upgrade_to_this(), to avoid automatic merges in this method. Reflecting this change in Create_field::upgrade_data_types(). - Replacing the hard-coded data type tests inside handler::check_old_types() to a call for the new virtual method Type_handler::type_handler_for_implicit_upgrade() - Overriding Type_handler_fbt::type_handler_for_implicit_upgrade() to call a new method FbtImpl::type_handler_for_implicit_upgrade(). Reasoning: Type_handler_fbt is a template, so it has access only to "this". So in case of UUID data types, the type handler for old UUID knows nothing about the type handler of new UUID inside sql_type_fixedbin.h. So let's have Type_handler_fbt delegate type_handler_for_implicit_upgrade() to its Type_collection, which knows both new UUID and old UUID. - Adding Type_collection_uuid::type_handler_for_implicit_upgrade(). It returns a pointer to the new UUID type handler. - Overriding Type_handler_var_string::type_handler_for_implicit_upgrade() to return a pointer to type_handler_varchar (true VARCHAR). - Cleanup: these two methods: handler::check_old_types() handler::ha_check_for_upgrade() were always called consequently. So moving the call for check_old_types() inside ha_check_for_upgrade(), and making check_old_types() private. - Cleanup: removing the "bool varchar" parameter from fill_alter_inplace_info(), as its not used any more.
This commit is contained in:
@@ -6601,8 +6601,6 @@ static KEY *find_key_ci(const char *key_name, KEY *key_start, KEY *key_end)
|
||||
|
||||
@param thd Thread
|
||||
@param table The original table.
|
||||
@param varchar Indicates that new definition has new
|
||||
VARCHAR column.
|
||||
@param[in/out] ha_alter_info Data structure which already contains
|
||||
basic information about create options,
|
||||
field and keys for the new version of
|
||||
@@ -6637,7 +6635,7 @@ static KEY *find_key_ci(const char *key_name, KEY *key_start, KEY *key_end)
|
||||
@retval false success
|
||||
*/
|
||||
|
||||
static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
|
||||
static bool fill_alter_inplace_info(THD *thd, TABLE *table,
|
||||
Alter_inplace_info *ha_alter_info)
|
||||
{
|
||||
Field **f_ptr, *field;
|
||||
@@ -6687,13 +6685,6 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
|
||||
if (alter_info->flags & ALTER_CHANGE_COLUMN)
|
||||
ha_alter_info->handler_flags|= ALTER_COLUMN_DEFAULT;
|
||||
|
||||
/*
|
||||
If we altering table with old VARCHAR fields we will be automatically
|
||||
upgrading VARCHAR column types.
|
||||
*/
|
||||
if (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar)
|
||||
ha_alter_info->handler_flags|= ALTER_STORED_COLUMN_TYPE;
|
||||
|
||||
DBUG_PRINT("info", ("handler_flags: %llu", ha_alter_info->handler_flags));
|
||||
|
||||
/*
|
||||
@@ -6735,6 +6726,30 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar,
|
||||
Check if type of column has changed.
|
||||
*/
|
||||
bool is_equal= field->is_equal(*new_field);
|
||||
|
||||
if (is_equal)
|
||||
{
|
||||
const Type_handler *th= field->type_handler();
|
||||
if (th != th->type_handler_for_implicit_upgrade())
|
||||
{
|
||||
/*
|
||||
The field data type says it wants upgrade.
|
||||
This should not be possible:
|
||||
- if this is a new column definition, e.g. from statements like:
|
||||
ALTER TABLE t1 ADD a INT;
|
||||
ALTER TABLE t1 MODIFY a INT;
|
||||
then it's coming from the parser, which returns
|
||||
only up-to-date data types.
|
||||
- if this is an old column definition, e.g. from:
|
||||
ALTER TABLE t1 COMMENT 'new comment';
|
||||
it should have ealier called Column_definition_implicit_upgrade(),
|
||||
which replaces old data types to up-to-date data types.
|
||||
*/
|
||||
DBUG_ASSERT(0);
|
||||
is_equal= false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_equal)
|
||||
{
|
||||
if (field->table->file->can_convert_nocopy(*field, *new_field))
|
||||
@@ -10105,12 +10120,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
|
||||
*/
|
||||
KEY *key_info;
|
||||
uint key_count;
|
||||
/*
|
||||
Remember if the new definition has new VARCHAR column;
|
||||
create_info->varchar will be reset in create_table_impl()/
|
||||
mysql_prepare_create_table().
|
||||
*/
|
||||
bool varchar= create_info->varchar, table_creation_was_logged= 0;
|
||||
bool table_creation_was_logged= 0;
|
||||
bool binlog_as_create_select= 0, log_if_exists= 0;
|
||||
uint tables_opened;
|
||||
handlerton *new_db_type= create_info->db_type, *old_db_type;
|
||||
@@ -10928,7 +10938,7 @@ do_continue:;
|
||||
bool use_inplace= true;
|
||||
|
||||
/* Fill the Alter_inplace_info structure. */
|
||||
if (fill_alter_inplace_info(thd, table, varchar, &ha_alter_info))
|
||||
if (fill_alter_inplace_info(thd, table, &ha_alter_info))
|
||||
goto err_new_table_cleanup;
|
||||
|
||||
alter_ctx.tmp_storage_engine_name_partitioned=
|
||||
|
Reference in New Issue
Block a user