在我的桌子上,我有一个阻止更新的触发器,因此意味着行在插入后实际上是不可变的。
当需要对此表执行追溯更新时(例如添加新的计算字段),我采取了以下方法:
ALTER TABLE my_table DISABLE TRIGGER USER;
UPDATE my_table
SET x = (...);
ALTER TABLE my_table ENABLE TRIGGER USER;
这种方法的缺点是它需要一个AccessExclusiveLock。
我想知道以下是否可以安全使用,因为保证UPDATE
中的行不会被其他查询更新:
BEGIN;
UPDATE pg_class
SET relhastriggers = FALSE
WHERE relname = 'my_table';
UPDATE my_table
SET x = (...);
UPDATE pg_class
SET relhastriggers = TRUE
WHERE relname = 'my_table';
COMMIT;
到目前为止我所做的尝试表明这是安全的,并且在此交易之外,触发器将继续正常应用。
另外,如果我的用例确实安全,那么它在哪些情况下是不安全的?
我正在使用 Postgres 9.4.8 。
谢谢: - )
答案 0 :(得分:1)
更新relhastriggers
的行为更像DISABLE TRIGGER ALL
,即它还会禁用用于外键和延迟唯一性检查的内部触发器。在您的情况下,这可能是也可能不是问题。
我不知道pg_class
的直接更新是否会违反Postgres代码库某些角落的某些假设。但总的来说,黑客目录表本质上是不安全的;即使它没有破坏任何现在,也不能保证将来的版本会出现这种情况。
REVOKE UPDATE ON my_table
是阻止更新的更好方法。超级用户可自动获得免费使用,因此获得[{1}}权限的任何人都可以对UPDATE pg_class
没有任何问题。
如果出于某种原因,你真的需要用触发器来做这件事,那么还有另一种(有些hacky,但至少得到支持)绕过它的方法。默认情况下,复制进程不会触发触发器(尽管可以通过ALTER TABLE
的my_table
子句来控制)。这意味着您可以通过模拟复制器来绕过触发器:
ENABLE ALWAYS
与目录更新一样,这也将禁用任何内部约束触发器。