在UPDATE期间捕获plpgsql中的列

时间:2013-02-27 15:34:51

标签: postgresql triggers plpgsql

我正在为Postgres 9.1在plpgsql中编写一个触发器。我需要能够捕获在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_id是什么(source_id),更新了什么列(source_column),还详细说明了old_value和列的new_value。

据我所知,列值必须是CAST()一种文本。我相信我可以通过访问NEW和OLD来访问old_value和new_value,但我很难弄清楚如何获取UPDATE查询的SET子句中使用的列名。我需要触发器为record子句中指定的每个列向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();

感谢您阅读这个漫长而棘手的问题!

1 个答案:

答案 0 :(得分:1)

你无法获得这些信息 - 不是PL级别 - 可能在C中。

足够好的解决方案基于记录NEW和OLD中已更改的字段。您可以从系统表中获取字段列表〜与已连接到触发器的表相关。