1997-08-31 13:42:21 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* trigger.h
|
2000-05-29 03:59:17 +02:00
|
|
|
* Declarations for trigger handling.
|
1997-08-31 13:42:21 +02:00
|
|
|
*
|
2024-01-04 02:49:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
2000-01-31 05:35:57 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/include/commands/trigger.h
|
1997-08-31 13:42:21 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#ifndef TRIGGER_H
|
|
|
|
#define TRIGGER_H
|
|
|
|
|
2022-03-28 16:45:58 +02:00
|
|
|
#include "access/tableam.h"
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
#include "catalog/objectaddress.h"
|
1998-12-15 13:47:01 +01:00
|
|
|
#include "nodes/execnodes.h"
|
2011-09-04 07:13:16 +02:00
|
|
|
#include "nodes/parsenodes.h"
|
1997-09-01 10:10:12 +02:00
|
|
|
|
2000-05-29 03:59:17 +02:00
|
|
|
/*
|
|
|
|
* TriggerData is the node type that is passed as fmgr "context" info
|
|
|
|
* when a function is called by the trigger manager.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define CALLED_AS_TRIGGER(fcinfo) \
|
|
|
|
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
|
|
|
|
|
1997-09-04 15:26:19 +02:00
|
|
|
typedef uint32 TriggerEvent;
|
1997-09-01 10:10:12 +02:00
|
|
|
|
1997-09-04 15:26:19 +02:00
|
|
|
typedef struct TriggerData
|
|
|
|
{
|
2000-05-29 03:59:17 +02:00
|
|
|
NodeTag type;
|
1997-09-04 15:26:19 +02:00
|
|
|
TriggerEvent tg_event;
|
|
|
|
Relation tg_relation;
|
|
|
|
HeapTuple tg_trigtuple;
|
|
|
|
HeapTuple tg_newtuple;
|
|
|
|
Trigger *tg_trigger;
|
2019-02-27 05:30:28 +01:00
|
|
|
TupleTableSlot *tg_trigslot;
|
|
|
|
TupleTableSlot *tg_newslot;
|
2016-11-04 16:49:50 +01:00
|
|
|
Tuplestorestate *tg_oldtable;
|
|
|
|
Tuplestorestate *tg_newtable;
|
2020-03-09 09:22:22 +01:00
|
|
|
const Bitmapset *tg_updatedcols;
|
1997-09-11 09:24:37 +02:00
|
|
|
} TriggerData;
|
1997-09-01 10:10:12 +02:00
|
|
|
|
2017-06-28 19:55:03 +02:00
|
|
|
/*
|
2017-06-28 19:59:01 +02:00
|
|
|
* The state for capturing old and new tuples into transition tables for a
|
2020-11-23 10:36:13 +01:00
|
|
|
* single ModifyTable node (or other operation source, e.g. copyfrom.c).
|
Fix SQL-spec incompatibilities in new transition table feature.
The standard says that all changes of the same kind (insert, update, or
delete) caused in one table by a single SQL statement should be reported
in a single transition table; and by that, they mean to include foreign key
enforcement actions cascading from the statement's direct effects. It's
also reasonable to conclude that if the standard had wCTEs, they would say
that effects of wCTEs applying to the same table as each other or the outer
statement should be merged into one transition table. We weren't doing it
like that.
Hence, arrange to merge tuples from multiple update actions into a single
transition table as much as we can. There is a problem, which is that if
the firing of FK enforcement triggers and after-row triggers with
transition tables is interspersed, we might need to report more tuples
after some triggers have already seen the transition table. It seems like
a bad idea for the transition table to be mutable between trigger calls.
There's no good way around this without a major redesign of the FK logic,
so for now, resolve it by opening a new transition table each time this
happens.
Also, ensure that AFTER STATEMENT triggers fire just once per statement,
or once per transition table when we're forced to make more than one.
Previous versions of Postgres have allowed each FK enforcement query
to cause an additional firing of the AFTER STATEMENT triggers for the
referencing table, but that's certainly not per spec. (We're still
doing multiple firings of BEFORE STATEMENT triggers, though; is that
something worth changing?)
Also, forbid using transition tables with column-specific UPDATE triggers.
The spec requires such transition tables to show only the tuples for which
the UPDATE trigger would have fired, which means maintaining multiple
transition tables or else somehow filtering the contents at readout.
Maybe someday we'll bother to support that option, but it looks like a
lot of trouble for a marginal feature.
The transition tables are now managed by the AfterTriggers data structures,
rather than being directly the responsibility of ModifyTable nodes. This
removes a subtransaction-lifespan memory leak introduced by my previous
band-aid patch 3c4359521.
In passing, refactor the AfterTriggers data structures to reduce the
management overhead for them, by using arrays of structs rather than
several parallel arrays for per-query-level and per-subtransaction state.
I failed to resist the temptation to do some copy-editing on the SGML
docs about triggers, above and beyond merely documenting the effects
of this patch.
Back-patch to v10, because we don't want the semantics of transition
tables to change post-release.
Patch by me, with help and review from Thomas Munro.
Discussion: https://postgr.es/m/20170909064853.25630.12825@wrigleys.postgresql.org
2017-09-16 19:20:32 +02:00
|
|
|
*
|
2020-10-19 13:11:54 +02:00
|
|
|
* This is per-caller to avoid conflicts in setting
|
Fix SQL-spec incompatibilities in new transition table feature.
The standard says that all changes of the same kind (insert, update, or
delete) caused in one table by a single SQL statement should be reported
in a single transition table; and by that, they mean to include foreign key
enforcement actions cascading from the statement's direct effects. It's
also reasonable to conclude that if the standard had wCTEs, they would say
that effects of wCTEs applying to the same table as each other or the outer
statement should be merged into one transition table. We weren't doing it
like that.
Hence, arrange to merge tuples from multiple update actions into a single
transition table as much as we can. There is a problem, which is that if
the firing of FK enforcement triggers and after-row triggers with
transition tables is interspersed, we might need to report more tuples
after some triggers have already seen the transition table. It seems like
a bad idea for the transition table to be mutable between trigger calls.
There's no good way around this without a major redesign of the FK logic,
so for now, resolve it by opening a new transition table each time this
happens.
Also, ensure that AFTER STATEMENT triggers fire just once per statement,
or once per transition table when we're forced to make more than one.
Previous versions of Postgres have allowed each FK enforcement query
to cause an additional firing of the AFTER STATEMENT triggers for the
referencing table, but that's certainly not per spec. (We're still
doing multiple firings of BEFORE STATEMENT triggers, though; is that
something worth changing?)
Also, forbid using transition tables with column-specific UPDATE triggers.
The spec requires such transition tables to show only the tuples for which
the UPDATE trigger would have fired, which means maintaining multiple
transition tables or else somehow filtering the contents at readout.
Maybe someday we'll bother to support that option, but it looks like a
lot of trouble for a marginal feature.
The transition tables are now managed by the AfterTriggers data structures,
rather than being directly the responsibility of ModifyTable nodes. This
removes a subtransaction-lifespan memory leak introduced by my previous
band-aid patch 3c4359521.
In passing, refactor the AfterTriggers data structures to reduce the
management overhead for them, by using arrays of structs rather than
several parallel arrays for per-query-level and per-subtransaction state.
I failed to resist the temptation to do some copy-editing on the SGML
docs about triggers, above and beyond merely documenting the effects
of this patch.
Back-patch to v10, because we don't want the semantics of transition
tables to change post-release.
Patch by me, with help and review from Thomas Munro.
Discussion: https://postgr.es/m/20170909064853.25630.12825@wrigleys.postgresql.org
2017-09-16 19:20:32 +02:00
|
|
|
* tcs_original_insert_tuple. Note, however, that the pointed-to
|
|
|
|
* private data may be shared across multiple callers.
|
2017-06-28 19:55:03 +02:00
|
|
|
*/
|
Fix SQL-spec incompatibilities in new transition table feature.
The standard says that all changes of the same kind (insert, update, or
delete) caused in one table by a single SQL statement should be reported
in a single transition table; and by that, they mean to include foreign key
enforcement actions cascading from the statement's direct effects. It's
also reasonable to conclude that if the standard had wCTEs, they would say
that effects of wCTEs applying to the same table as each other or the outer
statement should be merged into one transition table. We weren't doing it
like that.
Hence, arrange to merge tuples from multiple update actions into a single
transition table as much as we can. There is a problem, which is that if
the firing of FK enforcement triggers and after-row triggers with
transition tables is interspersed, we might need to report more tuples
after some triggers have already seen the transition table. It seems like
a bad idea for the transition table to be mutable between trigger calls.
There's no good way around this without a major redesign of the FK logic,
so for now, resolve it by opening a new transition table each time this
happens.
Also, ensure that AFTER STATEMENT triggers fire just once per statement,
or once per transition table when we're forced to make more than one.
Previous versions of Postgres have allowed each FK enforcement query
to cause an additional firing of the AFTER STATEMENT triggers for the
referencing table, but that's certainly not per spec. (We're still
doing multiple firings of BEFORE STATEMENT triggers, though; is that
something worth changing?)
Also, forbid using transition tables with column-specific UPDATE triggers.
The spec requires such transition tables to show only the tuples for which
the UPDATE trigger would have fired, which means maintaining multiple
transition tables or else somehow filtering the contents at readout.
Maybe someday we'll bother to support that option, but it looks like a
lot of trouble for a marginal feature.
The transition tables are now managed by the AfterTriggers data structures,
rather than being directly the responsibility of ModifyTable nodes. This
removes a subtransaction-lifespan memory leak introduced by my previous
band-aid patch 3c4359521.
In passing, refactor the AfterTriggers data structures to reduce the
management overhead for them, by using arrays of structs rather than
several parallel arrays for per-query-level and per-subtransaction state.
I failed to resist the temptation to do some copy-editing on the SGML
docs about triggers, above and beyond merely documenting the effects
of this patch.
Back-patch to v10, because we don't want the semantics of transition
tables to change post-release.
Patch by me, with help and review from Thomas Munro.
Discussion: https://postgr.es/m/20170909064853.25630.12825@wrigleys.postgresql.org
2017-09-16 19:20:32 +02:00
|
|
|
struct AfterTriggersTableData; /* private in trigger.c */
|
|
|
|
|
2017-06-28 19:55:03 +02:00
|
|
|
typedef struct TransitionCaptureState
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Is there at least one trigger specifying each transition relation on
|
|
|
|
* the relation explicitly named in the DML statement or COPY command?
|
Fix SQL-spec incompatibilities in new transition table feature.
The standard says that all changes of the same kind (insert, update, or
delete) caused in one table by a single SQL statement should be reported
in a single transition table; and by that, they mean to include foreign key
enforcement actions cascading from the statement's direct effects. It's
also reasonable to conclude that if the standard had wCTEs, they would say
that effects of wCTEs applying to the same table as each other or the outer
statement should be merged into one transition table. We weren't doing it
like that.
Hence, arrange to merge tuples from multiple update actions into a single
transition table as much as we can. There is a problem, which is that if
the firing of FK enforcement triggers and after-row triggers with
transition tables is interspersed, we might need to report more tuples
after some triggers have already seen the transition table. It seems like
a bad idea for the transition table to be mutable between trigger calls.
There's no good way around this without a major redesign of the FK logic,
so for now, resolve it by opening a new transition table each time this
happens.
Also, ensure that AFTER STATEMENT triggers fire just once per statement,
or once per transition table when we're forced to make more than one.
Previous versions of Postgres have allowed each FK enforcement query
to cause an additional firing of the AFTER STATEMENT triggers for the
referencing table, but that's certainly not per spec. (We're still
doing multiple firings of BEFORE STATEMENT triggers, though; is that
something worth changing?)
Also, forbid using transition tables with column-specific UPDATE triggers.
The spec requires such transition tables to show only the tuples for which
the UPDATE trigger would have fired, which means maintaining multiple
transition tables or else somehow filtering the contents at readout.
Maybe someday we'll bother to support that option, but it looks like a
lot of trouble for a marginal feature.
The transition tables are now managed by the AfterTriggers data structures,
rather than being directly the responsibility of ModifyTable nodes. This
removes a subtransaction-lifespan memory leak introduced by my previous
band-aid patch 3c4359521.
In passing, refactor the AfterTriggers data structures to reduce the
management overhead for them, by using arrays of structs rather than
several parallel arrays for per-query-level and per-subtransaction state.
I failed to resist the temptation to do some copy-editing on the SGML
docs about triggers, above and beyond merely documenting the effects
of this patch.
Back-patch to v10, because we don't want the semantics of transition
tables to change post-release.
Patch by me, with help and review from Thomas Munro.
Discussion: https://postgr.es/m/20170909064853.25630.12825@wrigleys.postgresql.org
2017-09-16 19:20:32 +02:00
|
|
|
* Note: in current usage, these flags could be part of the private state,
|
|
|
|
* but it seems possibly useful to let callers see them.
|
2017-06-28 19:55:03 +02:00
|
|
|
*/
|
|
|
|
bool tcs_delete_old_table;
|
|
|
|
bool tcs_update_old_table;
|
|
|
|
bool tcs_update_new_table;
|
|
|
|
bool tcs_insert_new_table;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For INSERT and COPY, it would be wasteful to convert tuples from child
|
|
|
|
* format to parent format after they have already been converted in the
|
|
|
|
* opposite direction during routing. In that case we bypass conversion
|
2020-11-23 10:36:13 +01:00
|
|
|
* and allow the inserting code (copyfrom.c and nodeModifyTable.c) to
|
|
|
|
* provide a slot containing the original tuple directly.
|
2017-06-28 19:55:03 +02:00
|
|
|
*/
|
2019-02-27 05:30:28 +01:00
|
|
|
TupleTableSlot *tcs_original_insert_tuple;
|
2017-06-28 19:59:01 +02:00
|
|
|
|
2017-06-28 20:00:55 +02:00
|
|
|
/*
|
Fix SQL-spec incompatibilities in new transition table feature.
The standard says that all changes of the same kind (insert, update, or
delete) caused in one table by a single SQL statement should be reported
in a single transition table; and by that, they mean to include foreign key
enforcement actions cascading from the statement's direct effects. It's
also reasonable to conclude that if the standard had wCTEs, they would say
that effects of wCTEs applying to the same table as each other or the outer
statement should be merged into one transition table. We weren't doing it
like that.
Hence, arrange to merge tuples from multiple update actions into a single
transition table as much as we can. There is a problem, which is that if
the firing of FK enforcement triggers and after-row triggers with
transition tables is interspersed, we might need to report more tuples
after some triggers have already seen the transition table. It seems like
a bad idea for the transition table to be mutable between trigger calls.
There's no good way around this without a major redesign of the FK logic,
so for now, resolve it by opening a new transition table each time this
happens.
Also, ensure that AFTER STATEMENT triggers fire just once per statement,
or once per transition table when we're forced to make more than one.
Previous versions of Postgres have allowed each FK enforcement query
to cause an additional firing of the AFTER STATEMENT triggers for the
referencing table, but that's certainly not per spec. (We're still
doing multiple firings of BEFORE STATEMENT triggers, though; is that
something worth changing?)
Also, forbid using transition tables with column-specific UPDATE triggers.
The spec requires such transition tables to show only the tuples for which
the UPDATE trigger would have fired, which means maintaining multiple
transition tables or else somehow filtering the contents at readout.
Maybe someday we'll bother to support that option, but it looks like a
lot of trouble for a marginal feature.
The transition tables are now managed by the AfterTriggers data structures,
rather than being directly the responsibility of ModifyTable nodes. This
removes a subtransaction-lifespan memory leak introduced by my previous
band-aid patch 3c4359521.
In passing, refactor the AfterTriggers data structures to reduce the
management overhead for them, by using arrays of structs rather than
several parallel arrays for per-query-level and per-subtransaction state.
I failed to resist the temptation to do some copy-editing on the SGML
docs about triggers, above and beyond merely documenting the effects
of this patch.
Back-patch to v10, because we don't want the semantics of transition
tables to change post-release.
Patch by me, with help and review from Thomas Munro.
Discussion: https://postgr.es/m/20170909064853.25630.12825@wrigleys.postgresql.org
2017-09-16 19:20:32 +02:00
|
|
|
* Private data including the tuplestore(s) into which to insert tuples.
|
2017-06-28 20:00:55 +02:00
|
|
|
*/
|
Fix SQL-spec incompatibilities in new transition table feature.
The standard says that all changes of the same kind (insert, update, or
delete) caused in one table by a single SQL statement should be reported
in a single transition table; and by that, they mean to include foreign key
enforcement actions cascading from the statement's direct effects. It's
also reasonable to conclude that if the standard had wCTEs, they would say
that effects of wCTEs applying to the same table as each other or the outer
statement should be merged into one transition table. We weren't doing it
like that.
Hence, arrange to merge tuples from multiple update actions into a single
transition table as much as we can. There is a problem, which is that if
the firing of FK enforcement triggers and after-row triggers with
transition tables is interspersed, we might need to report more tuples
after some triggers have already seen the transition table. It seems like
a bad idea for the transition table to be mutable between trigger calls.
There's no good way around this without a major redesign of the FK logic,
so for now, resolve it by opening a new transition table each time this
happens.
Also, ensure that AFTER STATEMENT triggers fire just once per statement,
or once per transition table when we're forced to make more than one.
Previous versions of Postgres have allowed each FK enforcement query
to cause an additional firing of the AFTER STATEMENT triggers for the
referencing table, but that's certainly not per spec. (We're still
doing multiple firings of BEFORE STATEMENT triggers, though; is that
something worth changing?)
Also, forbid using transition tables with column-specific UPDATE triggers.
The spec requires such transition tables to show only the tuples for which
the UPDATE trigger would have fired, which means maintaining multiple
transition tables or else somehow filtering the contents at readout.
Maybe someday we'll bother to support that option, but it looks like a
lot of trouble for a marginal feature.
The transition tables are now managed by the AfterTriggers data structures,
rather than being directly the responsibility of ModifyTable nodes. This
removes a subtransaction-lifespan memory leak introduced by my previous
band-aid patch 3c4359521.
In passing, refactor the AfterTriggers data structures to reduce the
management overhead for them, by using arrays of structs rather than
several parallel arrays for per-query-level and per-subtransaction state.
I failed to resist the temptation to do some copy-editing on the SGML
docs about triggers, above and beyond merely documenting the effects
of this patch.
Back-patch to v10, because we don't want the semantics of transition
tables to change post-release.
Patch by me, with help and review from Thomas Munro.
Discussion: https://postgr.es/m/20170909064853.25630.12825@wrigleys.postgresql.org
2017-09-16 19:20:32 +02:00
|
|
|
struct AfterTriggersTableData *tcs_private;
|
2017-06-28 19:55:03 +02:00
|
|
|
} TransitionCaptureState;
|
|
|
|
|
2008-03-28 01:21:56 +01:00
|
|
|
/*
|
|
|
|
* TriggerEvent bit flags
|
|
|
|
*
|
|
|
|
* Note that we assume different event types (INSERT/DELETE/UPDATE/TRUNCATE)
|
|
|
|
* can't be OR'd together in a single TriggerEvent. This is unlike the
|
|
|
|
* situation for pg_trigger rows, so pg_trigger.tgtype uses a different
|
|
|
|
* representation!
|
|
|
|
*/
|
1997-09-04 15:26:19 +02:00
|
|
|
#define TRIGGER_EVENT_INSERT 0x00000000
|
|
|
|
#define TRIGGER_EVENT_DELETE 0x00000001
|
|
|
|
#define TRIGGER_EVENT_UPDATE 0x00000002
|
2008-03-28 01:21:56 +01:00
|
|
|
#define TRIGGER_EVENT_TRUNCATE 0x00000003
|
1997-09-04 15:26:19 +02:00
|
|
|
#define TRIGGER_EVENT_OPMASK 0x00000003
|
2010-10-10 19:43:33 +02:00
|
|
|
|
1997-09-04 15:26:19 +02:00
|
|
|
#define TRIGGER_EVENT_ROW 0x00000004
|
2010-10-10 19:43:33 +02:00
|
|
|
|
1997-09-04 15:26:19 +02:00
|
|
|
#define TRIGGER_EVENT_BEFORE 0x00000008
|
2010-10-10 19:43:33 +02:00
|
|
|
#define TRIGGER_EVENT_AFTER 0x00000000
|
|
|
|
#define TRIGGER_EVENT_INSTEAD 0x00000010
|
|
|
|
#define TRIGGER_EVENT_TIMINGMASK 0x00000018
|
1997-09-01 10:10:12 +02:00
|
|
|
|
2004-09-10 20:40:09 +02:00
|
|
|
/* More TriggerEvent flags, used only within trigger.c */
|
|
|
|
|
2010-10-10 19:43:33 +02:00
|
|
|
#define AFTER_TRIGGER_DEFERRABLE 0x00000020
|
|
|
|
#define AFTER_TRIGGER_INITDEFERRED 0x00000040
|
1999-09-29 18:06:40 +02:00
|
|
|
|
2010-10-10 19:43:33 +02:00
|
|
|
#define TRIGGER_FIRED_BY_INSERT(event) \
|
|
|
|
(((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_INSERT)
|
1997-09-01 10:10:12 +02:00
|
|
|
|
2010-10-10 19:43:33 +02:00
|
|
|
#define TRIGGER_FIRED_BY_DELETE(event) \
|
|
|
|
(((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_DELETE)
|
1997-09-01 10:10:12 +02:00
|
|
|
|
2010-10-10 19:43:33 +02:00
|
|
|
#define TRIGGER_FIRED_BY_UPDATE(event) \
|
|
|
|
(((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_UPDATE)
|
1997-09-04 15:26:19 +02:00
|
|
|
|
2008-03-28 01:21:56 +01:00
|
|
|
#define TRIGGER_FIRED_BY_TRUNCATE(event) \
|
2010-10-10 19:43:33 +02:00
|
|
|
(((event) & TRIGGER_EVENT_OPMASK) == TRIGGER_EVENT_TRUNCATE)
|
|
|
|
|
|
|
|
#define TRIGGER_FIRED_FOR_ROW(event) \
|
|
|
|
((event) & TRIGGER_EVENT_ROW)
|
2008-03-28 01:21:56 +01:00
|
|
|
|
2010-10-10 19:43:33 +02:00
|
|
|
#define TRIGGER_FIRED_FOR_STATEMENT(event) \
|
|
|
|
(!TRIGGER_FIRED_FOR_ROW(event))
|
1997-09-04 15:26:19 +02:00
|
|
|
|
2010-10-10 19:43:33 +02:00
|
|
|
#define TRIGGER_FIRED_BEFORE(event) \
|
|
|
|
(((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_BEFORE)
|
1997-09-04 15:26:19 +02:00
|
|
|
|
2010-10-10 19:43:33 +02:00
|
|
|
#define TRIGGER_FIRED_AFTER(event) \
|
|
|
|
(((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_AFTER)
|
1997-09-04 15:26:19 +02:00
|
|
|
|
2010-10-10 19:43:33 +02:00
|
|
|
#define TRIGGER_FIRED_INSTEAD(event) \
|
|
|
|
(((event) & TRIGGER_EVENT_TIMINGMASK) == TRIGGER_EVENT_INSTEAD)
|
1997-09-01 10:10:12 +02:00
|
|
|
|
2007-03-20 00:38:32 +01:00
|
|
|
/*
|
2010-10-10 19:43:33 +02:00
|
|
|
* Definitions for replication role based firing.
|
2007-03-20 00:38:32 +01:00
|
|
|
*/
|
|
|
|
#define SESSION_REPLICATION_ROLE_ORIGIN 0
|
|
|
|
#define SESSION_REPLICATION_ROLE_REPLICA 1
|
|
|
|
#define SESSION_REPLICATION_ROLE_LOCAL 2
|
2008-09-19 16:43:46 +02:00
|
|
|
extern PGDLLIMPORT int SessionReplicationRole;
|
2007-03-20 00:38:32 +01:00
|
|
|
|
2009-01-22 20:16:31 +01:00
|
|
|
/*
|
|
|
|
* States at which a trigger can be fired. These are the
|
|
|
|
* possible values for pg_trigger.tgenabled.
|
|
|
|
*/
|
2007-03-20 00:38:32 +01:00
|
|
|
#define TRIGGER_FIRES_ON_ORIGIN 'O'
|
|
|
|
#define TRIGGER_FIRES_ALWAYS 'A'
|
|
|
|
#define TRIGGER_FIRES_ON_REPLICA 'R'
|
|
|
|
#define TRIGGER_DISABLED 'D'
|
1997-09-01 10:10:12 +02:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
extern ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
|
Avoid repeated name lookups during table and index DDL.
If the name lookups come to different conclusions due to concurrent
activity, we might perform some parts of the DDL on a different table
than other parts. At least in the case of CREATE INDEX, this can be
used to cause the permissions checks to be performed against a
different table than the index creation, allowing for a privilege
escalation attack.
This changes the calling convention for DefineIndex, CreateTrigger,
transformIndexStmt, transformAlterTableStmt, CheckIndexCompatible
(in 9.2 and newer), and AlterTable (in 9.1 and older). In addition,
CheckRelationOwnership is removed in 9.2 and newer and the calling
convention is changed in older branches. A field has also been added
to the Constraint node (FkConstraint in 8.4). Third-party code calling
these functions or using the Constraint node will require updating.
Report by Andres Freund. Patch by Robert Haas and Andres Freund,
reviewed by Tom Lane.
Security: CVE-2014-0062
2014-02-17 15:33:31 +01:00
|
|
|
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
|
2018-03-23 14:48:22 +01:00
|
|
|
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
|
|
|
|
bool isInternal, bool in_partition);
|
2021-07-16 19:01:43 +02:00
|
|
|
extern ObjectAddress CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
|
|
|
|
Oid relOid, Oid refRelOid, Oid constraintOid,
|
|
|
|
Oid indexOid, Oid funcoid, Oid parentTriggerOid,
|
|
|
|
Node *whenClause, bool isInternal, bool in_partition,
|
|
|
|
char trigger_fires_when);
|
2002-07-12 20:43:19 +02:00
|
|
|
|
2022-01-05 23:00:13 +01:00
|
|
|
extern void TriggerSetParentTrigger(Relation trigRel,
|
|
|
|
Oid childTrigId,
|
|
|
|
Oid parentTrigId,
|
|
|
|
Oid childTableId);
|
2002-07-12 20:43:19 +02:00
|
|
|
extern void RemoveTriggerById(Oid trigOid);
|
2022-09-20 22:09:30 +02:00
|
|
|
extern Oid get_trigger_oid(Oid relid, const char *trigname, bool missing_ok);
|
1997-08-31 13:42:21 +02:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
extern ObjectAddress renametrig(RenameStmt *stmt);
|
2002-04-26 21:29:47 +02:00
|
|
|
|
2023-03-04 19:32:35 +01:00
|
|
|
extern void EnableDisableTrigger(Relation rel, const char *tgname, Oid tgparent,
|
2022-08-04 20:02:02 +02:00
|
|
|
char fires_when, bool skip_system, bool recurse,
|
|
|
|
LOCKMODE lockmode);
|
2005-08-24 00:40:47 +02:00
|
|
|
|
2000-01-31 05:35:57 +01:00
|
|
|
extern void RelationBuildTriggers(Relation relation);
|
|
|
|
|
2002-10-14 18:51:30 +02:00
|
|
|
extern TriggerDesc *CopyTriggerDesc(TriggerDesc *trigdesc);
|
2000-01-31 05:35:57 +01:00
|
|
|
|
2017-06-28 19:55:03 +02:00
|
|
|
extern const char *FindTriggerIncompatibleWithInheritance(TriggerDesc *trigdesc);
|
Fix SQL-spec incompatibilities in new transition table feature.
The standard says that all changes of the same kind (insert, update, or
delete) caused in one table by a single SQL statement should be reported
in a single transition table; and by that, they mean to include foreign key
enforcement actions cascading from the statement's direct effects. It's
also reasonable to conclude that if the standard had wCTEs, they would say
that effects of wCTEs applying to the same table as each other or the outer
statement should be merged into one transition table. We weren't doing it
like that.
Hence, arrange to merge tuples from multiple update actions into a single
transition table as much as we can. There is a problem, which is that if
the firing of FK enforcement triggers and after-row triggers with
transition tables is interspersed, we might need to report more tuples
after some triggers have already seen the transition table. It seems like
a bad idea for the transition table to be mutable between trigger calls.
There's no good way around this without a major redesign of the FK logic,
so for now, resolve it by opening a new transition table each time this
happens.
Also, ensure that AFTER STATEMENT triggers fire just once per statement,
or once per transition table when we're forced to make more than one.
Previous versions of Postgres have allowed each FK enforcement query
to cause an additional firing of the AFTER STATEMENT triggers for the
referencing table, but that's certainly not per spec. (We're still
doing multiple firings of BEFORE STATEMENT triggers, though; is that
something worth changing?)
Also, forbid using transition tables with column-specific UPDATE triggers.
The spec requires such transition tables to show only the tuples for which
the UPDATE trigger would have fired, which means maintaining multiple
transition tables or else somehow filtering the contents at readout.
Maybe someday we'll bother to support that option, but it looks like a
lot of trouble for a marginal feature.
The transition tables are now managed by the AfterTriggers data structures,
rather than being directly the responsibility of ModifyTable nodes. This
removes a subtransaction-lifespan memory leak introduced by my previous
band-aid patch 3c4359521.
In passing, refactor the AfterTriggers data structures to reduce the
management overhead for them, by using arrays of structs rather than
several parallel arrays for per-query-level and per-subtransaction state.
I failed to resist the temptation to do some copy-editing on the SGML
docs about triggers, above and beyond merely documenting the effects
of this patch.
Back-patch to v10, because we don't want the semantics of transition
tables to change post-release.
Patch by me, with help and review from Thomas Munro.
Discussion: https://postgr.es/m/20170909064853.25630.12825@wrigleys.postgresql.org
2017-09-16 19:20:32 +02:00
|
|
|
|
|
|
|
extern TransitionCaptureState *MakeTransitionCaptureState(TriggerDesc *trigdesc,
|
|
|
|
Oid relid, CmdType cmdType);
|
2017-06-28 19:55:03 +02:00
|
|
|
|
2002-10-14 18:51:30 +02:00
|
|
|
extern void FreeTriggerDesc(TriggerDesc *trigdesc);
|
2000-01-31 05:35:57 +01:00
|
|
|
|
2002-11-23 04:59:09 +01:00
|
|
|
extern void ExecBSInsertTriggers(EState *estate,
|
|
|
|
ResultRelInfo *relinfo);
|
|
|
|
extern void ExecASInsertTriggers(EState *estate,
|
2017-06-28 19:59:01 +02:00
|
|
|
ResultRelInfo *relinfo,
|
|
|
|
TransitionCaptureState *transition_capture);
|
2019-02-27 05:30:28 +01:00
|
|
|
extern bool ExecBRInsertTriggers(EState *estate,
|
2001-06-01 04:41:36 +02:00
|
|
|
ResultRelInfo *relinfo,
|
2011-02-22 03:18:04 +01:00
|
|
|
TupleTableSlot *slot);
|
2001-01-22 01:50:07 +01:00
|
|
|
extern void ExecARInsertTriggers(EState *estate,
|
2001-06-01 04:41:36 +02:00
|
|
|
ResultRelInfo *relinfo,
|
2019-02-27 05:30:28 +01:00
|
|
|
TupleTableSlot *slot,
|
2017-06-28 19:55:03 +02:00
|
|
|
List *recheckIndexes,
|
|
|
|
TransitionCaptureState *transition_capture);
|
2019-02-27 05:30:28 +01:00
|
|
|
extern bool ExecIRInsertTriggers(EState *estate,
|
2010-10-10 19:43:33 +02:00
|
|
|
ResultRelInfo *relinfo,
|
2011-02-22 03:18:04 +01:00
|
|
|
TupleTableSlot *slot);
|
2002-11-23 04:59:09 +01:00
|
|
|
extern void ExecBSDeleteTriggers(EState *estate,
|
|
|
|
ResultRelInfo *relinfo);
|
|
|
|
extern void ExecASDeleteTriggers(EState *estate,
|
2017-06-28 19:59:01 +02:00
|
|
|
ResultRelInfo *relinfo,
|
|
|
|
TransitionCaptureState *transition_capture);
|
2001-06-01 04:41:36 +02:00
|
|
|
extern bool ExecBRDeleteTriggers(EState *estate,
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
EPQState *epqstate,
|
2003-03-27 15:33:11 +01:00
|
|
|
ResultRelInfo *relinfo,
|
2014-03-23 07:16:34 +01:00
|
|
|
ItemPointer tupleid,
|
2018-07-12 09:21:39 +02:00
|
|
|
HeapTuple fdw_trigtuple,
|
Fix concurrent update issues with MERGE.
If MERGE attempts an UPDATE or DELETE on a table with BEFORE ROW
triggers, or a cross-partition UPDATE (with or without triggers), and
a concurrent UPDATE or DELETE happens, the merge code would fail.
In some cases this would lead to a crash, while in others it would
cause the wrong merge action to be executed, or no action at all. The
immediate cause of the crash was the trigger code calling
ExecGetUpdateNewTuple() as part of the EPQ mechanism, which fails
because during a merge ri_projectNew is NULL, since merge has its own
per-action projection information, which ExecGetUpdateNewTuple() knows
nothing about.
Fix by arranging for the trigger code to exit early, returning the
TM_Result and TM_FailureData information, if a concurrent modification
is detected, allowing the merge code to do the necessary EPQ handling
in its own way. Similarly, prevent the cross-partition update code
from doing any EPQ processing for a merge, allowing the merge code to
work out what it needs to do.
This leads to a number of simplifications in nodeModifyTable.c. Most
notably, the ModifyTableContext->GetUpdateNewTuple() callback is no
longer needed, and mergeGetUpdateNewTuple() can be deleted, since
there is no longer any requirement for get-update-new-tuple during a
merge. Similarly, ModifyTableContext->cpUpdateRetrySlot is no longer
needed. Thus ExecGetUpdateNewTuple() and the retry_slot handling of
ExecCrossPartitionUpdate() can be restored to how they were in v14,
before the merge code was added, and ExecMergeMatched() no longer
needs any special-case handling for cross-partition updates.
While at it, tidy up ExecUpdateEpilogue() a bit, making it handle
recheckIndexes locally, rather than passing it in as a parameter,
ensuring that it is freed properly. This dates back to when it was
split off from ExecUpdate() to support merge.
Per bug #17809 from Alexander Lakhin, and follow-up investigation of
bug #17792, also from Alexander Lakhin.
Back-patch to v15, where MERGE was introduced, taking care to preserve
backwards-compatibility of the trigger API in v15 for any extensions
that might use it.
Discussion:
https://postgr.es/m/17809-9e6650bef133f0fe%40postgresql.org
https://postgr.es/m/17792-0f89452029662c36%40postgresql.org
2023-03-13 11:22:22 +01:00
|
|
|
TupleTableSlot **epqslot,
|
|
|
|
TM_Result *tmresult,
|
|
|
|
TM_FailureData *tmfd);
|
2001-06-01 04:41:36 +02:00
|
|
|
extern void ExecARDeleteTriggers(EState *estate,
|
|
|
|
ResultRelInfo *relinfo,
|
2017-06-28 19:55:03 +02:00
|
|
|
HeapTuple fdw_trigtuple,
|
Allow locking updated tuples in tuple_update() and tuple_delete()
Currently, in read committed transaction isolation mode (default), we have the
following sequence of actions when tuple_update()/tuple_delete() finds
the tuple updated by the concurrent transaction.
1. Attempt to update/delete tuple with tuple_update()/tuple_delete(), which
returns TM_Updated.
2. Lock tuple with tuple_lock().
3. Re-evaluate plan qual (recheck if we still need to update/delete and
calculate the new tuple for update).
4. Second attempt to update/delete tuple with tuple_update()/tuple_delete().
This attempt should be successful, since the tuple was previously locked.
This commit eliminates step 2 by taking the lock during the first
tuple_update()/tuple_delete() call. The heap table access method saves some
effort by checking the updated tuple once instead of twice. Future
undo-based table access methods, which will start from the latest row version,
can immediately place a lock there.
Also, this commit makes tuple_update()/tuple_delete() optionally save the old
tuple into the dedicated slot. That saves efforts on re-fetching tuples in
certain cases.
The code in nodeModifyTable.c is simplified by removing the nested switch/case.
Discussion: https://postgr.es/m/CAPpHfdua-YFw3XTprfutzGp28xXLigFtzNbuFY8yPhqeq6X5kg%40mail.gmail.com
Reviewed-by: Aleksander Alekseev, Pavel Borisov, Vignesh C, Mason Sharp
Reviewed-by: Andres Freund, Chris Travers
2024-03-26 00:27:56 +01:00
|
|
|
TupleTableSlot *slot,
|
Enforce foreign key correctly during cross-partition updates
When an update on a partitioned table referenced in foreign key
constraints causes a row to move from one partition to another,
the fact that the move is implemented as a delete followed by an insert
on the target partition causes the foreign key triggers to have
surprising behavior. For example, a given foreign key's delete trigger
which implements the ON DELETE CASCADE clause of that key will delete
any referencing rows when triggered for that internal DELETE, although
it should not, because the referenced row is simply being moved from one
partition of the referenced root partitioned table into another, not
being deleted from it.
This commit teaches trigger.c to skip queuing such delete trigger events
on the leaf partitions in favor of an UPDATE event fired on the root
target relation. Doing so is sensible because both the old and the new
tuple "logically" belong to the root relation.
The after trigger event queuing interface now allows passing the source
and the target partitions of a particular cross-partition update when
registering the update event for the root partitioned table. Along with
the two ctids of the old and the new tuple, the after trigger event now
also stores the OIDs of those partitions. The tuples fetched from the
source and the target partitions are converted into the root table
format, if necessary, before they are passed to the trigger function.
The implementation currently has a limitation that only the foreign keys
pointing into the query's target relation are considered, not those of
its sub-partitioned partitions. That seems like a reasonable
limitation, because it sounds rare to have distinct foreign keys
pointing to sub-partitioned partitions instead of to the root table.
This misbehavior stems from commit f56f8f8da6af (which added support for
foreign keys to reference partitioned tables) not paying sufficient
attention to commit 2f178441044b (which had introduced cross-partition
updates a year earlier). Even though the former commit goes back to
Postgres 12, we're not backpatching this fix at this time for fear of
destabilizing things too much, and because there are a few ABI breaks in
it that we'd have to work around in older branches. It also depends on
commit f4566345cf40, which had its own share of backpatchability issues
as well.
Author: Amit Langote <amitlangote09@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Reported-by: Eduard Català <eduard.catala@gmail.com>
Discussion: https://postgr.es/m/CA+HiwqFvkBCmfwkQX_yBqv2Wz8ugUGiBDxum8=WvVbfU1TXaNg@mail.gmail.com
Discussion: https://postgr.es/m/CAL54xNZsLwEM1XCk5yW9EqaRzsZYHuWsHQkA2L5MOSKXAwviCQ@mail.gmail.com
2022-03-20 18:43:40 +01:00
|
|
|
TransitionCaptureState *transition_capture,
|
|
|
|
bool is_crosspart_update);
|
2010-10-10 19:43:33 +02:00
|
|
|
extern bool ExecIRDeleteTriggers(EState *estate,
|
|
|
|
ResultRelInfo *relinfo,
|
|
|
|
HeapTuple trigtuple);
|
2002-11-23 04:59:09 +01:00
|
|
|
extern void ExecBSUpdateTriggers(EState *estate,
|
|
|
|
ResultRelInfo *relinfo);
|
|
|
|
extern void ExecASUpdateTriggers(EState *estate,
|
2017-06-28 19:59:01 +02:00
|
|
|
ResultRelInfo *relinfo,
|
|
|
|
TransitionCaptureState *transition_capture);
|
2019-02-27 05:30:28 +01:00
|
|
|
extern bool ExecBRUpdateTriggers(EState *estate,
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
EPQState *epqstate,
|
2003-03-27 15:33:11 +01:00
|
|
|
ResultRelInfo *relinfo,
|
|
|
|
ItemPointer tupleid,
|
2014-03-23 07:16:34 +01:00
|
|
|
HeapTuple fdw_trigtuple,
|
2022-09-20 22:09:30 +02:00
|
|
|
TupleTableSlot *newslot,
|
Fix concurrent update issues with MERGE.
If MERGE attempts an UPDATE or DELETE on a table with BEFORE ROW
triggers, or a cross-partition UPDATE (with or without triggers), and
a concurrent UPDATE or DELETE happens, the merge code would fail.
In some cases this would lead to a crash, while in others it would
cause the wrong merge action to be executed, or no action at all. The
immediate cause of the crash was the trigger code calling
ExecGetUpdateNewTuple() as part of the EPQ mechanism, which fails
because during a merge ri_projectNew is NULL, since merge has its own
per-action projection information, which ExecGetUpdateNewTuple() knows
nothing about.
Fix by arranging for the trigger code to exit early, returning the
TM_Result and TM_FailureData information, if a concurrent modification
is detected, allowing the merge code to do the necessary EPQ handling
in its own way. Similarly, prevent the cross-partition update code
from doing any EPQ processing for a merge, allowing the merge code to
work out what it needs to do.
This leads to a number of simplifications in nodeModifyTable.c. Most
notably, the ModifyTableContext->GetUpdateNewTuple() callback is no
longer needed, and mergeGetUpdateNewTuple() can be deleted, since
there is no longer any requirement for get-update-new-tuple during a
merge. Similarly, ModifyTableContext->cpUpdateRetrySlot is no longer
needed. Thus ExecGetUpdateNewTuple() and the retry_slot handling of
ExecCrossPartitionUpdate() can be restored to how they were in v14,
before the merge code was added, and ExecMergeMatched() no longer
needs any special-case handling for cross-partition updates.
While at it, tidy up ExecUpdateEpilogue() a bit, making it handle
recheckIndexes locally, rather than passing it in as a parameter,
ensuring that it is freed properly. This dates back to when it was
split off from ExecUpdate() to support merge.
Per bug #17809 from Alexander Lakhin, and follow-up investigation of
bug #17792, also from Alexander Lakhin.
Back-patch to v15, where MERGE was introduced, taking care to preserve
backwards-compatibility of the trigger API in v15 for any extensions
that might use it.
Discussion:
https://postgr.es/m/17809-9e6650bef133f0fe%40postgresql.org
https://postgr.es/m/17792-0f89452029662c36%40postgresql.org
2023-03-13 11:22:22 +01:00
|
|
|
TM_Result *tmresult,
|
2022-09-20 22:09:30 +02:00
|
|
|
TM_FailureData *tmfd);
|
2001-06-01 04:41:36 +02:00
|
|
|
extern void ExecARUpdateTriggers(EState *estate,
|
|
|
|
ResultRelInfo *relinfo,
|
Enforce foreign key correctly during cross-partition updates
When an update on a partitioned table referenced in foreign key
constraints causes a row to move from one partition to another,
the fact that the move is implemented as a delete followed by an insert
on the target partition causes the foreign key triggers to have
surprising behavior. For example, a given foreign key's delete trigger
which implements the ON DELETE CASCADE clause of that key will delete
any referencing rows when triggered for that internal DELETE, although
it should not, because the referenced row is simply being moved from one
partition of the referenced root partitioned table into another, not
being deleted from it.
This commit teaches trigger.c to skip queuing such delete trigger events
on the leaf partitions in favor of an UPDATE event fired on the root
target relation. Doing so is sensible because both the old and the new
tuple "logically" belong to the root relation.
The after trigger event queuing interface now allows passing the source
and the target partitions of a particular cross-partition update when
registering the update event for the root partitioned table. Along with
the two ctids of the old and the new tuple, the after trigger event now
also stores the OIDs of those partitions. The tuples fetched from the
source and the target partitions are converted into the root table
format, if necessary, before they are passed to the trigger function.
The implementation currently has a limitation that only the foreign keys
pointing into the query's target relation are considered, not those of
its sub-partitioned partitions. That seems like a reasonable
limitation, because it sounds rare to have distinct foreign keys
pointing to sub-partitioned partitions instead of to the root table.
This misbehavior stems from commit f56f8f8da6af (which added support for
foreign keys to reference partitioned tables) not paying sufficient
attention to commit 2f178441044b (which had introduced cross-partition
updates a year earlier). Even though the former commit goes back to
Postgres 12, we're not backpatching this fix at this time for fear of
destabilizing things too much, and because there are a few ABI breaks in
it that we'd have to work around in older branches. It also depends on
commit f4566345cf40, which had its own share of backpatchability issues
as well.
Author: Amit Langote <amitlangote09@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Reported-by: Eduard Català <eduard.catala@gmail.com>
Discussion: https://postgr.es/m/CA+HiwqFvkBCmfwkQX_yBqv2Wz8ugUGiBDxum8=WvVbfU1TXaNg@mail.gmail.com
Discussion: https://postgr.es/m/CAL54xNZsLwEM1XCk5yW9EqaRzsZYHuWsHQkA2L5MOSKXAwviCQ@mail.gmail.com
2022-03-20 18:43:40 +01:00
|
|
|
ResultRelInfo *src_partinfo,
|
|
|
|
ResultRelInfo *dst_partinfo,
|
2014-03-23 07:16:34 +01:00
|
|
|
HeapTuple fdw_trigtuple,
|
Allow locking updated tuples in tuple_update() and tuple_delete()
Currently, in read committed transaction isolation mode (default), we have the
following sequence of actions when tuple_update()/tuple_delete() finds
the tuple updated by the concurrent transaction.
1. Attempt to update/delete tuple with tuple_update()/tuple_delete(), which
returns TM_Updated.
2. Lock tuple with tuple_lock().
3. Re-evaluate plan qual (recheck if we still need to update/delete and
calculate the new tuple for update).
4. Second attempt to update/delete tuple with tuple_update()/tuple_delete().
This attempt should be successful, since the tuple was previously locked.
This commit eliminates step 2 by taking the lock during the first
tuple_update()/tuple_delete() call. The heap table access method saves some
effort by checking the updated tuple once instead of twice. Future
undo-based table access methods, which will start from the latest row version,
can immediately place a lock there.
Also, this commit makes tuple_update()/tuple_delete() optionally save the old
tuple into the dedicated slot. That saves efforts on re-fetching tuples in
certain cases.
The code in nodeModifyTable.c is simplified by removing the nested switch/case.
Discussion: https://postgr.es/m/CAPpHfdua-YFw3XTprfutzGp28xXLigFtzNbuFY8yPhqeq6X5kg%40mail.gmail.com
Reviewed-by: Aleksander Alekseev, Pavel Borisov, Vignesh C, Mason Sharp
Reviewed-by: Andres Freund, Chris Travers
2024-03-26 00:27:56 +01:00
|
|
|
TupleTableSlot *oldslot,
|
2022-09-20 22:09:30 +02:00
|
|
|
TupleTableSlot *newslot,
|
2017-06-28 19:55:03 +02:00
|
|
|
List *recheckIndexes,
|
Enforce foreign key correctly during cross-partition updates
When an update on a partitioned table referenced in foreign key
constraints causes a row to move from one partition to another,
the fact that the move is implemented as a delete followed by an insert
on the target partition causes the foreign key triggers to have
surprising behavior. For example, a given foreign key's delete trigger
which implements the ON DELETE CASCADE clause of that key will delete
any referencing rows when triggered for that internal DELETE, although
it should not, because the referenced row is simply being moved from one
partition of the referenced root partitioned table into another, not
being deleted from it.
This commit teaches trigger.c to skip queuing such delete trigger events
on the leaf partitions in favor of an UPDATE event fired on the root
target relation. Doing so is sensible because both the old and the new
tuple "logically" belong to the root relation.
The after trigger event queuing interface now allows passing the source
and the target partitions of a particular cross-partition update when
registering the update event for the root partitioned table. Along with
the two ctids of the old and the new tuple, the after trigger event now
also stores the OIDs of those partitions. The tuples fetched from the
source and the target partitions are converted into the root table
format, if necessary, before they are passed to the trigger function.
The implementation currently has a limitation that only the foreign keys
pointing into the query's target relation are considered, not those of
its sub-partitioned partitions. That seems like a reasonable
limitation, because it sounds rare to have distinct foreign keys
pointing to sub-partitioned partitions instead of to the root table.
This misbehavior stems from commit f56f8f8da6af (which added support for
foreign keys to reference partitioned tables) not paying sufficient
attention to commit 2f178441044b (which had introduced cross-partition
updates a year earlier). Even though the former commit goes back to
Postgres 12, we're not backpatching this fix at this time for fear of
destabilizing things too much, and because there are a few ABI breaks in
it that we'd have to work around in older branches. It also depends on
commit f4566345cf40, which had its own share of backpatchability issues
as well.
Author: Amit Langote <amitlangote09@gmail.com>
Reviewed-by: Masahiko Sawada <sawada.mshk@gmail.com>
Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Reported-by: Eduard Català <eduard.catala@gmail.com>
Discussion: https://postgr.es/m/CA+HiwqFvkBCmfwkQX_yBqv2Wz8ugUGiBDxum8=WvVbfU1TXaNg@mail.gmail.com
Discussion: https://postgr.es/m/CAL54xNZsLwEM1XCk5yW9EqaRzsZYHuWsHQkA2L5MOSKXAwviCQ@mail.gmail.com
2022-03-20 18:43:40 +01:00
|
|
|
TransitionCaptureState *transition_capture,
|
|
|
|
bool is_crosspart_update);
|
2019-02-27 05:30:28 +01:00
|
|
|
extern bool ExecIRUpdateTriggers(EState *estate,
|
2010-10-10 19:43:33 +02:00
|
|
|
ResultRelInfo *relinfo,
|
2011-02-22 03:18:04 +01:00
|
|
|
HeapTuple trigtuple,
|
2022-09-20 22:09:30 +02:00
|
|
|
TupleTableSlot *newslot);
|
2008-03-28 01:21:56 +01:00
|
|
|
extern void ExecBSTruncateTriggers(EState *estate,
|
|
|
|
ResultRelInfo *relinfo);
|
|
|
|
extern void ExecASTruncateTriggers(EState *estate,
|
|
|
|
ResultRelInfo *relinfo);
|
1999-09-29 18:06:40 +02:00
|
|
|
|
2004-09-10 20:40:09 +02:00
|
|
|
extern void AfterTriggerBeginXact(void);
|
|
|
|
extern void AfterTriggerBeginQuery(void);
|
2005-03-25 22:58:00 +01:00
|
|
|
extern void AfterTriggerEndQuery(EState *estate);
|
2005-04-11 21:51:16 +02:00
|
|
|
extern void AfterTriggerFireDeferred(void);
|
|
|
|
extern void AfterTriggerEndXact(bool isCommit);
|
2004-09-10 20:40:09 +02:00
|
|
|
extern void AfterTriggerBeginSubXact(void);
|
|
|
|
extern void AfterTriggerEndSubXact(bool isCommit);
|
|
|
|
extern void AfterTriggerSetState(ConstraintsSetStmt *stmt);
|
2008-01-03 00:34:42 +01:00
|
|
|
extern bool AfterTriggerPendingOnRel(Oid relid);
|
1999-09-29 18:06:40 +02:00
|
|
|
|
|
|
|
|
2000-01-06 21:47:01 +01:00
|
|
|
/*
|
|
|
|
* in utils/adt/ri_triggers.c
|
|
|
|
*/
|
2012-06-20 02:07:08 +02:00
|
|
|
extern bool RI_FKey_pk_upd_check_required(Trigger *trigger, Relation pk_rel,
|
2022-09-20 22:09:30 +02:00
|
|
|
TupleTableSlot *oldslot, TupleTableSlot *newslot);
|
2012-06-20 02:07:08 +02:00
|
|
|
extern bool RI_FKey_fk_upd_check_required(Trigger *trigger, Relation fk_rel,
|
2022-09-20 22:09:30 +02:00
|
|
|
TupleTableSlot *oldslot, TupleTableSlot *newslot);
|
2007-02-14 02:58:58 +01:00
|
|
|
extern bool RI_Initial_Check(Trigger *trigger,
|
|
|
|
Relation fk_rel, Relation pk_rel);
|
2019-04-03 19:38:20 +02:00
|
|
|
extern void RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel,
|
|
|
|
Relation pk_rel);
|
2001-10-28 07:26:15 +01:00
|
|
|
|
2007-02-14 02:58:58 +01:00
|
|
|
/* result values for RI_FKey_trigger_type: */
|
2005-05-30 09:20:59 +02:00
|
|
|
#define RI_TRIGGER_PK 1 /* is a trigger on the PK relation */
|
|
|
|
#define RI_TRIGGER_FK 2 /* is a trigger on the FK relation */
|
|
|
|
#define RI_TRIGGER_NONE 0 /* is not an RI trigger function */
|
|
|
|
|
|
|
|
extern int RI_FKey_trigger_type(Oid tgfoid);
|
|
|
|
|
1997-08-31 13:42:21 +02:00
|
|
|
#endif /* TRIGGER_H */
|