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
。这将避免触发调用和实际更新,除非更新。请参阅