Introduction
À partir de la version 5.1.6 de MySQL, les évènements ou triggers temporels sont introduits. Cette nouveauté se traduit par l’apparition d’un programmateur d’évènements (event scheduler) au sein du moteur MySQL sous la forme d’un thread.
Il n’existe pas de standard en ce qui concerne les programmateurs
d’évènements dans le monde des moteurs de bases de données et MySQL a décidé de
combiner les fonctionnalités du Job Scheduler d’Oracle (DBMS_JOB
) et la
simplicité de la syntaxe de Sybase SQL Anywhere.
Cette documentation présente techniquement le programmateur d’évènements de MySQL 5.1 (paramètres systèmes, syntaxes, comportement, privilèges, etc.).
La variable globale système event_scheduler
Activation et désactivation du programmateur d’évènements (events scheduler)
Le programmateur d’évènements est un thread qui tourne en tâche de fond (background task) à la recherche d’évènements à exécuter. Ce thread est dans la plupart du temps en mode « sleeping ». Pour mettre cette fonctionnalité en route :
mysql > SET GLOBAL event_scheduler = 1;
Pour désactiver l’event scheduler :
mysql > SET GLOBAL event_scheduler = 0;
Comme pour toutes les commandes SET GLOBAL
, le privilège SUPER
est requis
pour manier la variable système event_scheduler
. Il est également possible
d’appliquer la variable système event_scheduler
au démarrage du serveur :
mysqld … --event_scheduler=1
Visualisation du statut de l’event scheduler
Pour vérifier le statut actif ou inactif de l’event scheduler :
mysql > SHOW VARIABLES LIKE 'event_scheduler';
mysql > SELECT @@event_scheduler;
Commandes SQL de gestion des évènements
CREATE EVENT
Pour créer un évènement :
CREATE EVENT [ IF NOT EXISTS ] event_name
ON SCHEDULE schedule
[ ON COMPLETION [ NOT ] PRESERVE ]
[ ENABLED | DISABLED ]
[ COMMENT 'comment' ]
DO sql_statement;
Le nom de l’évènement 'event_name
' ne doit pas dépasser 64 caractères (les
délimiteurs ` sont autorisés) et peut être complètement qualifié
database1.event1
. Les évènements sont des objets d’une base de données et leurs
noms doivent être uniques dans une base de données. Pour vérifier l’unicité
d’un évènement d’une base de données, MySQL est case-insensitive (insensible à
la casse).
Clause ON SCHEDULE
La programmation 'schedule
' peut être un timestamp dans le futur, un
intervalle récurrent ou une combinaison d’intervalles récurrents et de
timestamp.
Les possibilités sont :
AT TIMESTAMP [ + intervalle valeur_entière]
EVERY interval
EVERY interval STARTS timestamp
EVERY interval ENDS timestamp
code>EVERY interval STARTS timestamp ENDS timestamp
'AT TIMESTAMP
' signifie 'À déclencher une seule fois à l’heure spécifiée'.
Le timestamp doit contenir à la fois la date et l’heure et doit être dans le
futur.
Quelques exemples avec la syntaxe 'AT TIMESTAMP
' :
CREATE EVENT `Something To Do`
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 5 DAY
DO DROP TABLE t;
Cet évènement s’exécutera une seule fois dans 5 jours à partir de maintenant
et supprimera la table t
.
CREATE EVENT The_Main_Event
ON SCHEDULE AT TIMESTAMP '2006-01-20 12:00:00'
DO DROP TABLE t;
Cet évènement s’exécutera une seule fois le 20 janvier 2006 et supprimera la
table t
.
'EVERY INTERVAL
' signifie 'À déclencher cycliquement'. Un intervalle
récurrent commence avec le mot clé EVERY
dans la commande CREATE EVENT
et est
suivi d’un entier positif plus un des mots clés YEAR, MONTH, WEEK, DAY, HOUR,
MINUTE
ou SECOND
afin de décrire le cycle.
Quelques exemples avec la syntaxe 'EVERY INTERVAL
' :
CREATE EVENT e
ON SCHEDULE EVERY 1 YEAR
DO DROP TABLE t;
Cet évènement s’exécutera une fois par an et supprimera la table t
.
CREATE EVENT e
ON SCHEDULE EVERY 1 YEAR
STARTS CURRENT_TIMESTAMP + INTERVAL 5 DAY
DO DROP TABLE t;
Cet évènement s’exécutera une fois par an, démarrera exactement dans 5 jours à partir de maintenant et supprimera la table t.
CREATE EVENT e
ON SCHEDULE EVERY 1 YEAR
ENDS CURRENT_TIMESTAMP + INTERVAL 5 YEAR
DO DROP TABLE t;
Cet évènement s’exécutera une fois par an, s’arrêtera exactement dans 5 ans
à partir de maintenant et supprimera la table t
.
CREATE EVENT e
ON SCHEDULE EVERY 1 YEAR
STARTS CURRENT_TIMESTAMP + INTERVAL 5 DAY
ENDS CURRENT_TIMESTAMP + INTERVAL 5 YEAR
DO DROP TABLE t;
Cet évènement s’exécutera une fois par an, démarrera exactement dans 5 jours
à partir de maintenant, s’arrêtera exactement dans 5 ans à partir de maintenant
et supprimera la table t
.
Clause ON COMPLETION [NOT] PRESERVE
Avec la commande ON COMPLETION NOT PRESERVE
(qui est le mode par défaut),
l’évènement est supprimé lorsque l’évènement n’a plus de raison de
s’exécuter.
Clause ENABLED | DISABLED
Le mode ENABLED
est le mode par défaut et indique que l’évènement est activé
dès la programmation spécifiée. Lorsqu’un évènement est désactivé (DISABLED
),
même si l’heure de programmation est atteinte, l’évènement n’est pas
déclenché.
Clause COMMENT
La clause COMMENT
est une chaîne de caractères uniquement utilisé à des fins
de documentations et cette chaîne est stockée dans la table de méta données
mysql.event
pour l’évènement en questions.
Clause sql_statement
La commande sql_statement
spécifie l’action à effectuer lorsque l’évènement
est exécuté. Il s’agit d’une commande unique, mais il peut s’agir aussi d’une
commande composée (comme les procédures stockées ou les triggers). La règle
générale est la suivante : toutes les commandes SQL qui peuvent être exécutées
dans des routines (procédures stockées, triggers), peuvent être exécutées dans
un évènement.
Exemple :
CREATE EVENT e
ON SCHEDULE EVERY 5 SECOND
DO
BEGIN
DECLARE v INTEGER;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
SET v = 0;
WHILE v < 5 DO
INSERT INTO t1 VALUES (0);
UPDATE t2 SET s1 = s1 + 1;
SET v = v + 1;
END WHILE;
END //
ALTER EVENT
Pour modifier un évènement, utiliser la commande ALTER EVENT :
ALTER EVENT event_name
[ ON SCHEDULE schedule ]
[ RENAME TO event_name2 ]
[ ON COMPLETION [ NOT ] PRESERVE ]
[ COMMENT 'comment' ]
[ ENABLED | DISABLED ]
[ DO sql_statement ]
La commande ALTER EVENT
doit invoquer un évènement qui existe déjà. Les
clauses de la commande ALTER EVENT
sont les mêmes clauses que celles de la
commande CREATE EVENT
, toutefois toutes les clauses de la commande ALTER EVENT
sont optionnelles. Lorsqu’une clause n’est pas spécifiée dans la commande ALTER
EVENT, la valeur originale pour cette clause appliquée lors de la commande
CREATE EVENT
ou bien lors de la dernière commande ALTER EVENT
modifiant cette
clause est conservée.
Ainsi , si la commande ALTER EVENT
invoque la clause ON SCHEDULE
, la
programmation de l’évènement change ; dans le cas contraire la programmation de
l’évènement reste inchangée.
La commande ALTER EVENT
inclut une seule clause qui n’existe pas dans la
commande CREATE EVENT
: 'RENAME TO event_name2
'. Cette clause permet de
renommer un évènement, la commande RENAME EVENT
n’existant pas.
Voici un exemple de commande ALTER EVENT
qui modifie la programmation, le
commentaire et la commande SQL déclenchée :
ALTER EVENT event1
ON SCHEDULE EVERY 5 WEEK
COMMENT 'This happens every 5 weeks'
DO DROP TABLE t1;
DROP EVENT
Pour supprimer un évènement :
DROP EVENT [ IF EXISTS ] event_name;
Comme d’habitude, si la clause IF EXISTS
est omise alors que l’évènement
n’existe pas, le serveur retourne une erreur :
mysql > DROP EVENT e6 ;
ERROR 1513 (HY000) : Unknown event 'e6'
Méta-données sur les évènements
La table système mysql.event
Pour stocker les méta données des évènements, il y a une nouvelle table
système dans la base de données mysql : mysql.event
. Si cette table n’apparaît
pas dans l’installation MySQL, exécuter le script mysql_fix_privilege_tables
.
(Lors de la migration depuis des versions précédentes de MySQL, il est
impératif de toujours exécuter le script mysql_fix_privilege_tables
pour créer
les nouveaux objets et privilèges qui ont été ajoutés dans la nouvelle
version).
La commande CREATE EVENT
ajoute une nouvelle ligne dans la table
mysql.event
, la commande ALTER EVENT
met à jour une ligne dans la table
mysql.event
, la commande DROP EVENT
supprime une ligne dans la table
mysql.event
. Il est fortement déconseillé de modifier directement la table
mysql.event.
Pour visualiser les informations sur les méta données des évènements :
mysql> SELECT * FROM mysql.event ;
Les commandes SHOW EVENTS, SHOW CREATE EVENT
ou SELECT … FROM
INFORMATION_SCHEMA.EVENTS
ne sont proposées et supportées qu’à partir de MySQL
5.1.6.
Exemple :
mysql> CREATE EVENT e ON SCHEDULE EVERY 5 SECOND STARTS TIMESTAMP '2006-01-01 16:00:00' ENDS TIMESTAMP '2006-12-31 12:00:00' ON COMPLETION PRESERVE COMMENT 'runs every 5 seconds in 2006' DO INSERT INTO tx VALUES (CURRENT_TIMESTAMP, 10); mysql> SELECT * FROM mysql.event\G
*************************** 1. row *************************** db: tp name: e body: INSERT INTO tx VALUES (CURRENT_TIMESTAMP, 10) definer: tp@localhost execute_at: NULL interval_value: 5 interval_field: SECOND created: 2005-12-20 14:53:03 modified: 2005-12-20 14:53:03 last_executed: NULL starts: 2006-01-01 23:00:00 ends: 2006-12-31 20:00:00 status: ENABLED on_completion: PRESERVE comment: runs every 5 seconds in 2006
Voici la description du résultat ci-dessus :
Colonne | Description |
---|---|
db |
nom de la base de données qui contient l’évènement. |
name |
nom de l’évènement, ce dernier doit être unique dans la base de données. |
definer |
colonne qui permet de vérifier les privilèges de l’utilisateur quand l’évènement est exécuté ; si l’utilisateur ne possède plus les privilèges requis pour exécuter des évènements, une erreur est retournée. |
execute_at |
indique quand l’évènement doit être exécuté lorsque cet évènement
n’est pas cyclique, cette colonne a la valeur NULL si la clause ON
SCHEDULE utilise l’option EVERY . |
interval_value |
indique la valeur numérique du cycle, cette colonne a la valeur NULL
si la clause ON SCHEDULE utilise l’option AT . |
interval_field |
indique l’unité du cycle (HOUR, SEC, MIN, DAY , etc.), cette
colonne a la valeur NULL si la clause ON SCHEDULE utilise l’option
AT . |
created |
date/heure de création de l’évènement. |
modified |
date/heure de modification de l’évènement. Cette colonne a la même
valeur que la colonne created lorsqu’aucune commande ALTER EVENT n’est
intervenu sur l’évènement. |
last_executed |
date/heure de la dernière exécution de l’évènement. Cette colonne a
la valeur NULL si l’évènement n’a pas encore été déclenché. |
starts |
indique la date/heure de démarrage de l’exécution de l’évènement,
cette colonne a la valeur NULL si la clause ON SCHEDULE utilise
l’option AT . |
ends |
indique la date/heure de fin de l’exécution de l’évènement, cette
colonne a la valeur NULL si la clause ON SCHEDULE utilise l’option
AT . |
status |
indique si l’évènement est actif ou inactif (enabled | disabled ).
Dans cet exemple, l’évènement est actif (ENABLED ), ce qui est la valeur
par défaut. |
on_completion |
indique si l’évènement est conservé ou supprimé lorsqu’il est terminé
au niveau de sa programmation. Dans cet exemple, l’évènement est
préservé, comme spécifié dans la commande CREATE EVENT . |
comment |
commentaire inclus dans la commande CREATE EVENT . |
Les commandes SHOW EVENTS et SHOW CREATE EVENT
Commande SHOW CREATE EVENT
La commande SHOW CREATE EVENT
permet de régénérer la commande de création
d’un évènement :
SHOW CREATE EVENT event_name
Exemple :
mysql> SHOW CREATE EVENT test.e_daily\G
*************************** 1. row *************************** Event: e_daily Create Event: CREATE EVENT e_daily ON SCHEDULE EVERY 1 DAY STARTS CURRENT_TIMESTAMP + INTERVAL 6 HOUR ENABLE COMMENT 'Saves total number of sessions and clears the table once per day.' DO BEGIN INSERT INTO site_activity.totals (when, total) SELECT CURRENT_TIMESTAMP, COUNT(*) FROM site_activity.sessions; DELETE FROM site_activity.sessions; END
Le résultat de la commande SHOW CREATE EVENT
retourne le statut courant de
l’évènement (ENABLE
) et non le statut lors de la création de l’évènement.
Commande SHOW EVENTS
Dans sa forme la plus simple, la commande SHOW EVENTS
liste tous les
évènements dans le schéma courant pour lequel l’utilisateur courant est le
créateur des évènements.
mysql> SELECT CURRENT_USER(), SCHEMA();
+----------------+----------+ | CURRENT_USER() | SCHEMA() | +----------------+----------+ | jon@ghidora | myschema | +----------------+----------+
mysql> SHOW EVENTS\G
*************************** 1. row *************************** Db: myschema Name: e_daily Definer: jon@ghidora Type: RECURRING Execute at: NULL Interval value: 10 Interval field: INTERVAL_SECOND Starts: 0000-00-00 00:00:00 Ends: 0000-00-00 00:00:00 Status: ENABLED
La syntaxe complète de la commande SHOW EVENTS
est la suivante :
mysql > SHOW [FULL] EVENTS [FROM schema_name] [LIKE pattern]
La vue INFORMATION_SCHEMA.EVENTS
La vue INFORMATION_SCHEMA.EVENTS
comporte toutes les informations sur les
évènements :
INFORMATION_SCHEMA Name | SHOW Name |
---|---|
EVENT_CATALOG |
|
EVENT_SCHEMA |
Db |
EVENT_NAME |
Name |
DEFINER |
Definer |
EVENT_BODY |
|
EVENT_TYPE |
Type |
EXECUTE_AT |
Execute at |
INTERVAL_VALUE |
Interval value |
INTERVAL_FIELD |
Interval field |
SQL_MODE |
|
STARTS |
Starts |
ENDS |
Ends |
STATUS |
Status |
ON_COMPLETION |
|
CREATED |
|
LAST_ALTERED |
|
LAST_EXECUTED |
|
EVENT_COMMENT |
Voici un exemple d’interrogation de la vue INFORMATION_SCHEMA.EVENTS
pour un
évènement :
mysql> SELECT * FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME = 'e_daily' AND EVENT_SCHEMA = 'myschema'\G
*************************** 1. row *************************** EVENT_CATALOG: NULL EVENT_SCHEMA: myschema EVENT_NAME: e_daily DEFINER: jon@ghidora EVENT_BODY: BEGIN INSERT INTO site_activity.totals (when, total) SELECT CURRENT_TIMESTAMP, COUNT(*) FROM site_activity.sessions; DELETE FROM site_activity.sessions; END EVENT_TYPE: RECURRING EXECUTE_AT: NULL INTERVAL_VALUE: 1 INTERVAL_FIELD: INTERVAL_DAY SQL_MODE: NULL STARTS: 2006-02-10 20:41:23 ENDS: NULL STATUS: ENABLED ON_COMPLETION: DROP CREATED: 2006-02-09 14:35:35 LAST_ALTERED: 2006-02-09 14:41:23 LAST_EXECUTED: NULL EVENT_COMMENT: Saves total number of sessions and clears the table once per day.
Privilèges
Un nouveau privilège a été introduit pour les évènements : le privilège
EVENT
. Ce droit peut être donné pour une base de données ou toutes les bases de
données :
GRANT EVENT ON database_name.* TO user [ , user ... ];
GRANT EVENT ON *.* TO user [ , user ... ];
Sans le privilège EVENT
, un utilisateur ne peut créer d’évènement.
Le privilège EVENT
ne peut être accordé que pour l’intégralité d’un schéma,
il ne peut pas être attribué pour une seule table, voici l’erreur générée si
l’on tente d’attribuer ce privilège uniquement pour une seule table :
mysql> GRANT EVENT ON myschema.mytable TO jon@ghidora;
ERROR 1144 (42000): Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used
Pour retirer le droit de création d’évènements :
REVOKE EVENT ON database_name.* FROM user [ , user ... ];
REVOKE EVENT ON *.* FROM user [ , user ... ];
Avec MySQL 5.1.6, si le user root
ou tout autre utilisateur disposant de ce droit retire le privilège EVENT
à un utilisateur,
le retrait de ce droit ne supprime pas ou ne désactive pas en cascade les évènements créés par cet utilisateur.
Pour supprimer les évènements créés par un autre utilisateur, la commande DELETE
doit être directement lancée sur la table mysql.event
.
Par exemple, pour supprimer l’évènement e_insert
, root
peut utiliser la commande ci-dessous :
DELETE FROM mysql.event
WHERE db = 'myschema'
AND definer = 'jon@ghidora'
AND name = 'e_insert';
À partir de MySQL 5.1.7, les commandes DROP USER
et DROP SCHEMA
supprimeront
en cascade les évènements associés à l’utilisateur à supprimer.
Pour retrouver les utilisateurs qui ont le privilège EVENT
, il suffit de
rechercher dans la table mysql.user
toutes les lignes pour lesquelles
Event_priv='Y'
.
Statistiques sur les évènements
Cinq variables de statut sont introduites pour compter les opérations relatives aux évènements :
Variable | Commandes exécutées depuis le démarrage du serveur |
---|---|
com_create_event |
nombre de commandes CREATE EVENT |
com_alter_event |
nombre de commandes ALTER EVENT |
com_drop_event |
nombre de commandes DROP EVENT |
com_show_create_event |
nombre de commandes SHOW CREATE EVENT |
com_show_events |
nombre de commandes SHOW EVENTS |
Pour visualiser les valeurs courantes de ces statistiques liées aux évènements :
mysql> show status like '%event%';
Troubleshooting des évènements
Deux méthodes sont disponibles pour vérifier les erreurs d’exécution des évènements :
- le fichier de log du serveur MySQL
- l’interrogation de la table
INFORMATION_SCHEMA.EVENTS
Le fichier de log du serveur MySQL retourne les échecs d’exécution des
évènements avec le mot clé RetCode=0
:
060209 22:39:44 [Note] EVEX EXECUTING event newdb.e [EXPR:10]
060209 22:39:44 [Note] EVEX EXECUTED event newdb.e [EXPR:10]. RetCode=0
060209 22:39:54 [Note] EVEX EXECUTING event newdb.e [EXPR:10]
060209 22:39:54 [Note] EVEX EXECUTED event newdb.e [EXPR:10]. RetCode=0
060209 22:40:04 [Note] EVEX EXECUTING event newdb.e [EXPR:10]
060209 22:40:04 [Note] EVEX EXECUTED event newdb.e [EXPR:10]. RetCode=0
Lorsque la colonne LAST_EXECUTED
est NULL
dans la vue
INFORMATION_SCHEMA.EVENTS
pour un évènement qui aurait du se produire, cela
signifie clairement que l’évènement a eu un statut d’échec :
mysql> SELECT * FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_NAME='e_store_ts' AND EVENT_SCHEMA='myschema'\G
*************************** 1. row *************************** EVENT_CATALOG: NULL EVENT_SCHEMA: myschema EVENT_NAME: e_store_ts DEFINER: jon@ghidora EVENT_BODY: INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP()) EVENT_TYPE: RECURRING EXECUTE_AT: NULL INTERVAL_VALUE: 5 INTERVAL_FIELD: INTERVAL_SECOND SQL_MODE: NULL STARTS: 0000-00-00 00:00:00 ENDS: 0000-00-00 00:00:00 STATUS: ENABLED ON_COMPLETION: NOT PRESERVE CREATED: 2006-02-09 22:36:06 LAST_ALTERED: 2006-02-09 22:36:06 LAST_EXECUTED: NULL EVENT_COMMENT:
Le thread event_scheduler
Chaque évènement s’exécute avec son propre thread qui demeure quoiqu’il arrive unique. Pour illustrer tout ça, créons un mauvais évènement qui génère une boucle infinie.
Première étape : création d’une procédure stockée qui effectue une boucle infinie et ne s’arrête jamais.
DELIMITER //
CREATE PROCEDURE pe () BEGIN x: LOOP ITERATE x; END LOOP; END//
Seconde étape : création d’un évènement qui invoque la procédure stockée, évènement déclenché toutes les 2 secondes.
CREATE EVENT ee
ON SCHEDULE EVERY 2 SECOND
COMMENT 'This is a bad idea'
DO CALL tp.pe() //
Si un évènement récurrent est encore en cours d’exécution alors qu’il est l’heure de déclencher une nouvelle exécution de cet évènement, le serveur n’ouvrira jamais un nouveau thread pour exécuter à nouveau l’évènement, ainsi le moteur MySQL garantit qu’il ne peut y avoir une infinité de threads suite à une erreur de développement ou bien qu’une concurrence d’un même évènement ne se produise. MySQL sait identifier un thread qui est rattaché à un évènement.
La commande SHOW PROCESSLIST
permet de voir le thread du scheduler et celui
de l’évènement en cours d’exécution :
mysql> SHOW PROCESSLIST\G
*************************** 1. row *************************** Id: 1 User: root Host: localhost db: tp Command: Query Time: 0 State: NULL Info: show processlist *************************** 2. row *************************** Id: 2 User: event_scheduler Host: db: NULL Command: Connect Time: 1 State: Sleeping Info: NULL *************************** 3. row *************************** Id: 31 User: root Host: db: tp Command: Connect Time: 0 State: NULL Info: CALL tp.pe( 3 rows in set (0.00 sec)
Quelques petites remarques
- Il est possible de créer deux évènements à la même programmation, mais il
n’y a aucun moyen de contrôler l’ordonnancement de l’un par rapport à
l’autre. L’évènement
e1
peut démarrer avant l’évènemente2
et vice versa. - Un évènement est toujours exécuté avec les privilèges du créateur.
- Les commandes
SELECT
etSHOW
peuvent être implémentées dans les évènements mais les résultats ne seront jamais affichées ! Dans le jargon Unix, la sortie est redirigée vers/dev/null
. - Comme pour les routines (procédures stockées et fonctions), l’éxècution
d’une commande dans un évènement ne modifie pas le nombre de fois que la
commande a été lancée. Plus techniquement, il n’y a pas d’effet sur les
variables de statut
com_insert, com_delete, com_update, com_select
,etc. par rapport aux commandes déclenchées dans les évènements. - Un évènement ne peut être être créé au sein de trigger, de procédures stockées ou d’un autre évènement. En revanche, un évènement peut créer , altérer, supprimer des triggers et des procédures stockées.