这就是问题所在。
create table customer (
customer_id int generated by default as identity (start with 100) primary key
);
create table cart (
cart_id int generated by default as identity (start with 100) primary key
);
我想保护customer_id
和cart_id
在插入**后不进行一般性更新。如何实现?
**UPD:**在我写问题的时候,我找到了我原来问题的答案。
create table cart (
cart_id int generated by default as identity (start with 100) primary key,
name text not null,
at timestamp with time zone
);
create or replace function table_update_guard() returns trigger
language plpgsql immutable parallel safe cost 1 as $body$
begin
raise exception
'trigger %: updating is prohibited for %',
tg_name, tg_argv[0]
using errcode = 'restrict_violation';
return null;
end;
$body$;
create or replace trigger cart_update_guard
before update of cart_id, name on cart for each row
-- NOTE: the WHEN clause below is optional
when (
old.cart_id is distinct from new.cart_id
or old.name is distinct from new.name
)
execute function table_update_guard('cart_id, name');
> insert into cart (cart_id, name) values (0, 'prado');
INSERT 0 1
> update cart set cart_id = -1 where cart_id = 0;
ERROR: trigger cart_update_guard: updating is prohibited for cart_id, name
CONTEXT: PL/pgSQL function table_update_guard() line 3 at RAISE
> update cart set name = 'nasa' where cart_id = 0;
ERROR: trigger cart_update_guard: updating is prohibited for cart_id, name
CONTEXT: PL/pgSQL function table_update_guard() line 3 at RAISE
> update cart set at = now() where cart_id = 0;
UPDATE 1
WHEN
子句是由Belayer在他的answer中建议的。完整的解释在我的research中。另外,我检查了the approach与玩弄特权。**注意:**有些人说像这样的触发器是性能杀手。他们是错误的。你认为postgres如何在内部实现约束?-使用像这样定义的隐式触发器。
3条答案
按热度按时间4uqofj5v1#
如果我没理解错的话,您希望防止任何用户在表ID建立后修改它,并让一个通用函数产生异常,同时仍然允许其他更新。您可以通过修改触发器而不是函数来实现这一点。在触发器本身上指定WHEN predicate 。对于
cart
表,则:对于
customer
表,触发器变为:触发函数本身不变。(demo here)
r8xiu3jd2#
TL; DR
我尝试了什么?撤消
UPDATE
特权不起作用。好吧,让我们派个警卫来。
现在让我们给他们一些工作。
好吧,我没有改变数值。这个怎么样:
是的,就是这样,很好,让我们也保护
cart_id
,我不想复制粘贴触发器函数,所以我们试着泛化它:正如您可能注意到的,我将列名传递给触发器函数并生成一个表达式,然后将该表达式的结果放入
equal
中进行测试。嗯......他是对的,什么是悬空的
old.cart_id = new.cart_id
?如果我写好吧,好吧...如果我写
啊哈,"老"关系并不存在...
好吧,这是最后一招:
我只是让它在任何尝试更新
cart_id
时触发。好了,我终于回答了我原来的问题,但是还有一个问题:如何将函数中编码的相同算法应用于该函数的args中给定的列?
vsdwdz233#
我在previous research中的第一个尝试是撤销特权,正如Laurenz Albe在他的评论中指出的,我必须撤销更新整个表的特权,而不是撤销更新某个列的特权,下面是代码:
我现在可以更新表格吗?
好的,让我们授予更新
cart_id
以外的列的权限:到目前为止,一切顺利。现在时间滴答作响,最终danissimo添加了另一列
item_ids
:danissimo现在可以更新新列了吗?请记住,他更新整个表的权限已被撤消,更新新列的权限也未被授予:
如果我给他特权呢?
这意味着什么呢?我考虑了两种方法。一种是一旦给列赋值,就禁止更新该列。另一种是玩弄特权。在我们的项目中,我们通常在项目发展的同时添加新列。如果我坚持使用特权,那么每次添加新列时,我都必须授予更新该列的特权。另一方面,如果我用触发器保护一些列,我只需添加新列,不再麻烦。
**结论:**使用如上所示的触发器👆🏼。