Re: 7.4 and 7.3.5 showstopper - Mailing list pgsql-sql

From Jan Wieck
Subject Re: 7.4 and 7.3.5 showstopper
Date
Msg-id 3FA1DE76.3030707@Yahoo.com
Whole thread Raw
In response to 7.4 and 7.3.5 showstopper (was: Re: Bug in Rule+Foreing key constrain?)  (Jan Wieck <JanWieck@Yahoo.com>)
List pgsql-sql
Jan Wieck wrote:

> Confirmed, that's a bug - pgsql-hackers CC'd and scipt for full 
> reproduction attached.

Assumptions where correct, bug fixed in REL7_3_STABLE and HEAD. I also 
added a slightly modified version of the script that reproduced the bug 
to the foreign_key regression test.


Jan

> 
> This can also be reproduced in 7.4-beta5.
> 
> My guess out of the blue would be, that the rewriter expands the insert 
> into one insert with the where clause, one update with the negated where 
> clause. Executed in that order, they are both true ... first there is no 
> such row, the insert happens, second the row exists and is being updated.
> 
> IIRC the refint trigger queue run at the end of the whole statement 
> tries to heap_fetch() the originally inserted tuple, which is invisible 
> by that time. I seem to remember that the original version did fetch 
> them with some snapshot override mode to get it anyway and fire the 
> trigger. That apparently does not happen any more, so now the duty would 
> be up to the on update refint trigger which ... er ... recently got 
> fixed not to check non-changed key references any more ... duh.
> 
> I will look a bit deeper into it later tonight. I think if we let the on 
> update refint trigger check the referenced key again if the old tuple 
> has xmin = current_xid we should be fine.
> 
> 
> 
> Thanks for reporting, Michele. In the meantime, you might want to use a 
> BEFORE INSERT trigger in PL/pgSQL that tries to UPDATE the row and if 
> GET DIAGNOSTICS tells it it succeeded, returns NULL to suppress the 
> INSERT. That should work around the bug for the time being.
> 
> 
> Jan
> 
> 
> Michele Bendazzoli wrote:
> 
>> On Thu, 2003-10-30 at 18:29, Jan Wieck wrote:
>> 
>>> Not entirely. On which table(s) are the REFERENCES constraints and are 
>>> they separate per column constraints or are they multi-column constraints?
>> 
>> here are the constraints of the abilitazione table
>> 
>> ALTER TABLE public.abilitazione
>>   ADD CONSTRAINT abilitazione_pkey PRIMARY KEY(comuneid, cassonettoid,
>> chiaveid);
>> 
>> ALTER TABLE public.abilitazione
>>   ADD CONSTRAINT abilitazione_cassonettoid_fkey FOREIGN KEY (comuneid,
>> cassonettoid) REFERENCES public.cassonetto (comuneid, cassonettoid) ON
>> UPDATE RESTRICT ON DELETE RESTRICT;
>> 
>> ALTER TABLE public.abilitazione
>>   ADD CONSTRAINT abilitazione_chiaveid_fkey FOREIGN KEY (comuneid,
>> chiaveid) REFERENCES public.chiave (comuneid, chiaveid) ON UPDATE
>> RESTRICT ON DELETE RESTRICT;
>> 
>> here those of cassonetto and chiave:
>> 
>> ALTER TABLE public.cassonetto
>>   ADD CONSTRAINT cassonetto_pkey PRIMARY KEY(comuneid, cassonettoid);
>> 
>> ALTER TABLE public.chiave
>>   ADD CONSTRAINT chiave_pkey PRIMARY KEY(comuneid, chiaveid);
>> 
>> I get the SQL from pgAdmin3 (great piece of sofware!;-)
>> 
>>> It's usually best to cut'n'paste the CREATE TABLE or ALTER TABLE 
>>> statements that are used to create the constraints. That way we know 
>>> exactly what you're talking about.
>> 
>> Excuse me for the missing SQL, but i had tried to keep the message as
>> simple as possible.
>> 
>> The unique difference form when the exception was raised and now (that
>> it isn't) is the rule added:
>> 
>> CREATE OR REPLACE RULE abilita_ins_rl AS  ON INSERT TO abilitazione 
>>   WHERE (EXISTS (
>>              SELECT 1 FROM abilitazione 
>>               WHERE (((abilitazione.comuneid = new.comuneid ) 
>>         AND (abilitazione.cassonettoid = new.cassonettoid )) 
>>         AND (abilitazione.chiaveid = new.chiaveid ))))ù
>>      DO INSTEAD UPDATE abilitazione SET abilitata = new.abilitata 
>>         WHERE (((abilitazione.comuneid = new.comuneid ) 
>>     AND (abilitazione.cassonettoid = new.cassonettoid )) 
>>     AND (abilitazione.chiaveid = new.chiaveid )); 
>> 
>> I hope now is more clear.
>> 
>> The version is that come with debian unstable (7.3.4 if I remember
>> correctly)
>> 
>> Thank you for the immediate responses
>> 
>> ciao, Michele
> 
> 
> 
> 
> ------------------------------------------------------------------------
> 
> #!/bin/sh
> 
> DBNAME=testdb
> export DBNAME
> 
> dropdb ${DBNAME}
> createdb ${DBNAME}
> 
> psql -e ${DBNAME} <<_EOF_
> 
> create table t1 (
>     id1a integer,
>     id1b integer,
>     
>     primary key (id1a, id1b)
> );
> 
> create table t2 (
>     id2a integer,
>     id2c integer,
>     
>     primary key (id2a, id2c)
> );
> 
> create table t3 (
>     id3a integer,
>     id3b integer,
>     id3c integer,
>     data text,
> 
>     primary key (id3a, id3b, id3c),
> 
>     foreign key (id3a, id3b) references t1 (id1a, id1b),
>     foreign key (id3a, id3c) references t2 (id2a, id2c)
> );
> 
> 
> insert into t1 values (1, 11);
> insert into t1 values (1, 12);
> insert into t1 values (2, 21);
> insert into t1 values (2, 22);
> 
> insert into t2 values (1, 11);
> insert into t2 values (1, 12);
> insert into t2 values (2, 21);
> insert into t2 values (2, 22);
> 
> insert into t3 values (1, 11, 11, 'row1');
> insert into t3 values (1, 11, 12, 'row2');
> insert into t3 values (1, 12, 11, 'row3');
> insert into t3 values (1, 12, 12, 'row4');
> insert into t3 values (1, 11, 13, 'row5');
> insert into t3 values (1, 13, 11, 'row6');
> 
> create rule t3_ins as on insert to t3
>     where (exists (select 1 from t3
>             where (((t3.id3a = new.id3a)
>             and (t3.id3b = new.id3b))
>             and (t3.id3c = new.id3c))))
>     do instead update t3 set data = new.data
>     where (((t3.id3a = new.id3a)
>     and (t3.id3b = new.id3b))
>     and (t3.id3c = new.id3c));
> 
> insert into t3 values (1, 11, 13, 'row7');
> insert into t3 values (1, 13, 11, 'row8');
> 
> select * from t3;
> 
> select version();
> _EOF_
> 
> 
> ------------------------------------------------------------------------
> 
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
> 
>                http://archives.postgresql.org


-- 
#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#================================================== JanWieck@Yahoo.com #



pgsql-sql by date:

Previous
From: "Kumar"
Date:
Subject: Re: Using UNION inside a cursor
Next
From: Michele Bendazzoli
Date:
Subject: Re: 7.4 and 7.3.5 showstopper (was: Re: Bug in Rule+Foreing