【问题标题】:Postgres: raise exception from trigger if column is in INSERT or UPDATE satementPostgres:如果列在 INSERT 或 UPDATE 语句中,则从触发器引发异常
【发布时间】:2021-12-02 03:05:49
【问题描述】:

我想使用触发器审核 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 查询中手动设置?

【问题讨论】:

  • Postgres 中的UPDATEDELETE(OLD) 记录和INSERT(NEW) 记录操作。这意味着所有列都将出现在每条记录中。如果您在触发器中将created_by 设置为current_user 之前进行测试,不知道为什么如果它们不相同则不能抛出异常?

标签: postgresql postgresql-triggers


【解决方案1】:

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 的情况可以在您的其他触发器中处理。

【讨论】:

  • 啊是的...看起来它可以正常工作。谢谢;我得测试一下。
  • 如果答案解决了您的问题,请接受。这有助于后来的提问者解决相同的问题,并从未回答的队列中删除该问题。请不要将已成功回答的问题视为未回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 2021-04-24
  • 2010-11-22
  • 1970-01-01
  • 2019-11-22
相关资源
最近更新 更多