=== Applying patches on top of PostgreSQL commit ID 3642df265d09779443a9f44f5cb873df40974e89 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Wed Mar 26 09:57:27 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 === patch: unrecognized option `--no-backup-if-mismatch' usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory] [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count] [-r rej-name] [-V t | nil | never | none] [-x number] [-z backup-ext] [--posix] [origfile [patchfile]] patch >>>>>> theirs /* @@@ -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); + appendStringInfoString(&intersectbuf, "("); + ri_GenerateQual(&intersectbuf, "", + attname, fk_period_type, + riinfo->period_intersect_oper, + paramname, pk_period_type); + appendStringInfoString(&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); }