1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +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

@ -3836,6 +3836,16 @@ public:
const Type_handler *res= type_handler_base();
return res ? res : this;
}
/*
In 10.11.8 the semantics of this method has changed to the opposite.
It used to be called with the old data type handler as "this".
Now it's called with the new data type hander as "this".
To avoid problems during merges, the method name was renamed.
*/
virtual const Type_handler *type_handler_for_implicit_upgrade() const
{
return this;
}
virtual const Type_handler *type_handler_for_comparison() const= 0;
virtual const Type_handler *type_handler_for_native_format() const
{
@ -3981,9 +3991,13 @@ public:
virtual bool validate_implicit_default_value(THD *thd,
const Column_definition &def)
const;
// Automatic upgrade, e.g. for ALTER TABLE t1 FORCE
virtual void Column_definition_implicit_upgrade(Column_definition *c) const
{ }
/*
Automatic upgrade, e.g. for REPAIR or ALTER TABLE t1 FORCE
- from the data type specified in old->type_handler()
- to the data type specified in "this"
*/
virtual void Column_definition_implicit_upgrade_to_this(
Column_definition *old) const;
// Validate CHECK constraint after the parser
virtual bool Column_definition_validate_check_constraint(THD *thd,
Column_definition *c)
@ -6188,7 +6202,8 @@ public:
const Type_handler *type_handler_for_comparison() const override;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
const override;
void Column_definition_implicit_upgrade(Column_definition *c) const override;
void Column_definition_implicit_upgrade_to_this(
Column_definition *old) const override;
bool Column_definition_fix_attributes(Column_definition *c) const override;
bool
Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
@ -6512,7 +6527,8 @@ public:
const Type_cast_attributes &attr) const override;
bool validate_implicit_default_value(THD *thd, const Column_definition &def)
const override;
void Column_definition_implicit_upgrade(Column_definition *c) const override;
void Column_definition_implicit_upgrade_to_this(
Column_definition *old) const override;
bool Column_definition_fix_attributes(Column_definition *c) const override;
bool
Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
@ -6650,7 +6666,8 @@ public:
{
return true;
}
void Column_definition_implicit_upgrade(Column_definition *c) const override;
void Column_definition_implicit_upgrade_to_this(
Column_definition *old) const override;
bool
Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
TABLE_SHARE *share,
@ -7000,6 +7017,7 @@ public:
{
return MYSQL_TYPE_VARCHAR;
}
const Type_handler *type_handler_for_implicit_upgrade() const override;
const Type_handler *type_handler_for_tmp_table(const Item *item) const override
{
return varstring_type_handler(item);
@ -7007,7 +7025,6 @@ public:
uint32 max_display_length_for_field(const Conv_source &src) const override;
void show_binlog_type(const Conv_source &src, const Field &dst, String *str)
const override;
void Column_definition_implicit_upgrade(Column_definition *c) const override;
bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,