Postgres 8.4在这里。想象一下this code snippet from Postgres doc:
CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$
BEGIN
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname cannot be null';
END IF;
IF NEW.salary IS NULL THEN
RAISE EXCEPTION '% cannot have null salary', NEW.empname;
END IF;
-- Who works for us when she must pay for it?
IF NEW.salary < 0 THEN
RAISE EXCEPTION '% cannot have a negative salary', NEW.empname;
END IF;
-- Remember who changed the payroll when
NEW.last_date := current_timestamp;
NEW.last_user := current_user;
RETURN NEW;
END;
$emp_stamp$ LANGUAGE plpgsql;
如果我们想要执行某些操作,例如登录自定义表,则会出现以下异常:
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
INSERT INTO my_log_table ('User didn't supplied empname')
RAISE EXCEPTION 'empname cannot be null';
END IF;
它不会起作用,因为我们在RAISE EXCEPTION
调用之前放置的任何内容都会被回滚RAISE EXCEPTION
暗示撤消,即我们创建的my_log_table行将在RAISE EXCEPTION
后立即删除调用。
完成这样的事情的最佳方法是什么?也许抓住我们的自定义异常?
关闭回滚@ TRIGGER不是一个选项,我需要它。
答案 0 :(得分:2)
您可以trap errors /捕获例外。
在EXCEPTION
块中,您可以执行任何其他操作,例如INSERT到另一个表中。之后你可以重新引发异常以传播出来,但这会将整个事务(包括INSERT)回滚到日志表中(除非异常被包装并被外部函数捕获)。
你可以:
使用类似dblink调用的技巧来模拟自动事务,当回滚包装事务时,该事务不会被撤消。相关:
RAISE
另外NOTICE
或WARNING
,ROOLBACK
也未撤消。
RAISE
另一个EXCEPTION
,带有您自己的文字。或者,您可以取消触发触发功能的行,不引发异常。交易中的其他所有内容都会正常进行。
假设这是一个触发器ON UPDATE
并且您有另一个具有相同结构的表来将失败的INSERT写入:
CREATE OR REPLACE FUNCTION emp_stamp()
RETURNS trigger AS
$func$
BEGIN
-- Check that empname and salary are given
IF NEW.empname IS NULL THEN
RAISE EXCEPTION 'empname cannot be null';
END IF;
IF ...
RETURN NEW; -- regular end
EXCEPTION WHEN others THEN -- or be more specific
INSERT INTO log_tbl VALUES (NEW.*); -- identical table structure
RETURN NULL; -- cancel row
END
$func$ LANGUAGE plpgsql;
请注意,NEW
包含发生异常之前的行的状态,包括同一函数中的先前成功语句。
触发:
CREATE TRIGGER emp_stamp
BEFORE INSERT OR UPDATE ON tbl
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
答案 1 :(得分:1)
实际上你有两个选择。