Bug #43039 mysql_truncate() uses ha_resolve_by_legacy_type()
Submitted: 20 Feb 2009 1:14 Modified: 26 Feb 2009 7:23
Reporter: Marc ALFF Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: General Severity:S1 (Critical)
Version:mysql-6.0.11, 5.1 OS:Any
Assigned to: CPU Architecture:Any

[20 Feb 2009 1:14] Marc ALFF
Description:
It's currently impossible to truly implement a dynamic plugin in MySQL,
due to the following flaw:

1)
The value of handlerton->db_type is allocated dynamically in
ha_initialize_handlerton(), as follows:

        int idx= (int) DB_TYPE_FIRST_DYNAMIC;

        while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
          idx++;

In other words, the value assigned depends of what *other* plugin is
currently installed in the server binary, and depends on the installation
order.

2)
This value is stored in the .frm file

3)
This value is read again from the .frm file, in mysql_frm_type():
  *dbt= (enum legacy_db_type) (uint) *(header + 3);

The problem is that 2) and 3) may not happen in the same instance of
./mysqld.
In particular, if the server is shutdown, and another server is restarted,
with a different set of (dynamic ?) plugin loaded, or plugins loaded in a
different order, the value of legacy_db_type stored in the .frm file will
now point to a *different* storage engine handlerton.

This affects in particular:
- TRUNCATE TABLE, which is confused about HTON_CAN_RECREATE, since it reads
  the engine flag of the wrong engine using ha_resolve_by_legacy_type()
  (this has been verified first hand)
- probably every code using the result of the 3rd parameter of
  mysql_frm_type().

The only way to implement a 'dynamic' storage engine is to actually *not*
rely on the db_type allocation in ha_initialize_handlerton(),
and add explicitly a new enum entry in enum legacy_db_type in handler.h

Of course, by doing so, a code change is required in the server code,
which defeats the purpose of a 'dynamic' plugin.

How to repeat:
Implement a storage engine 'E'
Start a server, load  set #1 of plugins, plus E
Create a table with E
Stop the server
Start a server, load a set #2 of plugins, plus E
TRUNCATE the table created: the code does not use the correct engine handlerton,
which leads to unpredictable results

Verified in 6.0.11.
Earlier versions (5.1) are most likely affected also

Suggested fix:
N/A
[21 Feb 2009 8:43] Sveta Smirnova
Thank you for the report.

I can not repeat described behavior with example, csv and daemon_example plugins.  Are there special requirements for plugins to repeat this? Ho mysqld should be restarted?
[25 Feb 2009 15:46] Marc ALFF
To clarify, not all plugin types are affected, only storage engines plugins are.
This is because the issue is with handlerton::db_type.

The CSV engine can not be used to reproduce the bug, since the CSV engine code contains the following line:
  storage/csv/ha_tina.cc:  tina_hton->db_type= DB_TYPE_CSV_DB;
which is what the bug report refers to in this paragraph:
"
The only way to implement a 'dynamic' storage engine is to actually *not*
rely on the db_type allocation in ha_initialize_handlerton(),
and add explicitly a new enum entry in enum legacy_db_type in handler.h
"

The problem is that line should not be there.

To reproduce the bug, either not set db_type at all in a storage engine initialization function, or set it to DB_TYPE_UNKNOWN, like in:
  storage/maria/ha_maria.cc:  maria_hton->db_type= DB_TYPE_UNKNOWN;

This corresponds to what a truly dynamic storage engine is supposed to implement, since a dynamic engine implementor is *not* supposed to change the server code what so ever, which imply not adding a new enum in the server code in sql/handler.h (db_type).
[26 Feb 2009 7:20] Sergei Golubchik
db_type is a legacy field and it shouldn't be used - exactly for the reason you described. If any of the sql/ code relies on db_type for anything besides old hard-coded values (like DB_TYPE_MYISAM or DB_TYPE_HEAP) feel free to report it as a bug.
[26 Feb 2009 7:23] Sergei Golubchik
let's just keep it open with a more appropriate synopsis.