Trigger raising: "ERROR: stack depth limit exceeded"
Trigger raising: "ERROR: stack depth limit exceeded"
我想在插入一幅画后创建一个触发器,然后我想将它插入到 In_Gallery
table 或 On_Loan
table但不是两者。当我尝试制作触发器功能时,我不断收到错误消息:
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();
你在 AFTER INSERT
触发器中再次 INSERT
,导致触发器在这一秒内再次被触发 INSERT
再次 INSERT
s 并重新触发触发器并且等等等等。在某些时候,堆栈因所有函数调用而耗尽,您会收到错误消息。
从触发器函数中删除 INSERT
,仅 RETURN new
。返回 new
将导致原来的 INSERT
完成。 AFTER INSERT
触发器的触发器函数中不需要手动 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;
其他触发功能为模拟。
你错误的直接原因是一个无限循环,就像当前接受的答案解释的那样。但你应该修复的可能不止于此。 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();
对于 AFTER
触发器,RETURN NEW
根本 没有任何意义。 The manual:
The return value is ignored for row-level triggers fired after an operation, and so they can return NULL
.
我有根据的猜测:您需要一个 BEFORE
触发器。剩下要做的就是引发异常。在 完成工作之前检查 比稍后回滚要便宜。为此,使用 IF EXISTS ...
检查是否存在通常比计数更有效。那么你不需要定义任何变量,也不需要 DECLARE
部分。
相关:
PL/pgSQL checking if a row exists
Rollback Transaction on Trigger ERROR
显然,在此设计中,您需要 table in_gallery
的另一个镜像触发器 - 开始时可能并不理想。
无论你怎么做,都会有剩余的竞争条件。在并发写入负载下,多个事务可能会尝试几乎同时在两个 table 中输入相同的 p_id
,而不会在 other[= 中看到 p_id
63=] table,然而,并在 both table 中输入它。它有助于保持交易简短以最大限度地减少时间框架,但问题仍然存在原则。
一个干净的解决方案是单个 table painting
和一个 boolean
标志指示其状态。一次只能有一个状态。详情取决于您的完整情况...
旁白:重新考虑 Postgres 中标识符的 CaMeL 大小写拼写。
- Are PostgreSQL column names case-sensitive?
我想在插入一幅画后创建一个触发器,然后我想将它插入到 In_Gallery
table 或 On_Loan
table但不是两者。当我尝试制作触发器功能时,我不断收到错误消息:
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();
你在 AFTER INSERT
触发器中再次 INSERT
,导致触发器在这一秒内再次被触发 INSERT
再次 INSERT
s 并重新触发触发器并且等等等等。在某些时候,堆栈因所有函数调用而耗尽,您会收到错误消息。
从触发器函数中删除 INSERT
,仅 RETURN new
。返回 new
将导致原来的 INSERT
完成。 AFTER INSERT
触发器的触发器函数中不需要手动 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;
其他触发功能为模拟。
你错误的直接原因是一个无限循环,就像当前接受的答案解释的那样。但你应该修复的可能不止于此。 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();
对于 AFTER
触发器,RETURN NEW
根本 没有任何意义。 The manual:
The return value is ignored for row-level triggers fired after an operation, and so they can return
NULL
.
我有根据的猜测:您需要一个 BEFORE
触发器。剩下要做的就是引发异常。在 完成工作之前检查 比稍后回滚要便宜。为此,使用 IF EXISTS ...
检查是否存在通常比计数更有效。那么你不需要定义任何变量,也不需要 DECLARE
部分。
相关:
PL/pgSQL checking if a row exists
Rollback Transaction on Trigger ERROR
显然,在此设计中,您需要 table in_gallery
的另一个镜像触发器 - 开始时可能并不理想。
无论你怎么做,都会有剩余的竞争条件。在并发写入负载下,多个事务可能会尝试几乎同时在两个 table 中输入相同的 p_id
,而不会在 other[= 中看到 p_id
63=] table,然而,并在 both table 中输入它。它有助于保持交易简短以最大限度地减少时间框架,但问题仍然存在原则。
一个干净的解决方案是单个 table painting
和一个 boolean
标志指示其状态。一次只能有一个状态。详情取决于您的完整情况...
旁白:重新考虑 Postgres 中标识符的 CaMeL 大小写拼写。
- Are PostgreSQL column names case-sensitive?