2017-02-10 86 views
3

考慮下面的代碼:有沒有辦法在pgsql中捕獲延遲約束的異常?

drop table if exists demo cascade; 
drop table if exists child cascade; 

create table demo 
(
    id bigint not null 
    constraint demo_pk primary key 
); 

create table child 
(
    id bigint not null 
     constraint child_pk primary key, 
    pid bigint, 
     constraint child_pid_fk 
     foreign key (pid) 
     references demo (id) 
     deferrable initially deferred -- remove this line and exceptions get caught 
); 

insert into demo values (1); 
insert into child values (11, 1); 

do language plpgsql $$ 
begin 
    delete from demo where id = 1; 
exception 
    when others then 
     raise notice 'exception caught'; 
end; 
$$; 

我想趕通過限制拋出的任何異常,但由於性能原因我推遲檢查的約束,直到提交(deferrable initially deferred)。有沒有辦法在不啓用immediate模式的情況下捕捉異常?

+0

不,你不能,因爲根據定義,延遲約束直到你提交後纔會被檢查。您需要在運行SQL –

+1

的代碼中處理異常您可以在觸發約束檢查的SQL上下文中嘗試在'DELETE'語句之後運行'SET CONSTRAINTS child_pid_fk IMMEDIATE;';但是我不確定在plpgsql上下文中是否也是如此。 - 編輯:只是看到你寫道,你尋求其他選擇。我不認爲有其他選擇。 – pozs

+0

@pozs:我認爲你畢竟是在正確的軌道上。我認爲OP只是不想改變表定義,'SET CONSTRAINTS'是他需要的。 –

回答

3

可以集延遲約束到IMMEDIATE只爲您的交易沒有「開啓即時模式」(不改變約束定義)。

這正是這個單獨的命令SET CONSTRAINTS是:

SET CONSTRAINTS child_pid_fk IMMEDIATE; 

,或者如果你不知道的約束姓名(或名稱):

SET CONSTRAINTS ALL IMMEDIATE; 

The manual:

SET CONSTRAINTS套curr內約束檢查的行爲交易

大膽重視我的。

和:

SET CONSTRAINTS變化的約束從 DEFERREDIMMEDIATE的模式,新的模式生效追溯: 這會在交易的 年底被檢查的數據修改而是在執行 SET CONSTRAINTS命令期間檢查。如果違反任何此類約束條件,則會失敗(並且不會更改約束模式)。 因此,SET CONSTRAINTS可用於強制檢查約束條件 發生在事務中的特定點。

正是你所需要的。

+1

謝謝。當我在同一事務中從DEFERRED切換到IMMEDIATE並多次返回時,PostgreSQL似乎足夠聰明,不再一次又一次地檢查相同的約束。我通過測量每次切換到IMMEDIATE時的時間檢查經驗,只檢查更新的行。 –

相關問題