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 1wIE0J-007tQh-2z for pgsql-general@arkaria.postgresql.org; Wed, 29 Apr 2026 23:07:40 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wIE0H-0052kp-0b for pgsql-general@arkaria.postgresql.org; Wed, 29 Apr 2026 23:07:37 +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 1wIE0G-0052kb-2a for pgsql-general@lists.postgresql.org; Wed, 29 Apr 2026 23:07:36 +0000 Received: from pmg-2.outbound.snap.net.nz ([202.37.100.107]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wIE0D-00000003svj-3GsJ for pgsql-general@lists.postgresql.org; Wed, 29 Apr 2026 23:07:36 +0000 Received: from pmg-2.snap.net.nz (localhost.localdomain [127.0.0.1]) by pmg-2.snap.net.nz (Proxmox) with ESMTP id 3B05F3A34F5 for ; Thu, 30 Apr 2026 11:07:26 +1200 (NZST) Received: from smtp.snap.net.nz (smtp.snap.net.nz [202.37.100.140]) by pmg-2.snap.net.nz (Proxmox) with ESMTP id 27B4431393D for ; Thu, 30 Apr 2026 11:07:25 +1200 (NZST) Received: from x24.msqr.us (msqr.us [123.255.47.99]) by rupert.snap.net.nz (Postfix) with ESMTPS id 0E09E2AD for ; Thu, 30 Apr 2026 11:07:25 +1200 (NZST) Received: from smtpclient.apple (unifi.localdomain [192.168.1.1]) (authenticated bits=0) by x24.msqr.us (8.18.2/8.16.1) with ESMTPSA id 63TN7ONr060186 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Thu, 30 Apr 2026 11:07:24 +1200 (NZST) (envelope-from postgresql.org@msqr.us) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=msqr.us; s=20121026; t=1777504044; bh=xnWAZ4pRsIZ2g1gGEIAQGWif3XfidNUBafSBATq4HoU=; h=From:Subject:Date:To; b=m6zBWom6v6EvPrfKOOogUwCzYa+Ov7TWHQs/mokYe+4APaVJ1hXfRQaEQDkN0uZKq J81epVUow14ECBDs/j1L9wikwIevY1pWe9Mb95l13vmgrqJkN57UjQ4C++puikt3P4 BkoY8qVfafMVV0kkuHoVjYzfQZeXc77IuHDB6//0= X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 1.5.2 at msqr.us From: Matt Magoffin Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3826.700.81.1.6\)) Subject: Confirmation on concurrent SELECT FOR UPDATE with ON CONFLICT DO NOTHING Message-Id: <087DA595-FB65-49F4-89E9-AE9F5CBF6E4C@msqr.us> Date: Thu, 30 Apr 2026 11:07:14 +1200 To: pgsql-general@lists.postgresql.org X-Mailer: Apple Mail (2.3826.700.81.1.6) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Hello, I was hoping to confirm some transaction behaviour I am seeing = (in Postgres 17) in read-committed isolation mode that caught me off = guard is, in fact, expected. First some setup: CREATE TABLE txtest (id INTEGER NOT NULL PRIMARY KEY); INSERT INTO txtest (id) VALUES (1); Then in one session, I run: BEGIN; SELECT * FROM txtest WHERE id =3D 1 FOR UPDATE; Then, in a different session, I run: INSERT INTO txtest SELECT id FROM (VALUES (1), (2) ) AS t(id) ON CONFLICT DO NOTHING; This completes immediately, with=20 INSERT 0 1 and indeed there are 2 rows now in that session: SELECT * FROM txtest; id=20 ---- 1 2 This is what caught be off guard, as I had been thinking the INSERT = would block until the first session=E2=80=99s transaction finished. Now, = back in session #1, I run: DELETE FROM txtest WHERE ID =3D 1; COMMIT; Now in both sessions there is 1 row, with =E2=80=9C2=E2=80=9D, where I = had been hoping to end up with both =E2=80=9C1=E2=80=9D and =E2=80=9C2=E2=80= =9D after the INSERT waited for the SELECT =E2=80=A6 FOR UPDATE to = complete first. If I change session #1=E2=80=99s query from SELECT =E2=80=A6 FOR UPDATE = to an immediate DELETE, I get what I expected, i.e. BEGIN; DELETE FROM txtest WHERE id =3D 1; Then in session #1 the same INSERT =E2=80=A6 ON CONFLICT DO NOTHING = statement blocks until session #1 commits, and it results in=20 INSERT 0 2 The difference in transaction behaviour between SELECT =E2=80=A6 FOR = UPDATE and DELETE I did not understand from the documentation, so would = appreciate any confirmation/clarification/insight on what I=E2=80=99m = seeing so I can better understand. Thank you, Matt Magoffin