1
0
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:
Dmitry Shulga
2025-04-19 18:36:03 +07:00
parent 86ec20189a
commit ecb7c9b692
24 changed files with 1245 additions and 74 deletions

View File

@@ -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");