如何在FOR FOR EACH STATEMENT触发器中避免无限递归?

时间:2018-02-09 09:38:33

标签: sql postgresql recursion

我有一个tbl列,dirty: boolean列。在事务期间,对于某些行,此标志设置为true。然后,我有以下触发器:

create function tbl_process() returns trigger as
$$ begin
    -- first, do something for all rows with dirty flag set to true
    ...

    -- then, reset the dirty flag
    update tbl set dirty = false where dirty = true;

    return null;
end $$ language plpgsql;

create trigger tbl_process after update on tbl for each statement execute procedure tbl_process();

这里的问题是第二个查询(update tbl set dirty = false where dirty = true)递归调用触发器。这种情况一直持续到我们得到堆栈溢出为止。

有没有办法避免这种情况?而且,为什么我们会遇到递归?在第一次迭代中,我们将所有行标记为dirty = false,因此在第二次迭代中,应该没有dirty = true的行?

我正在使用PostgreSQL 9.6。

2 个答案:

答案 0 :(得分:3)

在函数体的开头添加以下语句

IF pg_trigger_depth() <> 1 THEN
        RETURN NEW;
    END IF;

create function tbl_process() returns trigger as
$$ begin
    IF pg_trigger_depth() <> 1 THEN
        RETURN NEW;
    END IF;
    update tbl set dirty = false where dirty = true;

    return null;
end $$ language plpgsql;

答案 1 :(得分:0)

您可以在更新前验证此字段的NEW值是否为true。如果设置为false,则不必执行任何操作。

但是,为什么要处理设置此字段的所有记录?因为这个触发器只应该有这个,因为最终它被重置。 如果您需要更新当前记录,可以通过将NEW.dirty更新为false来正确地执行此操作。