Postgresql 触发器:允许更新到";除“foo”外,没有列;
假设我们有一张这样的桌子:Postgresql 触发器:允许更新到";除“foo”外,没有列;,postgresql,database-trigger,row-level-security,Postgresql,Database Trigger,Row Level Security,假设我们有一张这样的桌子: Table "someschema.todo" Column | Type | Nullable | Default --------------+--------------+----------+---------------------------------- id | integer | not null | nextval
Table "someschema.todo"
Column | Type | Nullable | Default
--------------+--------------+----------+----------------------------------
id | integer | not null | nextval('todo_id_seq'::regclass)
contract_id | integer | not null |
title | text | |
description | text | |
status | todo_status | | 'INCOMPLETE'::todo_status
Foreign-key constraints:
"todo_contract_id_fkey" FOREIGN KEY (contract_id) REFERENCES contract(id)
行级安全性已启用,我们将假设规则已正确设置,但有一个例外:通常不允许更新此表中的行的用户类型需要能够将状态
列从一个枚举
值切换到另一个。比如说,从未完成
到挂起
。该用户类型还需要能够在其他时间更新表(取决于与合同id相关的条件),因此我们不能只使用总括列授权
可以说,这可能会使该列成为新的todo_status
表中的候选列,但我们暂时将其排除在外。现在我们可以编写一个触发器,按名称检查每一列,看它是否已被修改,只允许那些修改状态的查询,而不允许其他任何查询。。。但这似乎是脆弱的(如果我们以后再增加一个专栏呢?)和痛苦的
触发器中是否有允许修改“除<代码>状态之外没有列”
?换句话说,“拒绝访问,除非唯一修改的列是status
”
补充:是否有一种方法可以在创建策略
中使用检查表达式
或使用表达式
来完成此操作?我一直在假设,因为我们在使用
表达式中没有新的
值,或者在检查
表达式中没有旧的
值,所以我不能使用RLS来实现我们所需要的
CREATE OR REPLACE FUNCTION validate_update()
RETURNS trigger AS
$BODY$
DECLARE
v_key TEXT;
v_value TEXT;
valid_update boolean := true;
BEGIN
FOR v_key, v_value IN select key, value from each(hstore(NEW)) each LOOP
if (coalesce(v_value,'') != coalesce((hstore(OLD) -> v_key),'')) then
if (v_key != 'status') then
valid_update := false;
end if;
end if;
END LOOP;
if (valid_update) then
raise info 'good update';
return NEW;
else
raise info 'bad update';
return null;
end if;
END;
$BODY$
LANGUAGE plpgsql;
create trigger validate_update before update on someschema.todo
for each row execute procedure validate_update();
谢谢,这是非常有趣的(并向我介绍了hstore
!)