postgres中超出堆栈深度限制

vof42yt1  于 2021-07-29  发布在  Java
关注(0)|答案(3)|浏览(576)
CREATE OR REPLACE FUNCTION verificar_pagina_inicial_final()
  RETURNS trigger AS
$BODY$
BEGIN
IF NEW.pg_inicial < NEW.pg_final THEN
 INSERT INTO artigos(id_artigo,id_editora,tipo_artigo,pg_inicial,pg_final)
VALUES(NEW.id_artigo,NEW.id_editora,NEW.tipo_artigo,NEW.pg_inicial,NEW.pg_final);
END IF;

END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER verifiar_paginas_novo_artigo
  BEFORE INSERT OR UPDATE
  ON artigos
  FOR EACH ROW
  EXECUTE PROCEDURE  verificar_pagina_inicial_final();

当我尝试插入时,它会返回以下内容:

INSERT INTO public.artigos(id_artigo, id_editora, tipo_artigo, pg_inicial, pg_final)
VALUES (30, 3, 'teste', 1, 2);

退货:

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.
CONTEXT:  SQL statement "INSERT INTO artigos(id_artigo,id_editora,tipo_artigo,pg_inicial,pg_final)
VALUES(NEW.id_artigo,NEW.id_editora,NEW.tipo_artigo,NEW.pg_inicial,NEW.pg_final)"
PL/pgSQL function verificar_pagina_inicial_final() line 4 at SQL statement
2ul0zpep

2ul0zpep1#

触发器反复插入同一行。有多种方法可以防止这种情况。比如:

CREATE TRIGGER verifiar_paginas_novo_artigo
BEFORE INSERT OR UPDATE ON artigos
FOR EACH ROW
WHEN (pg_trigger_depth() < 1)  -- !
EXECUTE FUNCTION verificar_pagina_inicial_final();

请参见:
如何防止postgresql触发器被另一个触发器触发? EXECUTE FUNCTION 需要11个博士后。请参见:
触发器函数不存在,但我很肯定它存在
但你似乎只是不同意 pg_inicial >= pg_final . 你可以用一个 CHECK 约束条件:

ALTER TABLE artigos ADD CONSTRAINT pg_final_must_be_greater_than_pg_inicial
CHECK (pg_inicial < pg_final);

CHECK 约束更简单、更快、更可靠。请参见:
触发器与检查约束
Postgres9.x中有多少成本检查限制?
当然,当违反时会引发异常,这通常是一种解决方法。
安静地做,你回到触发器。更简单:

CREATE OR REPLACE FUNCTION verificar_pagina_inicial_final()
  RETURNS trigger LANGUAGE plpgsql AS
$func$
BEGIN
   IF NEW.pg_inicial < NEW.pg_final THEN
      RETURN NEW;   -- proceed
   ELSE
      RETURN NULL;  -- skip insert / update
   END IF;
END
$func$;

正常进行 INSERT / UPDATE ,一个 BEFORE 触发器必须 RETURN NEW; . RETURN NULL 取消该行。

pexxcrt2

pexxcrt22#

因为您只“插入”新的列,所以在trigger函数中插入是完全不必要的——这就是将要插入的内容。如果new.pgèinical<new.pgèfinal“返回false,那么问题就变成了您想要什么。基本上有3种选择:
什么都不做,在这种情况下根本就没有触发器。
中止完整的insert语句。在这种情况下,创建一个check约束,并且根本没有触发器。或者在触发器中“引发异常”,但这不是一个好的计划。
静默忽略(跳过)这一行,否则继续查看文档
之前激发的行级触发器可以返回null,以指示触发器管理器跳过此行的其余操作(即,不会激发后续触发器,并且不会对此行执行插入/更新/删除操作)。
其中触发器功能实现如下:

create or replace 
function verificar_pagina_inicial_final()
  returns trigger 
  language plpgsql
as $$
begin
   if new.pg_inicial < new.pg_final 
   then
       return new;
   else 
       return null; 
   end if; 
end;
$$ ;
4nkexdtk

4nkexdtk3#

假设这只是插入之前的测试,因为您不修改数据,也许

IF (NEW.pg_inicial < NEW.pg_final) THEN
      RETURN NEW;
ELSE
      RETURN NULL;
END IF;

p、 s:我会做一个db小提琴来检查这个语法是否正确。这是小提琴,https://www.db-fiddle.com/f/9idx4bmjdk5ruzprfdevat/2 .
edit2:erwin brandstetter的答案是完整的,你应该添加一个约束而不是这个触发器。

相关问题