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 1r5cYK-00EFDo-Fw for pgsql-docs@arkaria.postgresql.org; Wed, 22 Nov 2023 02:01:20 +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 1r5cYJ-003wd2-2g for pgsql-docs@arkaria.postgresql.org; Wed, 22 Nov 2023 02:01:19 +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 1r5cYI-003wct-R2 for pgsql-docs@lists.postgresql.org; Wed, 22 Nov 2023 02:01:18 +0000 Received: from momjian.us ([72.94.173.45]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1r5cYG-006jYY-2m for pgsql-docs@postgresql.org; Wed, 22 Nov 2023 02:01:17 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=momjian.us; s=2023062407; h=In-Reply-To:Content-Type:MIME-Version:References:Message-ID: Subject:Cc:To:From:Date:Sender:Reply-To:Content-Transfer-Encoding:Content-ID: Content-Description; bh=egSAgq/gDiniOZ3b8R7tvKkxvH1lxXRHD8nOpITRbcc=; b=twPiV qDxEgxfhInLEP8pccPlQgVjC96k4lDTXwnzrPdbbsGoRo/I/za/XYYWn2DUMNFzsOkSvuWT6Rlnen l9C0BELbih9R3/kF5KpeOh3Eg+hmL59yEk++Dx/Sg6N+UgUytwywlpelBL04sg6GrJUSle1/rbvmM 4jEj9fPHvwlYYZn+1no5HdOm/q6BE19rO4yqDPQtUrVqWyGNJyZr5X75EvaI4YaPj4vMvUgk+Kkdq X7gP7YQyXYrW4gWq30xdQhR51DhHgUWFkGaOISGJZ1431K5s6yonV8YLP2Y3ql8JnR8ed2h8G/oAK w9n1H+RT2im2DmpmeRZPPbJjJ1/XQ==; Received: from bruce by momjian.us with local (Exim 4.96) (envelope-from ) id 1r5cYC-0080U9-2T; Tue, 21 Nov 2023 21:01:12 -0500 Date: Tue, 21 Nov 2023 21:01:12 -0500 From: Bruce Momjian To: Peter Geoghegan Cc: neil@fairwindsoft.com, PostgreSQL-documentation , Andres Freund , Heikki Linnakangas Subject: Re: [DOCS] Confusing Trigger Docs. Message-ID: References: <20170703200710.27956.64565@wrigleys.postgresql.org> <20170831132544.GC2355@momjian.us> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="L7G0y8AuqFMuGRTe" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --L7G0y8AuqFMuGRTe Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Thu, Aug 31, 2017 at 09:22:22AM -0700, Peter Geoghegan wrote: > On Thu, Aug 31, 2017 at 6:25 AM, Bruce Momjian wrote: > > On Mon, Jul 3, 2017 at 08:07:10PM +0000, neil@fairwindsoft.com wrote: > >> The following documentation comment has been logged on the website: > >> > >> Page: https://www.postgresql.org/docs/9.6/static/trigger-definition.html > >> Description: > >> > >> https://www.postgresql.org/docs/devel/static/trigger-definition.html > >> > >> This sentence: > >> > >> "If an INSERT contains an ON CONFLICT DO UPDATE clause, it is possible that > >> the effects of all row-level BEFORE INSERT triggers and all row-level BEFORE > >> UPDATE triggers can both be applied in a way that is apparent from the final > >> state of the updated row, if an EXCLUDED column is referenced." > >> > >> is very hard to digest. > > EXCLUDED.* is exactly what the name suggests -- the tuple that was not > inserted because of a conflict. So, naturally it has the effects of > any before insert trigger, and carries them forward. But you still > have before triggers on the update side. > > Typically, this won't matter at all, because before triggers tend to > be written in an idempotent fashion -- something gets filled in. But I > can imagine cases where it is not idempotent, and apply a before > update trigger modifies the row in a way that is surprising. Just > because ON CONFLICT DO UPDATE was used rather than UPDATE. That's what > the documentation warns about. I know this thread is six years old, but I still found it confusing, so the attached patch tries to simplify it. -- Bruce Momjian https://momjian.us EDB https://enterprisedb.com Only you can decide what is important to you. --L7G0y8AuqFMuGRTe Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="excluded.diff" diff --git a/doc/src/sgml/trigger.sgml b/doc/src/sgml/trigger.sgml new file mode 100644 index 6e1f370..0615f8a *** a/doc/src/sgml/trigger.sgml --- b/doc/src/sgml/trigger.sgml *************** *** 140,160 **** ! If an INSERT contains an ON CONFLICT ! DO UPDATE clause, it is possible that the effects of ! row-level BEFORE INSERT triggers and ! row-level BEFORE UPDATE triggers can ! both be applied in a way that is apparent from the final state of ! the updated row, if an EXCLUDED column is referenced. ! There need not be an EXCLUDED column reference for ! both sets of row-level BEFORE triggers to execute, ! though. The ! possibility of surprising outcomes should be considered when there ! are both BEFORE INSERT and ! BEFORE UPDATE row-level triggers ! that change a row being inserted/updated (this can be ! problematic even if the modifications are more or less equivalent, if ! they're not also idempotent). Note that statement-level UPDATE triggers are executed when ON CONFLICT DO UPDATE is specified, regardless of whether or not any rows were affected by the UPDATE (and --- 140,158 ---- ! If an INSERT contains an ON ! CONFLICT DO UPDATE clause, it is possible for both ! row-level BEFORE INSERT and ! BEFORE UPDATE triggers to be ! executed on the same row. The possibility of surprising outcomes ! should be considered when they change rows being inserted/updated ! (this can be problematic even if the modifications are more or less ! equivalent, if they're not also idempotent). The modification of ! EXCLUDED columns has similar interactions. ! ! ! ! Note that statement-level UPDATE triggers are executed when ON CONFLICT DO UPDATE is specified, regardless of whether or not any rows were affected by the UPDATE (and --L7G0y8AuqFMuGRTe--