=== Applying patches on top of PostgreSQL commit ID ad6ae52c49ac07b6ae2f8017b63ebd757b815d8f === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Mon Jul 20 10:59:27 UTC 2026 On branch cf/6981 nothing to commit, working tree clean === using 'git am' to apply patch ./v1-0001-Gate-the-NestLoop-inner-side-with-outer-only-join.patch === Applying: Gate the NestLoop inner side with outer-only join clauses Using index info to reconstruct a base tree... M contrib/postgres_fdw/expected/postgres_fdw.out M src/backend/optimizer/plan/createplan.c M src/include/nodes/plannodes.h M src/test/regress/expected/create_index.out M src/test/regress/expected/join.out M src/test/regress/expected/subselect.out M src/test/regress/sql/join.sql Falling back to patching base and 3-way merge... Auto-merging src/test/regress/sql/join.sql Auto-merging src/test/regress/expected/subselect.out Auto-merging src/test/regress/expected/join.out Auto-merging src/test/regress/expected/create_index.out Auto-merging src/include/nodes/plannodes.h Auto-merging src/backend/optimizer/plan/createplan.c CONFLICT (content): Merge conflict in src/backend/optimizer/plan/createplan.c Auto-merging contrib/postgres_fdw/expected/postgres_fdw.out error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Gate the NestLoop inner side with outer-only join clauses 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". === using patch(1) to apply patch ./v1-0001-Gate-the-NestLoop-inner-side-with-outer-only-join.patch === patching file contrib/postgres_fdw/expected/postgres_fdw.out Hunk #1 succeeded at 2532 (offset 75 lines). patching file src/backend/executor/nodeNestloop.c patching file src/backend/optimizer/plan/createplan.c Hunk #1 FAILED at 4191. Hunk #2 succeeded at 4245 (offset 7 lines). Hunk #3 succeeded at 4271 (offset 7 lines). Hunk #4 succeeded at 4293 with fuzz 2 (offset 12 lines). Hunk #5 succeeded at 4429 with fuzz 1 (offset 13 lines). 1 out of 5 hunks FAILED -- saving rejects to file src/backend/optimizer/plan/createplan.c.rej patching file src/include/nodes/plannodes.h Hunk #1 succeeded at 1010 (offset 2 lines). patching file src/test/regress/expected/create_index.out patching file src/test/regress/expected/join.out Hunk #12 succeeded at 4671 (offset 27 lines). Hunk #13 succeeded at 4723 (offset 27 lines). Hunk #14 succeeded at 4973 (offset 27 lines). Hunk #15 succeeded at 4982 (offset 27 lines). Hunk #16 succeeded at 5011 (offset 27 lines). Hunk #17 succeeded at 5018 (offset 27 lines). Hunk #18 succeeded at 5321 (offset 27 lines). Hunk #19 succeeded at 5384 (offset 27 lines). Hunk #20 succeeded at 5452 (offset 27 lines). Hunk #21 succeeded at 5587 (offset 27 lines). Hunk #22 succeeded at 5596 (offset 27 lines). Hunk #23 succeeded at 6267 (offset 27 lines). Hunk #24 succeeded at 6276 (offset 27 lines). Hunk #25 succeeded at 6532 (offset 27 lines). Hunk #26 succeeded at 8018 (offset 61 lines). Hunk #27 succeeded at 8047 (offset 61 lines). Hunk #28 succeeded at 8231 (offset 61 lines). Hunk #29 succeeded at 10234 (offset 61 lines). patching file src/test/regress/expected/predicate.out patching file src/test/regress/expected/subselect.out Hunk #1 succeeded at 3789 (offset 214 lines). patching file src/test/regress/sql/join.sql Hunk #1 succeeded at 3920 (offset 29 lines). Unstaged changes after reset: M contrib/postgres_fdw/expected/postgres_fdw.out M src/backend/executor/nodeNestloop.c M src/backend/optimizer/plan/createplan.c M src/include/nodes/plannodes.h M src/test/regress/expected/create_index.out M src/test/regress/expected/join.out M src/test/regress/expected/predicate.out M src/test/regress/expected/subselect.out M src/test/regress/sql/join.sql Removing src/backend/optimizer/plan/createplan.c.rej === using 'git apply' to apply patch ./v1-0001-Gate-the-NestLoop-inner-side-with-outer-only-join.patch === Applied patch to 'contrib/postgres_fdw/expected/postgres_fdw.out' cleanly. Applied patch to 'src/backend/executor/nodeNestloop.c' cleanly. Applied patch to 'src/backend/optimizer/plan/createplan.c' with conflicts. Applied patch to 'src/include/nodes/plannodes.h' cleanly. Applied patch to 'src/test/regress/expected/create_index.out' cleanly. Applied patch to 'src/test/regress/expected/join.out' cleanly. Applied patch to 'src/test/regress/expected/predicate.out' cleanly. Applied patch to 'src/test/regress/expected/subselect.out' cleanly. Applied patch to 'src/test/regress/sql/join.sql' cleanly. U src/backend/optimizer/plan/createplan.c diff --cc src/backend/optimizer/plan/createplan.c index 2c696ea0268,3d09c32d084..00000000000 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@@ -4197,9 -4191,11 +4197,15 @@@ create_nestloop_plan(PlannerInfo *root Plan *outer_plan; Plan *inner_plan; Relids outerrelids; ++<<<<<<< ours + Relids ojrelids; ++======= + Relids joinrelids = best_path->jpath.path.parent->relids; ++>>>>>>> theirs List *tlist = build_path_tlist(root, &best_path->jpath.path); List *joinrestrictclauses = best_path->jpath.joinrestrictinfo; + List *gating_clauses = NIL; + bool keep_inner_rewind = false; List *joinclauses; List *otherclauses; List *nestParams; @@@ -4264,11 -4284,68 +4294,73 @@@ replace_nestloop_params(root, (Node *) otherclauses); } + /* Identify any outer joins computed at this level */ + ojrelids = bms_difference(best_path->jpath.path.parent->relids, + bms_union(best_path->jpath.outerjoinpath->parent->relids, + best_path->jpath.innerjoinpath->parent->relids)); + + /* + * The gating clauses must be parameterized so the gating Result can + * evaluate them against the current outer tuple. + */ + if (gating_clauses != NIL) + { + Relids tmpOuterRels = root->curOuterRels; + Plan *subplan = inner_plan; + + /* + * Keep the inner side rewindable across rescans, but only when this + * gate is the sole source of nestloop parameters. + */ + keep_inner_rewind = + !bms_overlap(PATH_REQ_OUTER(best_path->jpath.innerjoinpath), + outerrelids); + + Assert(bms_is_subset(pull_varnos(root, (Node *) gating_clauses), + outerrelids)); + + /* + * replace_nestloop_params only converts Vars in curOuterRels, which + * was restored above and no longer covers this join's outer relids, + * so re-add them across the call. + */ + root->curOuterRels = bms_union(root->curOuterRels, outerrelids); + gating_clauses = (List *) + replace_nestloop_params(root, (Node *) gating_clauses); + bms_free(root->curOuterRels); + root->curOuterRels = tmpOuterRels; + + /* + * Avoid stacking Result nodes. If the inner plan is already a Result, + * merge our parameterized clauses into its resconstantqual. This + * mirrors create_gating_plan()'s logic. + */ + if (IsA(subplan, Result)) + { + Result *existing = (Result *) subplan; + List *clauses = (List *) existing->resconstantqual; + + Assert(clauses == NULL || IsA(clauses, List)); + + clauses = list_concat(gating_clauses, clauses); + clauses = order_qual_clauses(root, clauses); + existing->resconstantqual = (Node *) clauses; + + /* Gating quals could be unsafe, so use the Path's safety flag */ + existing->plan.parallel_safe = best_path->jpath.path.parallel_safe; + } + else + { + inner_plan = (Plan *) make_gating_result(subplan->targetlist, + (Node *) gating_clauses, + subplan); + copy_plan_costsize(inner_plan, subplan); + + /* Gating quals could be unsafe, so use the Path's safety flag */ + inner_plan->parallel_safe = best_path->jpath.path.parallel_safe; + } + } + /* * Identify any nestloop parameters that should be supplied by this join * node, and remove them from root->curOuterParams. @@@ -4340,9 -4417,10 +4432,11 @@@ outer_plan, inner_plan, best_path->jpath.jointype, + ojrelids, best_path->jpath.inner_unique); + join_plan->keep_inner_rewind = keep_inner_rewind; + copy_generic_path_info(&join_plan->join.plan, &best_path->jpath.path); return join_plan;