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)