1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-11412 Ensure that table is truly dropped when using DROP TABLE

don't do table discovery on DROP. DROP falls back to "force"
approach when a table isn't found and will try to drop in all
engines anyway. That is, trying to discover in all engines before
the drop is redundant and may be expensive.
This commit is contained in:
Sergei Golubchik
2020-06-16 10:33:48 +02:00
parent 79a3f96166
commit 7c2ba9e9d7
6 changed files with 85 additions and 73 deletions

View File

@ -2246,7 +2246,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
bool non_tmp_table_deleted= 0;
bool is_drop_tmp_if_exists_added= 0;
bool was_view= 0, was_table= 0, is_sequence, log_if_exists= if_exists;
bool was_view= 0, was_table= 0, log_if_exists= if_exists;
const char *object_to_drop= (drop_sequence) ? "SEQUENCE" : "TABLE";
String normal_tables;
String built_trans_tmp_query, built_non_trans_tmp_query;
@ -2306,13 +2306,14 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
for (table= tables; table; table= table->next_local)
{
bool is_trans= 0, frm_was_deleted= 0, temporary_table_was_dropped= 0;
bool is_trans= 0, temporary_table_was_dropped= 0;
bool table_creation_was_logged= 0;
bool local_non_tmp_error= 0, frm_exists= 0, wrong_drop_sequence= 0;
bool local_non_tmp_error= 0, wrong_drop_sequence= 0;
bool table_dropped= 0;
const LEX_CSTRING db= table->db;
const LEX_CSTRING table_name= table->table_name;
handlerton *table_type= 0;
handlerton *hton= 0;
Table_type table_type;
size_t path_length= 0;
char *path_end= 0;
@ -2410,13 +2411,32 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
if (drop_temporary)
{
/* "DROP TEMPORARY" but a temporary table was not found */
unknown_tables.append(&db);
unknown_tables.append('.');
unknown_tables.append(&table_name);
unknown_tables.append(',');
error= ENOENT;
not_found_errors++;
continue;
}
else if (((frm_exists= ha_table_exists(thd, &db, &alias, &table_type,
&is_sequence)) == 0 &&
table_type == 0) ||
(!drop_view && (was_view= (table_type == view_pseudo_hton))) ||
(drop_sequence && !is_sequence))
{
char engine_buf[NAME_CHAR_LEN + 1];
LEX_CSTRING engine= { engine_buf, 0 };
table_type= dd_frm_type(thd, path, &engine);
if (table_type == TABLE_TYPE_NORMAL || table_type == TABLE_TYPE_SEQUENCE)
{
plugin_ref p= plugin_lock_by_name(thd, &engine,
MYSQL_STORAGE_ENGINE_PLUGIN);
hton= p ? plugin_hton(p) : NULL;
}
// note that for TABLE_TYPE_VIEW and TABLE_TYPE_UNKNOWN hton == NULL
}
was_view= table_type == TABLE_TYPE_VIEW;
if ((table_type == TABLE_TYPE_UNKNOWN) || (was_view && !drop_view) ||
(table_type != TABLE_TYPE_SEQUENCE && drop_sequence))
{
/*
One of the following cases happened:
@ -2424,34 +2444,19 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
. "DROP TABLE" statement, but it's a view.
. "DROP SEQUENCE", but it's not a sequence
*/
wrong_drop_sequence= drop_sequence && table_type;
wrong_drop_sequence= drop_sequence && hton;
was_table|= wrong_drop_sequence;
local_non_tmp_error= 1;
error= -1;
if ((!frm_exists && !table_type)) // no .frm
error= ENOENT;
error= table_type == TABLE_TYPE_UNKNOWN ? ENOENT : -1;
}
else
{
if (WSREP(thd) && !wsrep_should_replicate_ddl(thd, table_type->db_type))
if (WSREP(thd) && hton && !wsrep_should_replicate_ddl(thd, hton->db_type))
{
error= 1;
goto err;
}
/*
It could happen that table's share in the table definition cache
is the only thing that keeps the engine plugin loaded
(if it is uninstalled and waits for the ref counter to drop to 0).
In this case, the tdc_remove_table() below will release and unload
the plugin. And ha_delete_table() will get a dangling pointer.
Let's lock the plugin till the end of the statement.
*/
if (table_type && table_type != view_pseudo_hton)
ha_lock_engine(thd, table_type);
if (thd->locked_tables_mode == LTM_LOCK_TABLES ||
thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)
{
@ -2474,13 +2479,12 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
// Remove extension for delete
*path_end= '\0';
if (table_type && table_type != view_pseudo_hton &&
table_type->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
if (hton && hton->flags & HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
log_if_exists= 1;
thd->replication_flags= 0;
error= ha_delete_table(thd, table_type, path, &db,
&table_name, !dont_log_query);
bool enoent_warning= !dont_log_query && !(hton && hton->discover_table);
error= ha_delete_table(thd, hton, path, &db, &table_name, enoent_warning);
if (!error)
table_dropped= 1;
@ -2508,8 +2512,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
{
int frm_delete_error= 0;
/* Delete the table definition file */
if (table_type && table_type != view_pseudo_hton &&
(table_type->discover_table || error))
if (hton && (hton->discover_table || error))
{
/*
Table type is using discovery and may not need a .frm file
@ -2527,7 +2530,6 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
frm_delete_error= my_errno;
DBUG_ASSERT(frm_delete_error);
}
frm_was_deleted= 1; // We tried to delete .frm
if (frm_delete_error)
{
@ -2548,10 +2550,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
scan all engines try to drop the table from there.
This is to ensure we don't have any partial table files left.
*/
if (non_existing_table_error(error) && !drop_temporary &&
table_type != view_pseudo_hton && !wrong_drop_sequence)
if (non_existing_table_error(error) && !wrong_drop_sequence)
{
int ferror= 0;
DBUG_ASSERT(!was_view);
/* Remove extension for delete */
*path_end= '\0';
@ -2567,14 +2569,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
{
ferror= 0; // Ignore table not found
/* Delete the table definition file */
if (!frm_was_deleted)
{
strmov(path_end, reg_ext);
if (mysql_file_delete(key_file_frm, path,
MYF(MY_WME | MY_IGNORE_ENOENT)))
ferror= my_errno;
}
/* Delete the frm file again (just in case it was rediscovered) */
strmov(path_end, reg_ext);
if (mysql_file_delete(key_file_frm, path, MYF(MY_WME|MY_IGNORE_ENOENT)))
ferror= my_errno;
}
if (!error)
error= ferror;
@ -2642,7 +2640,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
mysql_audit_drop_table(thd, table);
}
if (!dont_log_query && !drop_temporary &&
if (!dont_log_query &&
(!error || table_dropped || non_existing_table_error(error)))
{
non_tmp_table_deleted|= (if_exists || table_dropped);