让我们使用一个测试表:
CREATE TABLE labs.date_test
(
pkey int NOT NULL,
val integer,
date timestamp without time zone,
CONSTRAINT date_test_pkey PRIMARY KEY (pkey)
);
我有一个定义如下的触发函数。它是一个将日期插入表中指定列的函数。它的参数是主键、日期字段的名称和要插入的日期:
CREATE OR REPLACE FUNCTION tf_set_date()
RETURNS trigger AS
$BODY$
DECLARE
table_name text;
pkey_col text := TG_ARGV[0];
date_col text := TG_ARGV[1];
date_val text := TG_ARGV[2];
BEGIN
table_name := format('%I.%I', TG_TABLE_SCHEMA, TG_TABLE_NAME);
IF TG_NARGS != 3 THEN
RAISE 'Wrong number of args for tf_set_date()'
USING HINT='Check triggers for table ' || table_name;
END IF;
EXECUTE format('UPDATE %s SET %I = %s' ||
' WHERE %I = ($1::text::%s).%I',
table_name, date_col, date_val,
pkey_col, table_name, pkey_col )
USING NEW;
RAISE NOTICE '%', NEW;
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
实际的触发器定义如下:
CREATE TRIGGER t_set_ready_date
BEFORE UPDATE OF val
ON labs.date_test
FOR EACH ROW
EXECUTE PROCEDURE tf_set_date('pkey', 'date', 'localtimestamp(0)');
现在说我做:INSERT INTO TABLE
date_test(pkey) values(1);`
然后我执行如下更新:
UPDATE labs.date_test SET val = 1 WHERE pkey = 1;
现在日期按预期插入。但val
场依旧NULL
。它不像1
人们所期望的那样(或者更确切地说不像我所期望的那样)。
我究竟做错了什么?触发器中的 RAISE NOTICE 表明 NEW 仍然是我所期望的。触发器中不允许UPDATE
使用 s吗?关于postgres 触发器BEFORE UPDATE
的一条评论似乎表明,如果 BEFORE UPDATE 触发器中有 UPDATE 语句,则原始 UPDATE 将被覆盖。有人可以帮我吗?
编辑
我正在尝试更新调用触发器的同一个表,以及要由调用触发器的 UPDATE 语句修改的同一行。我正在运行 Postgresql 9.2