Re: CHECK Constraint Deferrable - Mailing list pgsql-hackers

From vignesh C
Subject Re: CHECK Constraint Deferrable
Date
Msg-id CALDaNm0GTzh76bquHBCFkM74t12yB0cgQ7rwcYHB7SS_F2F_HA@mail.gmail.com
Whole thread Raw
In response to Re: CHECK Constraint Deferrable  (Himanshu Upadhyaya <upadhyaya.himanshu@gmail.com>)
Responses Re: CHECK Constraint Deferrable
List pgsql-hackers
On Thu, 14 Sept 2023 at 15:33, Himanshu Upadhyaya
<upadhyaya.himanshu@gmail.com> wrote:
>
>
>
> On Thu, Sep 14, 2023 at 9:57 AM vignesh C <vignesh21@gmail.com> wrote:
>>
>> 3) Insert check is not deferred to commit:
>> This insert check here is deferred to commit:
>> postgres=# CREATE TABLE tbl (i int ) partition by range (i);
>> CREATE TABLE tbl_1 PARTITION OF tbl FOR VALUES FROM (0) TO (10);
>> CREATE TABLE tbl_2 PARTITION OF tbl FOR VALUES FROM (20) TO (30);
>> CREATE TABLE
>> CREATE TABLE
>> CREATE TABLE
>> postgres=# ALTER TABLE tbl ADD CONSTRAINT tbl_chk_1 CHECK(i<>1) DEFERRABLE;
>> ALTER TABLE
>> postgres=# begin;
>> BEGIN
>> postgres=*# SET CONSTRAINTS tbl_chk_1 DEFERRED;
>> SET CONSTRAINTS
>> postgres=*# INSERT INTO tbl values (1);
>> INSERT 0 1
>> postgres=*# commit;
>> ERROR:  new row for relation "tbl_1" violates check constraint "tbl_chk_1"
>> DETAIL:  Failing row contains (1).
>>
>> But the check here is not deferred to commit:
>> postgres=# CREATE TABLE tbl (i int check(i<>0) DEFERRABLE) partition
>> by range (i);
>> CREATE TABLE tbl_1 PARTITION OF tbl FOR VALUES FROM (0) TO (10);
>> CREATE TABLE tbl_2 PARTITION OF tbl FOR VALUES FROM (20) TO (30);
>> CREATE TABLE
>> CREATE TABLE
>> CREATE TABLE
>> postgres=# ALTER TABLE tbl ADD CONSTRAINT tbl_chk_1 CHECK(i<>1) DEFERRABLE;
>> ALTER TABLE
>> postgres=# begin;
>> BEGIN
>> postgres=*#  SET CONSTRAINTS tbl_chk_1 DEFERRED;
>> SET CONSTRAINTS
>> postgres=*# INSERT INTO tbl values (1);
>> ERROR:  new row for relation "tbl_1" violates check constraint "tbl_chk_1"
>> DETAIL:  Failing row contains (1).
>>
> I dont think it's a problem, in the second case there are two DEFERRABLE CHECK constraints and you are marking one as
DEFERREDbut other one will be INITIALLY IMMEDIATE. so we can use "SET CONSTRAINTS ALL DEFERRED;". 
> ‘postgres[1271421]=#’CREATE TABLE tbl (i int check(i<>0) DEFERRABLE) partition
> ‘...>’by range (i);
> CREATE TABLE
> ‘postgres[1271421]=#’CREATE TABLE tbl_1 PARTITION OF tbl FOR VALUES FROM (0) TO (10);
> CREATE TABLE
> ‘postgres[1271421]=#’CREATE TABLE tbl_2 PARTITION OF tbl FOR VALUES FROM (20) TO (30);
> CREATE TABLE
> ‘postgres[1271421]=#’ALTER TABLE tbl ADD CONSTRAINT tbl_chk_1 CHECK(i<>1) DEFERRABLE;
> ALTER TABLE
> ‘postgres[1271421]=#’\d tbl
>           Partitioned table "public.tbl"
>  Column |  Type   | Collation | Nullable | Default
> --------+---------+-----------+----------+---------
>  i      | integer |           |          |
> Partition key: RANGE (i)
> Check constraints:
>     "tbl_chk_1" CHECK (i <> 1) DEFERRABLE
>     "tbl_i_check" CHECK (i <> 0) DEFERRABLE
> Number of partitions: 2 (Use \d+ to list them.)
>  ‘postgres[1271421]=#’begin;
> BEGIN
> ‘postgres[1271421]=#*’SET CONSTRAINTS ALL DEFERRED;
> SET CONSTRAINTS
> ‘postgres[1271421]=#*’INSERT INTO tbl values (1);
> INSERT 0 1
> ‘postgres[1271421]=#*’commit;
> ERROR:  23514: new row for relation "tbl_1" violates check constraint "tbl_chk_1"
> DETAIL:  Failing row contains (1).
> SCHEMA NAME:  public
> TABLE NAME:  tbl_1
> CONSTRAINT NAME:  tbl_chk_1
> LOCATION:  ExecConstraints, execMain.c:2077

I think we should be able to defer one constraint like in the case of
foreign key constraint:
create table t1(c1 int primary key);
insert into t1 values(10);
create table t2(c1 int primary key);
insert into t2 values(10);
create table t3(c1 int, c2 int references t1(c1) deferrable, c3 int
references t2(c1) deferrable);

-- Set only one constraint as deferred
begin;
set CONSTRAINTS  t3_c2_fkey deferred;
-- c2 column constraint is deferred, we need not set all constraints
deferred in this case, insert was successful
postgres=*# insert into t3 values(1,11,10);
INSERT 0 1
-- Throws error for the constraint that is not deferred
postgres=*# insert into t3 values(1,10,11);
ERROR:  insert or update on table "t3" violates foreign key constraint
"t3_c3_fkey"
DETAIL:  Key (c3)=(11) is not present in table "t2".

Thoughts?

Regards,
Vignesh



pgsql-hackers by date:

Previous
From: Michael Paquier
Date:
Subject: Re: Bug fix for psql's meta-command \ev
Next
From: Amit Kapila
Date:
Subject: Re: [PoC] pg_upgrade: allow to upgrade publisher node