37.3. Escrita de funções de gatilho em C #

Esta seção descreve detalhes de baixo nível da interface para uma função de gatilho. Estas informações são necessárias apenas quando se escreve funções de gatilho em C. Se estiver sendo usada uma linguagem de alto nível, estes detalhes serão tratados pela própria linguagem. Geralmente, deve-se considerar o uso de uma linguagem procedural antes de escrever gatilhos em C. A documentação de cada linguagem procedural explica como escrever gatilho nesta linguagem.

As funções de gatilho devem usar a interface do gerenciador de função versão 1.

Quando uma função é chamada pelo gerenciador de gatilhos, ela não recebe nenhum argumento normal, mas é passado um ponteiro context apontando para uma estrutura TriggerData. As funções em C podem verificar se foram chamadas pelo gerenciador de gatilhos ou não, executando a macro:

CALLED_AS_TRIGGER(fcinfo)

que se expande para:

((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))

Se retornar o valor verdade, então é seguro converter fcinfo->context para o tipo TriggerData *, e usar a estrutura apontada por TriggerData. A função não deve alterar a estrutura de TriggerData, ou qualquer um dos dados para os quais ela aponta.

A estrutura struct TriggerData é definida no arquivo de cabeçalho commands/trigger.h:

typedef struct TriggerData
{
    NodeTag          type;
    TriggerEvent     tg_event;
    Relation         tg_relation;
    HeapTuple        tg_trigtuple;
    HeapTuple        tg_newtuple;
    Trigger         *tg_trigger;
    TupleTableSlot  *tg_trigslot;
    TupleTableSlot  *tg_newslot;
    Tuplestorestate *tg_oldtable;
    Tuplestorestate *tg_newtable;
    const Bitmapset *tg_updatedcols;
} TriggerData;

onde os campos são definidos da seguinte forma:

type

Sempre T_TriggerData.

tg_event

Descreve o evento para o qual a função é chamada. Podem ser usadas as seguintes macros para examinar tg_event:

TRIGGER_FIRED_BEFORE​(tg_event)

Retorna verdade se o gatilho foi disparado antes da operação.

TRIGGER_FIRED_AFTER​(tg_event)

Retorna verdade se o gatilho foi disparado após a operação.

TRIGGER_FIRED_INSTEAD​(tg_event)

Retorna verdade se o gatilho foi disparado em vez da operação.

TRIGGER_FIRED_FOR_ROW​(tg_event)

Retorna verdade se o gatilho foi disparado para um evento no nível de linha.

TRIGGER_FIRED_FOR_STATEMENT​(tg_event)

Retorna verdade se o gatilho foi disparado para um evento no nível de instrução.

TRIGGER_FIRED_BY_INSERT​(tg_event)

Retorna verdade se o gatilho foi disparado por um comando INSERT.

TRIGGER_FIRED_BY_UPDATE​(tg_event)

Retorna verdade se o gatilho foi disparado por um comando UPDATE.

TRIGGER_FIRED_BY_DELETE​(tg_event)

Retorna verdade se o gatilho foi disparado por um comando DELETE.

TRIGGER_FIRED_BY_TRUNCATE​(tg_event)

Retorna verdade se o gatilho foi disparado por um comando TRUNCATE.

tg_relation

Ponteiro para uma estrutura que descreve a relação para a qual o gatilho foi disparado. Deve ser consultado o arquivo de cabeçalho utils/rel.h para obter detalhes sobre esta estrutura. As informações de maior interesse são tg_relation->rd_att (descritor das tuplas da relação) e tg_relation->rd_rel->relname (nome da relação; o tipo não é char*, mas sim NameData; deve ser usado SPI_getrelname(tg_relation) para obter char*, se for necessário obter uma cópia do nome).

tg_trigtuple

Ponteiro para a linha para a qual o gatilho foi disparado. Esta é a linha que está sendo inserida, atualizada ou excluída. Se o gatilho foi disparado para um comando INSERT ou DELETE, então é isto que a função deve retornar se não quiser substituir a linha por uma linha diferente (no caso de INSERT), ou saltar a operação. Para os gatilhos em tabelas estrangeiras, os valores das colunas do sistema não são especificados aqui.

tg_newtuple

Ponteiro para a nova versão da linha, se o gatilho foi disparado por um comando UPDATE, ou NULL se foi por um INSERT ou DELETE. É isto que a função deve retornar, se o evento for um UPDATE e não se deseja substituir a linha por uma linha diferente ou saltar a operação. Para os gatilhos em tabelas estrangeiras, os valores das colunas do sistema não são especificados aqui.

tg_trigger

Ponteiro para uma estrutura do tipo Trigger, definida mo arquivo de cabeçalho utils/reltrigger.h:

typedef struct Trigger
{
    Oid         tgoid;
    char       *tgname;
    Oid         tgfoid;
    int16       tgtype;
    char        tgenabled;
    bool        tgisinternal;
    bool        tgisclone;
    Oid         tgconstrrelid;
    Oid         tgconstrindid;
    Oid         tgconstraint;
    bool        tgdeferrable;
    bool        tginitdeferred;
    int16       tgnargs;
    int16       tgnattr;
    int16      *tgattr;
    char      **tgargs;
    char       *tgqual;
    char       *tgoldtable;
    char       *tgnewtable;
} Trigger;

onde tgname é o nome do gatilho, tgnargs é o número de argumentos em tgargs, e tgargs é uma matriz de ponteiros para os argumentos especificados na instrução CREATE TRIGGER. Os demais campos são apenas para uso interno.

tg_trigslot

O encaixe contendo tg_trigtuple, ou um ponteiro NULL, caso não haja esta tupla.

tg_newslot

O encaixe contendo tg_newtuple, ou um ponteiro NULL, caso não haja esta tupla.

tg_oldtable

Um ponteiro para uma estrutura do tipo Tuplestorestate, contendo zero ou mais linhas no formato especificado por tg_relation, ou um ponteiro NULL, caso não haja a relação de transição OLD TABLE.

tg_newtable

Um ponteiro para uma estrutura do tipo Tuplestorestate, contendo zero ou mais linhas no formato especificado por tg_relation, ou um ponteiro NULL, caso não haja a relação de transição NEW TABLE.

tg_updatedcols

Para os gatilhos de UPDATE, um conjunto de bitmap indicando as colunas atualizadas pelo comando disparador. As funções de gatilho genéricas podem usar esta informação para otimizar ações, por não ter que lidar com colunas que não foram modificadas.

Por exemplo, para determinar se a coluna com número de atributo attnum (com base em 1) é membro desse conjunto de bitmap, deve-se chamar bms_is_member(attnum - FirstLowInvalidHeapAttribute​Number, trigdata->tg_updatedcols)).

Para os gatilhos diferentes dos gatilhos de UPDATE, será NULL.

Para permitir que consultas chamadas por meio de SPI façam referência a tabelas de transição, veja SPI_register_trigger_data.

Uma função de gatilho deve retornar um ponteiro HeapTuple ou um ponteiro NULL (e não um valor SQL nulo, ou seja, não se deve definir isNull como verdade). Deve-se tomar o cuidado de retornar tg_trigtuple ou tg_newtuple, conforme apropriado, se não for desejado modificar a linha que está sendo operada.