Обсуждение: Views and triggers more then one row returned by subquery.
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.
[11-1] user=redcom, db=ace_db, app=psql, client=[local] ERROR: 21000: more than one row returned by a subquery used as an expression
my view is modeling a table of translation "steps" in a phone switch application. "steps" are the components of "rules" and rules are components of "folders".
The VIEW columns of step, rule_seq, and a rule number are relative and derived from column content.
My triggers operate on rows.step_id which is a unique value across rules and folders.
I was expecting each row of the rendered DELETE VIEW to be executed in succession. That is one step at a time. Apparently that is not happening ???
Base Table.
Here is code that represent above.. .
"Day, David" <david.day@redcom.com> writes: > My presumption of views and instead of trigger behavior is that the VIEW first gets populated with the WHERE filter andthen 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
Sent: Tuesday, January 12, 2021 6:24 PM
To: Day, David <david.day@redcom.com>
Cc: pgsql-general@lists.postgresql.org <pgsql-general@lists.postgresql.org>
Subject: Re: Views and triggers more then one row returned by subquery.
> 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