mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
A fix and a test case for Bug#26141 mixing table types in trigger
causes full table lock on innodb table. Also fixes Bug#28502 Triggers that update another innodb table will block on X lock unnecessarily (duplciate). Code review fixes. Both bugs' synopses are misleading: InnoDB table is not X locked. The statements, however, cannot proceed concurrently, but this happens due to lock conflicts for tables used in triggers, not for the InnoDB table. If a user had an InnoDB table, and two triggers, AFTER UPDATE and AFTER INSERT, competing for different resources (e.g. two distinct MyISAM tables), then these two triggers would not be able to execute concurrently. Moreover, INSERTS/UPDATES of the InnoDB table would not be able to run concurrently. The problem had other side-effects (see respective bug reports). This behavior was a consequence of a shortcoming of the pre-locking algorithm, which would not distinguish between different DML operations (e.g. INSERT and DELETE) and pre-lock all the tables that are used by any trigger defined on the subject table. The idea of the fix is to extend the pre-locking algorithm to keep track, for each table, what DML operation it is used for and not load triggers that are known to never be fired.
This commit is contained in:
@@ -942,17 +942,6 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
|
||||
table->triggers= triggers;
|
||||
|
||||
/*
|
||||
Construct key that will represent triggers for this table in the set
|
||||
of routines used by statement.
|
||||
*/
|
||||
triggers->sroutines_key.length= 1+strlen(db)+1+strlen(table_name)+1;
|
||||
if (!(triggers->sroutines_key.str=
|
||||
alloc_root(&table->mem_root, triggers->sroutines_key.length)))
|
||||
DBUG_RETURN(1);
|
||||
triggers->sroutines_key.str[0]= TYPE_ENUM_TRIGGER;
|
||||
strxmov(triggers->sroutines_key.str+1, db, ".", table_name, NullS);
|
||||
|
||||
/*
|
||||
TODO: This could be avoided if there is no triggers
|
||||
for UPDATE and DELETE.
|
||||
@@ -991,6 +980,15 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
|
||||
DBUG_ASSERT(lex.sphead == 0);
|
||||
goto err_with_lex_cleanup;
|
||||
}
|
||||
/*
|
||||
Not strictly necessary to invoke this method here, since we know
|
||||
that we've parsed CREATE TRIGGER and not an
|
||||
UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to
|
||||
maintain the invariant that this method is called for each
|
||||
distinct statement, in case its logic is extended with other
|
||||
types of analyses in future.
|
||||
*/
|
||||
lex.set_trg_event_type_for_tables();
|
||||
|
||||
lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode);
|
||||
|
||||
@@ -1550,6 +1548,12 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||
new_field= record1_field;
|
||||
old_field= trigger_table->field;
|
||||
}
|
||||
/*
|
||||
This trigger must have been processed by the pre-locking
|
||||
algorithm.
|
||||
*/
|
||||
DBUG_ASSERT(trigger_table->pos_in_table_list->trg_event_map &
|
||||
static_cast<uint>(1 << static_cast<int>(event)));
|
||||
|
||||
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
|
||||
err_status= sp_trigger->execute_trigger
|
||||
@@ -1568,7 +1572,7 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
||||
SYNOPSIS
|
||||
mark_fields_used()
|
||||
thd Current thread context
|
||||
event Type of event triggers for which we are going to inspect
|
||||
event Type of event triggers for which we are going to ins
|
||||
|
||||
DESCRIPTION
|
||||
This method marks fields of subject table which are read/set in its
|
||||
|
Reference in New Issue
Block a user