在DB2中使用触发器使表只读

在DB2中使用触发器使表只读,db2,database-trigger,Db2,Database Trigger,我需要在DB2中将表设为只读 尽管有一个选项是撤销insert、update和delete特权,但我决定不尝试这个选项,因为它仍然允许DBA更改表中的数据。如果可能的话,我还想显示一条清晰的错误消息 因此,我想探索DB2触发器的选项,但恐怕我还不是这方面的专家。当我试图创建它时,我得到一个错误 在这一点上,我已经尝试了无数的变体,但无法使其工作。以下是DDL: create table employee_state ( id int primary key not null, descr

我需要在DB2中将表设为只读

尽管有一个选项是撤销insert、update和delete特权,但我决定不尝试这个选项,因为它仍然允许DBA更改表中的数据。如果可能的话,我还想显示一条清晰的错误消息

因此,我想探索DB2触发器的选项,但恐怕我还不是这方面的专家。当我试图创建它时,我得到一个错误

在这一点上,我已经尝试了无数的变体,但无法使其工作。以下是DDL:

create table employee_state (
  id int primary key not null,
  description varchar(40) not null
);

insert into employee_state (id, description) values (1, 'Applying');
insert into employee_state (id, description) values (2, 'Rejected');
insert into employee_state (id, description) values (3, 'Active');
insert into employee_state (id, description) values (4, 'Inactive');

create trigger employee_state_read_only 
  before delete on employee_state for each statement
begin
  raise_error(-20001, 
    'Delete operation not allowed on read-only table "employee_state".');
end//

DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=raise_error;ach statement
begin
;RETURN, DRIVER=4.21.29

我做错了什么?

您可以将
信号
SQLSTATE
与自定义消息一起使用

CREATE TRIGGER EMPLOYEE_STATE_READ_ONLY 
BEFORE DELETE ON EMPLOYEE_STATE FOR EACH ROW
WHEN (1=1)
  BEGIN ATOMIC
    SIGNAL SQLSTATE '80001' SET MESSAGE_TEXT = 'READ ONLY';
  END

然后,在尝试删除时,它将抛出错误,如SQLCODE-438 SQLSTATE 80001失败的GLTCUAT中的SQL触发器EMPLOYEE\u STATE\u READ ONLY\u。一个触发器可以覆盖所有三种情况。例如

CREATE OR REPLACE TRIGGER EMPLOYEE_STATE_READ_ONLY 
BEFORE INSERT OR DELETE OR UPDATE ON EMPLOYEE_STATE
FOR EACH ROW BEGIN SIGNAL SQLSTATE '80001' SET MESSAGE_TEXT = 'READ ONLY'; END

当然,DBA可以删除触发器,对表进行更改,然后再次添加触发器。

如果您担心DBA能够修改您的数据,创建触发器不会解决您的问题,因为DBA也可以删除触发器(h/t@p-vernon)


您应该在表上实现适当的权限,如果您不信任DBA,则实现职责分离,即让DBA以外的人管理权限(“安全管理员”)

一个问题(其实没什么大不了的,只是不必要的完美主义):如果我尝试
从id=5的employee_状态中删除,它不会失败,因为没有id=5。是否可以将触发器应用于语句而不是“每一行”?否,“for each statement”的激活时间仅在“AFTER”之后,因此据我所知,不能在此处应用。如果您担心DBA能够修改您的数据,则创建触发器不会产生任何效果。您需要在表上实现适当的权限,可能还需要实现职责分离(即,让DBA以外的人管理权限)。
RAISE\u ERROR()
是一个函数,因此必须从适当的上下文(例如分配)调用它。看到这个谢谢,我写了这个问题后意识到了这一点。现在我看到
raise\u error
函数非常有用;去年有一个案例,如果参数是禁止的,我可以用它来停止选择。谢谢你的建议。我确实信任DBA,我担心的是,如果他们盲目地运行脚本,他们可能会错误地对表进行更改。