41

我在 Postgresql 中有这个触发器,我不能只是开始工作(什么都不做)。为了理解,我是这样定义的:

CREATE TABLE documents (
    ...
    modification_time timestamp with time zone DEFAULT now()
);

CREATE FUNCTION documents_update_mod_time() RETURNS trigger
AS $$
    begin
    new.modification_time := now();
    return new;
    end
$$
    LANGUAGE plpgsql;

CREATE TRIGGER documents_modification_time
    BEFORE INSERT OR UPDATE ON documents
    FOR EACH ROW
    EXECUTE PROCEDURE documents_update_mod_time();

现在让它更有趣一点。你如何调试触发器?

4

3 回答 3

74
  1. 在触发函数中使用以下代码,然后查看 pgAdmin3 中的“消息”选项卡或 psql 中的输出:

    RAISE NOTICE 'myplpgsqlval is currently %', myplpgsqlval;       -- either this
    RAISE EXCEPTION 'failed';  -- or that
    
  2. 要查看实际调用了哪些触发器、调用了多少次等,下面的语句是选择的救命稻草:

    EXPLAIN ANALYZE UPDATE table SET foo='bar'; -- shows the called triggers
    

    请注意,如果您的触发器没有被调用并且您使用继承,则可能是您只在父表上定义了一个触发器,而子表不会自动继承触发器。

  3. 要单步执行该功能,您可以使用 pgAdmin3 内置的调试器,在 Windows 上默认启用该调试器;您所要做的就是针对您正在调试的数据库执行...\8.3\share\contrib\pldbgapi.sql中的代码,重新启动 pgAdmin3,右键单击您的触发函数,点击“设置断点”,然后执行会导致触发器触发的语句,例如上面的 UPDATE 语句。

于 2009-01-09T22:55:34.740 回答
7

原来我在上述问题中使用了继承而忘记提及它。现在对于可能遇到此问题的每个人,这里有一些调试提示:

使用以下代码调试触发器正在执行的操作:

RAISE NOTICE 'test';       -- either this
RAISE EXCEPTION 'failed';  -- or that

要查看实际调用了哪些触发器、调用了多少次等,下面的语句是选择的救命稻草:

EXPLAIN ANALYZE UPDATE table SET foo='bar'; -- shows the called triggers

然后是我以前不知道的一件事:触发器仅在更新它们定义的确切表时触发。如果你使用继承,你也必须在子表上定义它们!

于 2008-11-23T19:45:48.490 回答
4

您可以在触发函数中使用“引发通知”语句来调试它。调试根本没有被调用的触发器是另一回事。

如果您在触发函数中添加“引发异常”,您还可以进行插入/更新吗?

此外,如果您的更新测试与插入测试发生在同一事务中,则 now() 将是相同的(因为每个事务仅计算一次),因此更新似乎不会做任何事情。如果是这种情况,请在单独的事务中执行它们,或者如果这是一个单元测试并且您不能这样做,请使用 clock_timestamp()。

我有一个单元测试,它依赖于事务之间的一段时间,所以在单元测试开始时我有类似的东西:

ALTER TABLE documents
   ALTER COLUMN modification_time SET DEFAULT clock_timestamp();

然后在触发器中,使用“set modify_time = default”。

所以通常它不会做额外的计算,但在单元测试期间,这允许我在中间插入 pg_sleep 以模拟时间流逝,并实际反映在数据中。

于 2008-11-20T19:15:38.023 回答