Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pS0q9-0002ju-Ew for pgsql-bugs@arkaria.postgresql.org; Tue, 14 Feb 2023 19:19:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1pS0q7-00017B-Az for pgsql-bugs@arkaria.postgresql.org; Tue, 14 Feb 2023 19:19:43 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pS0q7-000172-2L for pgsql-bugs@lists.postgresql.org; Tue, 14 Feb 2023 19:19:43 +0000 Received: from out2-smtp.messagingengine.com ([66.111.4.26]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pS0q4-00015b-Ln for pgsql-bugs@lists.postgresql.org; Tue, 14 Feb 2023 19:19:42 +0000 Received: from compute5.internal (compute5.nyi.internal [10.202.2.45]) by mailout.nyi.internal (Postfix) with ESMTP id C6FBB5C0170; Tue, 14 Feb 2023 14:19:39 -0500 (EST) Received: from mailfrontend1 ([10.202.2.162]) by compute5.internal (MEProxy); Tue, 14 Feb 2023 14:19:39 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:date:date:feedback-id:feedback-id:from:from :in-reply-to:in-reply-to:message-id:mime-version:reply-to:sender :subject:subject:to:to:x-me-proxy:x-me-proxy:x-me-sender :x-me-sender:x-sasl-enc; s=fm1; t=1676402379; x=1676488779; bh=H Tqy0rjckhvG5pixxrzlhnjUAUuT+vAYDBrsw0Yigu4=; b=mkAZBcl9Sn19e2mwv UOf/KAYICK8uImLPBa5ppZ5bpDZ9XBgj8Lcbej44oXqrn88JL4khZrYBnVheVQAB 7+g+BgOMr1/gQHAc0Zd2eZetHpLw9vts0I4rxFCu93WozVr1XD0Hfkqe0dPoIrkJ xZjygV/iFSEKbhHsSp8cLWM1WK1SUAwlbFcanCZ/3QHlyoFvOY3W/ZT2wZgMTt6H l2S44FLM8FHCu+ijE9tQhwy3b38HoF6FLgU0Enj+NLcBjEi5oXN5ucjQtexbrax4 AYOUwN/EHu8aeHLSgd5dfaGCkunQflyJnVee7bw3FIDN5M3bqlj8nGPvLNWY3O8n qA5ww== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvhedrudeifedgudduhecutefuodetggdotefrod ftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfgh necuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd enucfjughrpeffhffvvefukfggtggugfgjsehmkeerredttdejnecuhfhrohhmpeetlhhv rghrohcujfgvrhhrvghrrgcuoegrlhhvhhgvrhhrvgesrghlvhhhrdhnohdqihhprdhorh hgqeenucggtffrrghtthgvrhhnpeduleekkefgtddttedtkefguddvieffleetgeejiefh teehkeevfeettdduvdfhueenucffohhmrghinhepvghnthgvrhhprhhishgvuggsrdgtoh hmnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomheprghl vhhhvghrrhgvsegrlhhvhhdrnhhoqdhiphdrohhrgh X-ME-Proxy: Feedback-ID: ia2694551:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue, 14 Feb 2023 14:19:39 -0500 (EST) Received: by perhan.alvh.no-ip.org (Postfix, from userid 1000) id 58D459E; Tue, 14 Feb 2023 20:19:37 +0100 (CET) Date: Tue, 14 Feb 2023 20:19:37 +0100 From: Alvaro Herrera To: Dean Rasheed Cc: exclusion@gmail.com, pgsql-bugs@lists.postgresql.org Subject: Re: BUG #17792: MERGE uses uninitialized pointer and crashes when target tuple is updated concurrently Message-ID: <20230214191937.sri5zsqqogpidmxp@alvherre.pgsql> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="fd2oymvm7svqwr3o" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --fd2oymvm7svqwr3o Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On 2023-Feb-14, Dean Rasheed wrote: > After trying to induce that, I realised that it doesn't appear to be > possible, because a delete after a failed update will always succeed, > because it has the target row locked by that point. So I think that it > will never need to retry more than once. Hmm, yeah, that makes sense. Thanks for checking. > That said, it seems wrong to be checking cpUpdateRetrySlot after an > attempted delete anyway. True. > Perhaps a better fix would be to just change > the check in ExecMergeMatched() to > > if (commandType == CMD_UPDATE && !TupIsNull(context->cpUpdateRetrySlot)) > goto lmerge_matched; > > and update the preceding comment, since only an update should set > cpUpdateRetrySlot. I agree, this looks to be a good fix. However, I couldn't in a quick try reproduce the problem, so I haven't been able to verify it. I'll try to do that early tomorrow. (I also delete the XXX comment there.) -- Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/ "Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end." (2nd Commandment for C programmers) --fd2oymvm7svqwr3o Content-Type: text/x-diff; charset=utf-8 Content-Disposition: attachment; filename="merge-uninit-2.patch" Content-Transfer-Encoding: 8bit gpg: Firmado el mar 14 feb 2023 20:17:10 CET gpg: usando RSA clave E2C96E4A9BCA7E92A8E3DA551C20ACB9D5C564AE gpg: Firma correcta de "Álvaro Herrera " [absoluta] gpg: alias "Álvaro Herrera (PostgreSQL Global Development Group) " [absoluta] gpg: alias "Álvaro Herrera (2ndQuadrant) " [absoluta] commit 14242c4f5bebb21f945c3f8f43b02d34bb060807 Author: Alvaro Herrera [Álvaro Herrera ] AuthorDate: Tue Feb 14 19:26:51 2023 +0100 CommitDate: Tue Feb 14 20:17:10 2023 +0100 fix crash on mis-set cpUpdateRetrySlot diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 1ac65172e4..c4b845160d 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2967,21 +2967,20 @@ lmerge_matched: */ /* - * If cpUpdateRetrySlot is set, ExecCrossPartitionUpdate() - * must have detected that the tuple was concurrently - * updated, so we restart the search for an appropriate - * WHEN MATCHED clause to process the updated tuple. + * During an UPDATE, if cpUpdateRetrySlot is set, then + * ExecCrossPartitionUpdate() must have detected that the + * tuple was concurrently updated, so we restart the search + * for an appropriate WHEN MATCHED clause to process the + * updated tuple. * * In this case, ExecDelete() would already have performed * EvalPlanQual() on the latest version of the tuple, * which in turn would already have been loaded into * ri_oldTupleSlot, so no need to do either of those * things. - * - * XXX why do we not check the WHEN NOT MATCHED list in - * this case? */ - if (!TupIsNull(context->cpUpdateRetrySlot)) + if (commandType == CMD_UPDATE && + !TupIsNull(context->cpUpdateRetrySlot)) goto lmerge_matched; /* --fd2oymvm7svqwr3o--