Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE

Lists: pgsql-general
From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: pgsql-general(at)postgresql(dot)org
Subject: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 12:35:52
Message-ID: AANLkTimMaAubbjElLBxuHFLBGzBwFKOLQm7fpHbHV09g@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

consider following example:

CREATE TABLE foob(id serial primary key, name varchar default '');
CREATE TABLE fooA(id serial primary key, fooB int not null references
fooB(id) on update cascade on delete cascade, name varchar default
'');

CREATE FUNCTION foobarrA() RETURNS trigger AS
$_$
BEGIN
RAISE NOTICE 'foobarred %', (SELECT name FROM fooB WHERE id = OLD.fooB);
RETURN OLD;
END;
$_$ LANGUAGE 'plpgsql';

CREATE TRIGGER foobarrrred BEFORE DELETE ON fooA FOR EACH ROW EXECUTE
PROCEDURE foobarrA();
insert into foob(name) select random()::varchar FROM generate_series(1,100);
insert into fooa(name, foob) select random()::varchar, (select id from
foob order by random() limit 1) FROM generate_series(1,100);

select foob from fooa order by random() limit 1;
foob
------
70
(1 row)

DELETE FROM foob where id =70;
NOTICE: foobarred <NULL>
CONTEXT: SQL statement "DELETE FROM ONLY "public"."fooa" WHERE $1
OPERATOR(pg_catalog.=) "foob""
NOTICE: foobarred <NULL>

I always assumed, that since triggers are set to BEFORE, the data will
still exist in the tables when they are fired, it will still be
accessible. I looked in the manual, and there is no mention of that
effect anywhere I can find.

And here's the question, is there any way in which I can overcome that
(to me) problem ? Other than, by substituting foreign key with my own
trigger, to handle that situation and than delete data.

thank you .

--
GJ


From: Thom Brown <thombrown(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 13:22:11
Message-ID: AANLkTinLacojJy-4G5rtkEALVpSMfFKzwR5iQnxd7ta-@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

2010/6/23 Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>:
> consider following example:
>
>
>
> CREATE TABLE foob(id serial primary key, name varchar default '');
> CREATE TABLE fooA(id serial primary key, fooB int not null references
> fooB(id) on update cascade on delete cascade, name varchar default
> '');
>
> CREATE FUNCTION foobarrA() RETURNS trigger AS
> $_$
> BEGIN
>  RAISE NOTICE 'foobarred %', (SELECT name FROM fooB WHERE id = OLD.fooB);
>  RETURN OLD;
> END;
> $_$ LANGUAGE 'plpgsql';
>
> CREATE TRIGGER foobarrrred BEFORE DELETE ON fooA FOR EACH ROW EXECUTE
> PROCEDURE foobarrA();
> insert into foob(name) select random()::varchar FROM generate_series(1,100);
> insert into fooa(name, foob) select random()::varchar, (select id from
> foob order by random() limit 1) FROM generate_series(1,100);
>
> select foob from fooa order by random() limit 1;
>  foob
> ------
>   70
> (1 row)
>
> DELETE FROM foob where id =70;
> NOTICE:  foobarred <NULL>
> CONTEXT:  SQL statement "DELETE FROM ONLY "public"."fooa" WHERE $1
> OPERATOR(pg_catalog.=) "foob""
> NOTICE:  foobarred <NULL>
>
>
>
> I always assumed, that since triggers are set to BEFORE, the data will
> still exist in the tables when they are fired, it will still be
> accessible. I looked in the manual, and there is no mention of that
> effect anywhere I can find.

It is in there: http://www.postgresql.org/docs/8.4/static/sql-createtrigger.html

"SQL specifies that BEFORE DELETE triggers on cascaded deletes fire
after the cascaded DELETE completes. The PostgreSQL behavior is for
BEFORE DELETE to always fire before the delete action, even a
cascading one. This is considered more consistent. There is also
unpredictable behavior when BEFORE triggers modify rows that are
later to be modified by referential actions. This can lead to
constraint violations or stored data that does not honor the
referential constraint. "

But it sounds like it's not doing that.

Thom


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: Thom Brown <thombrown(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 13:43:12
Message-ID: AANLkTild3vyTu9jQ5lNAAIfOvWBNvrv0axdssNex-0AL@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

this is 8.3.7, for the record. And no, They won't let me update it to 8.3.11 :/


From: Thom Brown <thombrown(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 13:50:31
Message-ID: AANLkTik0SYgfg_ezIyLxRYoVSQOvdMYt6Ok64tG6wA-f@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

2010/6/23 Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>:
> this is 8.3.7, for the record. And no, They won't let me update it to 8.3.11 :/
>

Well, same applies:
http://www.postgresql.org/docs/8.3/static/sql-createtrigger.html

I've just run the same set of statements you specified against 8.4.1,
8.4.4 and 9.0 beta2 and the same thing happens:

NOTICE: foobarred <NULL>
CONTEXT: SQL statement "DELETE FROM ONLY "public"."fooa" WHERE $1
OPERATOR(pg_catalog.=) "foob""

Thom


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: Thom Brown <thombrown(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 13:52:32
Message-ID: AANLkTilOQeKjs2NdhGcB2Kk1FyBt1octqgl5_ThgJJX3@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

any ideas than, how can make it actually do what I wanted it to do please ?
Making FK deferrable doesn't help.

thanks.


From: Adrian Klaver <adrian(dot)klaver(at)gmail(dot)com>
To: pgsql-general(at)postgresql(dot)org
Cc: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 14:00:02
Message-ID: 201006230700.03390.adrian.klaver@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

On Wednesday 23 June 2010 5:35:52 am Grzegorz Jaśkiewicz wrote:
> consider following example:
>
>
>
> CREATE TABLE foob(id serial primary key, name varchar default '');
> CREATE TABLE fooA(id serial primary key, fooB int not null references
> fooB(id) on update cascade on delete cascade, name varchar default
> '');
>
> CREATE FUNCTION foobarrA() RETURNS trigger AS
> $_$
> BEGIN
> RAISE NOTICE 'foobarred %', (SELECT name FROM fooB WHERE id = OLD.fooB);
> RETURN OLD;
> END;
> $_$ LANGUAGE 'plpgsql';
>
> CREATE TRIGGER foobarrrred BEFORE DELETE ON fooA FOR EACH ROW EXECUTE
> PROCEDURE foobarrA();
> insert into foob(name) select random()::varchar FROM
> generate_series(1,100); insert into fooa(name, foob) select
> random()::varchar, (select id from foob order by random() limit 1) FROM
> generate_series(1,100);
>
> select foob from fooa order by random() limit 1;
> foob
> ------
> 70
> (1 row)
>
> DELETE FROM foob where id =70;
> NOTICE: foobarred <NULL>
> CONTEXT: SQL statement "DELETE FROM ONLY "public"."fooa" WHERE $1
> OPERATOR(pg_catalog.=) "foob""
> NOTICE: foobarred <NULL>
>
>
>
> I always assumed, that since triggers are set to BEFORE, the data will
> still exist in the tables when they are fired, it will still be
> accessible. I looked in the manual, and there is no mention of that
> effect anywhere I can find.
>
>
> And here's the question, is there any way in which I can overcome that
> (to me) problem ? Other than, by substituting foreign key with my own
> trigger, to handle that situation and than delete data.
>
>
> thank you .
>
> --
> GJ

My suspicion is that this is an identifier problem. See error below:
CONTEXT: SQL statement "DELETE FROM ONLY "public"."fooa" WHERE $1
OPERATOR(pg_catalog.=) "foob"" <--- ***

It would seem to me there is confusion between the table fooB(b) and the column
foob. I am afraid at this point I can not be any more helpful.

--
Adrian Klaver
adrian(dot)klaver(at)gmail(dot)com


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: adrian(dot)klaver(at)gmail(dot)com
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 14:02:59
Message-ID: AANLkTimsOobrFHIaUMqwSHiqMP5fajv3gfoiAUgslyvp@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

nope, that's not the thing. This is just specific to my example. But
production code I have, doesn't have such confusing name, and still
fails.
Plus postgresql doesn't rely on names, but on oids rather.


From: Thom Brown <thombrown(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 14:03:06
Message-ID: AANLkTind0gE4K7lTiHdlmfJMD-P79J-Qgj32JYJQxZ9W@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

2010/6/23 Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>:
> any ideas than, how can make it actually do what I wanted it to do please ?
> Making FK deferrable doesn't help.
>
>
> thanks.
>

Is it practical to put the trigger on the other table instead?

Thom


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: Thom Brown <thombrown(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 14:07:36
Message-ID: AANLkTik73TGN9Ukh84R_2fIRYAH24EH83vM8DIo6wA0C@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

not really, as it depends on pretty much both tables.
This is where de-normalization would actually makes sens, except for
that it wouldn't - because it will badly effect all my other queries
(joining on varchar is so slow).

I could drop FK, and replace that with my own trigger(s), but that's a
lot of mess.
Other idea, is to maintain some sort of a temp table that will hold
all names deleted, and use it. But still, not very nice nor obviuos.

--
GJ


From: Adrian Klaver <adrian(dot)klaver(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 14:43:28
Message-ID: 201006230743.29111.adrian.klaver@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

On Wednesday 23 June 2010 7:02:59 am Grzegorz Jaśkiewicz wrote:
> nope, that's not the thing. This is just specific to my example. But
> production code I have, doesn't have such confusing name, and still
> fails.
> Plus postgresql doesn't rely on names, but on oids rather.

For what it worth I tried it on my versions of 8.3.7 and 8.4.3 and it worked, so
there is something else going on here. As to Postgres not relying on names, how
do you think the backend finds the OIDS?

--
Adrian Klaver
adrian(dot)klaver(at)gmail(dot)com


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: adrian(dot)klaver(at)gmail(dot)com
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 14:57:22
Message-ID: AANLkTind5DyBGrpKZLEYqcv7cwFoIUupDY_kAopgTyci@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

well, change foob column name to something else, and try yourself. It
still fails.


From: Adrian Klaver <adrian(dot)klaver(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 15:15:03
Message-ID: 201006230815.03229.adrian.klaver@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

On Wednesday 23 June 2010 7:57:22 am Grzegorz Jaśkiewicz wrote:
> well, change foob column name to something else, and try yourself. It
> still fails.

As I said in my previous post it did not fail on my instance of 8.3.7. In other
words the DELETE succeeded. At this point I do not have an explanation, other
then something different between my installation and your and Thom's
installations are causing the problem. For what it is worth I installed from
source with locale of en_US and encoding of UTF8.

--
Adrian Klaver
adrian(dot)klaver(at)gmail(dot)com


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: adrian(dot)klaver(at)gmail(dot)com
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 15:22:00
Message-ID: AANLkTimBJllquRD6fX3OC8cgtiNwDoe0T4DKh1gxYT78@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

the delete will succeed.
That's not the point of the exercise tho.

The point, is to print name in trigger, rather than null!


From: Thom Brown <thombrown(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: adrian(dot)klaver(at)gmail(dot)com, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 15:22:31
Message-ID: AANLkTilKw6C8RqNrFy3RSgJ_87fED3CuTmDCI9mKEeP_@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

2010/6/23 Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>:
> well, change foob column name to something else, and try yourself. It
> still fails.
>

Wait a minute... it's deleting from foob, which is considered deleted
for the remainder of that transaction. This cascades to fooa which
sets off the trigger before it does anything, and the result you're
getting out says that the same value is no longer is foob, which,
while not yet committed, is true as far as the transaction is
concerned. This is confusing because I thought the default
transaction isolation level was READ COMMITTED. :/

Regards

Thom


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: Thom Brown <thombrown(at)gmail(dot)com>
Cc: adrian(dot)klaver(at)gmail(dot)com, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 15:31:40
Message-ID: AANLkTin79_wj1KcfqG56ikqIKxMh7zVYPmuG3nuFAoLz@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

it is confusing to me, because I thought triggers are firring BEFORE
anything goes away. So I assume that all data is still going to be
visible to the trigger, as it is firing BEFORE. The only thing is, it
looks like the FKs are doing the deletion and than things are handed
over to triggers.


From: Thom Brown <thombrown(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: adrian(dot)klaver(at)gmail(dot)com, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 15:33:10
Message-ID: AANLkTinS_LBPGYIExNu-Amw16d9MGoDWtiiyrKv5tcVf@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

2010/6/23 Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>:
> the delete will succeed.
> That's not the point of the exercise tho.
>
> The point, is to print name in trigger, rather than null!
>

But if it's been deleted from foob already, how can it print it?

So if foob has a row with an id of 5, then:
DELETE FROM foob WHERE id = 5;

That row is deleted from foob.
This cascades to attempt to delete it from fooa.
The trigger happens first though which tries to find the row from foob
where id = 5... but it's already been deleted, so no name is selected.

To demonstrate, change your trigger function to:

create FUNCTION foobarrA() RETURNS trigger AS
$_$
BEGIN
RAISE NOTICE 'foobarred %', (SELECT name FROM fooB WHERE id = 999);
RETURN OLD;
END;
$_$ LANGUAGE 'plpgsql';

and add in:

insert into foob(id, name) values (999, 'stuff');
insert into fooa(id, foob) values (999, 999);

after your inserts. This will successfully select the value because
it's not deleted. And then running:

DELETE FROM foob where id =999;

Will return NULL again because it's just been deleted before the
trigger on fooa.

So cases where it's returning NULL is because there's been no match.

Thom


From: Thom Brown <thombrown(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: adrian(dot)klaver(at)gmail(dot)com, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 15:35:05
Message-ID: AANLkTinHaWfy7k0w8XREpBczNQRZOqUcR1PXs-aGrPQ4@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

2010/6/23 Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>:
> it is confusing to me, because I thought triggers are firring BEFORE
> anything goes away. So I assume that all data is still going to be
> visible to the trigger, as it is firing BEFORE. The only thing is, it
> looks like the FKs are doing the deletion and than things are handed
> over to triggers.
>

The trigger is on fooa though, not foob. foob's deletions occur
before cascading to fooa, and only then does the function trigger.

I still think tranaction isolation level should come into this somewhere.

Thom


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: Thom Brown <thombrown(at)gmail(dot)com>
Cc: adrian(dot)klaver(at)gmail(dot)com, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 15:41:13
Message-ID: AANLkTilqb9PztWek-tKxi_qvnOI0yM0RBacgErfYkWRh@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

I do understand what you are saying, but still it is highly
unintuitive. Since trigger is BEFORE, developer will expect that data
to be there.


From: Thom Brown <thombrown(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: adrian(dot)klaver(at)gmail(dot)com, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 15:43:27
Message-ID: AANLkTimcUk3ZShGC8Wcu8itdnsq-jsJLz0YkefHslywC@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

2010/6/23 Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>:
> I do understand what you are saying, but still it is highly
> unintuitive. Since trigger is BEFORE, developer will expect that data
> to be there.
>

Yes, I'm still not exactly sure why it's seeing uncommitted changes. :/

Thom


From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: Thom Brown <thombrown(at)gmail(dot)com>
Cc: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>, adrian(dot)klaver(at)gmail(dot)com, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 18:31:02
Message-ID: 25742.1277317862@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

Thom Brown <thombrown(at)gmail(dot)com> writes:
> Yes, I'm still not exactly sure why it's seeing uncommitted changes. :/

Because it's all one transaction. A transaction that couldn't see its
own changes wouldn't be very useful.

I think what the OP is unhappy about is that he imagines that the ON
CASCADE DELETE action is part of the original DELETE on the primary-key
table. But it is not: per SQL spec, it is a separate operation
happening after the original DELETE. (In fact, it might be quite a lot
after the original delete, if you have the FK constraint set as
deferred.) The trigger on the referencing table fires before the actual
delete of the referencing row, but it's going to see the original DELETE
statement as already completed, because it was a previous operation
within the current transaction.

regards, tom lane


From: Adrian Klaver <adrian(dot)klaver(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-23 19:07:51
Message-ID: 4C225B87.8080305@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

On 06/23/2010 08:22 AM, Grzegorz Jaśkiewicz wrote:
> the delete will succeed.
> That's not the point of the exercise tho.
>
> The point, is to print name in trigger, rather than null!

Sorry about the noise, I completely missed what you where getting at.
--
Adrian Klaver
adrian(dot)klaver(at)gmail(dot)com


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: Thom Brown <thombrown(at)gmail(dot)com>, adrian(dot)klaver(at)gmail(dot)com, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-24 08:48:12
Message-ID: AANLkTindynBfTTvUqZL5y3XdgNl-ivlyk3PLnii2A3DA@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

On Wed, Jun 23, 2010 at 7:31 PM, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
> Thom Brown <thombrown(at)gmail(dot)com> writes:
>> Yes, I'm still not exactly sure why it's seeing uncommitted changes. :/
>
> Because it's all one transaction.  A transaction that couldn't see its
> own changes wouldn't be very useful.
>
> I think what the OP is unhappy about is that he imagines that the ON
> CASCADE DELETE action is part of the original DELETE on the primary-key
> table.  But it is not: per SQL spec, it is a separate operation
> happening after the original DELETE.  (In fact, it might be quite a lot
> after the original delete, if you have the FK constraint set as
> deferred.)  The trigger on the referencing table fires before the actual
> delete of the referencing row, but it's going to see the original DELETE
> statement as already completed, because it was a previous operation
> within the current transaction.

That's all great Tom, but it breaks useful example like mine, and
gives no other benefits.

I will have to do something ugly, and create temp table to hold fooB
deleted values, for reference from other threads.
Temp, on commit drop. Not a very nice programming trick, but cleanest
I can come up with.

--
GJ


From: Adrian Klaver <adrian(dot)klaver(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Thom Brown <thombrown(at)gmail(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-24 13:51:28
Message-ID: 201006240651.28580.adrian.klaver@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

On Thursday 24 June 2010 1:48:12 am Grzegorz Jaśkiewicz wrote:
> On Wed, Jun 23, 2010 at 7:31 PM, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
> > Thom Brown <thombrown(at)gmail(dot)com> writes:
> >> Yes, I'm still not exactly sure why it's seeing uncommitted changes. :/
> >
> > Because it's all one transaction.  A transaction that couldn't see its
> > own changes wouldn't be very useful.
> >
> > I think what the OP is unhappy about is that he imagines that the ON
> > CASCADE DELETE action is part of the original DELETE on the primary-key
> > table.  But it is not: per SQL spec, it is a separate operation
> > happening after the original DELETE.  (In fact, it might be quite a lot
> > after the original delete, if you have the FK constraint set as
> > deferred.)  The trigger on the referencing table fires before the actual
> > delete of the referencing row, but it's going to see the original DELETE
> > statement as already completed, because it was a previous operation
> > within the current transaction.
>
> That's all great Tom, but it breaks useful example like mine, and
> gives no other benefits.
>
> I will have to do something ugly, and create temp table to hold fooB
> deleted values, for reference from other threads.
> Temp, on commit drop. Not a very nice programming trick, but cleanest
> I can come up with.

I know I was confused before, but now I am not sure. Unless there is more to
this problem, why not put the trigger on fooB?

CREATE FUNCTION foobarrb() RETURNS trigger AS
$_$
BEGIN
RAISE NOTICE 'foobarred %', (OLD.name );
RETURN OLD;
END;
$_$ LANGUAGE 'plpgsql';

CREATE TRIGGER foobarrrred BEFORE DELETE ON foob FOR EACH ROW EXECUTE
PROCEDURE foobarrb();

test=> DELETE FROM foob where id=8;
NOTICE: foobarred 0.37025912059471
DELETE 1

--
Adrian Klaver
adrian(dot)klaver(at)gmail(dot)com


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: adrian(dot)klaver(at)gmail(dot)com
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Thom Brown <thombrown(at)gmail(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-24 14:21:04
Message-ID: AANLkTiljmLsg5zxSYbnf9fgB_0CuFtuTYFSNrjGYk1sZ@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

because in my case I have many tables with FK pointing at foob. So
writing that many triggers is going to be a royal pain.


From: Adrian Klaver <adrian(dot)klaver(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Thom Brown <thombrown(at)gmail(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-24 14:29:20
Message-ID: 201006240729.21260.adrian.klaver@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

On Thursday 24 June 2010 7:21:04 am Grzegorz Jaśkiewicz wrote:
> because in my case I have many tables with FK pointing at foob. So
> writing that many triggers is going to be a royal pain.

I am trying to see how this is different from writing the triggers on the child
tables :) In any case are they not all pointing the at the same value in foob?
From what you have described you are trying to capture the name associated with
the id deleted in foob, so I am not sure why the child tables need to be
involved.

--
Adrian Klaver
adrian(dot)klaver(at)gmail(dot)com


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: adrian(dot)klaver(at)gmail(dot)com
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Thom Brown <thombrown(at)gmail(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-24 14:40:22
Message-ID: AANLkTin3ssamL1VX3pRUG6c6nyjMqAdxdV5yYxjw2RJb@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

that Id refers to 'name' column that I need. There still is FK on it,
so basically it is broken inside transaction, from trigger's
perspective.


From: Adrian Klaver <adrian(dot)klaver(at)gmail(dot)com>
To: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Thom Brown <thombrown(at)gmail(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-24 14:46:36
Message-ID: 201006240746.36548.adrian.klaver@gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

On Thursday 24 June 2010 7:40:22 am Grzegorz Jaśkiewicz wrote:
> that Id refers to 'name' column that I need. There still is FK on it,
> so basically it is broken inside transaction, from trigger's
> perspective.

I understand this part. What I am saying is think about reversing your point of
view. Instead of pulling the information from foob, push out the information
from foob.

--
Adrian Klaver
adrian(dot)klaver(at)gmail(dot)com


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: adrian(dot)klaver(at)gmail(dot)com
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Thom Brown <thombrown(at)gmail(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-24 15:02:50
Message-ID: AANLkTimHLCq69fv9ukDl4Shdiw7qcPXCXKu5vgbPXsYx@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

it is slightly more complicated than that, cos I need information from
fooA too. So we have a chicken and egg problem.


From: Grzegorz Jaśkiewicz <gryzman(at)gmail(dot)com>
To: adrian(dot)klaver(at)gmail(dot)com
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Thom Brown <thombrown(at)gmail(dot)com>, pgsql-general(at)postgresql(dot)org
Subject: Re: unexpected effect of FOREIGN KEY ON CASCADE DELETE
Date: 2010-06-24 15:04:40
Message-ID: AANLkTilC5kcY2RIIeGlh8ptHKIwjwwxop9bCEceiefcW@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-general

I'll fix it this way:

CREATE TABLE foob(id serial primary key, name varchar default '');
CREATE TABLE fooA(id serial primary key, fooBook int not null
references fooB(id) on update cascade on delete cascade DEFERRABLE,
name varchar default '');

CREATE FUNCTION foobarrB() RETURNS trigger AS
$_$
BEGIN
BEGIN
INSERT INTO foob_temp(id, name) VALUES(OLD.id, OLD.name);
EXCEPTION
WHEN undefined_table THEN
CREATE TEMP TABLE foob_temp(id bigint not null, name varchar not
null) ON COMMIT DROP;
INSERT INTO foob_temp(id, name) VALUES(OLD.id, OLD.name);
END;

RETURN OLD;
END;
$_$ LANGUAGE 'plpgsql';

CREATE TRIGGER foobbrrrred BEFORE DELETE ON fooB FOR EACH ROW EXECUTE
PROCEDURE foobarrB();

CREATE FUNCTION foobarrA() RETURNS trigger AS
$_$
DECLARE
_name varchar;
BEGIN
BEGIN
SELECT name INTO _name FROM foob_temp WHERE id = OLD.fooBook;
EXCEPTION
WHEN undefined_table THEN
SELECT name INTO _name FROM fooB WHERE id = OLD.fooBook;
END;

RAISE NOTICE 'foobarred %', _name;
RETURN OLD;
END;
$_$ LANGUAGE 'plpgsql';

CREATE TRIGGER fooaarrrred BEFORE DELETE ON fooA FOR EACH ROW EXECUTE
PROCEDURE foobarrA();

insert into foob(name) select random()::varchar FROM generate_series(1,1000);
insert into fooa(name, fooBook) select random()::varchar, bb.id FROM
(select id from foob order by random() limit 1) bb,
generate_series(1,100);

DELETE FROM foob where id in (select foobook from fooa order by
random() limit 3);