2014-09-03 66 views
2

Postgres 8.4在這裏。試想this code snippet from Postgres doc在Postgres觸發函數異常調用之前執行操作

CREATE FUNCTION emp_stamp() RETURNS trigger AS $emp_stamp$ 
BEGIN 
    -- Check that empname and salary are given 
    IF NEW.empname IS NULL THEN 
     RAISE EXCEPTION 'empname cannot be null'; 
    END IF; 
    IF NEW.salary IS NULL THEN 
     RAISE EXCEPTION '% cannot have null salary', NEW.empname; 
    END IF; 

    -- Who works for us when she must pay for it? 
    IF NEW.salary < 0 THEN 
     RAISE EXCEPTION '% cannot have a negative salary', NEW.empname; 
    END IF; 

    -- Remember who changed the payroll when 
    NEW.last_date := current_timestamp; 
    NEW.last_user := current_user; 
    RETURN NEW; 
END; 
$emp_stamp$ LANGUAGE plpgsql; 

如果我們想要做的事就像一個定製的表格記錄這些例外:

-- Check that empname and salary are given 
IF NEW.empname IS NULL THEN 
    INSERT INTO my_log_table ('User didn't supplied empname') 
    RAISE EXCEPTION 'empname cannot be null'; 
END IF; 

因爲任何一個我們呼籲RAISE EXCEPTION把之前被回滾撤消它不會工作RAISE EXCEPTION意味着,即我們創建的my_log_table行將在調用RAISE EXCEPTION後立即被刪除。

什麼是完成這樣的事情的最好方法?也許捕捉我們的自定義異常?

關閉回滾@ TRIGGER是不是一種選擇,我需要它。

+1

你真正想要的是一個子事務(東西大致相當於Oracle的'編譯autonomous'不幸的是,這仍然只是一個提議,尚未實現(Postgres的9.3 )。你可以看看這個[post](http://raghavt.blogspot.com.au/2012/05/autonomous-transaction-in-postgresql-91.html),詳細描述了一個通用的解決方法。 – Mureinik 2014-09-03 19:30:28

+0

這可以工作,雖然我感覺在這種特殊情況下會像使用大錘來破解堅果:) – jpp1jpp1 2014-09-03 20:11:47

+0

當您從*任何*來源添加長引文時,還請添加一個鏈接到來源。我添加了Postgres 8.4手冊的鏈接。 – 2014-09-03 20:21:03

回答

2

您可以trap errors /捕捉異常。

EXCEPTION塊,你可以做任何事情,就像插入到另一個表。之後,您可以重新引發異常以傳播出去,但是會將包括INSERT在內的整個事務回滾到日誌表(除非異常被包裝並捕獲到外部函數中)。

可能

或者,你可以取消觸發觸發功能和引發異常的行。交易中的其他一切都正常進行。

假設這是一個觸發ON UPDATE和你有相同的結構,另一個表寫失敗的INSERT到:

CREATE OR REPLACE FUNCTION emp_stamp() 
    RETURNS trigger AS 
$func$ 
BEGIN 
    -- Check that empname and salary are given 
    IF NEW.empname IS NULL THEN 
     RAISE EXCEPTION 'empname cannot be null'; 
    END IF; 

    IF ... 

    RETURN NEW; -- regular end 

EXCEPTION WHEN others THEN -- or be more specific 
    INSERT INTO log_tbl VALUES (NEW.*); -- identical table structure 
    RETURN NULL; -- cancel row 
END 
$func$ LANGUAGE plpgsql;

注意NEW包含的行權前的異常發生,包括以前成功的聲明狀態在相同的功能。

觸發:

CREATE TRIGGER emp_stamp 
BEFORE INSERT OR UPDATE ON tbl 
FOR EACH ROW EXECUTE PROCEDURE emp_stamp(); 
+0

內完成這個工作,我最終會使用類似的東西,我失去了在應用程序級別捕獲並顯示的異常,但至少啓動觸發器的plpgsql函數可以返回一個錯誤的價值應用程序(因爲它沒有檢測到行更新-FOUND-) 我發現其他更復雜的解決方案不值得的麻煩 – jpp1jpp1 2014-09-04 08:38:29

1

實際上你有兩個選擇。

  1. 您可以通過使用上揚一定程度上檢查manual
  2. 登錄錯誤您的應用程序,而不是在Db的事務日誌到PostgreSQL的日誌。例如,不應該像這樣在觸發函數中檢查負向工資。或者應該在插入調用上處理異常。
+0

1.事實上,我試圖保留的不是log_add(它只是一個例子),而是另一種不同的東西(插入另一個表格)。 – jpp1jpp1 2014-09-03 20:06:03

+0

2.我意識到這一點,但在應用程序級別執行操作會比較慢,因爲我必須使用更多數據庫查詢來檢查條件。我只是想知道postgresql是否有辦法在TRIGGERS – jpp1jpp1 2014-09-03 20:08:47

相關問題