• Alexander Barkov's avatar
    MDEV-33442 REPAIR TABLE corrupts UUIDs · 7246054c
    Alexander Barkov authored
    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.
    7246054c
sql_admin.cc 56.5 KB