Re: Views and triggers more then one row returned by subquery.

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: "Day, David" <david(dot)day(at)redcom(dot)com>
Cc: "pgsql-general(at)lists(dot)postgresql(dot)org" <pgsql-general(at)lists(dot)postgresql(dot)org>
Subject: Re: Views and triggers more then one row returned by subquery.
Date: 2021-01-12 23:24:53
Message-ID: 1237945.1610493893@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

"Day, David" <david(dot)day(at)redcom(dot)com> writes:
> My presumption of views and instead of trigger behavior is that the VIEW first gets populated with the WHERE filter and then the "DELETE or UPDATE" operation will fire against each of the rendered view rows. ( ? )
> If this is true then I can't explain the more then one row returned error.

This code makes my head hurt :-(

However, it's fairly easy to tell that the trigger successfully completes
on the first view row (you can check that by sticking some RAISE NOTICE
commands in it) and then the error is thrown while evaluating the next
view row. The error has to be complaining about the "WITH rule_heads ..."
subquery in the view's targetlist; the only other subquery is the MAX()
subquery, which most certainly isn't going to return more than one row.

The trigger is evidently running rule_delete_and_decrement(), which
I am not interested in deconstructing in full, but I can see that
it modifies the contents of the my_translator table. So what must
be happening is that the "WITH rule_heads ..." subquery is returning
more than one row after that modification occurs.

I have a rough theory as to why, though I'm not planning on tracing it
down in detail. The result of the WITH clause itself *does not see the
deletion*, as specified somewhere in our fine manual. (That part is
consistent with your expectation that the view output doesn't change
while this is all going on: my_translator is being scanned using the
original query snapshot, so the subquery doesn't see the already-applied
changes.) So when we re-execute the subquery at the second view row,
the "WITH rule_heads" output is the same as before. On the other hand,
the get_rule_seq() function is going to see the updated contents of
my_translator, since it's declared VOLATILE. I think that this
inconsistency results in more than one row getting let through the
WHERE filter, and voila we get the error.

You might be able to fix this by marking get_rule_seq() as STABLE
so that it sees the same snapshot as the calling query. At least,
when I change it to stable I don't see the error anymore. Whether
things are then consistent with your intent, I can't say. But
I will say that this code is an unmaintainable pile of spaghetti,
because when the side-effects occur and where they're visible
is going to be almost impossible to keep track of.

regards, tom lane

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Alex Williams 2021-01-13 01:01:19 Re: How to keep format of views source code as entered?
Previous Message Alban Hertroys 2021-01-12 21:17:36 Re: How to keep format of views source code as entered?