Thread: Delete rule chain stops unexpectedly

Delete rule chain stops unexpectedly

From
Wiebe Cazemier
Date:
Hi,

I've got the following table (contents not really relevant):

CREATE TABLE _rating_params (  id SERIAL PRIMARY KEY,  letter CHAR(1) NOT NULL CHECK (letter = 'E' OR letter = 'F'),
superparam_idINTEGER REFERENCES _rating_params,  seq_num INTEGER NOT NULL DEFAULT 1,  name_id INTEGER NOT NULL
REFERENCESmessages_eng,  max_score NUMERIC(4)
 
);

which I manipulate with the view "rating_params". The delete rules on this view 
act very strangely. They are, with comments I'll explain:

-- Actually delete the rating param, along with all it's subparams
CREATE RULE delete1 AS ON DELETE TO rating_params DO INSTEAD (  INSERT INTO debuglog (line) VALUES('step1');
  -- When I comment out this line, then the other rules _are_ executed. If I 
leave it here, execution stops here, after this query.  DELETE FROM _rating_params WHERE id = OLD.id OR
superparam_id=OLD.id;
  INSERT INTO debuglog (line) VALUES('step2');
);

-- Renumber sequences in order not to get any gaps
CREATE RULE delete2 AS ON DELETE TO rating_params DO ALSO (  UPDATE _rating_params SET seq_num = seq_num - 1  WHERE
superparam_id= OLD.superparam_id AND seq_num > OLD.seq_num;
 
  INSERT INTO debuglog (line) VALUES('step3');
);

-- Remove the max. score from any maximum total scores
CREATE RULE delete3 AS ON DELETE TO rating_params WHERE OLD.superparam_id IS NOT 
NULL DO ALSO (  UPDATE _rating_params SET max_score = rating_param_max_score(id)  WHERE id = OLD.superparam_id;
  INSERT INTO debuglog (line) VALUES('step4');
);

As you can see I've put several debug messages in the rules. As it is now, only 
step1 is put in the debuglog table. When I remove the query to delete from the 
_rating_params table, all other rules are executed and the debug messages are 
inserted.

The strangest is yet to come. Normally I would delete with "delete from 
rating_params where id=5". But, when I do "explain analyze delete from 
rating_params where id=5", all the rules _are_ executed properly.

I'm using postgresql 8.0.3.

Anybody got an idea?

Thanks in advance.


Re: Delete rule chain stops unexpectedly

From
Tom Lane
Date:
Wiebe Cazemier <halfgaar@gmail.com> writes:
> which I manipulate with the view "rating_params". The delete rules on this view 
> act very strangely.

The rule that actually deletes the rows from the underlying has to fire
last, since the rows are gone from the view (and hence from OLD) the
moment you delete them.

In practice, you'd be way better off using an ON DELETE trigger for
these tasks.
        regards, tom lane


Re: Delete rule chain stops unexpectedly

From
Wiebe Cazemier
Date:
Tom Lane wrote:> The rule that actually deletes the rows from the underlying has to fire> last, since the rows are gone
fromthe view (and hence from OLD) the> moment you delete them.
 

A quote from the postgresql manual:

"But for ON UPDATE and ON DELETE rules, the original query is done after the 
actions added by rules. This ensures that the actions can see the to-be-updated 
or to-be-deleted rows"

So, the actual delete should be done after all the rules. And even if it does 
delete before anything else, that does not explain why "step2" is not inserted 
into the debuglog table. Or, that all the rules _are_ executed when I call the 
query with "explain analayze".


Re: Delete rule chain stops unexpectedly

From
Tom Lane
Date:
Wiebe Cazemier <halfgaar@gmail.com> writes:
> Tom Lane wrote:
>>> The rule that actually deletes the rows from the underlying has to fire
>>> last, since the rows are gone from the view (and hence from OLD) the
>>> moment you delete them.

> A quote from the postgresql manual:

> "But for ON UPDATE and ON DELETE rules, the original query is done after the 
> actions added by rules. This ensures that the actions can see the to-be-updated 
> or to-be-deleted rows"

Yes, I know that quote.  I wrote it.  It's not relevant here because the
original query (the delete against the view) is never done at all, since
you have a DO INSTEAD rule.  What is relevant is the timing of the
delete issued against the underlying table, and you have that scheduled
to occur too early because the rule that does it is first in
alphabetical order.

> So, the actual delete should be done after all the rules. And even if
> it does delete before anything else, that does not explain why "step2"
> is not inserted into the debuglog table.

Because the rule converts those inserts into, effectively,
INSERT INTO debuglog SELECT ... WHERE EXISTS(some matching OLD row);

and there are no longer any matching OLD rows in the view.  (If it
didn't act that way then the INSERTs would execute even for a "DELETE
WHERE false".  If you find any of this surprising or not what you want,
you should probably be using triggers not rules.)

> Or, that all the rules _are_
> executed when I call the query with "explain analayze".

Hmm ... this appears to be a bug in EXPLAIN ANALYZE: it really should
bump the CommandCounter between plan trees, but fails to ...
        regards, tom lane


Re: Delete rule chain stops unexpectedly

From
Wiebe Cazemier
Date:
Tom Lane wrote:
>>A quote from the postgresql manual:
> 
>>"But for ON UPDATE and ON DELETE rules, the original query is done after the 
>>actions added by rules. This ensures that the actions can see the to-be-updated 
>>or to-be-deleted rows"
> 
> Yes, I know that quote.  I wrote it.  It's not relevant here because the
> original query (the delete against the view) is never done at all, since
> you have a DO INSTEAD rule.  What is relevant is the timing of the
> delete issued against the underlying table, and you have that scheduled
> to occur too early because the rule that does it is first in
> alphabetical order.

Oh yeah, whoops, I was under a false impression of what the original query was...

> Because the rule converts those inserts into, effectively,
> 
>     INSERT INTO debuglog SELECT ... WHERE EXISTS(some matching OLD row);
> 
> and there are no longer any matching OLD rows in the view.  (If it
> didn't act that way then the INSERTs would execute even for a "DELETE
> WHERE false".  If you find any of this surprising or not what you want,
> you should probably be using triggers not rules.)

Ah, I see. I'll convert them to triggers, or just put the delete at the end. I 
could even put all this in one rule, that would be easier.

> 
> 
>>Or, that all the rules _are_
>>executed when I call the query with "explain analayze".
> 
> 
> Hmm ... this appears to be a bug in EXPLAIN ANALYZE: it really should
> bump the CommandCounter between plan trees, but fails to ...

Is this something I have to report?


Re: Delete rule chain stops unexpectedly

From
Tom Lane
Date:
Wiebe Cazemier <halfgaar@gmail.com> writes:
> Tom Lane wrote:
>> Hmm ... this appears to be a bug in EXPLAIN ANALYZE: it really should
>> bump the CommandCounter between plan trees, but fails to ...

> Is this something I have to report?

Nah, I fixed it already (only in CVS HEAD though).
        regards, tom lane


Re: Delete rule chain stops unexpectedly

From
Wiebe Cazemier
Date:
Tom Lane wrote:
>>So, the actual delete should be done after all the rules. And even if
>>it does delete before anything else, that does not explain why "step2"
>>is not inserted into the debuglog table.
> 
> 
> Because the rule converts those inserts into, effectively,
> 
>     INSERT INTO debuglog SELECT ... WHERE EXISTS(some matching OLD row);
> 
> and there are no longer any matching OLD rows in the view.  (If it
> didn't act that way then the INSERTs would execute even for a "DELETE
> WHERE false".  If you find any of this surprising or not what you want,
> you should probably be using triggers not rules.)

I've got a late addition question about this.

Is this behaviour also present in Postgres 7? I am continuing on work that was 
done by someone else in version 7. He said that what he made worked fine and 
tested OK, but with what you told me in mind, what he made can't possibly work 
(and it didn't when I tested it, and I have postgres 8).


Re: Delete rule chain stops unexpectedly

From
Tom Lane
Date:
Wiebe Cazemier <halfgaar@gmail.com> writes:
> Tom Lane wrote:
>> Because the rule converts those inserts into, effectively,
>> 
>> INSERT INTO debuglog SELECT ... WHERE EXISTS(some matching OLD row);
>> 
>> and there are no longer any matching OLD rows in the view.

> Is this behaviour also present in Postgres 7?

It's always been like that.  We've jiggered some details about the order
of rule firing, but not much else.  If you want a more detailed response
you need to be more specific about what version you're comparing to and
exactly what rules you're worried about.
        regards, tom lane