触发器内的函数 returns 错误值

Function returns bad value inside of a trigger

我有两个功能,return 物有所值。但是当我在触发器内部调用这些函数时,它们总是 returns 0 而不是好的值。

这些函数的 return 类型是 real。直接和戏剧性的后果是触发器在调用时在表中插入了错误的值。

函数:

create or replace function get_remaining_hour(id_user_v integer,id_absence_v_type integer,id_year_v integer) returns real as
$BODY$
BEGIN
    return (select sum(number_hour) 
            from remaining_absence_day 
            where id_user=  
              and id_absence_type= 
              and id_year= );
END;
$BODY$
LANGUAGE 'plpgsql' ;

触发器函数(为测试而修改!):

create  OR REPLACE  function update_absence() returns TRIGGER  AS
$BODY$
DECLARE
  old_number_hour real;
BEGIN
  old_number_hour:=get_remaining_hour(3,2,8);
  insert into debugging(col,val) values('old_number_hour', old_number_hour);
  return null;
END;
$BODY$
LANGUAGE 'plpgsql' ;

触发器定义:

drop trigger if exists update_absence on absence;
CREATE  TRIGGER update_absence
    after update of type,duration_hour,duration_day on absence
    for each ROW
    execute procedure update_absence();

提供的代码应该可以工作。

你看到 0 结果特别奇怪。如果在 remaining_absence_day 中找不到匹配的行,您将看到 NULL,而不是 0。但是,如果您在相同的环境中使用相同的参数调用该函数,您应该会看到相同的结果。

我能想到的剩下的可能解释:与架构搜索路径混淆。比如:您在不同的架构中有函数 get_remaining_hour() 或 table remaining_absence_day 的第二个实例。然后您使用 search_path 的不同设置调用该函数。 您 运行 是否在同一会话中进行了比较?

  • How does the search_path influence identifier resolution and the "current schema"

或者,由于您使用 AFTER 触发器:table absence 上可能有 其他触发器 修改 table remaining_absence_day,在你的触发器之前被触发。

我所做的所有其他修改都是装饰性的或轻微的简化

CREATE OR REPLACE FUNCTION get_remaining_hour(id_user_v int
                                            , id_absence_v_type int
                                            , id_year_v int)
  RETURNS real AS
$func$
BEGIN
   RETURN (
   SELECT sum(number_hour) 
   FROM   remaining_absence_day  -- referencing the right table? see search_path
   WHERE  id_user         =  
   AND    id_absence_type =  
   AND    id_year         = 
   );
END
$func$  LANGUAGE plpgsql STABLE;  -- don't quote the language name

CREATE OR REPLACE FUNCTION update_absence()
  RETURNS TRIGGER AS
$func$
BEGIN   
   INSERT INTO debugging(col, val)
   VALUES('old_number_hour', get_remaining_hour(3,2,8));  -- hard coded only for testing?
   RETURN null;  -- only good for AFTER trigger
END
$func$  LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS update_absence ON absence;
CREATE TRIGGER update_absence
AFTER UPDATE OF type, duration_hour, duration_day ON absence
FOR EACH ROW EXECUTE PROCEDURE update_absence();