On Thu, Aug 31, 2017 at 09:22:22AM -0700, Peter Geoghegan wrote:
> On Thu, Aug 31, 2017 at 6:25 AM, Bruce Momjian <[email protected]> wrote:
> > On Mon, Jul 3, 2017 at 08:07:10PM +0000, [email protected] 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 <[email protected]> https://momjian.us
EDB https://enterprisedb.com
Only you can decide what is important to you.
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 ****
</para>
<para>
! If an <command>INSERT</command> contains an <literal>ON CONFLICT
! DO UPDATE</literal> clause, it is possible that the effects of
! row-level <literal>BEFORE</literal> <command>INSERT</command> triggers and
! row-level <literal>BEFORE</literal> <command>UPDATE</command> triggers can
! both be applied in a way that is apparent from the final state of
! the updated row, if an <varname>EXCLUDED</varname> column is referenced.
! There need not be an <varname>EXCLUDED</varname> column reference for
! both sets of row-level <literal>BEFORE</literal> triggers to execute,
! though. The
! possibility of surprising outcomes should be considered when there
! are both <literal>BEFORE</literal> <command>INSERT</command> and
! <literal>BEFORE</literal> <command>UPDATE</command> 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
<command>UPDATE</command> triggers are executed when <literal>ON
CONFLICT DO UPDATE</literal> is specified, regardless of whether or not
any rows were affected by the <command>UPDATE</command> (and
--- 140,158 ----
</para>
<para>
! If an <command>INSERT</command> contains an <literal>ON
! CONFLICT DO UPDATE</literal> clause, it is possible for both
! row-level <literal>BEFORE</literal> <command>INSERT</command> and
! <literal>BEFORE</literal> <command>UPDATE</command> 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
! <varname>EXCLUDED</varname> columns has similar interactions.
! </para>
!
! <para>
! Note that statement-level
<command>UPDATE</command> triggers are executed when <literal>ON
CONFLICT DO UPDATE</literal> is specified, regardless of whether or not
any rows were affected by the <command>UPDATE</command> (and