Il est aussi possible d'écrire une fonction déclencheur en C bien que
la plupart des gens trouvent plus facile d'utiliser un des langages
de procédure. Il n'est pas possible actuellement d'écrire une
fonction déclencheur dans le langage de fonction SQL.
34.1. Aperçu du comportement des déclencheurs
Un déclencheur est une spécification précisant que la base de
données doit exécuter une fonction particulière quand un certain
type d'opération est traité. Les fonctions déclencheur peuvent être
définies pour s'exécuter avant ou après une commande
INSERT
,
UPDATE
ou
DELETE
, soit une fois par ligne
modifiée soit une fois par expression SQL. Si un élément déclencheur se produit, le
gestionnaire de déclencheurs est appelé au bon moment pour gérer
l'événement.
La fonction déclencheur doit être définie avant que le déclencheur
lui-même puisse être créé. La fonction déclencheur doit être
déclarée comme une fonction ne prenant aucun argument et retournant
un type trigger (la fonction déclencheur
reçoit ses entrées via une structure TriggerData passée spécifiquement, et pas sous
la forme d'arguments ordinaires de fonctions).
Une fois qu'une fonction déclencheur est créée, le déclencheur
(trigger) est créé avec CREATE TRIGGER.
La même fonction déclencheur est utilisable par plusieurs
déclencheurs.
PostgreSQL™ offre des
déclencheurs par ligne et par instruction. Avec un déclencheur mode ligne,
la fonction du déclencheur est appelée une fois pour chaque ligne
affectée par l'instruction qui a lancé le déclencheur. Au
contraire, un déclencheur mode instruction n'est appelé qu'une
seule fois lorsqu'une instruction appropriée est exécutée, quelque
soit le nombre de lignes affectées par cette instruction. En
particulier, une instruction n'affectant aucune ligne résultera
toujours en l'exécution de tout déclencheur mode instruction
applicable. Ces deux types sont quelque fois appelés respectivement
des déclencheurs niveau ligne et des
déclencheurs niveau instruction.
Les déclencheurs sont aussi classifiés comme des déclencheurs
avant et des déclencheurs après. Les déclencheurs avant au niveau
instruction se déclenchent naturellement avant que l'instruction ne
fasse quoi que ce soit alors que les déclencheurs après au niveau
instruction sont exécutés à la fin de l'instruction. Les
déclencheurs avant au niveau ligne s'exécutent immédiatement avant
qu'une ligne particulière ne soit traitée alors que les
déclencheurs après au niveau ligne s'exécutent à la fin de
l'instruction (mais avant tout déclencheur après au niveau
instruction).
Les fonctions déclencheurs appelées par des déclencheurs niveau
instruction devraient toujours renvoyer NULL. Les fonctions déclencheurs appelées par des
déclencheurs niveau ligne peuvent renvoyer une ligne de la table
(une valeur de type HeapTuple) vers
l'exécuteur appelant, s'ils le veulent. Un déclencheur niveau ligne
exécuté avant une opération a les choix suivants :
-
Il peut retourner un pointeur NULL pour sauter l'opération pour la ligne
courante. Ceci instruit l'exécuteur de ne pas exécuter
l'opération niveau ligne qui a lancé le déclencheur
(l'insertion ou la modification d'une ligne particulière de
la table).
-
Pour les seuls déclencheurs
INSERT
et
UPDATE
au niveau ligne, la
valeur de retour devient la ligne qui sera insérée ou
remplacera la ligne en cours de mise à jour. Ceci permet à la
fonction déclencheur de modifier la ligne en cours
d'insertion ou de mise à jour.
Un déclencheur avant niveau ligne, qui n'est pas conçu pour avoir
l'un de ces comportements, doit prendre garde à retourner la même
ligne que celle qui lui a été passée comme nouvelle ligne
(c'est-à-dire, la nouvelle (NEW) ligne
pour des déclencheurs
INSERT
et
UPDATE
, l'ancienne (OLD) ligne pour les déclencheurs
DELETE
).
La valeur de retour est ignorée pour les déclencheurs niveau ligne
lancés après une opération. Ils pourraient donc très bien renvoyer
la valeur NULL.
Si plus d'un déclencheur est défini pour le même événement sur la
même relation, les déclencheurs seront lancés dans l'ordre
alphabétique de leur nom. Dans le cas de déclencheurs avant, les
lignes, susceptibles d'être modifiées, renvoyées par chaque
déclencheur deviennent l'argument du prochain déclencheur. Si un
des déclencheurs avant renvoie un pointeur NULL, l'opération est abandonnée pour cette ligne
et les déclencheurs suivants ne sont pas lancés.
Typiquement, les déclencheurs avant en mode ligne sont utilisés
pour vérifier ou modifier les données qui seront insérées ou mises
à jour. Par exemple, un déclencheur avant pourrait être utilisé
pour insérer l'heure actuelle dans une colonne de type timestamp ou pour vérifier que deux éléments d'une
ligne sont cohérents. Les déclencheurs après en mode ligne sont
pour la plupart utilisés pour propager des mises à jour vers
d'autres tables ou pour réaliser des tests de cohérence avec
d'autres tables. La raison de cette division du travail est qu'un
déclencheur après peut être certain qu'il voit la valeur finale de
la ligne alors qu'un déclencheur avant ne l'est pas ; il pourrait
exister d'autres déclencheurs avant qui seront exécutés après lui.
Si vous n'avez aucune raison spéciale pour le moment du
déclenchement, le cas avant est plus efficace car l'information sur
l'opération n'a pas besoin d'être sauvegardée jusqu'à la fin du
traitement.
Si une fonction déclencheur exécute des commandes SQL, alors ces
commandes peuvent relancer des déclencheurs. On appelle ceci un
déclencheur en cascade. Il n'y a pas de limitation directe du
nombre de niveaux de cascade. Il est possible que les cascades
causent un appel récursif du même déclencheur ; par exemple, un
déclencheur
INSERT
pourrait exécuter une commande qui insère une ligne supplémentaire
dans la même table, entraînant un nouveau lancement du déclencheur
INSERT
. Il est de la
responsabilité du programmeur d'éviter les récursions infinies dans
de tels scénarios.
Quand un déclencheur est défini, des arguments peuvent être
spécifiés pour lui. L'objectif de l'inclusion d'arguments dans la
définition du déclencheur est de permettre à différents
déclencheurs ayant des exigences similaires d'appeler la même
fonction. Par exemple, il pourrait y avoir une fonction déclencheur
généralisée qui prend comme arguments deux noms de colonnes et
place l'utilisateur courant dans l'une et un horodatage dans
l'autre. Correctement écrit, cette fonction déclencheur serait
indépendante de la table particulière sur laquelle il se déclenche.
Ainsi, la même fonction pourrait être utilisée pour des événements
INSERT
sur n'importe
quelle table ayant des colonnes adéquates, pour automatiquement
suivre les créations d'enregistrements dans une table de
transactions par exemple. Elle pourrait aussi être utilisée pour
suivre les dernières mises à jours si elle est définie comme un
déclencheur
UPDATE
.
Chaque langage de programmation supportant les déclencheurs a sa
propre méthode pour rendre les données en entrée disponible à la
fonction du déclencheur. Cette donnée en entrée inclut le type
d'événement du déclencheur (c'est-à-dire
INSERT
ou
UPDATE
) ainsi que tous les
arguments listés dans
CREATE
TRIGGER
. Pour un déclencheur niveau ligne, la
donnée en entrée inclut aussi la ligne NEW
pour les déclencheurs
INSERT
et
UPDATE
et/ou la ligne OLD pour les déclencheurs
UPDATE
et
DELETE
. Les déclencheurs niveau
instruction n'ont actuellement aucun moyen pour examiner le(s)
ligne(s) individuelle(s) modifiées par l'instruction.