mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-10164: Add support for TRIGGERS that fire on multiple events
Added capability to create a trigger associated with several trigger events. For this goal, the syntax of the CREATE TRIGGER statement was extended to support the syntax structure { event [ OR ... ] } for the `trigger_event` clause. Since one trigger will be able to handle several events it should be provided a way to determine what kind of event is handled on execution of a trigger. For this goal support of the clauses INSERTING, UPDATING , DELETING was added by this patch. These clauses can be used inside a trigger body to detect what kind of trigger action is currently processed using the following boilerplate: IF INSERTING THEN ... ELSIF UPDATING THEN ... ELSIF DELETING THEN ... In case one of the clauses INSERTING, UPDATING, DELETING specified in a trigger's body not matched with a trigger event type, the error ER_INCOMPATIBLE_EVENT_FLAG is emitted. After this patch be pushed, one Trigger object will be associated with several trigger events. It means that the array Table_triggers_list::triggers can contain several pointers to the same Trigger object in array members corresponding to different events. Moreover, support of several trigger events for the same trigger requires that the data members `next` and `action_order` of the Trigger class be converted to arrays to store relating information per trigger event base. Ability to specify the same trigger for different event types results in necessity to handle invalid cases on execution of the multi-event trigger, when the OLD or NEW qualifiers doesn't match a current event type against that the trigger is run. The clause OLD should produces the NULL value for INSERT event, whereas the clause NEW should produce the NULL value for DELETE event.
This commit is contained in:
@@ -4289,6 +4289,62 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get a type of DML statement currently is running
|
||||
*/
|
||||
|
||||
active_dml_stmt Statement::current_active_stmt()
|
||||
{
|
||||
return *m_running_stmts.back();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Store information about a type of the current DML statement being executed
|
||||
*/
|
||||
|
||||
bool Statement::push_active_stmt(active_dml_stmt new_active_stmt)
|
||||
{
|
||||
return m_running_stmts.push(new_active_stmt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remove information about a type of completed DML statement
|
||||
*/
|
||||
|
||||
void Statement::pop_current_active_stmt()
|
||||
{
|
||||
m_running_stmts.pop();
|
||||
}
|
||||
|
||||
|
||||
trg_event_type Statement::current_trg_event()
|
||||
{
|
||||
/*
|
||||
current_trg_event() is called indirectly by Item_trigger_field::fix_fields
|
||||
both on handling DML statements INSERT/UPDATE/DELETE and DDL statement
|
||||
CREATE TRIGGER. For the last one, m_running_trgs is empty since the
|
||||
method push_current_trg_event() is run only on processing triggers, not on
|
||||
thier creation. So take care about this case.
|
||||
*/
|
||||
if (unlikely(m_running_trgs.elements() == 0))
|
||||
return TRG_EVENT_MAX;
|
||||
return *m_running_trgs.back();
|
||||
}
|
||||
|
||||
|
||||
bool Statement::push_current_trg_event(trg_event_type trg_event)
|
||||
{
|
||||
return m_running_trgs.push(trg_event);
|
||||
}
|
||||
|
||||
|
||||
void Statement::pop_current_trg_event()
|
||||
{
|
||||
m_running_trgs.pop();
|
||||
}
|
||||
|
||||
void THD::end_statement()
|
||||
{
|
||||
DBUG_ENTER("THD::end_statement");
|
||||
|
Reference in New Issue
Block a user