A seguir está um exemplo muito simples de uma função de gatilho escrita em C. (Exemplos de gatilhos escritos em linguagens procedurais podem ser encontrados na documentação das linguagens procedurais.)
A função trigf informa o número de linhas na
tabela ttest, e salta a operação se o comando
tentar inserir um valor nulo na coluna x.
(Portanto, o gatilho age como uma restrição de não nulo, mas não
interrompe a transação.)
Primeiro, a definição da tabela:
CREATE TABLE ttest (
x integer
);
This is the source code of the trigger function:
#include "postgres.h"
#include "fmgr.h"
#include "executor/spi.h" /* necessário para trabalhar com SPI */
#include "commands/trigger.h" /* ... gatilhos ... */
#include "utils/rel.h" /* ... e relações */
PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(trigf);
Datum
trigf(PG_FUNCTION_ARGS)
{
TriggerData *trigdata = (TriggerData *) fcinfo->context;
TupleDesc tupdesc;
HeapTuple rettuple;
char *when;
bool checknull = false;
bool isnull;
int ret, i;
/* certifique-se de que é chamado como um gatilho */
if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "trigf: não foi chamada pelo gerenciador de gatilho");
/* tupla para retornar ao executor */
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
rettuple = trigdata->tg_newtuple;
else
rettuple = trigdata->tg_trigtuple;
/* verificar valores nulos */
if (!TRIGGER_FIRED_BY_DELETE(trigdata->tg_event)
&& TRIGGER_FIRED_BEFORE(trigdata->tg_event))
checknull = true;
if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
when = "before";
else
when = "after ";
tupdesc = trigdata->tg_relation->rd_att;
/* conectar ao gerenciador SPI */
if ((ret = SPI_connect()) < 0)
elog(ERROR, "trigf (disparado %s): SPI_connect returned %d", when, ret);
/* obter o número de linhas na tabela */
ret = SPI_exec("SELECT count(*) FROM ttest", 0);
if (ret < 0)
elog(ERROR, "trigf (disparado %s): SPI_exec retornou %d", when, ret);
/* count(*) retorna int8, então tenha o cuidado de converter */
i = DatumGetInt64(SPI_getbinval(SPI_tuptable->vals[0],
SPI_tuptable->tupdesc,
1,
&isnull));
elog (INFO, "trigf (disparado %s): existem %d linhas em ttest", when, i);
SPI_finish();
if (checknull)
{
SPI_getbinval(rettuple, tupdesc, 1, &isnull);
if (isnull)
rettuple = NULL;
}
return PointerGetDatum(rettuple);
}
Após compilar o código-fonte (veja Compilação e ligação de funções carregadas dinamicamente), são declarados a função e os gatilhos:
CREATE FUNCTION trigf() RETURNS trigger
AS 'filename'
LANGUAGE C;
CREATE TRIGGER tbefore BEFORE INSERT OR UPDATE OR DELETE ON ttest
FOR EACH ROW EXECUTE FUNCTION trigf();
CREATE TRIGGER tafter AFTER INSERT OR UPDATE OR DELETE ON ttest
FOR EACH ROW EXECUTE FUNCTION trigf();
Agora pode ser testado o funcionamento do gatilho:
=# INSERT INTO ttest VALUES (NULL); INFO: trigf (disparado before): existem 0 linhas em ttest INSERT 0 0 -- Inserção ignorada e gatilho AFTER não disparado =# SELECT * FROM ttest; x --- (0 linha) =# INSERT INTO ttest VALUES (1); INFO: trigf (disparado before): existem 0 linhas em ttest INFO: trigf (disparado after ): existem 1 linhas em ttest ^^^^^^^^ lembre-se do que foi dito sobre visibilidade INSERT 0 1 =# SELECT * FROM ttest; x --- 1 (1 linha) =# INSERT INTO ttest SELECT x * 2 FROM ttest; INFO: trigf (disparado before): existem 1 linhas em ttest INFO: trigf (disparado after ): existem 2 linhas em ttest ^^^^^^^^ lembre-se do que foi dito sobre visibilidade INSERT 0 1 =# SELECT * FROM ttest; x --- 1 2 (2 linhas) =# UPDATE ttest SET x = NULL WHERE x = 2; INFO: trigf (disparado before): existem 2 linhas em ttest UPDATE 0 =# UPDATE ttest SET x = 4 WHERE x = 2; INFO: trigf (disparado before): existem 2 linhas em ttest INFO: trigf (disparado after ): existem 2 linhas em ttest UPDATE 1 =# SELECT * FROM ttest; x --- 1 4 (2 linhas) =# DELETE FROM ttest; INFO: trigf (disparado before): existem 2 linhas em ttest INFO: trigf (disparado before): existem 1 linhas em ttest INFO: trigf (disparado after ): existem 0 linhas em ttest INFO: trigf (disparado after ): existem 0 linhas em ttest ^^^^^^^^ lembre-se do que foi dito sobre visibilidade DELETE 2 =# SELECT * FROM ttest; x --- (0 linha)
Existem exemplos mais complexos no arquivo
src/test/regress/regress.c
da distribuição do código-fonte, e em
spi
[120].
[120]
O código-fonte da função, o arquivo Makefile,
o comando CREATE FUNCTION, que vincula a função
C à função SQL, e demais
comandos SQL, podem ser vistos em
Exemplo completo de gatilho em C no GitLab. (N. T.)