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.94.2) (envelope-from ) id 1sbRDG-00Gam0-7O for pgsql-bugs@arkaria.postgresql.org; Tue, 06 Aug 2024 20:55:22 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1sbRDE-002hBd-2c for pgsql-bugs@arkaria.postgresql.org; Tue, 06 Aug 2024 20:55:20 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1sbRDD-002hBV-QM for pgsql-bugs@lists.postgresql.org; Tue, 06 Aug 2024 20:55:19 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1sbRDB-003R8h-2I for pgsql-bugs@lists.postgresql.org; Tue, 06 Aug 2024 20:55: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 476KtFlU1831309; Tue, 6 Aug 2024 16:55:16 -0400 From: Tom Lane To: tilman.vogel@web.de cc: pgsql-bugs@lists.postgresql.org Subject: Re: BUG #18571: A CTE with a DELETE auxiliary statement only deletes when the DELETE results are referenced later In-reply-to: <18571-4286b331d0b701f4@postgresql.org> References: <18571-4286b331d0b701f4@postgresql.org> Comments: In-reply-to PG Bug reporting form message dated "Tue, 06 Aug 2024 18:51:12 -0000" MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <1831307.1722977715.1@sss.pgh.pa.us> Content-Transfer-Encoding: quoted-printable Date: Tue, 06 Aug 2024 16:55:15 -0400 Message-ID: <1831308.1722977715@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk PG Bug reporting form writes: > The following code fails with "psycopg.errors.UniqueViolation: duplicate= key > value violates unique constraint "test_pkey" DETAIL: Key (name)=3D(key1= ) > already exists." > CREATE TEMPORARY TABLE test(name TEXT PRIMARY KEY, value TEXT); > INSERT INTO test(name, value) VALUES('key1', 'value1'); > WITH deleted AS ( > DELETE FROM test > WHERE name =3D 'key1' > RETURNING * > ) > INSERT INTO test(name, value) VALUES('key1', 'value1'); > However, this succeeds: > CREATE TEMPORARY TABLE test(name TEXT PRIMARY KEY, value TEXT); > INSERT INTO test(name, value) VALUES('key1', 'value1'); > WITH deleted AS ( > DELETE FROM test > WHERE name =3D 'key1' > RETURNING * > ), > inserted AS ( > INSERT INTO test(name, value) VALUES('key1', 'value1') > RETURNING * > ) > SELECT NULL FROM deleted; > So, I am puzzled whether this optimization that the "deleted" sub-expres= sion > is not evaluated at all when not used later which breaks the second > sub-expression is to be expected. I don't see any bug here. The executor will run DML (INSERT/UPDATE/DELETE) WITH clauses to completion whether they are read by the outer query or not --- but if they are not, that happens after completion of the outer query. In your first example, the INSERT happens first and so it fails. (You could have avoided that by making the pkey constraint deferrable, but you didn't.) In the second example, the "deleted" subquery is run to completion as a side-effect of completing the outer query, and then the "inserted" subquery gets run, so there's no error. Our SELECT man page says that The primary query and the WITH queries are all (notionally) executed at the same time. This implies that the effects of a data-modifying statement in WITH cannot be seen from other parts of the query, other than by reading its RETURNING output. If two such data-modifying statements attempt to modify the same row, the results are unspecified. I'd argue that the last sentence covers the fact that these examples behave oddly. Perhaps we ought to mention the fact that constraint violations provide a separate pathway for WITH sub-queries to affect each other; but if such a violation could happen then you're already doing something that's explicitly stated to be unspecified. There's also relevant disclaimers in the main docs: https://www.postgresql.org/docs/current/queries-with.html#QUERIES-WITH-MOD= IFYING regards, tom lane