Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to catch exception of a deferred constraint in pgsql?

Consider the following code:

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;
$$;

I would like to catch any exception thrown by constraints, but for performance reasons I defer checking constraints until commit (deferrable initially deferred). Is there a way to catch exceptions without turning immediate mode on?

like image 550
Marcin Barczyński Avatar asked Feb 10 '17 11:02

Marcin Barczyński


People also ask

What is deferrable in Postgres?

If a constraint is deferrable, this clause specifies the default time to check the constraint. If the constraint is INITIALLY IMMEDIATE, it is checked after each statement, which is the default. If the constraint is INITIALLY DEFERRED, it is checked only at the end of the transaction.

What is exclusion constraint in PostgreSQL?

EXCLUSION Constraint − The EXCLUDE constraint ensures that if any two rows are compared on the specified column(s) or expression(s) using the specified operator(s), not all of these comparisons will return TRUE.

What is a deferred constraint?

A deferred constraint is one that is enforced when a transaction is committed. A deferrable constraint is specified by using DEFERRABLE clause. Once you've added a constraint, you cannot change it to DEFERRABLE. You must drop and recreate the constraint.


1 Answers

You can set deferrable constraints to IMMEDIATE just for your transaction without "turning immediate mode on" (without changing the constraint definition).

That's exactly what this separate command SET CONSTRAINTS is for:

SET CONSTRAINTS child_pid_fk IMMEDIATE;

Or if you don't know constraint name(s):

SET CONSTRAINTS ALL IMMEDIATE;

The manual:

SET CONSTRAINTS sets the behavior of constraint checking within the current transaction.

Bold emphasis mine.

And:

When SET CONSTRAINTS changes the mode of a constraint from DEFERRED to IMMEDIATE, the new mode takes effect retroactively: any outstanding data modifications that would have been checked at the end of the transaction are instead checked during the execution of the SET CONSTRAINTS command. If any such constraint is violated, the SET CONSTRAINTS fails (and does not change the constraint mode). Thus, SET CONSTRAINTS can be used to force checking of constraints to occur at a specific point in a transaction.

Exactly what you need.

like image 76
Erwin Brandstetter Avatar answered Oct 11 '22 12:10

Erwin Brandstetter