2009-10-08 44 views
1

我想強制用戶指定某個表(sometbl)的更新源,例如 。指定「本地」或「遠程」(對於COL2) - 但這一要求應該發生在數據庫級別檢查時,執行UPDATE語句,以便:PostgreSQL 8.2:要求在UPDATE語句中存在特定的列

UPDATE sometbl SET col1 = 'abc'; 

應該拋出錯誤(異常),但:

UPDATE sometbl SET col1 = 'abc', col2 = 'remote'; 

...將成功。

我試圖爲該表創建BEFORE更新觸發器,但我無法檢查是否顯式設置了NEW.col2的 。

我使用狀態

IF NEW.col2 IS NULL THEN 
    RAISE EXCEPTION 'you must specify source of this update (local/remote)' 
END IF; 

但每次,當在更新未指定COL2(UPDATE SET sometbl COL1 = 'ABC')

我在NEW.col2得到了字段的當前值僞var,而不是假設NULL。

是否有任何解決方法來防止UPDATING指定的字段在UPDATE stmt中不存在?

回答

0

您可以創建第二個表,其中包含具有ID值的本地和遠程條目,然後只需使用第一個表中該表的非空外鍵即可。

+0

該解決方案將不會在我的情況下工作,因爲在第一個表中的行(或多個)具有有效的外鍵將在更新之前存在,所以即使沒有指定外鍵字段值更新會成功。 – 2009-10-09 13:02:57

0

您可以創建幾個存儲過程,一拉

create or replace function update_remote(text) returns void 
    as 'update sometbl SET col1 = $1, col2 = ''remote''' 
    language SQL 
    volatile 
    strict; 
+0

這部分解決了我面臨的問題 - 強制某人更新表格以明確設置該更新的來源。我的意思是部分因爲必須告訴某人使用該過程而不使用直接的UPDATE語句。擁有權限的用戶無法做到這一點 - 如果db用戶對該函數有EXECUTE,爲了通過該函數更新表,他還必須擁有UPDATE權限(這反過來允許在沒有必需的字段集的情況下執行UPDATE)。 – 2009-10-09 12:58:21

1

如何約上幾個triggers?一個在之前運行更新,並將列設置爲空。一個更新和pukes(返回NULL),如果列仍然爲空。 (如果觸發器返回NULL,則更新失敗。)

+0

一個聰明的解決方案。 – Kev 2009-10-09 20:25:26

+0

我會稱之爲「抓住吸管」。 :) – 2009-10-09 20:49:42

+0

初看起來,這對我來說是很有希望的解決方案......但是,您是否真的試過了這個實例?仍然不適合我。首先AFTER觸發器可能會返回NULL,並且UPDATE不會失敗,只有當您在AFTER觸發器函數的主體中明確地拋出異常時它纔會失敗。你建議在觸發之前將列設置爲null - 但是如何?在那個觸發器中使用單獨的UPDATE stmt?這導致了遞歸調用相同的觸發器,甚至如果這可以避免使用一些有條件的檢查 - 不可能找出'col2'是否明確設置爲updt stmt,因爲我需要 – 2009-10-12 12:01:18

1

我想使用security definer函數,該函數由除admin和/或表所有者之外的唯一用戶擁有,並具有sometbl的更新權限。

事情是這樣的:

create table sometbl (
    id serial primary key, 
    col1 text, 
    col2 text not null, 
    check (col2 in ('local','remote')) 
); 
create role sometbl_updater; 
grant update on sometbl to sometbl_updater; 

create function update_sometbl(integer, text, text) 
returns void as 
$$ 
    update sometbl set col1=$2, col2=$3 where id=$1; 
$$ security definer volatile language sql; 
alter function update_sometbl(integer, text, text) 
    owner to sometbl_updater; 

但要小心security definer functions security

0

好的,讀過文檔並試用後,我可以報告一個BEFORE觸發器是要走的路。觸發器提供名稱NEW和OLD綁定到新元組和舊元組。從BEFORE觸發器返回NULL可防止更新。因此:

CREATE OR REPLACE FUNCTION prevent_not_changing_col2() 
    RETURNS trigger AS $$ 
begin 
    if NEW.col2 = OLD.col2 then return NULL; end if; 
    return NEW; 
end ; 
$$ LANGUAGE plpgsql; 

CREATE TRIGGER col2_check 
    BEFORE UPDATE 
    ON sometbl 
    FOR EACH ROW 
    EXECUTE PROCEDURE prevent_not_changing_col2(); 
+0

好的,但該解決方案有一個缺點 - 它會阻止UPDATE,其中col2被顯式設置爲與更新行相同的值,假設sometbl(id,col1,col2)中有行:1,'abc','local',我們嘗試「UPDATE sometbl SET col1 ='def',col2 ='local'WHERE id = 1「,那麼這個觸發器也會阻止我想強制使用所有開發者的更新stmt(他們必須在updt stmts中提供col2,不管if它的價值改變了,或者不)。我對嗎 ? – 2009-10-12 15:26:13