É ruim usar o pg_trigger_depth () para impedir a cascata (recursão) do gatilho?

8

Por que é pg_trigger_depth() = 0ruim de usar (para qualquer coisa que não seja a depuração) ao impedir a cascata de gatilhos (recursão)?

Alguém pode fornecer código para demonstrar por que isso é ruim?

Eu estou supondo que, se vários gatilhos estiverem trabalhando nos mesmos dados ao mesmo tempo, uma condição que interrompe o uso de um gatilho pg_trigger_depth() = 0interromperá qualquer gatilho que seja o segundo na fila para fazer o trabalho.

Eu pensei que seria uma boa solução para esta (minha) pergunta aqui, mas disseram-me o contrário:

Pensei que seria uma boa pergunta.

É oferecido aqui como uma solução:

Documentação do Postgres 9.3:

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

alpinista
fonte

Respostas:

1

Sim, sempre é ruim tornar o comportamento dependente pg_trigger_depth()

Talvez eu seja um pouco menos avesso a declarações gerais, mas que bem isso poderia fazer? Não há argumento que possa entender por que você desejaria esse recurso. O principal objetivo de um banco de dados é garantir a integridade dos dados. E até onde posso ver, e posso estar errado, esse uso sempre é uma violação potencial da integridade dos dados. Na resposta de @ Erwin, ele diz "se você esquecer" . O objetivo de garantir a integridade é eliminar essa possibilidade. Se um agente pode se lembrar de tudo e entender as conseqüências e o código ao seu redor, você pode obter a integridade dos dados de qualquer coisa .

Vamos introduzir alguns termos, na programação, temos

  • "state" que inclui qualquer coisa a que um programador tenha acesso.
  • "contexto de execução", que inclui o ambiente para execução.

Além disso, temos um termo para uma função, que não possui um estado que chamamos de função pura ,

A função sempre avalia o mesmo valor de resultado, dados os mesmos valores de argumento. O valor do resultado da função não pode depender de nenhuma informação ou estado oculto que possa ser alterado durante a execução do programa ou entre diferentes execuções do programa, nem de nenhuma entrada externa de dispositivos de E / S (normalmente - veja abaixo).

A distinção de pureza é útil porque elimina qualquer ônus de lembrar qualquer coisa em nome do computador ou do programador: sempref(x) = y é verdade. Aqui você está violando a pureza no pior lugar - o banco de dados. E você está fazendo isso de uma maneira complexa e propensa a erros - tornando o contexto de execução interna algo palpável no estado do seu aplicativo de banco de dados.

Eu não iria querer isso. Apenas considere as complexidades que você precisa para amortecer mentalmente.

  • Table Aé Trigger Aincêndios
    • Trigger Asempre emite DML para Table B, disparando Trigger B.
      • Trigger Bcondicionalmente emite DML para Table A, disparando Trigger A.
      • Trigger Bsempre emite DML para Table A, disparando Trigger A.
    • Trigger Acondicionalmente emite DML para Table B, disparando Trigger B.
      • Trigger Bcondicionalmente emite DML para Table A, disparando Trigger A.
      • Trigger Bsempre emite DML para Table A, disparando Trigger A.

Se isso parecer complexo, lembre-se de que "condicionalmente" pode ser expandido para "aconteceu, mas nem sempre pode acontecer" e "não aconteceu, mas pode acontecer em outro lugar".

Para pg_trigger_depth()ser útil, você precisa ter uma série de eventos igualmente complexos. E agora, você deseja que a execução dependa do conteúdo de execução nessa cadeia?

Eu evitaria isso. Se o seu sistema de gatilho é complexo, você está jogando batata quente com uma granada de mão em um armário sozinho e não parece provável que termine bem.

Evan Carroll
fonte
10

É não ruim para usar per se (IMHO). Você só precisa estar ciente das implicações.

Prefiro fazê-lo em pg_trigger_depth() < 1vez de pg_trigger_depth() = 0, por princípio, mas isso não é importante aqui. Estamos falando de gatilhos como:

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

Se você posteriormente adicionar gatilhos que, por sua vez, acionariam seu gatilho, nada acontecerá. Seu gatilho reage apenas a eventos que não são gatilhos. Dependendo da sua configuração, isso pode ser exatamente o que você deseja - ou tipo de armadilha, se você esquecer disso e depois adicionar mais gatilhos que, por sua vez, também deverão acionar esse gatilho. Você está mudando o comportamento padrão. Certifique-se de documentar isso claramente.

Esteja ciente de que pg_trigger_depth()conta qualquer gatilho , não apenas o mesmo gatilho para impedir a recursão; portanto, a condição evita que o gatilho seja disparado se for chamado de qualquer outro gatilho também.
O manual:

nível atual de aninhamento de gatilhos do PostgreSQL (0 se não for chamado, direta ou indiretamente, de dentro de um gatilho)

Palavras-chave:

Erwin Brandstetter
fonte