1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +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

@ -23,6 +23,7 @@
#include <atomic>
#include "dur_prop.h"
#include <waiting_threads.h>
#include "sql_array.h"
#include "sql_const.h"
#include "lex_ident.h"
#include "sql_used.h"
@ -55,6 +56,8 @@
#include "scope.h"
#include "ddl_log.h" /* DDL_LOG_STATE */
#include "ha_handler_stats.h" // ha_handler_stats */
#include "sql_basic_types.h" // enum class active_dml_stmt
#include "sql_trigger.h"
extern "C"
void set_thd_stage_info(void *thd,
@ -1734,6 +1737,63 @@ public:
void restore_backup_statement(Statement *stmt, Statement *backup);
/* return class type */
Type type() const override;
private:
Dynamic_array<active_dml_stmt> m_running_stmts{PSI_INSTRUMENT_MEM};
/**
Stack of events of triggers being invoked on running a DML statement.
E.g. if there is a trigger BEFORE INSERT ON t1 that calls the statement
`DELETE FROM t2` and there is a BEFORE DELETE trigger for the table t2
that runs the statement `UPDATE t3` and there is a BEFORE UPDATE trigger
for the table t3 then at the moment when the statement `UPDATE t3 ...`
be invoked, the stack m_running_trgs would contain the following events:
top -> TRG_EVENT_UPDATE
TRG_EVENT_DELETE
bottom ->TRG_EVENT_INSERT
}
*/
Dynamic_array<trg_event_type> m_running_trgs{PSI_INSTRUMENT_MEM};
public:
active_dml_stmt current_active_stmt();
bool push_active_stmt(active_dml_stmt new_active_stmt);
void pop_current_active_stmt();
trg_event_type current_trg_event();
bool push_current_trg_event(trg_event_type trg_event);
void pop_current_trg_event();
};
/**
This class is responsible for storing a kind of current DML statement
for further matching with type of statement represented by the clauses
INSERTING / UPDATING / DELETING.
On handling the statements INSERT / UPDATE / DELETE the corresponding type
of the statement specified by the enum active_dml_stmt is pushed on top of
the Statement's stack in constructor of the class Running_stmt_guard and
popped up on finishing execution of the statement by destructor of the class
Running_stmt_guard.
Every time when the one of the clauses INSERTING / UPDATING / DELETING
is evaluated, the last pushed type of DML statement matched with the type
representing by the clause INSERTING / UPDATING / DELETING.
@see Item_trigger_type_of_statement::val_bool()
*/
class Running_stmt_guard
{
Statement *m_stmt;
public:
Running_stmt_guard(Statement *stmt,
active_dml_stmt new_active_stmt)
: m_stmt{stmt}
{
m_stmt->push_active_stmt(new_active_stmt);
}
~Running_stmt_guard()
{
m_stmt->pop_current_active_stmt();
}
};