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?
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.
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.
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.
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 fromDEFERRED
toIMMEDIATE
, 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 theSET CONSTRAINTS
command. If any such constraint is violated, theSET 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With