允许某些角色更新列,如果列为 NULL,则允许其他角色更新

Ric*_*ard 3 postgresql privileges triggers database-design postgresql-9.2

我在表中有一个列A(类型int),在插入其他值时,该列的数据不可用。我不想拆分桌子,因为没有其他真正的理由这样做。我正在数据库级别实现权限分离。

只有某些用户(属于 A 类)才可以column A随时进行修改。但是其他用户(在类别 B 中,不一定与类别 A 互斥)应该能够更新该列(如果其值尚未设置),即。如果是NULL
我正在使用 PostgreSQL 9.2.4。

我怎样才能做到这一点?触发器?规则?还有别的事吗?

Erw*_*ter 7

只有某些用户应该能够修改列 A
...
其他用户应该能够更新该列,如果...它是 NULL。

撤销UPDATE(和DELETE?!?)public以及其他所有人不应该拥有该特权的人。

REVOKE UPDATE ON TABLE tbl FROM public;
REVOKE UPDATE ON TABLE tbl FROM ...
Run Code Online (Sandbox Code Playgroud)

创建一个some_users允许更新col_a(仅允许更新)的(组)角色:

CREATE ROLE some_users;
GRANT SELECT, UPDATE (col_a) ON TABLE tbl TO some_users;
Run Code Online (Sandbox Code Playgroud)

为什么SELECT手册上GRANT

实际上,任何重要的UPDATE命令也都需要SELECT 特权,因为它必须引用表列来确定要更新哪些行,和/或计算列的新值。

这样,您就可以在一个点上授予该列的权限。
创建另一个(组)角色certain_users,它可以做所有some_users可以做的事情(还有更多):

CREATE ROLE certain_users;
GRANT some_users TO certain_users;
Run Code Online (Sandbox Code Playgroud)

根据需要将这些角色的成员资格授予用户角色:

GRANT some_users TO lowly_user;
GRANT certain_users TO chief_user;
Run Code Online (Sandbox Code Playgroud)

创建一个条件触发器,类似于@Daniel 提供的,但使用另一个条件pg_has_role()

CREATE TRIGGER tbl_value_trigger
BEFORE UPDATE ON tbl
FOR EACH ROW
WHEN (OLD.col_a IS NOT NULL AND NOT pg_has_role('some_users', 'member'))
EXECUTE PROCEDURE always_fail();
Run Code Online (Sandbox Code Playgroud)

使用触发函数:

CREATE FUNCTION always_fail()
  RETURNS trigger
  LANGUAGE plpgsql AS
$func$
BEGIN
   -- To fail with exception, rolling back the whole transaction
   -- use this instead:
   -- RAISE EXCEPTION 'value is not null';
    
   -- Do nothing instead, letting the rest of the transaction commit.
   -- Requires BEFORE trigger.
   RAISE WARNING 'col_a IS NOT NULL. User % is too ambitious!', current_user;
   RETURN NULL;  -- effectively aborts UPDATE
END
$func$;
Run Code Online (Sandbox Code Playgroud)

现在:

  • 公众无法完全更新该表。
  • some_userscertain_users允许更新该列col_a(仅此而已),
  • 仅从certain_users经历一次开始发生变化col_a is NOT NULL

请注意超级用户自动成为任何组的成员。因此,该表单NOT pg_has_role(...) 支持超级用户,而逆逻辑可能会禁止超级用户更新列。