Re: simplifying foreign key/RI checks

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: simplifying foreign key/RI checks
Дата
Msg-id 1627848.1636676261@sss.pgh.pa.us
обсуждение исходный текст
Ответ на simplifying foreign key/RI checks  (Amit Langote <amitlangote09@gmail.com>)
Список pgsql-hackers
Alvaro Herrera <alvherre@2ndquadrant.com> writes:
> I think we (I) should definitely pursue fixing whatever was broken by
> DETACH CONCURRENTLY, back to pg14, independently of this patch ...  but
> I would appreciate some insight into what the problem is.

Here's what I'm on about:

regression=# create table pk (f1 int primary key);
CREATE TABLE
regression=# insert into pk values(1);
INSERT 0 1
regression=# create table fk (f1 int references pk);
CREATE TABLE
regression=# begin isolation level repeatable read ;
BEGIN
regression=*# select * from pk;  -- to establish xact snapshot
 f1
----
  1
(1 row)

now, in another session, do:

regression=# insert into pk values(2);
INSERT 0 1

back at the RR transaction, we can't see that:

regression=*# select * from pk;  -- still no row 2
 f1
----
  1
(1 row)

so we get:

regression=*# insert into fk values(1);
INSERT 0 1
regression=*# insert into fk values(2);
ERROR:  insert or update on table "fk" violates foreign key constraint "fk_f1_fkey"
DETAIL:  Key (f1)=(2) is not present in table "pk".

IMO that behavior is correct.  If you use READ COMMITTED, then
SELECT can see row 2 as soon as it's committed, and so can the
FK check, and again that's correct.

In v13, the behavior is the same if "pk" is a partitioned table instead
of a plain one.  In HEAD, it's not:

regression=# drop table pk, fk;
DROP TABLE
regression=# create table pk (f1 int primary key) partition by list(f1);
CREATE TABLE
regression=# create table pk1 partition of pk for values in (1,2);
CREATE TABLE
regression=# insert into pk values(1);
INSERT 0 1
regression=# create table fk (f1 int references pk);
CREATE TABLE
regression=# begin isolation level repeatable read ;
BEGIN
regression=*# select * from pk;  -- to establish xact snapshot
 f1
----
  1
(1 row)

--- now insert row 2 in another session

regression=*# select * from pk;  -- still no row 2
 f1
----
  1
(1 row)

regression=*# insert into fk values(1);
INSERT 0 1
regression=*# insert into fk values(2);
INSERT 0 1
regression=*#

So I say that's busted, and the cause is this hunk from 71f4c8c6f:

@@ -392,11 +392,15 @@ RI_FKey_check(TriggerData *trigdata)

     /*
      * Now check that foreign key exists in PK table
+     *
+     * XXX detectNewRows must be true when a partitioned table is on the
+     * referenced side.  The reason is that our snapshot must be fresh
+     * in order for the hack in find_inheritance_children() to work.
      */
     ri_PerformCheck(riinfo, &qkey, qplan,
                     fk_rel, pk_rel,
                     NULL, newslot,
-                    false,
+                    pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE,
                     SPI_OK_SELECT);

     if (SPI_finish() != SPI_OK_FINISH)

I think you need some signalling mechanism that's less global than
ActiveSnapshot to tell the partition-lookup machinery what to do
in this context.

            regards, tom lane



В списке pgsql-hackers по дате отправления:

Предыдущее
От: "Euler Taveira"
Дата:
Сообщение: Re: [BUG]Invalidate relcache when setting REPLICA IDENTITY
Следующее
От: Bruce Momjian
Дата:
Сообщение: Re: storing an explicit nonce