 src/backend/optimizer/plan/planner.c | 117 +++++++++++++++++++++++++----------
 src/include/foreign/fdwapi.h         |   7 ++-
 src/include/optimizer/clauses.h      |   2 +-
 src/include/optimizer/planner.h      |  21 ++++++-
 4 files changed, 108 insertions(+), 39 deletions(-)

diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index fc0a2d8..14c6a20 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -109,15 +109,13 @@ static double get_number_of_groups(PlannerInfo *root,
 static RelOptInfo *create_grouping_paths(PlannerInfo *root,
 					  RelOptInfo *input_rel,
 					  PathTarget *target,
-					  List *rollup_lists,
-					  List *rollup_groupclauses);
+					  UpperPathExtraData *extra);
 static RelOptInfo *create_window_paths(PlannerInfo *root,
 					RelOptInfo *input_rel,
 					PathTarget *input_target,
 					PathTarget *output_target,
 					List *tlist,
-					WindowFuncLists *wflists,
-					List *activeWindows);
+					UpperPathExtraData *extra);
 static void create_one_window_path(PlannerInfo *root,
 					   RelOptInfo *window_rel,
 					   Path *path,
@@ -127,11 +125,12 @@ static void create_one_window_path(PlannerInfo *root,
 					   WindowFuncLists *wflists,
 					   List *activeWindows);
 static RelOptInfo *create_distinct_paths(PlannerInfo *root,
-					  RelOptInfo *input_rel);
+					  RelOptInfo *input_rel,
+					  UpperPathExtraData *extra);
 static RelOptInfo *create_ordered_paths(PlannerInfo *root,
 					 RelOptInfo *input_rel,
 					 PathTarget *target,
-					 double limit_tuples);
+					 UpperPathExtraData *extra);
 static PathTarget *make_group_input_target(PlannerInfo *root,
 						PathTarget *final_target);
 static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
@@ -917,6 +916,40 @@ preprocess_phv_expression(PlannerInfo *root, Expr *expr)
 }
 
 /*
+ * Let extensions, particularly FDWs and CustomScan providers, consider
+ * injecting extension Paths into the query's upperrels, where they will
+ * compete with the Paths we create below.  We pass a relation currently
+ * focused on because that's not so easily findable from the PlannerInfo
+ * struct; anything else the hooks want to know should be obtainable via
+ * "root" or "extra".
+ */
+static inline void
+create_extension_upper_paths(UpperRelationKind upper_kind,
+							 PlannerInfo *root,
+							 RelOptInfo *current_rel,
+							 UpperPathExtraData *extra)
+{
+	/*
+	 * For foreign data wrappers
+	 *
+	 * XXX - Right now, 'fdwroutine' field has a valid pointer only if
+	 * current_rel is the final join/scan relation. So, we may have to
+	 * give a chance for FDW driver, if current_rel is one of upper
+	 * relation. FDW may need to have a flag to show whether it is
+	 * capable to push-down upper path stuff like grouping, sorting,
+	 * and so on.
+	 */
+	if (current_rel->fdwroutine &&
+		current_rel->fdwroutine->GetForeignUpperPaths)
+		current_rel->fdwroutine->GetForeignUpperPaths(upper_kind, root,
+													  current_rel, extra);
+
+	/* For custom-scan providers */
+	if (create_upper_paths_hook)
+		(*create_upper_paths_hook) (upper_kind, root, current_rel, extra);
+}
+
+/*
  * inheritance_planner
  *	  Generate Paths in the case where the result relation is an
  *	  inheritance set.
@@ -1395,6 +1428,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 	RelOptInfo *current_rel;
 	RelOptInfo *final_rel;
 	ListCell   *lc;
+	UpperPathExtraData extra;
 
 	/* Tweak caller-supplied tuple_fraction if have LIMIT/OFFSET */
 	if (parse->limitCount || parse->limitOffset)
@@ -1474,6 +1508,10 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 		root->sort_pathkeys = make_pathkeys_for_sortclauses(root,
 															parse->sortClause,
 															tlist);
+
+		/* only limit_tuples may be referenced in this code path */
+		memset(&extra, 0, sizeof(UpperPathExtraData));
+		extra.limit_tuples = limit_tuples;
 	}
 	else
 	{
@@ -1751,20 +1789,12 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 		root->upper_targets[UPPERREL_WINDOW] = sort_input_target;
 		root->upper_targets[UPPERREL_GROUP_AGG] = grouping_target;
 
-		/*
-		 * Let extensions, particularly FDWs and CustomScan providers,
-		 * consider injecting extension Paths into the query's upperrels,
-		 * where they will compete with the Paths we create below.  We pass
-		 * the final scan/join rel because that's not so easily findable from
-		 * the PlannerInfo struct; anything else the hooks want to know should
-		 * be obtainable via "root".
-		 */
-		if (current_rel->fdwroutine &&
-			current_rel->fdwroutine->GetForeignUpperPaths)
-			current_rel->fdwroutine->GetForeignUpperPaths(root, current_rel);
-
-		if (create_upper_paths_hook)
-			(*create_upper_paths_hook) (root, current_rel);
+		/* Extra arguments */
+		extra.rollup_lists = rollup_lists;
+		extra.rollup_groupclauses = rollup_groupclauses;
+		extra.wflists = wflists;
+		extra.activeWindows = activeWindows;
+		extra.limit_tuples = (have_postponed_srfs ? -1.0 : limit_tuples);
 
 		/*
 		 * If we have grouping and/or aggregation, consider ways to implement
@@ -1776,8 +1806,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 			current_rel = create_grouping_paths(root,
 												current_rel,
 												grouping_target,
-												rollup_lists,
-												rollup_groupclauses);
+												&extra);
 		}
 
 		/*
@@ -1791,8 +1820,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 											  grouping_target,
 											  sort_input_target,
 											  tlist,
-											  wflists,
-											  activeWindows);
+											  &extra);
 		}
 
 		/*
@@ -1802,7 +1830,8 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 		if (parse->distinctClause)
 		{
 			current_rel = create_distinct_paths(root,
-												current_rel);
+												current_rel,
+												&extra);
 		}
 
 	}							/* end of if (setOperations) */
@@ -1819,8 +1848,7 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 		current_rel = create_ordered_paths(root,
 										   current_rel,
 										   final_target,
-										   have_postponed_srfs ? -1.0 :
-										   limit_tuples);
+										   &extra);
 	}
 
 	/*
@@ -1942,6 +1970,9 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 		add_path(final_rel, path);
 	}
 
+	/* Extension may also add its custom path for final relation */
+	create_extension_upper_paths(UPPERREL_FINAL, root, current_rel, &extra);
+
 	/* Note: currently, we leave it to callers to do set_cheapest() */
 }
 
@@ -3157,9 +3188,10 @@ static RelOptInfo *
 create_grouping_paths(PlannerInfo *root,
 					  RelOptInfo *input_rel,
 					  PathTarget *target,
-					  List *rollup_lists,
-					  List *rollup_groupclauses)
+					  UpperPathExtraData *extra)
 {
+	List	   *rollup_lists = extra->rollup_lists;
+	List	   *rollup_groupclauses = extra->rollup_groupclauses;
 	Query	   *parse = root->parse;
 	Path	   *cheapest_path = input_rel->cheapest_total_path;
 	RelOptInfo *grouped_rel;
@@ -3409,6 +3441,10 @@ create_grouping_paths(PlannerInfo *root,
 								 dNumGroups));
 	}
 
+	/* Extension may also add its custom path for grouping */
+	create_extension_upper_paths(UPPERREL_GROUP_AGG,
+								 root, input_rel, extra);
+
 	/* Give a helpful error if we failed to find any implementation */
 	if (grouped_rel->pathlist == NIL)
 		ereport(ERROR,
@@ -3442,9 +3478,10 @@ create_window_paths(PlannerInfo *root,
 					PathTarget *input_target,
 					PathTarget *output_target,
 					List *tlist,
-					WindowFuncLists *wflists,
-					List *activeWindows)
+					UpperPathExtraData *extra)
 {
+	WindowFuncLists *wflists = extra->wflists;
+	List	   *activeWindows = extra->activeWindows;
 	RelOptInfo *window_rel;
 	ListCell   *lc;
 
@@ -3472,6 +3509,10 @@ create_window_paths(PlannerInfo *root,
 								   activeWindows);
 	}
 
+	/* Extension may also add its custom path for window function */
+	create_extension_upper_paths(UPPERREL_WINDOW,
+								 root, input_rel, extra);
+
 	/* Now choose the best path(s) */
 	set_cheapest(window_rel);
 
@@ -3588,7 +3629,8 @@ create_one_window_path(PlannerInfo *root,
  */
 static RelOptInfo *
 create_distinct_paths(PlannerInfo *root,
-					  RelOptInfo *input_rel)
+					  RelOptInfo *input_rel,
+					  UpperPathExtraData *extra)
 {
 	Query	   *parse = root->parse;
 	Path	   *cheapest_input_path = input_rel->cheapest_total_path;
@@ -3738,6 +3780,10 @@ create_distinct_paths(PlannerInfo *root,
 								 numDistinctRows));
 	}
 
+	/* Extension may also add its custom path for distinct */
+	create_extension_upper_paths(UPPERREL_DISTINCT,
+								 root, input_rel, extra);
+
 	/* Give a helpful error if we failed to find any implementation */
 	if (distinct_rel->pathlist == NIL)
 		ereport(ERROR,
@@ -3769,8 +3815,9 @@ static RelOptInfo *
 create_ordered_paths(PlannerInfo *root,
 					 RelOptInfo *input_rel,
 					 PathTarget *target,
-					 double limit_tuples)
+					 UpperPathExtraData *extra)
 {
+	double		limit_tuples = extra->limit_tuples;
 	Path	   *cheapest_input_path = input_rel->cheapest_total_path;
 	RelOptInfo *ordered_rel;
 	ListCell   *lc;
@@ -3806,6 +3853,10 @@ create_ordered_paths(PlannerInfo *root,
 		}
 	}
 
+	/* Extension may also add its custom path for grouping */
+	create_extension_upper_paths(UPPERREL_ORDERED,
+								 root, input_rel, extra);
+
 	/*
 	 * No need to bother with set_cheapest here; grouping_planner does not
 	 * need us to do it.
diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h
index 7164360..fd61bb8 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -59,8 +59,11 @@ typedef void (*GetForeignJoinPaths_function) (PlannerInfo *root,
 														  JoinType jointype,
 												   JoinPathExtraData *extra);
 
-typedef void (*GetForeignUpperPaths_function) (PlannerInfo *root,
-											   RelOptInfo *scan_join_rel);
+struct UpperPathExtraData;		/* not to include planner.h here */
+typedef void (*GetForeignUpperPaths_function) (UpperRelationKind upper_kind,
+											   PlannerInfo *root,
+											   RelOptInfo *scan_join_rel,
+											struct UpperPathExtraData *extra);
 
 typedef void (*AddForeignUpdateTargets_function) (Query *parsetree,
 												   RangeTblEntry *target_rte,
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 3b3fd0f..f1261e4 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -20,7 +20,7 @@
 #define is_opclause(clause)		((clause) != NULL && IsA(clause, OpExpr))
 #define is_funcclause(clause)	((clause) != NULL && IsA(clause, FuncExpr))
 
-typedef struct
+typedef struct WindowFuncLists
 {
 	int			numWindowFuncs; /* total number of WindowFuncs found */
 	Index		maxWinRef;		/* windowFuncs[] is indexed 0 .. maxWinRef */
diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h
index a95e73f..0ea6b88 100644
--- a/src/include/optimizer/planner.h
+++ b/src/include/optimizer/planner.h
@@ -24,9 +24,24 @@ typedef PlannedStmt *(*planner_hook_type) (Query *parse,
 												  ParamListInfo boundParams);
 extern PGDLLIMPORT planner_hook_type planner_hook;
 
-/* Hook for plugins to get control before grouping_planner plans upper rels */
-typedef void (*create_upper_paths_hook_type) (PlannerInfo *root,
-												  RelOptInfo *scan_join_rel);
+/*
+ * Struct for extra information passed to custom-scan provider or foreign
+ * data wrapper during upper path consideratioin.
+ */
+typedef struct UpperPathExtraData
+{
+	List	   *rollup_lists;			/* for grouping_paths */
+	List	   *rollup_groupclauses;	/* for grouping_paths */
+	struct WindowFuncLists *wflists;	/* for windows_paths */
+	List	   *activeWindows;			/* for windows_paths */
+	double		limit_tuples;			/* for ordered_paths */
+} UpperPathExtraData;
+
+/* Hook for plugins to get control during upper path investigation */
+typedef void (*create_upper_paths_hook_type) (UpperRelationKind upper_kind,
+											  PlannerInfo *root,
+											  RelOptInfo *current_rel,
+											  UpperPathExtraData *extra);
 extern PGDLLIMPORT create_upper_paths_hook_type create_upper_paths_hook;
 
 
