diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2023-03-04 13:32:35 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2023-03-04 13:32:35 -0500 |
commit | f61e60102f08305f3cb9e55a7958b8036a02fe39 (patch) | |
tree | c2c039a0f98a6ee77493e583e151dd21b67a1e31 /src/backend/commands/trigger.c | |
parent | 9d41ecfcd9a7cb4ec6b20add4a55603ebba03f0d (diff) | |
download | postgresql-f61e60102f08305f3cb9e55a7958b8036a02fe39.tar.gz postgresql-f61e60102f08305f3cb9e55a7958b8036a02fe39.zip |
Avoid failure when altering state of partitioned foreign-key triggers.
Beginning in v15, if you apply ALTER TABLE ENABLE/DISABLE TRIGGER to
a partitioned table, it also affects the partitions' cloned versions
of the affected trigger(s). The initial implementation of this
located the clones by name, but that fails on foreign-key triggers
which have names incorporating their own OIDs. We can fix that, and
also make the behavior more bulletproof in the face of user-initiated
trigger renames, by identifying the cloned triggers by tgparentid.
Following the lead of earlier commits in this area, I took care not
to break ABI in the v15 branch, even though I rather doubt there
are any external callers of EnableDisableTrigger.
While here, update the documentation, which was not touched when
the semantics were changed.
Per bug #17817 from Alan Hodgson. Back-patch to v15; older versions
do not have this behavior.
Discussion: https://postgr.es/m/17817-31dfb7c2100d9f3d@postgresql.org
Diffstat (limited to 'src/backend/commands/trigger.c')
-rw-r--r-- | src/backend/commands/trigger.c | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 36f10824077..d9d9201ac38 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -1754,7 +1754,8 @@ renametrig_partition(Relation tgrel, Oid partitionId, Oid parentTriggerOid, * to change 'tgenabled' field for the specified trigger(s) * * rel: relation to process (caller must hold suitable lock on it) - * tgname: trigger to process, or NULL to scan all triggers + * tgname: name of trigger to process, or NULL to scan all triggers + * tgparent: if not zero, process only triggers with this tgparentid * fires_when: new value for tgenabled field. In addition to generic * enablement/disablement, this also defines when the trigger * should be fired in session replication roles. @@ -1766,9 +1767,9 @@ renametrig_partition(Relation tgrel, Oid partitionId, Oid parentTriggerOid, * system triggers */ void -EnableDisableTriggerNew(Relation rel, const char *tgname, - char fires_when, bool skip_system, bool recurse, - LOCKMODE lockmode) +EnableDisableTriggerNew2(Relation rel, const char *tgname, Oid tgparent, + char fires_when, bool skip_system, bool recurse, + LOCKMODE lockmode) { Relation tgrel; int nkeys; @@ -1805,6 +1806,9 @@ EnableDisableTriggerNew(Relation rel, const char *tgname, { Form_pg_trigger oldtrig = (Form_pg_trigger) GETSTRUCT(tuple); + if (OidIsValid(tgparent) && tgparent != oldtrig->tgparentid) + continue; + if (oldtrig->tgisinternal) { /* system trigger ... ok to process? */ @@ -1855,9 +1859,10 @@ EnableDisableTriggerNew(Relation rel, const char *tgname, Relation part; part = relation_open(partdesc->oids[i], lockmode); - EnableDisableTriggerNew(part, NameStr(oldtrig->tgname), - fires_when, skip_system, recurse, - lockmode); + /* Match on child triggers' tgparentid, not their name */ + EnableDisableTriggerNew2(part, NULL, oldtrig->oid, + fires_when, skip_system, recurse, + lockmode); table_close(part, NoLock); /* keep lock till commit */ } } @@ -1886,16 +1891,27 @@ EnableDisableTriggerNew(Relation rel, const char *tgname, } /* - * ABI-compatible wrapper for the above. To keep as close possible to the old - * behavior, this never recurses. Do not call this function in new code. + * ABI-compatible wrappers to emulate old versions of the above function. + * Do not call these versions in new code. */ void +EnableDisableTriggerNew(Relation rel, const char *tgname, + char fires_when, bool skip_system, bool recurse, + LOCKMODE lockmode) +{ + EnableDisableTriggerNew2(rel, tgname, InvalidOid, + fires_when, skip_system, + recurse, lockmode); +} + +void EnableDisableTrigger(Relation rel, const char *tgname, char fires_when, bool skip_system, LOCKMODE lockmode) { - EnableDisableTriggerNew(rel, tgname, fires_when, skip_system, - true, lockmode); + EnableDisableTriggerNew2(rel, tgname, InvalidOid, + fires_when, skip_system, + true, lockmode); } |