Le module contrib/spi fournit plusieurs exemples fonctionnels d'utilisation de SPI et des déclencheurs. Bien que ces fonctions aient un intérêt certain, elles sont encore plus utiles en tant qu'exemples à modifier pour atteindre ses propres buts. Les fonctions sont suffisamment généralistes pour être utilisées avec une table quelconque, mais la création d'un déclencheur impose que les noms des tables et des champs soient précisés (comme cela est décrit ci-dessous).
check_primary_key() et check_foreign_key() sont utilisées pour vérifier les contraintes de clé étrangère. (Cette fonctionnalité est dépassée depuis longtemps par le mécanisme interne, mais le module conserve un rôle d'exemple.)
check_primary_key() vérifie la table de référence. Pour l'utiliser, on crée un déclencheur BEFORE INSERT OR UPDATE qui utilise cette fonction sur une table référençant une autre table. En arguments du déclencheur, on trouve : le nom de la colonne de la table référençant qui forme la clé étrangère, le nom de la table référencée et le nom de la colonne de la table référencée qui forme la clé primaire/unique. Il peut y avoir plusieurs colonnes. Pour gérer plusieurs clés étrangères, on crée un déclencheur pour chaque référence.
check_foreign_key() vérifie la table référencée. Pour l'utiliser, on crée un déclencheur BEFORE DELETE OR UPDATE qui utilise cette fonction sur une table référencée par d'autres tables. En arguments du déclencheur, on trouve : le nombre de tables référençant pour lesquelles la fonction réalise la vérification, l'action à exécuter si une clé de référence est trouvée (cascade -- pour supprimer une ligne qui référence, restrict -- pour annuler la transaction si des clés de référence existent, setnull -- pour initialiser les champs des clés référençant à NULL), les noms des colonnes de la table surveillées par le déclencheur, colonnes qui forment la clé primaire/unique, puis le nom de la table référençant et les noms des colonnes (répétés pour autant de tables référençant que cela est précisé par le premier argument). Les colonnes de clé primaire/unique doivent être marquées NOT NULL et posséder un index d'unicité.
Il y a des exemples dans refint.example.
Dans le passé, PostgreSQL™ disposait d'une fonctionnalité de voyage dans le temps, permettant de conserver l'heure d'insertion et de suppression de chaque ligne. Ce comportement peut être émulé en utilisant ces fonctions. Pour les utiliser, il faut ajouter deux champs de type abstime à la table pour stocker le moment où une ligne a été insérée (start_date) et le moment où elle a été modifiée/supprimée (stop_date) :
CREATE TABLE mytab ( ... ... start_date abstime, stop_date abstime ... ... );
Le nom des colonnes n'a aucune importance, mais dans ce chapitre, elles sont nommées start_date et stop_date.
À l'insertion d'une nouvelle ligne, start_date doit normalement être initialisée à l'heure courante et stop_date à infinity. Le déclencheur substitue automatiquement ces valeurs si les données insérées sont NULL pour ces colonnes. L'insertion de données explicitement non-NULL dans ces colonnes n'intervient qu'au rechargement de données sauvegardées.
Les lignes pour lesquelles stop_date vaut infinity sont des lignes « actuellement valides », et peuvent être modifiées. Les lignes dont stop_date est fini ne peuvent plus être modifiées -- le déclencheur les protège. (Pour les modifier, il est nécessaire de désactiver le voyage dans le temps comme indiqué ci-dessous.)
Pour une ligne modifiable en mise à jour, seul stop_date est modifié (positionné à l'heure courante) et une nouvelle ligne avec la donnée modifiée est insérée. Pour cette nouvelle ligne, start_date est positionné à l'heure courante et stop_date à infinity.
Une suppression ne supprime pas réellement la ligne mais positionne stop_date à l'heure courante.
Pour trouver les lignes « actuellement valides », on ajoute la clause stop_date = 'infinity' dans la condition WHERE de la requête. (Cela peut se faire au travers d'une vue.) De façon similaire, une requête peut être exécutée sur les lignes valides à un moment du passé si des conditions adéquates sont posées sur start_date et stop_date.
timetravel() est la fonction déclencheur générique associée à ce fonctionnement. On crée un déclencheur BEFORE INSERT OR UPDATE OR DELETE qui utilise cette fonction pour chaque table sur laquelle la fonctionnalité de voyage dans le temps est activée. Le déclencheur accepte deux arguments : les noms réels des colonnes start_date et stop_date. La fonction accepte jusqu'à trois arguments optionnels qui doivent faire référence à des colonnes de type text. Le déclencheur stocke le nom de l'utilisateur courant dans la première de ces colonnes lors d'un INSERT, dans la seconde lors d'un UPDATE et dans la troisième lors un DELETE.
set_timetravel() permet d'activer et de désactiver la fonctionnalité de voyage dans le temps pour une table. set_timetravel('ma_table', 1) l'active pour la table ma_table. set_timetravel('ma_table', 0) la désactive pour la table ma_table. Dans les deux cas, l'ancien statut est rapporté. Quand elle est désactivée, les colonnes start_date et stop_date peuvent être librement modifiées. Le statut actif/inactif est local à la session courante -- toute session commence avec cette fonctionnalité activée sur toutes les tables.
get_timetravel() renvoie l'état de la fonctionnalité du voyage dans le temps pour une table sans le modifier.
Il y a un exemple dans timetravel.example.
autoinc() est un déclencheur qui stocke la prochaine valeur d'une séquence dans un champ de type integer. Cela recouvre quelque peu la fonctionnalité interne de la colonne « serial », mais ce n'est pas strictement identique : autoinc() surcharge les tentatives de substitution d'une valeur différente pour ce champ lors des insertions et, optionnellement, peut aussi être utilisé pour incrémenter le champ lors des mises à jour.
Pour l'utiliser, on crée un déclencheur BEFORE INSERT (ou en option BEFORE INSERT OR UPDATE) qui utilise cette fonction. Le déclencheur accepte deux arguments : le nom de la colonne de type integer à modifier et le nom de la séquence qui fournit les valeurs. (En fait, plusieurs paires de noms peuvent être indiquées pour actualiser plusieurs colonnes.)
Un exemple est fourni dans autoinc.example.
insert_username() est un déclencheur qui stocke le nom de l'utilisateur courant dans un champ texte. C'est utile pour savoir quel est le dernier utilisateur à avoir modifié une ligne particulière d'une table.
Pour l'utiliser, on crée un déclencheur BEFORE INSERT et/ou UPDATE qui utilise cette fonction. Le déclencheur prend pour seul argument le nom de la colonne texte à modifier.
Un exemple est fourni dans insert_username.example.
moddatetime() est un déclencheur qui stocke la date et l'heure de la dernière modification dans un champ de type timestamp. C'est utile pour savoir quand a eu lieu la dernière modification sur une ligne particulière d'une table.
Pour l'utiliser, on crée un déclencheur BEFORE UPDATE qui utilise cette fonction. Le déclencheur prend pour seul argument le nom de la colonne de type timestamp à modifier.
Un exemple est fourni dans moddatetime.example.