web-dev-qa-db-fra.com

Comment empêcher un déclencheur PostgreSQL d'être tiré par un autre déclencheur?

J'ai 2 déclencheurs sur une table; on travaille pour les insertions:

CREATE TRIGGER "get_user_name"
AFTER INSERT ON "field_data"
FOR EACH ROW EXECUTE PROCEDURE "add_info"();

Cela met à jour certaines valeurs dans le tableau.
[.____] et une pour les mises à jour (pour remplir une table d'histoire):

CREATE TRIGGER "set_history"
BEFORE UPDATE ON "field_data"
FOR EACH ROW EXECUTE PROCEDURE "gener_history"();

Le problème est que lorsque j'insère une nouvelle ligne dans le tableau, la procédure "add_info"() fait une mise à jour et déclenche donc le deuxième déclencheur, qui se termine par une erreur:

ERROR:  record "new" has no field "field1"

Comment puis-je éviter ça?

7
dd_a

(Erreur évidente dans la logique de déclenchement de côté.)
[.____] dans Postgres 9.2 ou ultérieure, utilisez la fonction pg_trigger_depth() That @ Akash déjà mentionné Dans A Condition sur la gâchette elle-même (au lieu du corps de la fonction de déclenchement), de sorte que la fonction de déclenchement n'est même pas exécutée lorsqu'elle est appelée à partir d'un autre déclencheur (y compris elle-même - évitant ainsi boucles).
[.____] Cela fonctionne généralement mieux et est plus simple et plus propre:

CREATE TRIGGER set_history
BEFORE UPDATE ON field_data
FOR EACH ROW 
WHEN (pg_trigger_depth() < 1)
EXECUTE PROCEDURE gener_history();

L'expression pg_trigger_depth() < 1 est évaluée avant La fonction de déclenchement est entrée. Donc, il évalue à 0 dans le premier appel. Lorsque cela est appelé à partir d'un autre déclencheur, la valeur est plus élevée et la fonction de déclenchement n'est pas exécutée.

12

Si vous ne voulez pas que la mise à jour de la gâchette soit exécutée lorsque c'est appelé de l'intérieur de la gâchette insertion, vous pouvez surmonter vos instructions avec une condition de pg_trigger_depth() qui retourne la profondeur . Ce qui ne sera pas 0 lorsque vous exécutez la gâchette directement/indirectement d'un autre déclencheur .

Donc, dans votre fonction gener_history(), vous pouvez faire quelque chose comme ça

IF pg_trigger_depth() = 1 THEN
.. your statements..
END IF;

Voici un autre exemple: http://www.depesz.com/2012/02/01/waitting-for-9-2-trigger-depth/

4
Akash

Suggestion n ° 1

Retirer le AFTER INSERT déclencheur et appel add_info de votre application

Suggestion n ° 2

Changer la AFTER INSERT déclencher dans BEFORE INSERT

1
RolandoMySQLDBA