我试图在插入绘画后将其插入In_Gallery
表或On_Loan
表中,但不能同时插入其中。当我尝试制作触发函数时,我不断收到错误消息:
ERROR: stack depth limit exceeded HINT: Increase the configuration parameter "max_stack_depth" (currently 2048kB), after ensuring the platform's stack depth limit is adequate.
我不确定这是怎么回事:
CREATE OR REPLACE FUNCTION checkOnLoan()
RETURNS trigger AS
$$
DECLARE
countGal numeric;
BEGIN
SELECT COUNT(*) INTO countGal FROM IN_GALLERY WHERE P_id = new.P_id;
IF countGal = 0 THEN
INSERT INTO ON_LOAN VALUES (new.Certid, new.P_id, new.Insurer);
ELSE
RAISE EXCEPTION 'ALREADY IN GALLERY';
END IF;
RETURN new;
END;
$$
LANGUAGE 'plpgsql';
CREATE TRIGGER OnLoan
AFTER INSERT ON ON_LOAN
FOR EACH ROW
EXECUTE PROCEDURE checkOnLoan();
答案 0 :(得分:3)
您在INSERT
触发器中再次AFTER INSERT
,导致在第二个INSERT
再次触发该触发器,而该INSERT
又触发并重新触发该触发器,依此类推等等。在某些时候,所有的函数调用都会耗尽堆栈,您会得到错误。
从触发功能中删除INSERT
,仅删除RETURN new
。返回new
将使原始INSERT
完成。无需手动使用INSERT
触发器的AFTER INSERT
触发器功能。
赞:
CREATE OR REPLACE FUNCTION checkOnLoan()
RETURNS trigger AS
$$
DECLARE
countGal numeric;
BEGIN
SELECT COUNT(*) INTO countGal FROM IN_GALLERY WHERE P_id = new.P_id;
IF countGal = 0 THEN
RETURN new;
ELSE
RAISE EXCEPTION 'ALREADY IN GALLERY';
END IF;
END;
$$
LANGUAGE plpgsql;
和其他触发功能的模拟信号。
答案 1 :(得分:1)
直接导致您出错的原因是一个无休止的循环,就像当前接受的答案一样。但是,您可能不仅应该解决此问题。 BEFORE
触发器将改善情况……
触发功能:
CREATE OR REPLACE FUNCTION check_onloan()
RETURNS trigger AS
$$
BEGIN
IF EXISTS (SELECT FROM in_gallery WHERE p_id = NEW.p_id) THEN
RAISE EXCEPTION 'p_id % already in gallery!', NEW.p_id;
END IF;
RETURN NEW; -- for BEFORE trigger
END
$$ LANGUAGE plpgsql;
触发:
CREATE TRIGGER insert_after_on_loan
BEFORE INSERT ON on_loan -- !!!
FOR EACH ROW EXECUTE PROCEDURE check_onloan();
RETURN NEW
对于AFTER
触发器完全没有意义。 The manual:
在操作后触发的行级触发器的返回值将被忽略,因此它们可以返回
NULL
。
我的有根据的猜测:您想要一个BEFORE
触发器。剩下要做的就是提出一个例外。在进行工作之前检查 比以后回滚要便宜。为此,通常使用IF EXISTS ...
而不是计数来检查是否存在。然后,您无需定义任何变量,也无需定义DECLARE
部分。
相关:
显然,在此设计中,您需要为表in_gallery
使用另一个镜像触发器-可能一开始并不理想。
无论您怎么做,都会有剩余比赛条件。在并发写入负载下,多个事务可能会尝试几乎同时在两个表中输入相同的p_id
,但在 other 表中却看不到p_id
,并且毕竟在两个表中输入它。它有助于缩短交易时间以最大程度地缩短时间范围,但问题仍然存在。
一个干净的解决方案是使用单个表painting
和一个boolean
标志来指示其状态。一次只能拥有一个状态。详细信息取决于您的完整情况...
此外:重新考虑Postgres中标识符的CaMeL大小写拼写。