我在表中有column A
(类型 int ),其数据在其他值的插入时间不可用。我不想分开桌子,因为没有其他真正的理由这样做。我正在数据库级别实现权限分离。并且只有某些用户(属于A类)应该能够随时修改column A
。但是其他用户(在类别B中,mot必须与A类互斥)应该能够更新列,如果其值尚未设置,即。如果是NULL
。
我正在使用PostgreSQL 9.2.4。
我怎样才能做到这一点?触发器?规则是什么?还有别的吗?
答案 0 :(得分:3)
更新触发器应该有效。如果不是NULL
,则需要检查旧值并中止更新。
答案 1 :(得分:2)
示例:
-- setup
CREATE TABLE tbl (tbl_id serial PRIMARY KEY, value int);
-- trigger function that always fails
CREATE FUNCTION always_fail() RETURNS trigger as $$ begin raise exception 'value is not null'; end; $$ LANGUAGE plpgsql;
-- create the trigger
CREATE TRIGGER tbl_value_trigger BEFORE UPDATE ON tbl FOR EACH ROW WHEN (old.value is not null) EXECUTE PROCEDURE always_fail();
-- test it
INSERT INTO tbl(value) VALUES (NULL);
INSERT INTO tbl(value) VALUES (NULL);
UPDATE tbl SET value=2 WHERE tbl_id=1;
UPDATE tbl SET value=3 WHERE tbl_id=1; -- fails
UPDATE tbl SET value=2 WHERE tbl_id=2;
UPDATE tbl SET value=3 WHERE tbl_id=2; -- fails
-- cleanup
DROP TABLE tbl;
DROP FUNCTION always_fail();
注意:
CREATE FUNCTION
),因为CREATE TRIGGER
需要一个触发器函数并且不接受正常函数,因此无法使用CREATE TRIGGER ... EXECUTE PROCEDURE raise exception 'value not null'
FOR EACH ROW
,否则我将无法查看OLD.value
答案 2 :(得分:1)
实现 实际要求的 :
只有某些用户才能修改A列 ...
其他用户应该能够更新列,如果......它是NULL。
从公众和其他应有此特权的人撤销UPDATE
(以及DELETE
?!?)。
REVOKE UPDATE ON TABLE tbl FROM public;
REVOKE UPDATE ON TABLE tbl FROM ...
创建一个(组)角色some_users
,允许更新col_a
(以及其他任何内容):
CREATE ROLE some_users;
GRANT SELECT, UPDATE (col_a) ON TABLE tbl TO some_users;
为什么SELECT
?请考虑the manual ON GRANT
中的这句话:
实际上,任何重要的
UPDATE
命令都需要SELECT
特权,因为它必须引用表列来确定 要更新哪些行,和/或计算列的新值。
通过这种方式,您可以使用单点来执行列的权限
创建另一个(群组)角色certain_users
,可以执行some_users
可以执行的所有操作(以及更多内容):
CREATE ROLE certain_users;
GRANT some_users TO certain_users;
根据需要将这些角色的成员资格授予用户角色:
GRANT some_users TO lowly_user;
GRANT certain_users TO chief_user;
创建条件触发器,类似于@Daniel provided,但使用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();
使用触发功能:
CREATE FUNCTION always_fail()
RETURNS trigger AS
$func$
BEGIN
-- Fail with an exception, rolling back the whole transaction.
-- 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$ LANGUAGE plpgsql;
some_users
和certain_users
可以更新列col_a
(没有其他内容),certain_users
的更改通过col_a is NOT NULL
。 注意 超级用户自动成为任何群组的成员。因此,NOT pg_has_role(...)
形式启用超级用户,而反向逻辑可能会禁止超级用户更新列。
答案 3 :(得分:0)
要向某些用户授予无条件更新权限,请使其成为具有该权限的角色的成员。
create role the_role;
grant update on table t to the_role;
grant the_role to the_user;
现在,此更新查询仅在当前用户是the_role
的成员或值为null时才有效:
update t
set A = 1
where
id = 1
and (
A is null
or
pg_has_role('the_role', 'usage')
)