PostgreSQL suppress_redundant_updates_trigger 中的错误?
A bug in PostgreSQL suppress_redundant_updates_trigger?
我在 PostgreSQL 中研究一组触发器,我想我无意中发现了内置 function/trigger suppress_redundant_updates_trigger()
的错误。它在我的配置(笔记本电脑上的 PostgreSQL 12)上完全可重现。
首先我设置了一个 table,有两个“每行前”触发器:
CREATE TABLE test (id int, val text);
INSERT INTO test VALUES (1, 'one'), (2, 'two');
CREATE OR REPLACE FUNCTION am_i_touched() RETURNS trigger LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RAISE NOTICE 'Yes, I am touched!';
RETURN NEW;
END;
$BODY$;
CREATE TRIGGER az_test_suppress_redundant_update
BEFORE UPDATE ON public.test
FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
-- Make sure trigger name is after the previous one
-- in alphabetical order as it drives execution order
CREATE TRIGGER bz_am_I_touched
BEFORE UPDATE ON public.test
FOR EACH ROW EXECUTE PROCEDURE am_i_touched();
我然后运行UPDATE test SET id = 1 WHERE id = 1
。正如预期的那样,更新被第一个触发器抑制,因为该行保持不变,并且 bz_am_i_touched()
永远不会触发。到目前为止一切顺利。
但后来我运行:
ALTER TABLE test ADD COLUMN newcol int
现在,我再次 运行 UPDATE test SET id = 1 WHERE id = 1
...而这一次,更新未被抑制并且 bz_am_i_touched()
触发! PGAdmin (v4) 报告更新了一条记录,而不是像以前那样为零!
这是一次性事件。进一步 UPDATE test SET id = 1 WHERE id = 1
按预期工作...但后来我尝试了 UPDATE test SET id = 2 WHERE id = 2
... 我再次遇到这种奇怪的行为 - 更新未被抑制。
这是预期的行为吗?我无法理解 UPDATE test SET id = 1 WHERE id = 1
如何导致更新不被抑制。
newcol NULL 值在新元组和旧元组之间的表示方式不同。所以他们不被认为是相同的,所以更新没有被抑制。
元组与 memcmp 的总数进行比较,因此即使 user-invisible 字节的差异也会很明显。它不会循环遍历每个字段,就哪些差异在语义上有意义做出单独的 type-dependent 决定。这似乎是故意的,为了速度和简单。我怀疑它会被认为是一个错误。
我在 PostgreSQL 中研究一组触发器,我想我无意中发现了内置 function/trigger suppress_redundant_updates_trigger()
的错误。它在我的配置(笔记本电脑上的 PostgreSQL 12)上完全可重现。
首先我设置了一个 table,有两个“每行前”触发器:
CREATE TABLE test (id int, val text);
INSERT INTO test VALUES (1, 'one'), (2, 'two');
CREATE OR REPLACE FUNCTION am_i_touched() RETURNS trigger LANGUAGE 'plpgsql'
AS $BODY$
BEGIN
RAISE NOTICE 'Yes, I am touched!';
RETURN NEW;
END;
$BODY$;
CREATE TRIGGER az_test_suppress_redundant_update
BEFORE UPDATE ON public.test
FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
-- Make sure trigger name is after the previous one
-- in alphabetical order as it drives execution order
CREATE TRIGGER bz_am_I_touched
BEFORE UPDATE ON public.test
FOR EACH ROW EXECUTE PROCEDURE am_i_touched();
我然后运行UPDATE test SET id = 1 WHERE id = 1
。正如预期的那样,更新被第一个触发器抑制,因为该行保持不变,并且 bz_am_i_touched()
永远不会触发。到目前为止一切顺利。
但后来我运行:
ALTER TABLE test ADD COLUMN newcol int
现在,我再次 运行 UPDATE test SET id = 1 WHERE id = 1
...而这一次,更新未被抑制并且 bz_am_i_touched()
触发! PGAdmin (v4) 报告更新了一条记录,而不是像以前那样为零!
这是一次性事件。进一步 UPDATE test SET id = 1 WHERE id = 1
按预期工作...但后来我尝试了 UPDATE test SET id = 2 WHERE id = 2
... 我再次遇到这种奇怪的行为 - 更新未被抑制。
这是预期的行为吗?我无法理解 UPDATE test SET id = 1 WHERE id = 1
如何导致更新不被抑制。
newcol NULL 值在新元组和旧元组之间的表示方式不同。所以他们不被认为是相同的,所以更新没有被抑制。
元组与 memcmp 的总数进行比较,因此即使 user-invisible 字节的差异也会很明显。它不会循环遍历每个字段,就哪些差异在语义上有意义做出单独的 type-dependent 决定。这似乎是故意的,为了速度和简单。我怀疑它会被认为是一个错误。