2016-01-30 71 views
0

我想保留我的表的所有更改。我有一個工作解決方案爲每個表格創建一個觸發器,但是複製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。

回答

0

我發現這個「相關的問題」 https://stackoverflow.com/a/1997417/844731

我沒想到做「執行使用」與新老的解決方案。所以現在一個工作解決方案是:

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; 
+0

注意 - 此示例易受SQL注入攻擊。任何參數都是動態查詢字符串必須清理(轉義)。 –

+0

hi @PavelStehule。它如何或在哪裏是可以虛擬的? (這是一個觸發器,我不使用任何用戶輸入的變量,但尚未被postgres解釋) –

+0

@PavelStehule您能否指出它可以在哪裏使用或演示更好的解決方案?謝謝:-) –

0

@Pascal_dher,有人可以創建包含攻擊者代碼的名稱的表。由於Postgresql這可能dosnt做一些非常糟糕的,只有失敗的查詢。但是如果你的觸發器會更復雜,那麼影響可能會更糟糕。

+0

但是如果他們可以在利用之前創建表,他們已經不能做所有事情了?將使用quote_ident(tg_table_name ||'_hist')和quote_literal(tg_op)修復潛在的SQL注入? –