1
0
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:
Alexander Barkov
2024-02-14 12:21:59 +04:00
parent 74c97a41fc
commit 7246054cbb
17 changed files with 1154 additions and 64 deletions

View File

@@ -8804,41 +8804,48 @@ bool Type_handler_string_result::union_element_finalize(Item_type_holder* item)
/***************************************************************************/
void Type_handler_var_string::
Column_definition_implicit_upgrade(Column_definition *c) const
const Type_handler *
Type_handler_var_string::type_handler_for_implicit_upgrade() const
{
// Change old VARCHAR to new VARCHAR
c->set_handler(&type_handler_varchar);
return &type_handler_varchar;
}
void Type_handler::
Column_definition_implicit_upgrade_to_this(Column_definition *old) const
{
old->set_handler(this);
}
void Type_handler_time_common::
Column_definition_implicit_upgrade(Column_definition *c) const
Column_definition_implicit_upgrade_to_this(Column_definition *old) const
{
if (opt_mysql56_temporal_format)
c->set_handler(&type_handler_time2);
old->set_handler(&type_handler_time2);
else
c->set_handler(&type_handler_time);
old->set_handler(&type_handler_time);
}
void Type_handler_datetime_common::
Column_definition_implicit_upgrade(Column_definition *c) const
Column_definition_implicit_upgrade_to_this(Column_definition *old) const
{
if (opt_mysql56_temporal_format)
c->set_handler(&type_handler_datetime2);
old->set_handler(&type_handler_datetime2);
else
c->set_handler(&type_handler_datetime);
old->set_handler(&type_handler_datetime);
}
void Type_handler_timestamp_common::
Column_definition_implicit_upgrade(Column_definition *c) const
Column_definition_implicit_upgrade_to_this(Column_definition *old) const
{
if (opt_mysql56_temporal_format)
c->set_handler(&type_handler_timestamp2);
old->set_handler(&type_handler_timestamp2);
else
c->set_handler(&type_handler_timestamp);
old->set_handler(&type_handler_timestamp);
}