OperationalError:超出堆栈深度限制

时间:2014-08-12 14:29:34

标签: database postgresql openerp

使用openerp 6.1,我想创建一个触发器来创建两个电话,其日期与插入行中的日期不同(一个在6个月之后,一个在一年之后)。

我创建了这个函数:

CREATE OR REPLACE FUNCTION create_first_phonecall()
  RETURNS trigger AS
$BODY$
BEGIN
select * from crm_phonecall where id= (select max(id) from crm_phonecall);
   insert into crm_phonecall (name,date,state,active,user_id,x_contractnumber,x_instdate)
values('Hany', CURRENT_TIMESTAMP,'open',true,16,123456789999,CURRENT_TIMESTAMP);
return null;
END;
$BODY$
  LANGUAGE 'plpgsql'

然后我创建了以下触发器:

CREATE TRIGGER create_first_phonecall
    AFTER insert ON crm_phonecall
    EXECUTE PROCEDURE create_first_phonecall();

但是当我尝试插入电话时,我收到以下错误:

Client Traceback (most recent call last):
  File "C:\Program Files (x86)\OpenERP\Server\server\openerp\addons\web\common\http.py", line 180, in dispatch
  File "C:\Program Files (x86)\OpenERP\Server\server\openerp\addons\web\controllers\main.py", line 970, in create
  File "C:\Program Files (x86)\OpenERP\Server\server\openerp\addons\web\common\openerplib\main.py", line 250, in proxy
  File "C:\Program Files (x86)\OpenERP\Server\server\openerp\addons\web\common\openerplib\main.py", line 117, in proxy
  File "C:\Program Files (x86)\OpenERP\Server\server\openerp\addons\web\common\http.py", line 608, in send


Server Traceback (most recent call last):
  File "C:\Program Files (x86)\OpenERP\Server\server\openerp\addons\web\common\http.py", line 593, in send
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\netsvc.py", line 360, in dispatch_rpc
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\service\web_services.py", line 586, in dispatch
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\osv\osv.py", line 167, in execute_kw
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\osv\osv.py", line 121, in wrapper
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\osv\osv.py", line 176, in execute
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\osv\osv.py", line 164, in execute_cr
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\osv\orm.py", line 4194, in create
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\sql_db.py", line 152, in wrapper
  File "C:\Program Files (x86)\OpenERP\Server\server\.\openerp\sql_db.py", line 212, in execute
OperationalError: stack depth limit exceeded
HINT:  Increase the configuration parameter "max_stack_depth", after ensuring the platform's stack depth limit is adequate.
CONTEXT:  SQL statement "SELECT 1 FROM ONLY "public"."res_users" x WHERE "id" OPERATOR(pg_catalog.=) $1 FOR SHARE OF x"
SQL statement "INSERT INTO crm_phonecall (name,date,state,active,user_id,x_contractnumber,x_instdate) values('Hany', CURRENT_TIMESTAMP,'open',true,16,123456789999,CURRENT_TIMESTAMP)"
PL/pgSQL function "create_first_phonecall" line 3 at SQL statement
SQL statement "INSERT INTO crm_phonecall (name,date,state,active,user_id,x_contractnumber,x_instdate) values('Hany', CURRENT_TIMESTAMP,'open',true,16,123456789999,CURRENT_TIMESTAMP)"
PL/pgSQL function "create_first_phonecall" line 3 at SQL statement
SQL statement "INSERT INTO crm_phonecall (name,date,state,active,user_id,x_contractnumber,x_instdate) values('Hany', CURRENT_TIMESTAMP,'open',true,16,123456789999,CURRENT_TIMESTAMP)"
...

(更多来自Postgres的消息。)

任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

RETURN NULL不会取消AFTER触发器中的操作。触发器插入一个新行,触发下一个INSERT ...导致无限循环 因此堆栈溢出 - 是的,你来到了正确的站点。 ;)

你需要一个“休息条件”:让Postgres看到自动添加和最初插入的行之间的区别。 (我的第一个草案单独使用BEFORE触发器并没有解决这个问题。)可能是任何明确定义的东西。像布尔标志一样:

ALTER TABLE crm_phonecall ADD COLUMN auto_insert bool;

在自动插入的行中将标志设置为TRUE并为这些行打破:

CREATE OR REPLACE FUNCTION create_first_phonecall()
  RETURNS trigger AS
$func$
BEGIN

-- Removed incoherent code

IF NEW.auto_insert THEN
   -- do nothing
ELSE
   INSERT INTO crm_phonecall
         (name,    ..., auto_insert)
   VALUES('Hany',  ..., TRUE );        -- automatically inserted row
END IF;

RETURN NULL;

END
$func$ LANGUAGE plpgsql;

然后触发BEFORE,而不是AFTER

CREATE TRIGGER create_first_phonecall
BEFORE INSERT ON crm_phonecall
EXECUTE PROCEDURE create_first_phonecall();

替代方案:RULE

替代方案是RULE。通常,触发器更容易处理,但RULE也可以避免无限循环。