我正在 plpgsql 中为 Postgres 9.1 编写触发器。我需要能够捕获在 UPDATE 的 SET 子句中发出的列名,以便我可以在审计表中记录指定的操作。Postgres 文档中的示例很简单,不足以满足我的需要。我已经在互联网上搜索了几天,但我找不到任何其他试图实现我想要在这里做的事情的例子。
我的时间很紧,要尽快解决这个问题。我不知道 Tcl 所以 pl/Tcl 在这一点上对我来说是不可能的。pl/Perl 可能有用,但我不知道从哪里开始。此外,如果可能的话,我想在 pl/pgsql 中找到一种方法来实现这一点,以实现可移植性和维护。如果有人可以为此推荐一个 pl/Perl 解决方案,我将不胜感激。
这是将被审计的目标表的表结构:
注意:记录表中还有许多其他列,但为了简单起见,我没有在这里列出它们。但是触发器应该能够记录对行中任何列的更改。
CREATE TABLE record (
record_id integer NOT NULL PRIMARY KEY,
lastname text,
frstname text,
dob date,
created timestamp default NOW(),
created_by integer,
inactive boolean default false
);
create sequence record_record_id_seq;
alter table record alter record_id set default nextval('record_record_id_seq');
这是我的审计表:
CREATE TABLE record_audit (
id integer NOT NULL PRIMARY KEY,
operation char(1) NOT NULL, -- U, I or D
source_column text,
source_id integer,
old_value text,
new_value text,
created_date timestamp default now(),
created_by integer
);
create sequence record_audit_id_seq;
alter table record_audit alter id set default nextval('record_audit_id_seq');
我的目标是将 INSERTS 和 UPDATES 记录到 record_audit 表中的记录表中,这不仅会详细说明更新的目标记录 ID(source_id)和更新的列(source_column),还会详细说明 old_value 和 new_value柱子。
我知道列值必须是 CAST() 类型的文本。我相信我可以通过访问 NEW 和 OLD 来访问 old_value 和 new_value,但是我很难弄清楚如何获取 UPDATE 查询的 SET 子句中使用的列名。我需要触发器为 SET 子句中指定的每一列向 record_audit 表添加一条新记录。请注意,没有 DELETE 操作,因为记录只是更新为 inactive = 't' (因此记录在审计表中)
到目前为止,这是我的触发器(显然不完整)。请原谅我,我正在学习 pl/pgsql。
-- Trigger function for record_audit table
CREATE OR REPLACE FUNCTION audit_record() RETURNS TRIGER AS $$
DECLARE
insert_table text;
ref_col text; --how to get the referenced column name??
BEGIN
--
-- Create a new row in record_audit depending on the operation (TG_OP)
--
IF (TG_OP = 'INSERT') THEN
-- old_value and new_value are meaningless for INSERTs. Just record the new ID.
INSERT INTO record_audit
(operation,source_id,created_by)
VALUES
('I', NEW.record_id, NEW.created_by);
ELSIF (TG_OP = 'UPDATE') THEN
FOR i in 1 .. TG_ARGV[0] LOOP
ref_col := TG_ARGV[i].column; -- I know .column doesn't exist but what to use?
INSERT INTO record_audit
(operation, source_column, source_id, old_value, new_value, created_by)
VALUES
('U', ref_col, NEW.record_id, OLD.ref_col, NEW.ref_col, NEW.created_by);
END LOOP;
END IF;
RETURN NULL; -- result is ignored anyway since this is an AFTER trigger
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER record_audit_trig
AFTER INSERT OR UPDATE on record
FOR EACH ROW EXECUTE PROCEDURE audit_record();
感谢您阅读这个冗长而曲折的问题!