web-dev-qa-db-fra.com

Est-ce que pg_trigger_depth () mauvais à utiliser pour empêcher la déclenchement de la gâchette (récursivité)?

Pourquoi pg_trigger_depth() = 0 mauvais à utiliser (pour autre chose que de débogage) lors de la prévention de la déclenchement de la gâchette (récursivité)?

Quelqu'un peut-il fournir un code pour démontrer pourquoi il est mauvais?

Je suppose que si plusieurs déclencheurs travaillent sur les mêmes données simultanément une condition qui arrête un déclencheur à l'aide de pg_trigger_depth() = 0 _ _ Arrêtera tout déclencheur qui est en second lieu pour fonctionner.

Je pensais que ce serait une bonne solution à cette question (ma) question ici, mais on me dit autrement:

Pensé que cela ferait une bonne question.

Il est proposé ici comme une solution:

Postgres 9.3 Documentation:

https://www.postgresql.org/docs/9.3/static/functions-info.html

8
mountainclimber

Oui, il est toujours mauvais de rendre le comportement dépendant de pg_trigger_depth()

Peut-être que je suis un peu moins opposé aux déclarations générales, mais qu'est-ce que ça pouvait faire? Je ne peux voir que je ne peux voir que pourquoi Vous voudriez une telle fonctionnalité. L'objectif principal d'une base de données est d'assurer l'intégrité des données. Et autant que je puisse le voir, et je me trompe peut-être, une telle utilisation Toujours est un potentiel violation de données-intégrité . Dans la réponse de @ erwin, il dit "si vous oubliez" . Le point d'assurer l'intégrité est d'éliminer cette possibilité. Si un agent peut se rappeler tout et comprendre les conséquences et le code autour d'eux, vous pouvez obtenir une intégrité de données sur n'importe quoi .

Introduisons quelques termes, dans la programmation, nous avons

  • "état" qui inclut rien == Un programmateur a accès à.
  • "Contexte d'exécution" qui inclut l'environnement à exécution.

Nous avons en outre un terme pour une fonction, qui n'a aucun état que nous appelons cela a fonction pure ,

La fonction évalue toujours la même valeur de résultat compte tenu de la même valeur d'argument. La valeur de résultat de la fonction ne peut dépendre d'une information ou d'un état caché pouvant être modifié lorsque l'exécution du programme se poursuit ou entre différentes exécutions du programme, ni dépendre de toute entrée externe des périphériques d'E/S (généralement - voir ci-dessous).

La distinction pour la pureté est utile car elle élimine tout fardeau pour se souvenir de tout ce qui est au nom de l'ordinateur, ou du programmeur: f(x) = y IS Toujours True. Ici vous violez la pureté dans le pire endroit - la base de données. Et, vous le faites d'une manière complexe et d'erreur tendance - faire du contexte d'exécution interne une chose palpable dans l'état de votre application DB.

Je ne voudrais pas ça. Considérez simplement les complexités que vous devez tamponner mentalement.

  • Table A 'S Trigger A Incendies
    • Trigger A Numifie toujours DML à Table B, Tir Trigger B [.____]
      • Trigger B Problèmes de manière conditionnelle DML à Table A, Terminez Trigger A.
      • Trigger B Numifie toujours DML à Table A, Tir Trigger A.
    • Trigger A Problèmes de manière conditionnelle DML à Table B, Terminez Trigger B [.____]
      • Trigger B Problèmes de manière conditionnelle DML à Table A, Terminez Trigger A.
      • Trigger B Numifie toujours DML à Table A, Tir Trigger A.

Si cela a l'air complexe, gardez à l'esprit que "conditionnellement" Il est possible de développer davantage à ", mais cela peut ne pas toujours arriver" == @, et ", cela ne s'est pas produit, mais cela peut arriver ailleurs."

Pour pg_trigger_depth() Pour même être utile, vous devez avoir une série d'événements similaires complexes. Et, maintenant, vous voulez que l'exécution soit dépendante du contenu d'exécution dans cette chaîne?

Je l'éviterais. Si votre système de déclenchement est ce complexe, vous jouez de la pomme de terre chaude avec une grenade à main dans une armoire tout seul et il ne semble pas trop se terminer.

1
Evan Carroll

C'est pas mauvais à utiliser en soi (IMHO). Il vous suffit de prendre conscience des implications.

Je préférerais le faire pg_trigger_depth() < 1 au lieu de pg_trigger_depth() = 0, sur le principal, mais ce n'est pas important ici. Nous parlons de déclencheurs comme:

CREATE TRIGGER my_trigger
AFTER INSERT ON my_tbl
FOR EACH ROW
WHEN (pg_trigger_depth() < 1)
EXECUTE PROCEDURE my_trigger_func();

Si vous ajoutez plus tard des déclencheurs qui feraient tourner votre déclencheur, rien ne se passera à la place. Votre déclencheur ne réagit que des événements non déclencheurs. Selon votre configuration, cela peut être exactement ce que vous voulez - ou une sorte de piège, si vous oubliez cela et ajoutez plus tard plus de déclencheurs qui devraient à leur tour (aussi) tirer ce déclencheur. Vous changez de comportement par défaut. Assurez-vous de le documenter clairement.

Sachez que pg_trigger_depth() comptes tout déclencheur , non seulement le même déclencheur pour empêcher la récursion, la condition empêche la gâchette de tirer de la cuisson si appelé de tout autre déclencheur aussi.
[.____] le manuel :

niveau de nidification actuel des déclencheurs PostgreSQL (0 si non appelé, directement ou indirectement, de l'intérieur d'une gâchette)

En rapport:

10
Erwin Brandstetter