| Documentação do PostgreSQL 8.0.0 | ||||
|---|---|---|---|---|
| Anterior | Início | Capítulo 39. PL/Ruby - Linguagem procedural Ruby | Fim | Próxima |
No comando CREATE TRIGGER do PostgreSQL é especificada uma função fornecida pelo usuário, declarada como não recebendo nenhum argumento e retornando o tipo trigger, que é executada quando o gatilho dispara. No PL/Ruby o procedimento é chamado com quatro argumentos:
Um hash contendo os valores da nova linha da tabela para as operações de INSERT e UPDATE, ou vazio para DELETE.
Um hash contendo os valores da linha antiga da tabela para as operações de DELETE e UPDATE, ou vazio para INSERT.
Uma matriz de argumentos para o procedimento, conforme passado pelo comando CREATE TRIGGER.
Estão definidas as seguintes chaves:
O nome do gatilho do comando CREATE TRIGGER.
O nome da relação que disparou o gatilho.
O ID de objeto da tabela que causou a chamada do procedimento de gatilho.
Matriz contendo os nomes dos campos da tabela.
A constante PL::BEFORE, PL::AFTER ou PL::UNKNOWN dependendo do evento de chamada do gatilho.
A constante PL::ROW ou PL::STATEMENT dependendo do evento de chamada do gatilho.
A constante PL::INSERT, PL::UPDATE ou PL::DELETE dependendo do evento de chamada do gatilho.
O valor retornado pelo procedimento de gatilho é uma das constantes PL::OK ou PL::SKIP, ou um hash. Se o valor retornado for PL::OK, a operação (INSERT/UPDATE/DELETE) que disparou o gatilho prossegue normalmente. O valor PL::SKIP informa ao gerenciador de gatilhos para suprimir em silêncio a operação. O hash informa ao PL/Ruby para retornar para o gerenciador de gatilhos a linha modificada que deve ser inserida no lugar da nova linha fornecida (apenas para as operações de INSERT e UPDATE). É desnecessário dizer que isto tudo só faz sentido quando o gatilho é BEFORE e FOR EACH ROW.
A seguir são mostrados exemplos de gatilhos escritos em PL/Ruby:
Exemplo 39-13. Gatilho em PL/Ruby registrar as atualizações da linha
Neste exemplo é mostrado um gatilho escrito em PL/Ruby que conta e registra o número de atualizações das linhas de uma tabela, além de registrar o momento e o login do usuário da última atualização.
CREATE TABLE tbl_registra_modif (
nome TEXT,
salario INTEGER,
num_modif INTEGER,
data_ult_modif TIMESTAMP,
login_ult_modif TEXT);
CREATE OR REPLACE FUNCTION fun_registra_modif() RETURNS TRIGGER AS $$
case tg["op"]
when PL::INSERT
new["num_modif"] = 0
new["data_ult_modif"] = Time.now
new["login_ult_modif"] = (PLruby.exec("SELECT current_user"))[0]["current_user"]
when PL::UPDATE
new["num_modif"] = old["num_modif"] + 1
new["data_ult_modif"] = Time.now
new["login_ult_modif"] = (PLruby.exec("SELECT current_user"))[0]["current_user"]
else
return PL::OK
end
new
$$ LANGUAGE 'plruby';
CREATE TRIGGER gat_registra_modif BEFORE INSERT OR UPDATE ON tbl_registra_modif
FOR EACH ROW EXECUTE PROCEDURE fun_registra_modif();
Para testar o gatilho foram utilizados os comandos:
INSERT INTO tbl_registra_modif (nome,salario) VALUES ('Joana',1500);
INSERT INTO tbl_registra_modif (nome,salario) VALUES ('Pedro',1000);
INSERT INTO tbl_registra_modif (nome,salario) VALUES ('Maria',1100);
UPDATE tbl_registra_modif SET salario = 1200 WHERE nome = 'Pedro';
UPDATE tbl_registra_modif SET salario = 1300 WHERE nome = 'Maria';
UPDATE tbl_registra_modif SET salario = 1400 WHERE nome = 'Pedro';
UPDATE tbl_registra_modif SET salario = 1500 WHERE nome = 'Maria';
UPDATE tbl_registra_modif SET salario = 1500 WHERE nome = 'Pedro';
SELECT * FROM tbl_registra_modif;
nome | salario | num_modif | data_ult_modif | login_ult_modif
-------+---------+-----------+----------------------------+-----------------
Joana | 1500 | 0 | 2006-01-14 12:56:52.046658 | postgres
Maria | 1500 | 2 | 2006-01-14 12:56:52.074648 | postgres
Pedro | 1500 | 3 | 2006-01-14 12:56:52.077713 | postgres
(3 linhas)
Exemplo 39-14. Gatilho em PL/Ruby para auditoria
Este gatilho garante que todas as inserções, atualizações e exclusões de linha na tabela emp são registradas na tabela emp_audit, para permitir auditar as operações efetuadas na tabela emp. O nome de usuário e a hora corrente são gravadas na linha, junto com o tipo de operação que foi realizada.
A inserção das linhas na tabela emp_audit são feitas através da execução de um plano preparado através de PL::PLan::new, usando substituição de variáveis. Os comandos utilizados para criar as tabelas e o gatilho estão mostrados abaixo:
CREATE TABLE emp (
nome_emp text NOT NULL,
salario integer
);
CREATE TABLE emp_audit(
operacao char(1) NOT NULL,
usuario text NOT NULL,
data timestamp NOT NULL,
nome_emp text NOT NULL,
salario integer
);
CREATE OR REPLACE FUNCTION processa_emp_audit() RETURNS TRIGGER AS $emp_audit$
$Plans["plan"] = PL::Plan.new(
"INSERT INTO emp_audit SELECT $1, user, now(), $2, $3",
["text","text","int4"]).save
case tg["op"]
when PL::INSERT
n = $Plans["plan"].exec(["I",new["nome_emp"], new["salario"]], 1)
when PL::UPDATE
n = $Plans["plan"].exec(["A",new["nome_emp"], new["salario"]], 1)
when PL::DELETE
n = $Plans["plan"].exec(["E",old["nome_emp"], old["salario"]], 1)
end
# o resultado é ignorado uma vez que este é um gatilho AFTER
return PL::OK
$emp_audit$ LANGUAGE 'plruby';
CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW EXECUTE PROCEDURE processa_emp_audit();
Para testar o gatilho foram utilizados os comandos:
INSERT INTO emp (nome_emp, salario) VALUES ('João',1000);
INSERT INTO emp (nome_emp, salario) VALUES ('José',1500);
INSERT INTO emp (nome_emp, salario) VALUES ('Maria',250);
UPDATE emp SET salario = 2500 WHERE nome_emp = 'Maria';
DELETE FROM emp WHERE nome_emp = 'João';
SELECT * FROM emp;
nome_emp | salario
----------+---------
José | 1500
Maria | 2500
(2 linhas)
SELECT * FROM emp_audit;
operacao | usuario | data | nome_emp | salario
----------+----------+----------------------------+----------+---------
I | postgres | 2006-01-14 17:30:08.172759 | João | 1000
I | postgres | 2006-01-14 17:30:08.177594 | José | 1500
I | postgres | 2006-01-14 17:30:08.211178 | Maria | 250
A | postgres | 2006-01-14 17:30:08.214325 | Maria | 2500
E | postgres | 2006-01-14 17:30:08.217439 | João | 1000
(5 linhas)