在Postgres触发函数异常调用之前执行操作
Postgres 8.4在这里。试想this code snippet from Postgres doc:在Postgres触发函数异常调用之前执行操作
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是不是一种选择,我需要它。
您可以trap errors /捕捉异常。
在EXCEPTION
块,你可以做任何事情,就像插入到另一个表。之后,您可以重新引发异常以传播出去,但是会将包括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();
内完成这个工作,我最终会使用类似的东西,我失去了在应用程序级别捕获并显示的异常,但至少启动触发器的plpgsql函数可以返回一个错误的价值应用程序(因为它没有检测到行更新-FOUND-) 我发现其他更复杂的解决方案不值得的麻烦 – jpp1jpp1 2014-09-04 08:38:29
实际上你有两个选择。
- 您可以通过使用上扬一定程度上检查manual
- 登录错误您的应用程序,而不是在Db的事务日志到PostgreSQL的日志。例如,不应该像这样在触发函数中检查负向工资。或者应该在插入调用上处理异常。
你真正想要的是一个子事务(东西大致相当于Oracle的'编译autonomous'不幸的是,这仍然只是一个提议,尚未实现(Postgres的9.3 )。你可以看看这个[post](http://raghavt.blogspot.com.au/2012/05/autonomous-transaction-in-postgresql-91.html),详细描述了一个通用的解决方法。 – Mureinik 2014-09-03 19:30:28
这可以工作,虽然我感觉在这种特殊情况下会像使用大锤来破解坚果:) – jpp1jpp1 2014-09-03 20:11:47
当您从*任何*来源添加长引文时,还请添加一个链接到来源。我添加了Postgres 8.4手册的链接。 – 2014-09-03 20:21:03