Re: Update with subselect sometimes returns wrong result - Mailing list pgsql-bugs

From Alvaro Herrera
Subject Re: Update with subselect sometimes returns wrong result
Date
Msg-id 20131218221343.GG11006@eldon.alvh.no-ip.org
Whole thread Raw
In response to Re: Update with subselect sometimes returns wrong result  (Andres Freund <andres@2ndquadrant.com>)
Responses Re: Update with subselect sometimes returns wrong result
List pgsql-bugs
Andres Freund escribió:

> Several things:
> a) If the old lockmode is stronger than the new one, we can just promote
>    the new one. That's fine.
> b) the old xmax cannot be an update, we wouldn't see the row version in that
>    case. And in any way, ISUPDATE_from_mxstatus() isn't sufficient to
>    determine whether the old row was an update, one needs to look at
>    LOCK_ONLY as well, no?
> c) Any reason we can't apply this optimization for subtransactions in
>    some scenarios?
>
> a), b) are relatively easy. Patch attached. Being a clear regression, I
> think it should be backpatched, but I'm not sure if it has to be this
> point release. It's simple enough, but ...

Nice idea.  I modified the patch slightly, please see attached.

I'm not sure about the added assert that the tuple cannot possibly be
locked.  I fear cursors provide strange ways to access at tuples.  I
haven't been able to reproduce a problem but consider an example such as
the one below.  Is it possible, I wonder, to arrive at the problematic
scenario considering that we might try to traverse an update chain to
lock future versions of the tuple?  I suspect not, because if the tuple
was updated (so that there is an update chain to traverse in the first
place) then we wouldn't be able to update the original anyway.  (I guess
I'm mainly talking to myself to assure me that there's no real problem
here.)

In any case I think it's easy to handle the case by doing something like
    is_update |= ISUPDATE_from_mxstatus(old_status);
and remove the Assert().


alvherre=# create table f (a int primary key, b text);
CREATE TABLE
alvherre=# insert into f values (1, 'one');
INSERT 0 1

alvherre=# begin;
BEGIN
alvherre=# select * from f for update;
 a |   b
---+-------
 1 | three
(1 fila)

alvherre=# declare f cursor for select * from f;
DECLARE CURSOR
alvherre=# fetch 1 from f;
 a |   b
---+-------
 1 | three
(1 fila)

alvherre=# update f set b = 'two';
UPDATE 1
alvherre=# move backward all from f;
MOVE 0
alvherre=# fetch 1 from f;
 a |   b
---+-------
 1 | three
(1 fila)

alvherre=# update f set b = 'four' where current of f;
UPDATE 1
alvherre=# select * from f;
 a |  b
---+------
 1 | four
(1 fila)

alvherre=# commit;

--
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachment

pgsql-bugs by date:

Previous
From: David Johnston
Date:
Subject: Re: BUG #8685: "alter default privileges" cannot revoke default execute privilege on functions
Next
From: Andres Freund
Date:
Subject: Re: Update with subselect sometimes returns wrong result