1

我想使用触发器审核 PostgreSQL 表中的 created_by、created_timestamp、modified_by 和 modified_timestamp 列。创建 BEFORE INSERT 和 BEFORE UPDATE 触发器以将这些值设置为 current_user 和 now() 相当简单。

但是,如果有人试图这样做:

INSERT INTO SOMETABLE(someColumn, created_by) VALUES ('test', 'someOtherUser');

我宁愿抛出一个异常,例如“不允许在 INSERT 查询中手动设置 created_by。”而不是让触发器静默地将 'someOtherUser' 更改为 current_user。

我想我可以通过以下方式在触发器中完成此操作:

if new.created_by is not null then raise exception 'Manually setting created_by in an INSERT query is not allowed.'; end if;

这对 INSERT 查询和触发器按预期工作。

但是,对 UPDATE 触发器使用相同的策略,我发现它有点困难,因为除了 UPDATE 查询中的更改值之外,NEW 记录还具有来自现有行的未更改值。(至少,我认为这就是正在发生的事情。)

我可以将 new.created_by 与 old.created_by 进行比较以确保它们相同,从而防止查询更改值,但即使最终结果相似(即表中的值没有改变),这实际上与根本不允许列在 UPDATE 查询中是不一样的。

是否有一种优雅的方法来确定 INSERT 或 UPDATE 查询中是否存在列?我在这里看到了一些转换为 JSON 并以这种方式进行测试的建议,但这对我来说似乎是一个相当丑陋的解决方案。

是否有其他解决方案来确保这些列(created_by、created_timestamp 等)仅由触发器函数设置,并且不能在 INSERT 和 UPDATE 查询中手动设置?

4

1 回答 1

0

使用字母表中早期的名称创建一个特殊触发器UPDATE,以便在其他触发器之前调用它:

CREATE FUNCTION yell() RETURNS trigger
   LANGUAGE plpgsql AS
$$BEGIN
   RAISE EXCEPTION 'direct update of "created_by" is forbidden';
END;$$;

CREATE TRIGGER aa_nosuchupdate
   BEFORE UPDATE OF created_by FOR EACH ROW
   EXECUTE PROCEDURE yell();

INSERT案例可以在您的其他触发器中处理。

于 2021-10-13T19:19:21.120 回答