多表审计触发器功能

时间:2016-01-30 12:31:28

标签: postgresql triggers plpgsql

我想保留表格的所有更改。我有一个工作解决方案,用于为每个表创建一个触发器,但复制代码foreach表似乎很愚蠢。有没有办法创建一个单独的触发器功能呢?

我的每表触发器工作示例(包括表定义):

CREATE TABLE departments (
    id                  bigserial Primary Key,
    name                varchar not null,
    created             bigint not null default date_part('epoch', NOW()),
    created_by          bigint references Employees (id) not null
);
create table Departments_hist ("action" varchar not null, change_date bigint not null, rev bigserial not null, like Departments);
CREATE OR REPLACE FUNCTION add_to_history_Departments() RETURNS TRIGGER AS $$
BEGIN
IF(TG_OP='INSERT' OR TG_OP='UPDATE') THEN
    INSERT INTO Departments_hist values (TG_OP,date_part('epoch', NOW()),DEFAULT,NEW.*);
END IF;
IF (TG_OP='DELETE') THEN
    INSERT INTO Departments_hist values (TG_OP,date_part('epoch', NOW()),DEFAULT,OLD.*);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trigger_history_Departments AFTER INSERT OR UPDATE OR DELETE ON Departments FOR EACH ROW EXECUTE PROCEDURE add_to_history_Departments();

我试图通过将'_hist'连接到TG_TABLE_NAME来使其成为多表:

CREATE OR REPLACE FUNCTION add_to_hist_table() RETURNS TRIGGER AS $$
DECLARE
    histTable text :=TG_TABLE_NAME || '_hist';
BEGIN
    IF (TG_OP='INSERT' OR TG_OP='UPDATE') THEN
        INSERT INTO histTable values (TG_OP,date_part('epoch', NOW()),DEFAULT,NEW.*);
    ELSIF TG_OP='DELETE' THEN
        INSERT INTO histTable values (TG_OP,date_part('epoch', NOW()),DEFAULT,OLD.*);
    END IF;
    RETURN null; --ignored since it is an AFTER triggger.
END;
$$ LANGUAGE plpgsql;

但是我收到了一个错误:

ERROR:  syntax error at or near "$1"
LINE 1: INSERT INTO  $1  values ( $2 ,date_part('epoch', NOW()),DEFA...
                     ^
QUERY:  INSERT INTO  $1  values ( $2 ,date_part('epoch', NOW()),DEFAULT, $3 .*)
CONTEXT:  SQL statement in PL/PgSQL function "add_to_hist_table" near line 5

我猜这是变量替换的问题(http://www.postgresql.org/docs/8.4/static/plpgsql-implementation.html)。

如何实现此功能?

PS。我正在使用postgresql 8.4但很快就会升级到9.3。

2 个答案:

答案 0 :(得分:0)

我找到了解决这个“相关问题”的问题https://stackoverflow.com/a/1997417/844731

我没想到用NEW和OLD做'执行使用'。所以现在一个有效的解决方案是:

CREATE OR REPLACE FUNCTION add_to_hist_table() RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP='INSERT' OR TG_OP='UPDATE') THEN
    execute 'INSERT INTO '|| TG_TABLE_NAME ||'_hist values (''' || TG_OP || ''',date_part(''epoch'', NOW()),DEFAULT,$1.*)' using NEW;
ELSIF TG_OP='DELETE' THEN
    execute 'INSERT INTO '|| TG_TABLE_NAME ||'_hist values (''' || TG_OP || ''',date_part(''epoch'', NOW()),DEFAULT,$1.*)'  using OLD;
END IF;
RETURN null; --ignored since it is an AFTER triggger.
END;
$$ LANGUAGE plpgsql;

答案 1 :(得分:0)

@Pascal_dher,有人可以使用包含攻击者代码的名称创建表。由于Postgresql这可能dosnt做了一些非常糟糕的,只有失败的查询。但如果你的触发器会更复杂,那么影响会更加糟糕。