Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vayCO-00Geax-0a for pgsql-general@arkaria.postgresql.org; Wed, 31 Dec 2025 15:33:20 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vayCL-006cpM-35 for pgsql-general@arkaria.postgresql.org; Wed, 31 Dec 2025 15:33:18 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vayCL-006cpD-1z for pgsql-general@lists.postgresql.org; Wed, 31 Dec 2025 15:33:18 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vayCJ-003nAM-3D for pgsql-general@lists.postgresql.org; Wed, 31 Dec 2025 15:33:18 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 5BVFXCiq3914050; Wed, 31 Dec 2025 10:33:13 -0500 From: Tom Lane To: "Khan, Tanzeel" cc: "pgsql-general@lists.postgresql.org" Subject: Re: SELECT FOR UDPATE behavior inside joins In-reply-to: References: Comments: In-reply-to "Khan, Tanzeel" message dated "Mon, 29 Dec 2025 09:15:58 +0000" MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <3914048.1767195192.1@sss.pgh.pa.us> Content-Transfer-Encoding: quoted-printable Date: Wed, 31 Dec 2025 10:33:12 -0500 Message-ID: <3914049.1767195192@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk "Khan, Tanzeel" writes: > I am trying to understand the SELECT FOR UPDATE behavior when it is not = returning rows back to client. > postgres=3D> CREATE TABLE t (col1 INT, col2 INT); > postgres=3D> INSERT INTO t VALUES (1, 1); > S1: BEGIN; UPDATE t SET col2 =3D col2 + 1 WHERE col1 =3D 1; > S2: BEGIN; WITH cte AS (SELECT * FROM t WHERE col1 =3D 1 FOR UPDATE) UPD= ATE t SET col2 =3D t.col2 + 1 FROM cte AS t_self_join WHERE (t.col2 =3D 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