O
ELSE
ramo pode ser radicalmente simplificado. Mas mais algumas coisas são ineficientes / imprecisas / perigosas:CREATE OR REPLACE FUNCTION sample_trigger_func()
RETURNS TRIGGER AS
$func$
BEGIN
IF TG_OP = 'DELETE' THEN
RAISE INFO 'OLD: %', OLD.name;
EXECUTE format('INSERT INTO %I SELECT ($1).*', TG_TABLE_NAME || '_deletes')
USING OLD #= hstore('{mod_op, mod_datetime}'::text[]
, ARRAY[left(TG_OP, 1), now()::text]);
RETURN OLD;
ELSE -- insert, update
NEW.mod_op := left(TG_OP, 1);
NEW.mod_datetime := now();
RETURN NEW;
END IF;
END
$func$ LANGUAGE plpgsql;
-
NoELSE
branch apenas atribua aNEW
diretamente. Não há necessidade de SQL mais dinâmico - o que dispararia o mesmo gatilho novamente, causando um loop infinito. Esse é o erro primário.
-
RETORNAR NOVO;
fora doSE
construção quebraria sua função de gatilho paraDELETE
, poisNOVO
não é atribuído para DELETEs.
-
Um recurso importante é o uso dehstore
e o operador hstore#=
para alterar dinamicamente dois campos selecionados do tipo de linha conhecido - que é desconhecido no momento de escrever o código. Dessa forma, você não adultera oOLD
original valor, o que pode ter um efeito colateral surpreendente se você tiver mais gatilhos na cadeia de eventos.
OLD #= hstore('{mod_op, mod_datetime}'::text[] , ARRAY[left(TG_OP, 1), now()::text]);
O módulo adicionalhstore
Deve ser instalado. Detalhes:
- Como definir o valor do campo de variável composta usando SQL dinâmico
- Passando nomes de colunas dinamicamente para uma variável de registro no PostgreSQL
Usando ohstore(text[], text[])
variante aqui para construir umhstore
valor com vários campos em tempo real.
-
O operador de atribuição em plpgsql é:=
:
-
Observe que usei o nome da colunamod_datetime
em vez do enganosomod_date
, já que a coluna é obviamente umtimestamp
e não umadata
.
Eu adicionei algumas outras melhorias enquanto estava nisso. E o próprio gatilho deve ficar assim:
CREATE TRIGGER insupdel_bef
BEFORE INSERT OR UPDATE OR DELETE ON table_name
FOR EACH ROW EXECUTE PROCEDURE sample_trigger_func();
SQL Fiddle.