Re: SELECT FOR UDPATE behavior inside joins

From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: "Khan, Tanzeel" <tzlkhan(at)amazon(dot)com>
Cc: "pgsql-general(at)lists(dot)postgresql(dot)org" <pgsql-general(at)lists(dot)postgresql(dot)org>
Subject: Re: SELECT FOR UDPATE behavior inside joins
Date: 2025-12-31 15:33:12
Message-ID: 3914049.1767195192@sss.pgh.pa.us
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-general

"Khan, Tanzeel" <tzlkhan(at)amazon(dot)com> writes:
> I am trying to understand the SELECT FOR UPDATE behavior when it is not returning rows back to client.

> postgres=> CREATE TABLE t (col1 INT, col2 INT);
> postgres=> INSERT INTO t VALUES (1, 1);

> S1: BEGIN; UPDATE t SET col2 = col2 + 1 WHERE col1 = 1;
> S2: BEGIN; WITH cte AS (SELECT * FROM t WHERE col1 = 1 FOR UPDATE) UPDATE t SET col2 = t.col2 + 1 FROM cte AS t_self_join WHERE (t.col2 = t_self_join.col2);
> S1: COMMIT;
> S2: zero rows updated

> Why does session 2 update zero rows ?

Since the CTE has FOR UPDATE, it blocks and returns the updated-by-S1
version of the row. But the outer query initially reads the old
version of the row, so the join condition fails, and we never get
to the lock-row-and-recheck behavior of UPDATE.

I am not sure what you are hoping to accomplish with that self-join.
I suppose this is an oversimplified example, but it's too
oversimplified for anyone to see why you'd want to do it like that.

regards, tom lane

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message Adrian Klaver 2025-12-31 15:35:38 Re: SELECT FOR UDPATE behavior inside joins
Previous Message Daniel Gustafsson 2025-12-30 08:24:30 Re: PQprepare result