¿Es malo usar pg_trigger_depth () para evitar la activación en cascada del disparador (recursividad)?

8

¿Por qué es pg_trigger_depth() = 0malo usarlo (para otra cosa que no sea la depuración) cuando se evita la activación en cascada del disparador (recursividad)?

¿Alguien puede proporcionar un código para demostrar por qué es malo?

Supongo que porque si varios disparadores están trabajando en los mismos datos al mismo tiempo, una condición que detiene un disparador usando pg_trigger_depth() = 0detendrá cualquier disparador que sea el segundo en la línea para hacer el trabajo.

Pensé que sería una buena solución para esta (mi) pregunta aquí, pero me dicen lo contrario:

Pensé que sería una buena pregunta.

Se ofrece aquí como una solución:

Documentación de Postgres 9.3:

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

montañista
fuente

Respuestas:

1

Sí, siempre es malo hacer que el comportamiento dependa de pg_trigger_depth()

Tal vez soy un poco menos reacio a las declaraciones generales, pero ¿qué bien podría hacer? No puedo ver ningún argumento sobre por qué querrías tal característica. El objetivo principal de una base de datos es garantizar la integridad de los datos. Y hasta donde puedo ver, y puedo estar equivocado, tal uso siempre es una violación potencial de la integridad de los datos. En la respuesta de @ Erwin, dice "si te olvidas" . El objetivo de garantizar la integridad es eliminar esa posibilidad. Si un agente puede recordar todo y comprender las consecuencias y el código que lo rodea, puede obtener integridad de los datos de cualquier cosa .

Vamos a introducir algunos términos, en programación, tenemos

  • "estado" que incluye cualquier cosa a la que un programador tenga acceso.
  • "contexto de ejecución" que incluye el entorno para la ejecución.

Además tenemos un término para una función, que no tiene un estado que llamamos función pura ,

La función siempre evalúa el mismo valor de resultado dados los mismos valores de argumento. El valor del resultado de la función no puede depender de ninguna información oculta o estado que pueda cambiar mientras se ejecuta la ejecución del programa o entre diferentes ejecuciones del programa, ni puede depender de ninguna entrada externa de los dispositivos de E / S (generalmente, ver más abajo).

La distinción por la pureza es útil porque elimina cualquier carga de recordar algo en nombre de la computadora o del programador: siempref(x) = y es cierto. Aquí estás violando la pureza en el peor lugar: la base de datos. Y lo está haciendo de una manera compleja y propensa a errores, lo que hace que el contexto de ejecución interna sea algo palpable en el estado de su aplicación de base de datos.

No me gustaría eso. Solo considera las complejidades que tienes para amortiguar mentalmente.

  • Table AEs por Trigger Aincendios
    • Trigger Asiempre emite DML para Table Bdisparar Trigger B.
      • Trigger Bemite condicionalmente DML a Table A, disparando Trigger A.
      • Trigger Bsiempre emite DML para Table Adisparar Trigger A.
    • Trigger Aemite condicionalmente DML a Table B, disparando Trigger B.
      • Trigger Bemite condicionalmente DML a Table A, disparando Trigger A.
      • Trigger Bsiempre emite DML para Table Adisparar Trigger A.

Si eso parece complejo, tenga en cuenta que "condicionalmente" puede expandirse aún más a "sucedió, pero puede que no siempre suceda" y "no sucedió, pero puede suceder en otros lugares".

Para pg_trigger_depth()ser incluso útil, debes tener una serie de eventos que sean igualmente complejos. Y, ahora, ¿quieres que la ejecución dependa del contenido de ejecución en esa cadena?

Yo evitaría esto. Si su sistema de activación es tan complejo, está jugando a la papa caliente con una granada de mano en un armario y no parece que termine bien.

Evan Carroll
fuente
10

Es no mal utilizar per se (en mi humilde opinión). Solo necesita estar al tanto de las implicaciones.

Prefiero hacerlo en pg_trigger_depth() < 1lugar de pg_trigger_depth() = 0, por director, pero eso no es importante aquí. Estamos hablando de desencadenantes como:

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

Si luego agrega disparadores que a su vez dispararían su disparador, no pasará nada en su lugar. Su disparador solo reacciona a eventos no disparadores. Dependiendo de su configuración, esto puede ser exactamente lo que desea, o una especie de trampa, si se olvida de esto y luego agrega más disparadores que a su vez (también) dispararán este disparador. Estás cambiando el comportamiento predeterminado. Asegúrese de documentar esto claramente.

Tenga en cuenta que pg_trigger_depth()cuenta cualquier desencadenante , no solo el mismo desencadenante para evitar la recurrencia, por lo que la condición evita que el desencadenante se active si se llama desde cualquier otro desencadenante también.
El manual:

nivel de anidamiento actual de los desencadenadores PostgreSQL (0 si no se llama, directa o indirectamente, desde el interior de un desencadenante)

Relacionado:

Erwin Brandstetter
fuente