Re: foreign key on virtual generated column - Mailing list pgsql-hackers

From Srinath Reddy Sadipiralla
Subject Re: foreign key on virtual generated column
Date
Msg-id CAFC+b6pZxP53cD=PF36OT4UUdd4MwswfHnobicW4RFtt08zytA@mail.gmail.com
Whole thread Raw
In response to Re: foreign key on virtual generated column  (Srinath Reddy Sadipiralla <srinath2133@gmail.com>)
List pgsql-hackers
Hi Jian,

while continuing my review , i observed these:

1) if we have multiple virtual generated columns in table,
and foreign key on a virtual generated column, during
RI check in RI_FKey_check, i observed that we are
computing other virtual generated columns which are
not part of foreign key,which i think is (not too) slow but
slowness depends on how complex the generated
expressions are, number of virtual generated columns
in the table ,i think we can use riinfo inside
ExecComputeGenerated to only compute the columns
in foreign key.

                         Table "public.gtest23b"
 Column |  Type   | Collation | Nullable |            Default            
--------+---------+-----------+----------+-------------------------------
 a      | integer |           | not null |
 b      | bigint  |           |          | generated always as ((a * 1))
 c      | integer |           |          | generated always as ((a * 2))
Indexes:
    "gtest23b_pkey" PRIMARY KEY, btree (a)
Foreign-key constraints:
    "gtest23b_b_fkey" FOREIGN KEY (b) REFERENCES gtest23a(x) ON DELETE CASCADE

when we do "insert into gtest23b values(3);"
RI kicks in and computes the b,c columns
to check the values of "b" exists in primary key,
but here the virtual generated columns which
are not part of the foreign key like "c" are also
computed.

2) during ALTER type or expression of a column
which is involved in foreign key , we go through
TryReuseForeignKey to determine whether
revalidation of this constraint can be skipped, here
i observed for this patch that if we saw a virtual
generated column in foreign key we simply bail out
and won't skip the revalidation, i have a doubt and
an observation here

doubt:- why are we simply bailing out and doing
revalidation if we found out if there's a virtual
generated column in foreign key? in TryReuseForeignKey,
is it because if we change the expression obviously get
new values ,so we anyway need to revalidate them with
primary key but what about if virtual column's type gets
ALTERed in such a way that the equality operator is same
underneath like varchar(10) to varchar(40) , then i think
we can allow the normal flow as we do with normal columns
by appending the OID to old_conpfeqop as below.

for (i = 0; i < numkeys; i++)
con->old_conpfeqop = lappend_oid(con->old_conpfeqop, conpfeqop[i]);

observation:- if we go with current logic of bailing out and
doing the revalidation if a virtual gen column is present in
foreign key, then even if we are only altering a standard
column that is perfectly safe (binary compatible) like
varchar(10) to varchar(40) and not doing any change
to the virtual generated column in a composite foreign
key, even then we are going to do revalidation and
goes to validateForeignKeyConstraint which is
kind of slow, as the values in foreign key are same
as before even after ALTER, so its not needed to
revalidate again primary key, and if we try to simulate
the same scenario without the virtual generated column
and instead a normal column then postgres skips the revalidation,
because the ALTERed column is a standard column
and the type underneath is "compatible",so there won't
be any changes to the values in foreign key to revalidate
with the primary key, so it's skipped.

for example:

CREATE TABLE parent (
    id_std text,
    id_extra int,
    PRIMARY KEY (id_std, id_extra)
);

INSERT INTO parent VALUES ('A', 1), ('B', 2);


Scenario 1:  No Virtual Columns
Here, we have a composite FK, but both columns are standard.
We alter 'col_std' (varchar 10 -> 40).
Expectation: Optimization SUCCEEDS. Validation SKIPPED.

CREATE TABLE child_a (
    col_std varchar(10),
    col_extra int,
    FOREIGN KEY (col_std, col_extra) REFERENCES parent(id_std, id_extra)
);

INSERT INTO child_a VALUES ('A', 1);

ALTER TABLE child_a ALTER COLUMN col_std TYPE varchar(40);


Scenario 2: With Virtual Column
Here, we have a composite FK where one column is Virtual.
We alter 'col_std' (varchar 10 -> 50). 'col_virt' is Untouched.
Expectation: Optimization FAILS. Validation FORCED (Slow).

CREATE TABLE child_b (
    col_std varchar(10),
    col_virt int GENERATED ALWAYS AS (1) VIRTUAL,
    FOREIGN KEY (col_std, col_virt) REFERENCES parent_comp(id_std, id_extra)
);

INSERT INTO child_b VALUES ('A');

This should trigger the "validateForeignKeyConstraint" path because TryReuseForeignKey bails out.
ALTER TABLE child_b ALTER COLUMN col_std TYPE varchar(40);

--
Thanks,
Srinath Reddy Sadipiralla
EDB: https://www.enterprisedb.com/

pgsql-hackers by date:

Previous
From: Fujii Masao
Date:
Subject: Re: Allow GUC settings in CREATE SUBSCRIPTION CONNECTION to take effect
Next
From: jian he
Date:
Subject: Re: IS JSON predicate support for domain base type as JSON/JSONB/BYTEA/TEXT