Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Postgresql postgres-防止规则/触发器调用自己-无限循环_Postgresql_Triggers_Rules_Infinite Loop - Fatal编程技术网

Postgresql postgres-防止规则/触发器调用自己-无限循环

Postgresql postgres-防止规则/触发器调用自己-无限循环,postgresql,triggers,rules,infinite-loop,Postgresql,Triggers,Rules,Infinite Loop,假设我有下表: create table A ( identifier integer not null primary key, title text not null, ... -- other fields ); 在A上执行更新时,我不一定只想更新目标行,我还想将更新应用于A中的另一行。我尝试编写“重写规则”或“在触发器之前”,但我总是以无限循环结束: create function A(in A

假设我有下表:

create table A
(
    identifier      integer       not null     primary key,
    title           text          not null,
    ... -- other fields
);
在A上执行更新时,我不一定只想更新目标行,我还想将更新应用于A中的另一行。我尝试编写“重写规则”或“在触发器之前”,但我总是以无限循环结束:

create function A(in A, in A) returns void as
$$
    declare
            i integer;
    begin
            -- do some logic which finds other row (hardcoded in this example)
            i = 2;

            -- update old row
            update A set title = $2.title where identifier = $1.identifier;

            -- apply updates to other row
            update A set ... where identifier = i;
    end;
$$ language plpgsql;

create rule A as on update to A do instead select A(old, new);
我测试的数据:

insert into A (identifier, title) values (1, 'old title 1');
insert into A (identifier, title) values (2, 'old title 2');

update A set title = 'new title 1' where identifier = 1;
当使用“触发器前”而不是“重写规则”时,同样的问题也会出现

如果需要,是否有办法绕过规则/触发器?我不能在第一行之后更改表A禁用规则A,在返回之前更改表A启用规则A,因为表A正在由我们自己使用

更新

我通过创建一个虚拟继承表来实现这一点,并在该表上直接执行“内部更新”。这绕过了触发器/规则

    drop table if exists A cascade;

    create table A
    (
        identifier      serial       not null     primary key,
        title           text         not null
    );

    create table A_
    (

    ) inherits (A);

    create or replace function A() returns trigger as
    $$
            declare
                    i integer;
            begin
                    -- create duplicate row
                    insert into A (title) values (new.title) returning identifier into i;

                    -- update new row
                    update A_ set title = new.title where identifier = i;

                    -- do not propagate update
                    return null;
            end
    $$ language plpgsql;

    create trigger A before update on A for each row execute procedure A();

    insert into A (title) values ('old title 1');
    insert into A (title) values ('old title 2');

    update A set title = 'new title 1' where identifier = 1;

    select * from A;

为了避免触发器中出现无限循环,您需要添加一个额外的where子句,以避免多次重新影响行:

update foo
set bar = 'baz'
where bar <> 'baz'
更新foo
设置条='baz'
“巴兹”酒吧在哪里

同样不能避免规则中的递归,因为在解析原始查询(和新查询)时会抛出新查询,不考虑单个查询的where子句。

您可以使用该函数来区分用户启动的
更新
和触发器启动的
更新
。您甚至可以将其放入触发器声明的
WHEN
子句中。这是。

我没有真正理解你的意思?你能再详细一点吗?我找到了另一个解决方案,请参见我的原始问题。你怎么看?你做了一些与我的建议相似的事情,但反过来,用两张桌子而不是一张桌子。这也是可行的,但是如果您依赖于
FOUND
任何地方,请小心返回的行计数。我希望避免引入第二个虚拟表,但我并没有真正看到它。你能再补充一些见解或例子吗?我想你的另一行是修订版还是备份版。因此,您基本上要在after触发器的定义中使用when条件(例如
when(old.title new.title)
),然后执行:
更新set title=old.title,其中id=some_变量和title old.title
。这将避免触发调用和实际更新,除非更新。请参阅