=== Applying patches on top of PostgreSQL commit ID 2f5b05620330baed1648a1a6e2f231c7ba1368d1 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Sun Apr 27 21:09:26 UTC 2025 On branch cf/5450 nothing to commit, working tree clean === using 'git am' to apply patch ./v1-0001-Explicitly-pass-snapshot-necessary-for-omit_detac.patch === Applying: Explicitly pass snapshot necessary for omit_detached logic Using index info to reconstruct a base tree... M src/backend/catalog/pg_inherits.c M src/backend/executor/execPartition.c M src/backend/optimizer/util/plancat.c M src/backend/partitioning/partdesc.c M src/include/catalog/pg_inherits.h M src/include/partitioning/partdesc.h Falling back to patching base and 3-way merge... Auto-merging src/include/partitioning/partdesc.h Auto-merging src/include/catalog/pg_inherits.h Auto-merging src/backend/partitioning/partdesc.c Auto-merging src/backend/optimizer/util/plancat.c Auto-merging src/backend/executor/execPartition.c Auto-merging src/backend/catalog/pg_inherits.c === using 'git am' to apply patch ./v1-0002-Avoid-using-SPI-in-RI-trigger-functions.patch === Applying: Avoid using SPI in RI trigger functions Using index info to reconstruct a base tree... M src/backend/executor/spi.c M src/backend/utils/adt/ri_triggers.c Falling back to patching base and 3-way merge... Auto-merging src/backend/utils/adt/ri_triggers.c CONFLICT (content): Merge conflict in src/backend/utils/adt/ri_triggers.c Auto-merging src/backend/executor/spi.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Avoid using SPI in RI trigger functions When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". Unstaged changes after reset: M src/backend/executor/spi.c M src/backend/utils/adt/ri_triggers.c === using patch(1) to apply patch ./v1-0002-Avoid-using-SPI-in-RI-trigger-functions.patch === patching file src/backend/executor/spi.c Hunk #1 succeeded at 765 (offset 1 line). patching file src/backend/utils/adt/ri_triggers.c Hunk #3 succeeded at 137 (offset 2 lines). Hunk #4 succeeded at 199 (offset 2 lines). Hunk #5 succeeded at 262 (offset 2 lines). Hunk #6 succeeded at 272 (offset 2 lines). Hunk #7 FAILED at 286. Hunk #8 succeeded at 303 (offset 2 lines). Hunk #9 succeeded at 400 (offset 2 lines). Hunk #10 succeeded at 484 with fuzz 1 (offset 2 lines). Hunk #11 succeeded at 502 (offset 2 lines). Hunk #12 succeeded at 557 (offset 2 lines). Hunk #13 succeeded at 649 with fuzz 1 (offset 2 lines). Hunk #14 succeeded at 663 (offset 2 lines). Hunk #15 succeeded at 757 (offset 2 lines). Hunk #16 succeeded at 788 (offset 5 lines). Hunk #17 succeeded at 921 with fuzz 1 (offset 90 lines). Hunk #18 succeeded at 935 (offset 90 lines). Hunk #19 succeeded at 957 (offset 90 lines). Hunk #20 succeeded at 975 (offset 90 lines). Hunk #21 succeeded at 1018 (offset 90 lines). Hunk #22 succeeded at 1033 (offset 90 lines). Hunk #23 succeeded at 1056 (offset 90 lines). Hunk #24 succeeded at 1076 (offset 90 lines). Hunk #25 succeeded at 1132 (offset 90 lines). Hunk #26 succeeded at 1146 (offset 90 lines). Hunk #27 succeeded at 1228 (offset 90 lines). Hunk #28 succeeded at 1244 (offset 90 lines). Hunk #29 succeeded at 1356 (offset 90 lines). Hunk #30 succeeded at 1370 (offset 90 lines). Hunk #31 succeeded at 1560 (offset 90 lines). Hunk #32 succeeded at 2149 (offset 90 lines). Hunk #33 succeeded at 2168 (offset 90 lines). Hunk #34 succeeded at 2458 (offset 91 lines). Hunk #35 succeeded at 2836 (offset 91 lines). Hunk #36 succeeded at 2852 (offset 91 lines). Hunk #37 succeeded at 2919 (offset 91 lines). Hunk #38 succeeded at 2955 (offset 91 lines). Hunk #39 succeeded at 2975 (offset 91 lines). Hunk #40 succeeded at 3260 (offset 91 lines). Hunk #41 succeeded at 3295 (offset 91 lines). Hunk #42 succeeded at 3304 (offset 91 lines). Hunk #43 succeeded at 3316 (offset 91 lines). 1 out of 43 hunks FAILED -- saving rejects to file src/backend/utils/adt/ri_triggers.c.rej Unstaged changes after reset: M src/backend/executor/spi.c M src/backend/utils/adt/ri_triggers.c Removing src/backend/utils/adt/ri_triggers.c.rej === using 'git apply' to apply patch ./v1-0002-Avoid-using-SPI-in-RI-trigger-functions.patch === Applied patch to 'src/backend/executor/spi.c' cleanly. Applied patch to 'src/backend/utils/adt/ri_triggers.c' with conflicts. U src/backend/utils/adt/ri_triggers.c diff --cc src/backend/utils/adt/ri_triggers.c index 6239900fa28,804a2a69e47..00000000000 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@@ -235,10 -282,18 +284,25 @@@ static bool ri_PerformCheck(const RI_Co static void ri_ExtractValues(Relation rel, TupleTableSlot *slot, const RI_ConstraintInfo *riinfo, bool rel_is_pk, Datum *vals, char *nulls); ++<<<<<<< ours +pg_noreturn static void ri_ReportViolation(const RI_ConstraintInfo *riinfo, + Relation pk_rel, Relation fk_rel, + TupleTableSlot *violatorslot, TupleDesc tupdesc, + int queryno, bool is_restrict, bool partgone); ++======= + static void ri_ReportViolation(const RI_ConstraintInfo *riinfo, + Relation pk_rel, Relation fk_rel, + TupleTableSlot *violatorslot, TupleDesc tupdesc, + int queryno, bool is_restrict, bool partgone) pg_attribute_noreturn(); + static void ri_SqlStringPlanCreate(RI_Plan *plan, + const char *querystr, int nargs, Oid *paramtypes); + static bool ri_SqlStringPlanIsValid(RI_Plan *plan); + static int ri_SqlStringPlanExecute(RI_Plan *plan, Relation fk_rel, Relation pk_rel, + Datum *vals, char *nulls, + Snapshot crosscheck_snapshot, + int limit, CmdType *last_stmt_cmdtype); + static void ri_SqlStringPlanFree(RI_Plan *plan); ++>>>>>>> theirs /* @@@ -434,11 -487,12 +496,12 @@@ RI_FKey_check(TriggerData *trigdata paramname, fk_type, riinfo->agged_period_contained_by_oper, "pg_catalog.range_agg", ANYMULTIRANGEOID); - appendStringInfo(&querybuf, "(x1.r)"); + appendStringInfoString(&querybuf, "(x1.r)"); } - /* Prepare and save the plan */ - qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids, + /* Prepare and save the plan using ri_SqlStringPlanCreate(). */ + qplan = ri_PlanCheck(ri_SqlStringPlanCreate, + querybuf.data, riinfo->nkeys, queryoids, &qkey, fk_rel, pk_rel); } @@@ -603,11 -652,12 +661,12 @@@ ri_Check_Pk_Match(Relation pk_rel, Rela paramname, fk_type, riinfo->agged_period_contained_by_oper, "pg_catalog.range_agg", ANYMULTIRANGEOID); - appendStringInfo(&querybuf, "(x1.r)"); + appendStringInfoString(&querybuf, "(x1.r)"); } - /* Prepare and save the plan */ - qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids, + /* Prepare and save the plan using ri_SqlStringPlanCreate(). */ + qplan = ri_PlanCheck(ri_SqlStringPlanCreate, + querybuf.data, riinfo->nkeys, queryoids, &qkey, fk_rel, pk_rel); } @@@ -797,93 -837,11 +851,94 @@@ ri_restrict(TriggerData *trigdata, boo querysep = "AND"; queryoids[i] = pk_type; } + + /*---------- + * For temporal foreign keys, a reference could still be valid if the + * referenced range didn't change too much. Also if a referencing + * range extends past the current PK row, we don't want to check that + * part: some other PK row should fulfill it. We only want to check + * the part matching the PK record we've changed. Therefore to find + * invalid records we do this: + * + * SELECT 1 FROM [ONLY] x WHERE $1 = x.fkatt1 [AND ...] + * -- begin temporal + * AND $n && x.fkperiod + * AND NOT coalesce((x.fkperiod * $n) <@ + * (SELECT range_agg(r) + * FROM (SELECT y.pkperiod r + * FROM [ONLY] y + * WHERE $1 = y.pkatt1 [AND ...] AND $n && y.pkperiod + * FOR KEY SHARE OF y) y2), false) + * -- end temporal + * FOR KEY SHARE OF x + * + * We need the coalesce in case the first subquery returns no rows. + * We need the second subquery because FOR KEY SHARE doesn't support + * aggregate queries. + */ + if (riinfo->hasperiod && is_no_action) + { + Oid pk_period_type = RIAttType(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1]); + Oid fk_period_type = RIAttType(fk_rel, riinfo->fk_attnums[riinfo->nkeys - 1]); + StringInfoData intersectbuf; + StringInfoData replacementsbuf; + char *pk_only = pk_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ? + "" : "ONLY "; + + quoteOneName(attname, RIAttName(fk_rel, riinfo->fk_attnums[riinfo->nkeys - 1])); + sprintf(paramname, "$%d", riinfo->nkeys); + + appendStringInfoString(&querybuf, " AND NOT coalesce("); + + /* Intersect the fk with the old pk range */ + initStringInfo(&intersectbuf); + appendStringInfoChar(&intersectbuf, '('); + ri_GenerateQual(&intersectbuf, "", + attname, fk_period_type, + riinfo->period_intersect_oper, + paramname, pk_period_type); + appendStringInfoChar(&intersectbuf, ')'); + + /* Find the remaining history */ + initStringInfo(&replacementsbuf); + appendStringInfoString(&replacementsbuf, "(SELECT pg_catalog.range_agg(r) FROM "); + + quoteOneName(periodattname, RIAttName(pk_rel, riinfo->pk_attnums[riinfo->nkeys - 1])); + quoteRelationName(pkrelname, pk_rel); + appendStringInfo(&replacementsbuf, "(SELECT y.%s r FROM %s%s y", + periodattname, pk_only, pkrelname); + + /* Restrict pk rows to what matches */ + querysep = "WHERE"; + for (int i = 0; i < riinfo->nkeys; i++) + { + Oid pk_type = RIAttType(pk_rel, riinfo->pk_attnums[i]); + + quoteOneName(attname, + RIAttName(pk_rel, riinfo->pk_attnums[i])); + sprintf(paramname, "$%d", i + 1); + ri_GenerateQual(&replacementsbuf, querysep, + paramname, pk_type, + riinfo->pp_eq_oprs[i], + attname, pk_type); + querysep = "AND"; + queryoids[i] = pk_type; + } + appendStringInfoString(&replacementsbuf, " FOR KEY SHARE OF y) y2)"); + + ri_GenerateQual(&querybuf, "", + intersectbuf.data, fk_period_type, + riinfo->agged_period_contained_by_oper, + replacementsbuf.data, ANYMULTIRANGEOID); + /* end of coalesce: */ + appendStringInfoString(&querybuf, ", false)"); + } + appendStringInfoString(&querybuf, " FOR KEY SHARE OF x"); - /* Prepare and save the plan */ - qplan = ri_PlanCheck(querybuf.data, riinfo->nkeys, queryoids, + /* Prepare and save the plan using ri_SqlStringPlanCreate(). */ + qplan = ri_PlanCheck(ri_SqlStringPlanCreate, + querybuf.data, riinfo->nkeys, queryoids, &qkey, fk_rel, pk_rel); }