summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2021-05-10 20:36:38 +0300
committerMonty <monty@mariadb.org>2021-05-10 21:11:46 +0300
commit621501f38bd8db1a334a6cd873db787a5a5070aa (patch)
treedfc0ac9c0ba0f51d3c5f4646bd28e72512f9dd78
parent5d8684863c630d8a13793963ef8fbd95e65bfe1c (diff)
downloadmariadb-git-621501f38bd8db1a334a6cd873db787a5a5070aa.tar.gz
MDEV-25606: Concurrent CREATE TRIGGER statements mix up in binlog and break replication
The bug is that we don't have a a lock on the trigger name, so it is possible for two threads to try to create the same trigger at the same time and both thinks that they have succeed. Same thing can happen with drop trigger or a combinations of create and drop trigger. Fixed by adding a mdl lock for the trigger name for the duration of the create/drop. Patch tested by Elena
-rw-r--r--sql/sql_trigger.cc14
1 files changed, 14 insertions, 0 deletions
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 9417ec667ff..24bd7001eea 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -397,6 +397,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
String stmt_query;
bool lock_upgrade_done= FALSE;
MDL_ticket *mdl_ticket= NULL;
+ MDL_request mdl_request_for_trn;
Query_tables_list backup;
DBUG_ENTER("mysql_create_or_drop_trigger");
@@ -446,6 +447,16 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
}
+ /* Protect against concurrent create/drop */
+ MDL_REQUEST_INIT(&mdl_request_for_trn, MDL_key::TABLE,
+ create ? tables->db.str : thd->lex->spname->m_db.str,
+ thd->lex->spname->m_name.str,
+ MDL_EXCLUSIVE, MDL_EXPLICIT);
+ if (thd->mdl_context.acquire_lock(&mdl_request_for_trn,
+ thd->variables.lock_wait_timeout))
+ goto end;
+
+
if (!create)
{
bool if_exists= thd->lex->if_exists();
@@ -635,6 +646,9 @@ end:
thd->lex->spname->m_name.str, static_cast<uint>(thd->lex->spname->m_name.length));
}
+ if (mdl_request_for_trn.ticket)
+ thd->mdl_context.release_lock(mdl_request_for_trn.ticket);
+
DBUG_RETURN(result);
#ifdef WITH_WSREP
wsrep_error_label: