Este capítulo descreve como escrever funções de gatilho. As funções de gatilho podem ser escritas na linguagem C, ou em uma das várias linguagens procedurais disponíveis. No momento não é possível escrever funções de gatilho na linguagem SQL.
O gatilho pode ser definido para executar antes ou depois de uma operação de INSERT, UPDATE ou DELETE, tanto uma vez para cada linha modificada quanto uma vez por instrução SQL. Quando ocorre o evento do gatilho, a função de gatilho é chamada no momento apropriado para tratar o evento.
A função de gatilho deve ser definida antes do gatilho ser criado. A função de gatilho deve ser declarada como uma função que não recebe argumentos e que retorna o tipo trigger (A função de gatilho recebe sua entrada através de estruturas TriggerData passadas especialmente para estas funções, e não na forma comum de argumentos de função).
Tendo sido criada a função de gatilho adequada, o gatilho é estabelecido através do comando CREATE TRIGGER. A mesma função de gatilho pode ser utilizada por vários gatilhos.
Existem dois tipos de gatilhos: gatilhos-por-linha e gatilhos-por-instrução. Em um gatilho-por-linha, a função é chamada uma vez para cada linha afetada pela instrução que disparou o gatilho. Em contraste, um gatilho-por-instrução é chamado somente uma vez quando a instrução apropriada é executada, a despeito do número de linhas afetadas pela instrução. Em particular, uma instrução que não afeta nenhuma linha ainda assim resulta na execução dos gatilhos-por-instrução aplicáveis. Este dois tipos de gatilho são algumas vezes chamados de "gatilhos no nível-de-linha" e "gatilhos no nível-de-instrução", respectivamente.
Os gatilhos no nível-de-instrução "BEFORE" (antes) naturalmente disparam antes da instrução começar a fazer alguma coisa, enquanto os gatilhos no nível-de-instrução "AFTER" (após) disparam bem no final da instrução. Os gatilhos no nível-de-linha "BEFORE" (antes) disparam logo antes da operação em uma determinada linha, enquanto os gatilhos no nível-de-linha "AFTER" (após) disparam no fim da instrução (mas antes dos gatilhos no nível-de-instrução "AFTER").
As funções de gatilho chamadas por gatilhos-por-instrução devem sempre retornar NULL. As funções de gatilho chamadas por gatilhos-por-linha podem retornar uma linha da tabela (um valor do tipo HeapTuple) para o executor da chamada, se assim o decidirem. Os gatilhos no nível-de-linha disparados antes de uma operação possuem as seguintes escolhas:
Podem retornar NULL para saltar a operação para a linha corrente. Isto instrui ao executor a não realizar a operação no nível-de-linha que chamou o gatilho (a inserção ou a modificação de uma determinada linha da tabela).
Para os gatilhos de INSERT e UPDATE, no nível-de-linha apenas, a linha retornada se torna a linha que será inserida ou que substituirá a linha sendo atualizada. Isto permite à função de gatilho modificar a linha sendo inserida ou atualizada.
Um gatilho no nível-de-linha, que não pretenda causar nenhum destes comportamentos, deve ter o cuidado de retornar como resultado a mesma linha que recebeu (ou seja, a linha NEW para os gatilhos de INSERT e UPDATE, e a linha OLD para os gatilhos de DELETE).
O valor retornado é ignorado nos gatilhos no nível-de-linha disparados após a operação e, portanto, podem muito bem retornar NULL.
Se for definido mais de um gatilho para o mesmo evento na mesma relação, os gatilhos são disparados pela ordem alfabética de seus nomes. No caso dos gatilhos para antes, a linha possivelmente modificada retornada por cada gatilho se torna a entrada do próximo gatilho. Se algum dos gatilhos para antes retornar NULL, a operação é abandonada e os gatilhos seguintes não são disparados.
Tipicamente, os gatilhos no nível-de-linha que disparam antes são utilizados para verificar ou modificar os dados que serão inseridos ou atualizados. Por exemplo, um gatilho que dispara antes pode ser utilizado para inserir a hora corrente em uma coluna do tipo timestamp, ou para verificar se dois elementos da linha são consistentes. Os gatilhos no nível-de-linha que disparam depois fazem mais sentido para propagar as atualizações para outras tabelas, ou fazer verificação de consistência com relação a outras tabelas. O motivo desta divisão de trabalho é porque um gatilho que dispara depois pode ter certeza de estar vendo o valor final da linha, enquanto um gatilho que dispara antes não pode ter esta certeza; podem haver outros gatilhos que disparam antes disparando após o mesmo. Se não houver nenhum motivo específico para fazer um gatilho disparar antes ou depois, o gatilho para antes é mais eficiente, uma vez que a informação sobre a operação não precisa ser salva até o fim da instrução.
Se a função de gatilho executar comandos SQL, então estes comandos podem disparar gatilhos novamente. Isto é conhecido como cascatear gatilhos. Não existe limitação direta do número de níveis de cascateamento. É possível que o cascateamento cause chamadas recursivas do mesmo gatilho; por exemplo, um gatilho para INSERT pode executar um comando que insere uma linha adicional na mesma tabela, fazendo com que o gatilho para INSERT seja disparado novamente. É responsabilidade do programador do gatilho evitar recursões infinitas nestes casos.
Ao se definir um gatilho, podem ser especificados argumentos para o mesmo. A finalidade de se incluir argumentos na definição do gatilho é permitir que gatilhos diferentes com requisitos semelhantes chamem a mesma função. Por exemplo, pode existir uma função de gatilho generalizada que recebe como argumentos dois nomes de colunas e coloca o usuário corrente em uma e a data corrente em outra. Escrita de maneira apropriada, esta função de gatilho se torna independente da tabela específica para a qual está sendo utilizada. Portanto, a mesma função pode ser utilizada para eventos de INSERT em qualquer tabela com colunas apropriadas, para acompanhar automaticamente a criação de registros na tabela de transação, por exemplo. Também pode ser utilizada para acompanhar os eventos de última atualização, se for definida em um gatilho de UPDATE.
Cada linguagem de programação que suporta gatilhos possui o seu próprio método para tornar os dados de entrada do gatilho disponíveis para a função de gatilho. Estes dados de entrada incluem o tipo de evento do gatilho (ou seja, INSERT ou UPDATE), assim como os argumentos listados em CREATE TRIGGER. Para um gatilho no nível-de-linha, os dados de entrada também incluem as linhas NEW para os gatilhos de INSERT e UPDATE, e/ou a linha OLD para os gatilhos de UPDATE e DELETE. Atualmente não há maneira de examinar individualmente as linhas modificadas pela instrução nos gatilhos no nível-de-instrução.