Banco de Dados

13 jun, 2008

Triggers no Firebird

Publicidade

Vamos criar um mecanismo de auto-incremento utilizando triggers e generators, apresentando recursos úteis que podem ser utilizados dentro das triggers.

Para os exemplos, vamos utilizar a ferramenta IBOConsole, que pode ser adquirida no seguinte endereço http://www.firebase.com.br/fb/downloads.php?categ=2.

Criando uma trigger

A sintaxe para a criação de uma trigger é apresentada abaixo:

CREATE TRIGGER name FOR {table  view}
[ACTIVE | INACTIVE]
{BEFORE  AFTER} {DELETE  INSERT  UPDATE}
[POSITION number]
AS
<variable_declaration_list> =DECLARE VARIABLE variable datatype;
[DECLARE VARIABLE variable datatype;...]
BEGIN
<trigger_body>
END

Argumentos:

  • table view é o nome tabela ou view que estará associada à trigger.
  • active inactive indica se a trigger estará ativa ou não.
  • before after indica em que momento a trigger será disparada. A trigger pode ser dispara antes ou depois de um evento de DELETE, UPDATE ou INSERT.
  • delete insert update indica em qual evento a trigger será executada.
  • position é utilizado para definir a seqência de execução de triggers que estão associadas a um mesmo momento e evento. Por exemplo, posso ter duas triggers do tipo BEFORE DELETE. Como saber qual delas será executada primeiro? O parâmetro POSITION indicará isso.
  • trigger body é o corpo da trigger, o código dela.

Um exemplo de criação de uma trigger simples é apresentado abaixo:

SET TERM !;

CREATE EXCEPTION EX_NOT_DELETE_UF
Não é possível excluir um estado. !

CREATE TRIGGER DB_X
FOR UF
BEFORE DELETE
AS
BEGIN
  EXCEPTION EX_NOT_DELETE_UF;
END!

SET TERM;!

Explicação:

Estamos trabalhando com o IBOConsole, e esta ferramenta identifica o fim de cada comando pelo caractere “;”. O problema é que queremos que o IBOConsole execute o comando CREATE TRIGGER como um único comando e isso significa que ele deveria terminar com um “;”. Entretanto, cada um dos comandos no corpo da trigger que se está sendo criada também termina com “;” e o IBOConsole acha que encontrou o fim do CREATE TRIGGER quando ele encontra o primeiro “;”. Para resolver isso utilizamos o comando SET TERM, e informamos um novo caractere para indicar o término de um comando SQL.

Logo em seguida criamos uma exception (exceção), mais tarde você entenderá por que.

Depois criamos a trigger propriamente dita. O comando “FOR UF” indica que esta trigger vai ser disparada quando houver algum evento de DELETE, UPDATE ou INSERT na tabela. Mas qual evento? Isso está especificado na linha “BEFORE DELETE”, indicando que a trigger será executada antes de ocorrer um comando DELETE. O corpo dessa trigger possui apenas uma linha importante, “EXCEPTION EX_NOT_DELETE_UF;”. Este comando dispara a exceção anteriormente criada, cancelando a ação que está sendo executada, ou seja, cancelando o comando DELETE.

Assim, percebemos que a única função desta trigger é evitar qualquer exclusão da tabela “UF”.

As variáveis NEW e OLD

O Firebird disponibiliza duas variáveis muito úteis para serem usadas no contexto de uma trigger. São elas: NEW e OLD.

A variável NEW, no caso do INSERT, armazena o registro que está sendo inserido. No caso do UPDATE, armazena o registro depois de atualizado.

A variável OLD, no caso do DELETE, armazena o registro que está sendo excluído. No caso do UPDATE, armazena o registro antes de sofrer a atualização.

Por exemplo, em minha tabela possuo os campos IDADE e PESTIPO. O campo PESTIPO é atualizado de acordo com o valor do campo IDADE:

Se IDADE < 18, então PESTIPO deve ser J.

Se IDADE > 18, então PESTIPO deve ser A.

Vamos criar uma trigger para exemplificar isso. Antes vou criar a tabela com os comandos abaixo:

CREATE TABLE PESSOA
(
  PESCOD INT NOT NULL,
  PESIDADE INT NOT NULL,
  PESTIPO CHAR(1)
);

Agora criemos a trigger:

SET TERM !;
CREATE TRIGGER ATUALIZA_PESTIPO
FOR PESSOA
ACTIVE
BEFORE INSERT OR UPDATE
POSITION 0
AS
BEGIN
  IF (NEW.PESIDADE < 18) THEN BEGIN
    NEW.PESTIPO = J;
  END
  ELSE
    NEW.PESTIPO = A;
END;

Repare que nossa trigger está associada aos eventos de INSERT e UPDATE. Essa funcionalidade está presente a partir da versão 1.5 do Firebird.

Agora, vamos fazer um insert para testar o funcionamento da trigger, observe os comandos abaixo:

INSERT INTO PESSOA (PESCOD, PESIDADE)
VALUES (1, 10);

Agora se fizermos um select na tabela pessoa, obteremos o seguinte resultado:

Outro insert:

INSERT INTO PESSOA (PESCOD, PESIDADE)
VALUES (2, 20)

Resultado:

Agora um update:

UPDATE PESSOA SET PESIDADE = 5;

Resultado:

Nossa trigger está OK.

Alterando uma trigger

Vamos agora alterar essa trigger que criamos para que, quando o evento for UPDATE, atualizamos o campo PESTIPO com letra minúscula e quando for INSERT, com letra maiúscula.

A sintaxe para a alteração da trigger é apresentada abaixo:

{ALTER TRIGGER name}  {CREATE OR ALTER TRIGGER name FOR {table  view}
[ACTIVE | INACTIVE]
[{BEFORE | AFTER} {DELETE | INSERT | UPDATE}]
[POSITION number]
AS <trigger_body>;

Observe os comandos abaixo:

SET TERM !;
ALTER TRIGGER ATUALIZA_PESTIPO
ACTIVE
BEFORE INSERT OR UPDATE
POSITION 0
AS
DECLARE APESTIPO CHAR(1);
DECLARE JPESTIPO CHAR(1);
BEGIN
  IF (INSERTING) THEN BEGIN
    IF (NEW.PESIDADE < 18) THEN BEGIN
      NEW.PESTIPO = J;
    END
    ELSE
      NEW.PESTIPO = A;
  END
  ELSE BEGIN
    IF (UPDATING) THEN BEGIN
      IF (NEW.PESIDADE < 18) THEN BEGIN
        NEW.PESTIPO = j;
      END
      ELSE
        NEW.PESTIPO = a;
  END
  END
END;

Observe o uso de duas novas variáveis: INSERTING e UPDATING.

Lembra que criamos nossa trigger associada a eventos de INSERT e UPDATE? Pois então, como saberemos se essa trigger foi disparada em um evento de INSERT ou UPDATE? Simples, através das variáveis de evento INSERTING e UPDATING. Ainda existe a variável DELETING para eventos disparados pelo DELETE.

Essas variáveis indicam qual o evento que disparou a trigger. Assim, podemos criar uma trigger para ser disparada por todos os eventos (INSERT, UPDATE, DELETE), e executá-la de forma diferente dependendo deste evento.

Para verificar o funcionamento da trigger, efetue alguns inserts e updates e observe os resultados.

Excluindo uma trigger

Para excluir uma trigger basta executar o comando abaixo:

DROP TRIGGER nome_trigger;

Exemplo:

DROP TRIGGER DB_X;

Ativando/Desativando uma trigger

Para desativar uma trigger execute o comando abaixo:

ALTER TRIGGER nome_trigger INACTIVE; 

Exemplo:

ALTER TRIGGER DB_X INACTIVE;

Criando um mecanismo de auto-incremento

Nesta seção, vou mostrar como podemos criar um mecanismo de auto-incremento no Firebird utilizando trigger e generator (contador).

Primeiro, criamos um generator:

CREATE GENERATOR GEN_PK_PESSOA;

E depois a trigger:

SET TERM !;
CREATE TRIGGER GERA_ID_PESSOA
FOR PESSOA
ACTIVE
BEFORE INSERT
POSITION 0
AS
BEGIN
  IF (NEW.PESCOD IS NULL) THEN BEGIN
    NEW.PESCOD = GEN_ID(GEN_PK_PESSOA, 1);
  END
END;

Para testarmos o mecanismo, execute os comandos abaixo:

DELETE FROM PESSOA;
INSERT INTO PESSOA (PESIDADE)
VALUES (40);
INSERT INTO PESSOA (PESIDADE)
VALUES (10);
INSERT INTO PESSOA (PESIDADE)
VALUES (8);
SELECT * FROM PESSOA;

O resultado será algo como abaixo:

É isso ai pessoal, valeu!