From 9274b32c9a551d6eda17d1ed023f3fdd5e7ad813 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <andrew@dunslane.net>
Date: Sat, 9 May 2026 14:57:09 -0400
Subject: [PATCH v2 1/1] Fire create_upper_paths_hook for
 UPPERREL_PARTIAL_GROUP_AGG

The planner already invites FDWs and extensions to add partial paths
on UPPERREL_PARTIAL_DISTINCT (see create_partial_distinct_paths), but
the symmetric create_upper_paths_hook call on UPPERREL_PARTIAL_GROUP_AGG
is missing.  Without it, an extension cannot register a partial-aggregate
path through the standard hook surface: by the time its
create_upper_paths_hook runs on UPPERREL_GROUP_AGG, the planner has
already gathered partial paths from partially_grouped_rel and built
Finalize Aggregate on top, so paths added late are dead code.

Fire create_upper_paths_hook on partially_grouped_rel at the end of
create_partial_grouping_paths, right next to the existing
GetForeignUpperPaths call for UPPERREL_PARTIAL_GROUP_AGG.  This mirrors
create_partial_distinct_paths, which pairs its GetForeignUpperPaths and
create_upper_paths_hook calls together at the end of that function for
UPPERREL_PARTIAL_DISTINCT.  Extensions adding partial paths here are
picked up naturally by the caller's subsequent gather_grouping_paths
call and become candidates for the upstream Finalize Aggregate built by
add_paths_to_grouping_rel.

The motivating use case is a CustomScan that wants to participate in
partial aggregation -- e.g. a table access method extension whose pushdown
runs cheaper than nodeAgg's standard transition path.  Without this
hook, the extension is forced to choose between sequential agg
pushdown (losing parallelism) or letting nodeAgg run unmodified
above its parallel scan (losing the pushdown).

Heap and other AMs are unaffected: this commit only adds a single
create_upper_paths_hook call at a place where it wasn't being fired
before.
---
 src/backend/optimizer/plan/planner.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index f4689e7c9f8..1ad6fee1cf2 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8016,6 +8016,24 @@ create_partial_grouping_paths(PlannerInfo *root,
 										 extra);
 	}

+	/*
+	 * Let extensions possibly add some more partial paths, mirroring the
+	 * FDW call above and the analogous extension hook on
+	 * UPPERREL_PARTIAL_DISTINCT in create_partial_distinct_paths.  Paths
+	 * added here are picked up by the caller's subsequent
+	 * gather_grouping_paths call and become candidates for the upstream
+	 * Finalize Aggregate that add_paths_to_grouping_rel builds.
+	 */
+	if (create_upper_paths_hook)
+	{
+		root->upper_targets[UPPERREL_PARTIAL_GROUP_AGG] =
+			partially_grouped_rel->reltarget;
+
+		(*create_upper_paths_hook) (root, UPPERREL_PARTIAL_GROUP_AGG,
+									input_rel, partially_grouped_rel,
+									extra);
+	}
+
 	return partially_grouped_rel;
 }

--
2.43.0
