mariadb-syntax-triggers-events-views
Installation
SKILL.md
MariaDB Triggers, Events, and Views
Deterministic guidance for row-level triggers, the event scheduler, and views in MariaDB. Use this skill when wiring side-effects to INSERT / UPDATE / DELETE, scheduling recurring SQL jobs, building updatable views with security boundaries, or simulating materialized views via the table-plus-event refresh pattern.
Quick Reference
- ALWAYS turn on the event scheduler before relying on events. The global
event_schedulervariable defaults toOFFon most distros. ACREATE EVENTstatement succeeds, but the event never fires untilSET GLOBAL event_scheduler = ONis executed AND persisted in[mysqld]ofmy.cnfso it survives restart. Verify withSHOW VARIABLES LIKE 'event_scheduler'. Verified : KBevents/. - ALWAYS use FOR EACH ROW. MariaDB has NO statement-level triggers. Every trigger fires once per affected row, so a 10 000-row bulk DML fires the trigger 10 000 times. Keep trigger bodies short ; move heavy logic to stored procedures invoked once by the application. Verified : KB
create-trigger/. - NEVER expect materialized views in MariaDB. The keyword
MATERIALIZED VIEWdoes not exist. The supported alternative isCREATE TABLE snapshot AS SELECT ... ;plus an event-scheduled refresh that truncates and reloads the snapshot. The optimizer columnselect_type = MATERIALIZEDrefers to derived-table materialization, NOT to materialized-view objects. Verified : KBcreate-view/. - NEVER use COMMIT, ROLLBACK, SAVEPOINT, or START TRANSACTION inside a trigger. The statement parses at CREATE time but raises
Explicit or implicit commit is not allowed in stored function or triggerat runtime. Triggers run inside the calling statement's transaction and cannot manage it. Verified : KBtrigger-limitations/. - ALWAYS choose the right view ALGORITHM.
UNDEFINED(default) lets the optimizer pickMERGEwhen possible.MERGEinlines the view body into the outer query, preserves index pushdown, and keeps the view updatable.TEMPTABLEmaterializes the entire view result into a per-query temp table, breaks index pushdown, and forces a full scan on every reference. NEVER useTEMPTABLEon a multi-million-row base table unless the view body contains a non-mergeable construct (DISTINCT, GROUP BY, aggregate, UNION) that the optimizer cannot push down anyway. Verified : KBcreate-view/. - ALWAYS set DEFINER explicitly on security-sensitive objects. Views, triggers, events, and stored routines all carry a
DEFINERclause. If the DEFINER account is dropped, the object becomes invalid and access fails withThe user specified as a definer ... does not exist. For shared / multi-DBA environments, setDEFINER = 'role_owner'@'localhost'to a stable service account. Verified : KBcreate-view/, KBcreate-trigger/. - NEVER use DEFINER + SQL SECURITY DEFINER for code that must respect caller permissions.
SQL SECURITY DEFINER(default) means the view / trigger / routine runs with the definer's privileges, bypassing the caller's GRANTs. UseSQL SECURITY INVOKERwhen the caller's GRANT set must be enforced. Verified : KBcreate-view/. - Multi-trigger per event requires explicit ordering since 10.2.3+. Use
FOLLOWS other_triggerorPRECEDES other_triggerin theCREATE TRIGGERclause. Order is observable inINFORMATION_SCHEMA.TRIGGERS.ACTION_ORDER. Without explicit ordering, the engine assigns the next freeACTION_ORDERvalue, which is fragile across migrations. Verified : KBcreate-trigger/. - DISABLE ON SLAVE prevents double-execution of events under replication. Without it, the same event fires on both primary and replica with statement-based or mixed binlog.
DISABLE ON SLAVEis the standard safety for any event that already replicates its effects through binlog. Verified : KBevents/. - WITH CHECK OPTION rejects INSERT / UPDATE that produces a row outside the view's WHERE predicate.
CASCADED(default) walks every view in the chain ;LOCALchecks only the immediate view. WithoutWITH CHECK OPTION, a row can be inserted through the view that the view itself cannot see. Verified : KBcreate-view/. - Pseudo-rows are scoped per timing.
NEW.colis readable in BEFORE / AFTER INSERT and UPDATE triggers ; it is writable only in BEFORE triggers viaSET NEW.col = expr.OLD.colis read-only in UPDATE and DELETE triggers. NEW does not exist in DELETE triggers ; OLD does not exist in INSERT triggers. Verified : KBtrigger-overview/.