Обсуждение: a row not deletes

Поиск
Список
Период
Сортировка

a row not deletes

От
Rafał Pietrak
Дата:
Hi the list,

I've just experienced an unexpected (for me) "loss" of DELETE. Is this a
feature or a bug (postgres v.s. SQL)?

-------------------- test case -------------------------
test=# CREATE  TABLE test (a int, b text);
test=# INSERT  INTO  test (a,b) values (1,'asd');
test=# INSERT  INTO  test (a,b) values (2,'dfg');
test=# INSERT  INTO  test (a,b) values (3,'ghj');
test=# CREATE or replace FUNCTION test_del () returns trigger language
plpgsql as $$ begin  update test t set b = 'will delete this' where
t.a=old.a; return old; end; $$;
test=# CREATE  TRIGGER  test_trig BEFORE DELETE ON test for each row
execute procedure test_del();

test=# DELETE FROM  test where a=2;
DELETE 0
test=# SELECT * from test;
  a  |  b
----+-----
   1 | asd
   3 | ghj
   2 | will delete this
(3 rows)
--------------------------------------------------------

e.g.: an indicated row is not deleted, despite the fact, that the
selector wasn't changed by the intermediate UPDATE.  I understand, that
the bucket was changed by the update, but should that matter?

-R


Re: a row not deletes

От
Andres Freund
Дата:
Hi,

On 2014-04-27 10:23:18 +0200, Rafał Pietrak wrote:
> I've just experienced an unexpected (for me) "loss" of DELETE. Is this a
> feature or a bug (postgres v.s. SQL)?
>
> -------------------- test case -------------------------
> test=# CREATE  TABLE test (a int, b text);
> test=# INSERT  INTO  test (a,b) values (1,'asd');
> test=# INSERT  INTO  test (a,b) values (2,'dfg');
> test=# INSERT  INTO  test (a,b) values (3,'ghj');
> test=# CREATE or replace FUNCTION test_del () returns trigger language
> plpgsql as $$ begin  update test t set b = 'will delete this' where
> t.a=old.a; return old; end; $$;
> test=# CREATE  TRIGGER  test_trig BEFORE DELETE ON test for each row execute
> procedure test_del();
>
> test=# DELETE FROM  test where a=2;
> DELETE 0
> test=# SELECT * from test;
>  a  |  b
> ----+-----
>   1 | asd
>   3 | ghj
>   2 | will delete this
> (3 rows)
> --------------------------------------------------------
>
> e.g.: an indicated row is not deleted, despite the fact, that the selector
> wasn't changed by the intermediate UPDATE.  I understand, that the bucket
> was changed by the update, but should that matter?

I guess you're using 9.2 or older? You are not allowed to update the
deleted row in a BEFORE trigger. The source has this comment about it
(in 9.3 onwards):

/*
 * The target tuple was already updated or deleted by the
 * current command, or by a later command in the current
 * transaction.  The former case is possible in a join DELETE
 * where multiple tuples join to the same target tuple. This
 * is somewhat questionable, but Postgres has always allowed
 * it: we just ignore additional deletion attempts.
 *
 * The latter case arises if the tuple is modified by a
 * command in a BEFORE trigger, or perhaps by a command in a
 * volatile function used in the query.  In such situations we
 * should not ignore the deletion, but it is equally unsafe to
 * proceed.  We don't want to discard the original DELETE
 * while keeping the triggered actions based on its deletion;
 * and it would be no better to allow the original DELETE
 * while discarding updates that it triggered.  The row update
 * carries some information that might be important according
 * to business rules; so throwing an error is the only safe
 * course.
 *
 * If a trigger actually intends this type of interaction, it
 * can re-execute the DELETE and then return NULL to cancel
 * the outer delete.
 */
if (hufd.cmax != estate->es_output_cid)
        ereport(ERROR,
                        (errcode(ERRCODE_TRIGGERED_DATA_CHANGE_VIOLATION),
                         errmsg("tuple to be updated was already modified by an operation triggered by the current
command"),
                         errhint("Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to
otherrows."))); 



Greetings,

Andres Freund

--
 Andres Freund                       http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training & Services


Re: a row not deletes

От
David G Johnston
Дата:
Andres Freund-3 wrote
> Hi,
>
> On 2014-04-27 10:23:18 +0200, Rafał Pietrak wrote:
>> I've just experienced an unexpected (for me) "loss" of DELETE. Is this a
>> feature or a bug (postgres v.s. SQL)?
>
> I guess you're using 9.2 or older? You are not allowed to update the
> deleted row in a BEFORE trigger. The source has this comment about it
> (in 9.3 onwards):

IOW, it is a bug discovered during the 9.2 release that was deemed improper
to back-patch.

However, the bug applies to behavior that should only happen by mistake; you
should not have a trigger that updates the row you are currently deleting.
But since the behavior results is working code breaking it in a released
branch is frowned upon.

David J.





--
View this message in context: http://postgresql.1045698.n5.nabble.com/a-row-not-deletes-tp5801654p5801658.html
Sent from the PostgreSQL - general mailing list archive at Nabble.com.


Re: a row not deletes

От
Rafał Pietrak
Дата:
Thenx for explanations.


W dniu 27.04.2014 16:56, David G Johnston pisze:
> Andres Freund-3 wrote
>> Hi,
>>
>> On 2014-04-27 10:23:18 +0200, Rafał Pietrak wrote:
>>> I've just experienced an unexpected (for me) "loss" of DELETE. Is this a
>>> feature or a bug (postgres v.s. SQL)?
>> I guess you're using 9.2 or older? You are not allowed to update the
>> deleted row in a BEFORE trigger. The source has this comment about it
>> (in 9.3 onwards):

I'm using 9.1 (as of debian wheezy)

> IOW, it is a bug discovered during the 9.2 release that was deemed improper
> to back-patch.
>
> However, the bug applies to behavior that should only happen by mistake; you
> should not have a trigger that updates the row you are currently deleting.

Hmmm. I was just exersising it, as the most "elegant" resolve to my case:
1. I have a shopping chart with items
2. which (conditionally) turns into an invoice on chart deletion.
3. the assumption is: the chart is not very rigouroiusly checked during
its lifetime.
4. but the invoice have to .... so some "cleanup" is due just before an
item is deleted from the chart.

But, I understand that as of now, I cannot do that by "trigger
avalanche" :(

-R