mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
MDEV-28956 Locking is broken if CREATE OR REPLACE fails under LOCK TABLES
add_back_last_deleted_lock() was called when the lock was never removed. Lock is removed in finalize_atomic_replace() in close_all_tables_for_name(). finalize_atomic_replace() is done only for successful operation. In non-atomic codepath it drops the table first, if anything fails later we don't need to return back the lock since there is no table now. So the fix is required as well.
This commit is contained in:
@ -4509,27 +4509,47 @@ void HA_CREATE_INFO::finalize_ddl(THD *thd, bool roll_back)
|
||||
}
|
||||
|
||||
|
||||
bool HA_CREATE_INFO::finalize_locked_tables(THD *thd)
|
||||
/**
|
||||
Finalize operation of LOCK TABLES mode for CREATE TABLE family of commands.
|
||||
|
||||
@param operation_failed Notify if the callee CREATE fails the operation
|
||||
@return true on error, false on success
|
||||
*/
|
||||
bool HA_CREATE_INFO::finalize_locked_tables(THD *thd, bool operation_failed)
|
||||
{
|
||||
DBUG_ASSERT(pos_in_locked_tables);
|
||||
DBUG_ASSERT(thd->locked_tables_mode);
|
||||
DBUG_ASSERT(thd->variables.option_bits & OPTION_TABLE_LOCK);
|
||||
/*
|
||||
Add back the deleted table and re-created table as a locked table
|
||||
This should always work as we have a meta lock on the table.
|
||||
*/
|
||||
thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables);
|
||||
if (!operation_failed)
|
||||
{
|
||||
/*
|
||||
Add back the deleted table and re-created table as a locked table
|
||||
This should always work as we have a meta lock on the table.
|
||||
*/
|
||||
thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables);
|
||||
}
|
||||
if (thd->locked_tables_list.reopen_tables(thd, false))
|
||||
{
|
||||
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
The lock was made exclusive in create_table_impl(). We have now
|
||||
to bring it back to it's orginal state
|
||||
*/
|
||||
TABLE *table= pos_in_locked_tables->table;
|
||||
table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
||||
if (is_atomic_replace() || !operation_failed)
|
||||
{
|
||||
/*
|
||||
The lock was made exclusive in create_table_impl(). We have now
|
||||
to bring it back to it's orginal state.
|
||||
*/
|
||||
TABLE *table= pos_in_locked_tables->table;
|
||||
table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
In failed non-atomic we have nothing to downgrade:
|
||||
original table was deleted and the lock was already removed.
|
||||
*/
|
||||
DBUG_ASSERT(!pos_in_locked_tables->table);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -5278,7 +5298,7 @@ err:
|
||||
*/
|
||||
if (thd->locked_tables_mode && pos_in_locked_tables &&
|
||||
create_info->or_replace())
|
||||
result|= (int) create_info->finalize_locked_tables(thd);
|
||||
result|= (int) create_info->finalize_locked_tables(thd, result);
|
||||
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
@ -6023,7 +6043,7 @@ err:
|
||||
*/
|
||||
if (thd->locked_tables_mode && pos_in_locked_tables &&
|
||||
create_info->or_replace())
|
||||
res|= (int) local_create_info.finalize_locked_tables(thd);
|
||||
res|= (int) local_create_info.finalize_locked_tables(thd, res);
|
||||
|
||||
DBUG_RETURN(res != 0);
|
||||
}
|
||||
|
Reference in New Issue
Block a user