简体   繁体   English

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

[英]How can I avoid infinite recursion in this FOR EACH STATEMENT trigger?

I have a table tbl which has a dirty: boolean column. 我有一个表tbl ,其中有一个dirty: boolean列。 During the transaction, for certain rows this flag is set to true . 在事务期间,对于某些行,此标志设置为true Then, I have the following trigger: 然后,我有以下触发器:

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();

The problem here is that the second query ( update tbl set dirty = false where dirty = true ) calls the trigger recursively. 这里的问题是第二个查询( update tbl set dirty = false where dirty = true )递归调用触发器。 This keeps on going until we get a stack overflow. 这一直持续到我们出现堆栈溢出为止。

Is there a way to avoid this? 有办法避免这种情况吗? And also, why are we running into recursion? 而且,为什么我们要递归? In the first iteration, we mark all rows as dirty = false , so in the second iteration, there should be no rows for which dirty = true ? 在第一次迭代中,我们将所有行都标记为dirty = false ,因此,在第二次迭代中,不应存在dirty = true行?

I am using PostgreSQL 9.6. 我正在使用PostgreSQL 9.6。

Add this below statement at the start of function body 在函数体的开头添加以下语句

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

like 喜欢

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;

You could validate if the NEW value for this field is true before updating. 您可以在更新之前验证此字段的NEW值是否为true。 If it is set to false you shouldn't have to do anything. 如果将其设置为false,则无需执行任何操作。

But, why do you process all records where this field is set? 但是,为什么要处理设置了该字段的所有记录? Because of this trigger there only should be this one, because in the end it is resetted. 由于此触发器,因此只应存在此触发器,因为最后将其重置。 And if you need to update the current record you can do that properly by updating the NEW.dirty to false. 而且,如果您需要更新当前记录,则可以通过将NEW.dirty更新为false来正确地进行操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM