2017-02-10 16 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

Вы можете попробовать и запустить 'SET CONSTRAINTS child_pid_fk IMMEDIATE;' после оператора 'DELETE', в контексте SQL, который запускает проверку ограничений; однако я не уверен, что это правда в контексте 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 наборы поведение проверки ограничений в пределах текущей ent transaction.

Смелый акцент мой.

И:

Когда SET CONSTRAINTS изменяет режим ограничение от DEFERRED к IMMEDIATE, новый режим вступает в силу задним числом: любые невыполненные изменения данных, которые были проверены на конце сделки вместо этого проверяются во время выполнения команды SET CONSTRAINTS. Если любое такое ограничение нарушено, SET CONSTRAINTS терпит неудачу (и не изменяет режим ограничения). Таким образом, SET CONSTRAINTS может использоваться для принудительной проверки ограничений на случай определенной транзакции.

Точно, что вам нужно.

+1

Спасибо. PostgreSQL кажется достаточно умным, чтобы не повторять одинаковые ограничения снова и снова, когда я переключаюсь с DEFERRED на IMMEDIATE и обратно несколько раз в одной транзакции. Я проверил эмпирически, измеряя время, которое каждый раз, когда я переключаюсь на IMMEDIATE, проверяются только обновленные строки. –