From bba58ae1e6b770b8a9c7b9fd2b467288691805c4 Mon Sep 17 00:00:00 2001 From: "Paul A. Jungwirth" Date: Fri, 13 Jun 2025 16:11:47 -0700 Subject: [PATCH v66 5/7] Look up additional temporal foreign key helper proc To implement CASCADE/SET NULL/SET DEFAULT on temporal foreign keys, we need an intersect function. We can look them it when we look up the operators already needed for temporal foreign keys (including NO ACTION constraints). Author: Paul A. Jungwirth --- src/backend/catalog/pg_constraint.c | 32 ++++++++++++++++++++++++----- src/backend/commands/tablecmds.c | 5 +++-- src/backend/parser/analyze.c | 2 +- src/backend/utils/adt/ri_triggers.c | 11 ++++++---- src/include/catalog/pg_constraint.h | 9 ++++---- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index b12765ae691..edb66a41fd6 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -1652,7 +1652,7 @@ DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, } /* - * FindFKPeriodOpers - + * FindFKPeriodOpersAndProcs - * * Looks up the operator oids used for the PERIOD part of a temporal foreign key. * The opclass should be the opclass of that PERIOD element. @@ -1663,12 +1663,15 @@ DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, * That way foreign keys can compare fkattr <@ range_agg(pkattr). * intersectoperoid is used by NO ACTION constraints to trim the range being considered * to just what was updated/deleted. + * intersectprocoid is used to limit the effect of CASCADE/SET NULL/SET DEFAULT + * when the PK record is changed with FOR PORTION OF. */ void -FindFKPeriodOpers(Oid opclass, - Oid *containedbyoperoid, - Oid *aggedcontainedbyoperoid, - Oid *intersectoperoid) +FindFKPeriodOpersAndProcs(Oid opclass, + Oid *containedbyoperoid, + Oid *aggedcontainedbyoperoid, + Oid *intersectoperoid, + Oid *intersectprocoid) { Oid opfamily = InvalidOid; Oid opcintype = InvalidOid; @@ -1710,6 +1713,17 @@ FindFKPeriodOpers(Oid opclass, aggedcontainedbyoperoid, &strat); + /* + * Hardcode intersect operators for ranges and multiranges, because we + * don't have a better way to look up operators that aren't used in + * indexes. + * + * If you change this code, you must change the code in + * transformForPortionOfClause. + * + * XXX: Find a more extensible way to look up the operator, permitting + * user-defined types. + */ switch (opcintype) { case ANYRANGEOID: @@ -1721,6 +1735,14 @@ FindFKPeriodOpers(Oid opclass, default: elog(ERROR, "unexpected opcintype: %u", opcintype); } + + /* + * Look up the intersect proc. We use this in temporal foreign keys with + * CASCADE/SET NULL/SET DEFAULT to build the FOR PORTION OF bounds. If + * this is missing we don't need to complain here, because FOR PORTION OF + * will not be allowed. + */ + *intersectprocoid = get_opcode(*intersectoperoid); } /* diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f976c0e5c7e..98ee5bab6cc 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -10602,9 +10602,10 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel, Oid periodoperoid; Oid aggedperiodoperoid; Oid intersectoperoid; + Oid intersectprocoid; - FindFKPeriodOpers(opclasses[numpks - 1], &periodoperoid, &aggedperiodoperoid, - &intersectoperoid); + FindFKPeriodOpersAndProcs(opclasses[numpks - 1], &periodoperoid, &aggedperiodoperoid, + &intersectoperoid, &intersectprocoid); } /* First, create the constraint catalog entry itself. */ diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 56d422c36f5..a1fa43be7c8 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1548,7 +1548,7 @@ transformForPortionOfClause(ParseState *pstate, /* * Whatever operator is used for intersect by temporal foreign keys, * we can use its backing procedure for intersects in FOR PORTION OF. - * XXX: Share code with FindFKPeriodOpers? + * XXX: Share code with FindFKPeriodOpersAndProcs? */ switch (opcintype) { diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index bbadecef5f9..526afa49d2d 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -131,6 +131,8 @@ typedef struct RI_ConstraintInfo Oid agged_period_contained_by_oper; /* fkattr <@ range_agg(pkattr) */ Oid period_intersect_oper; /* anyrange * anyrange (or * multiranges) */ + Oid period_intersect_proc; /* anyrange * anyrange (or + * multiranges) */ dlist_node valid_link; /* Link in list of valid entries */ } RI_ConstraintInfo; @@ -2339,10 +2341,11 @@ ri_LoadConstraintInfo(Oid constraintOid) { Oid opclass = get_index_column_opclass(conForm->conindid, riinfo->nkeys); - FindFKPeriodOpers(opclass, - &riinfo->period_contained_by_oper, - &riinfo->agged_period_contained_by_oper, - &riinfo->period_intersect_oper); + FindFKPeriodOpersAndProcs(opclass, + &riinfo->period_contained_by_oper, + &riinfo->agged_period_contained_by_oper, + &riinfo->period_intersect_oper, + &riinfo->period_intersect_proc); } ReleaseSysCache(tup); diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index d5661b5bdff..caeaa816cf6 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -288,10 +288,11 @@ extern void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks, AttrNumber *conkey, AttrNumber *confkey, Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs, int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols); -extern void FindFKPeriodOpers(Oid opclass, - Oid *containedbyoperoid, - Oid *aggedcontainedbyoperoid, - Oid *intersectoperoid); +extern void FindFKPeriodOpersAndProcs(Oid opclass, + Oid *containedbyoperoid, + Oid *aggedcontainedbyoperoid, + Oid *intersectoperoid, + Oid *intersectprocoid); extern bool check_functional_grouping(Oid relid, Index varno, Index varlevelsup, -- 2.47.3