虽然我仍在寻找这个的根本原因(这是不可能的重复),但我想要某种临时黑客来防止列值不断变化.这是表模式:
CREATE TABLE TPM_INITIATIVES ( INITIATIVEID NUMBER NOT NULL,NAME VARCHAR2(100) NOT NULL,ACTIVE CHAR(1) NULL,SORTORDER NUMBER NULL,SHORTNAME VARCHAR2(100) NULL,PROJECTTYPEID NUMBER NOT NULL,CONSTRAINT TPM_INITIATIVES_PK PRIMARY KEY(INITIATIVEID) NOT DEFERRABLE VALIDATE )
我们当然需要能够创建新行,但我想阻止ANYTHING永远改变INITIATIVEID,无论运行什么奇怪的查询.
我能想到的一些想法:
>我不太熟悉Oracle的表权限(我更多
一个Postgres家伙),但你不能授予或拒绝更新权利
所有用户都在某栏?这只会影响更新,或者
INSERTS也是? DENY更新到此列的命令是什么?
>创建一些在ROW UPDATE上运行的触发器.我们可以吗
检测是否正在更改INITIATIVEID,如果是,则抛出一个
异常或以某种方式爆炸?
至少,我们可以捕获和/或记录此事件以查看它何时发生以及导致INITIATIVEID发生变化的查询是什么?
谢谢!
解决方法
如果您的应用程序已定义子表但未声明适当的外键约束,那么这将是解决问题的最佳方法.
话虽这么说,Arnon创建视图的解决方案应该有效.您将重命名该表,创建一个与现有表同名的视图,并(可能)在视图上定义一个INSTEAD OF触发器,该触发器将永远不会更新INITIATIVEID列.这不应该要求更改应用程序的其他位.
您还可以在表上定义触发器
CREATE TRIGGER trigger_name BEFORE UPDATE ON TPM_INITIATIVES FOR EACH ROW DECLARE BEGIN IF( :new.initiativeID != :old.initiativeID ) THEN RAISE_APPLICATION_ERROR( -20001,'Sorry Charlie. You can''t update the initiativeID column' ); END IF; END;
当然,有人可以禁用触发器并发出更新.但我假设你并没有试图阻止攻击者,只是一个有缺陷的代码.
然而,根据您所看到的症状的描述,将更改历史记录记录到此表中的列中似乎更有意义,这样您就可以实际确定正在进行的操作而不是猜测并尝试插入一个逐之一.所以,你可以做这样的事情
CREATE TABLE TPM_INITIATIVES_HIST ( INITIATIVEID NUMBER NOT NULL,OPERATIONTYPE VARCHAR2(1) NOT NULL,CHANGEUSERNAME VARCHAR2(30),CHANGEDATE DATE,COMMENT VARCHAR2(4000) ); CREATE TRIGGER trigger_name BEFORE INSERT or UPDATE or DELETE ON TPM_INITIATIVES FOR EACH ROW DECLARE l_comment VARCHAR2(4000); BEGIN IF( inserting ) THEN INSERT INTO tpm_initiatives_hist( INITIATIVEID,NAME,ACTIVE,SORTORDER,SHORTNAME,PROJECTTYPEID,OPERATIONTYPE,CHANGEUSERNAME,CHANGEDATE ) VALUES( :new.initiativeID,:new.name,:new.active,:new.sortOrder,:new.shortName,:new.projectTypeID,'I',USER,SYSDATE ); ELSIF( inserting ) THEN IF( :new.initiativeID != :old.initiativeID ) THEN l_comment := 'Initiative ID changed from ' || :old.initiativeID || ' to ' || :new.initiativeID; END IF; INSERT INTO tpm_initiatives_hist( INITIATIVEID,CHANGEDATE,COMMENT ) VALUES( :new.initiativeID,'U',SYSDATE,l_comment ); ELSIF( deleting ) THEN INSERT INTO tpm_initiatives_hist( INITIATIVEID,CHANGEDATE ) VALUES( :old.initiativeID,:old.name,:old.active,:old.sortOrder,:old.shortName,:old.projectTypeID,'D',SYSDATE ); END IF; END;
然后,您可以查询TPM_INITIATIVES_HIST以查看随时间对特定行所做的所有更改.因此,您可以查看主键值是否正在更改,或者是否有人只是更改非键字段.理想情况下,您可以添加其他列以添加到历史记录表中以帮助跟踪更改(即,可能有来自V $SESSION的内容可能有用).