add_PlannerContext.patch

text/plain

Filename: add_PlannerContext.patch
Type: text/plain
Part: 0
Message: Re: Properly pathify the union planner

Patch

Format: unified
File+
src/backend/optimizer/path/allpaths.c 6 3
src/backend/optimizer/plan/planner.c 16 28
src/backend/optimizer/plan/subselect.c 22 11
src/backend/optimizer/prep/prepunion.c 8 4
src/include/nodes/pathnodes.h 31 0
src/include/optimizer/planner.h 1 1
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 7bad404458..26cbe2c9a2 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -2494,6 +2494,7 @@ static void
 set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
 					  Index rti, RangeTblEntry *rte)
 {
+	PlannerContext context;
 	Query	   *parse = root->parse;
 	Query	   *subquery = rte->subquery;
 	bool		trivial_pathtarget;
@@ -2644,10 +2645,12 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
 	/* plan_params should not be in use in current query level */
 	Assert(root->plan_params == NIL);
 
+	context.hasRecursion = false;
+	context.tuple_fraction = tuple_fraction;
+	context.setops = NULL;
+
 	/* Generate a subroot and Paths for the subquery */
-	rel->subroot = subquery_planner(root->glob, subquery,
-									root,
-									false, tuple_fraction);
+	rel->subroot = subquery_planner(root->glob, subquery, root, &context);
 
 	/* Isolate the params needed by this specific subplan */
 	rel->subplan_params = root->plan_params;
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 38d070fa00..56fa445ae8 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -127,7 +127,7 @@ typedef struct
 /* Local functions */
 static Node *preprocess_expression(PlannerInfo *root, Node *expr, int kind);
 static void preprocess_qual_conditions(PlannerInfo *root, Node *jtnode);
-static void grouping_planner(PlannerInfo *root, double tuple_fraction);
+static void grouping_planner(PlannerInfo *root, PlannerContext *context);
 static grouping_sets_data *preprocess_grouping_sets(PlannerInfo *root);
 static List *remap_to_groupclause_idx(List *groupClause, List *gsets,
 									  int *tleref_to_colnum_map);
@@ -288,6 +288,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 {
 	PlannedStmt *result;
 	PlannerGlobal *glob;
+	PlannerContext context;
 	double		tuple_fraction;
 	PlannerInfo *root;
 	RelOptInfo *final_rel;
@@ -410,9 +411,12 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 		tuple_fraction = 0.0;
 	}
 
+	context.hasRecursion = false;
+	context.tuple_fraction = tuple_fraction;
+	context.setops = NULL;
+
 	/* primary planning entry point (may recurse for subqueries) */
-	root = subquery_planner(glob, parse, NULL,
-							false, tuple_fraction);
+	root = subquery_planner(glob, parse, NULL, &context);
 
 	/* Select best Path and turn it into a Plan */
 	final_rel = fetch_upper_rel(root, UPPERREL_FINAL, NULL);
@@ -600,9 +604,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
  * glob is the global state for the current planner run.
  * parse is the querytree produced by the parser & rewriter.
  * parent_root is the immediate parent Query's info (NULL at the top level).
- * hasRecursion is true if this is a recursive WITH query.
- * tuple_fraction is the fraction of tuples we expect will be retrieved.
- * tuple_fraction is interpreted as explained for grouping_planner, below.
  *
  * Basically, this routine does the stuff that should only be done once
  * per Query object.  It then calls grouping_planner.  At one time,
@@ -623,7 +624,7 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 PlannerInfo *
 subquery_planner(PlannerGlobal *glob, Query *parse,
 				 PlannerInfo *parent_root,
-				 bool hasRecursion, double tuple_fraction)
+				 PlannerContext *context)
 {
 	PlannerInfo *root;
 	List	   *newWithCheckOptions;
@@ -667,8 +668,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
 	root->hasPseudoConstantQuals = false;
 	root->hasAlternativeSubPlans = false;
 	root->placeholdersFrozen = false;
-	root->hasRecursion = hasRecursion;
-	if (hasRecursion)
+	root->hasRecursion = context->hasRecursion;
+	if (context->hasRecursion)
 		root->wt_param_id = assign_special_exec_param(root);
 	else
 		root->wt_param_id = -1;
@@ -1082,7 +1083,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
 	/*
 	 * Do the main planning.
 	 */
-	grouping_planner(root, tuple_fraction);
+	grouping_planner(root, context);
 
 	/*
 	 * Capture the set of outer-level param IDs we have access to, for use in
@@ -1274,14 +1275,6 @@ preprocess_phv_expression(PlannerInfo *root, Expr *expr)
  * This function adds all required top-level processing to the scan/join
  * Path(s) produced by query_planner.
  *
- * tuple_fraction is the fraction of tuples we expect will be retrieved.
- * tuple_fraction is interpreted as follows:
- *	  0: expect all tuples to be retrieved (normal case)
- *	  0 < tuple_fraction < 1: expect the given fraction of tuples available
- *		from the plan to be retrieved
- *	  tuple_fraction >= 1: tuple_fraction is the absolute number of tuples
- *		expected to be retrieved (ie, a LIMIT specification)
- *
  * Returns nothing; the useful output is in the Paths we attach to the
  * (UPPERREL_FINAL, NULL) upperrel in *root.  In addition,
  * root->processed_tlist contains the final processed targetlist.
@@ -1291,7 +1284,7 @@ preprocess_phv_expression(PlannerInfo *root, Expr *expr)
  *--------------------
  */
 static void
-grouping_planner(PlannerInfo *root, double tuple_fraction)
+grouping_planner(PlannerInfo *root, PlannerContext *context)
 {
 	Query	   *parse = root->parse;
 	int64		offset_est = 0;
@@ -1305,6 +1298,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
 	RelOptInfo *current_rel;
 	RelOptInfo *final_rel;
 	FinalPathExtraData extra;
+	double		tuple_fraction = context->tuple_fraction;
 	ListCell   *lc;
 
 	/* Tweak caller-supplied tuple_fraction if have LIMIT/OFFSET */
@@ -1507,16 +1501,10 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
 		qp_extra.gset_data = gset_data;
 
 		/*
-		 * Check if we're a subquery for a set operation.  If we are, store
-		 * the SetOperationStmt in qp_extra.
+		 * If we're a subquery for a set operation, store the SetOperationStmt in
+		 * qp_extra.
 		 */
-		if (root->parent_root != NULL &&
-			root->parent_root->parse->setOperations != NULL &&
-			IsA(root->parent_root->parse->setOperations, SetOperationStmt))
-			qp_extra.setop =
-				(SetOperationStmt *) root->parent_root->parse->setOperations;
-		else
-			qp_extra.setop = NULL;
+		qp_extra.setop = (SetOperationStmt *) context->setops;
 
 		/*
 		 * Generate the best unsorted and presorted paths for the scan/join
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index d5fa281b10..49be10e29b 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -167,6 +167,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
 	bool		simple_exists = false;
 	double		tuple_fraction;
 	PlannerInfo *subroot;
+	PlannerContext context;
 	RelOptInfo *final_rel;
 	Path	   *best_path;
 	Plan	   *plan;
@@ -217,10 +218,12 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
 	/* plan_params should not be in use in current query level */
 	Assert(root->plan_params == NIL);
 
+	context.hasRecursion = false;
+	context.tuple_fraction = tuple_fraction;
+	context.setops = NULL;
+
 	/* Generate Paths for the subquery */
-	subroot = subquery_planner(root->glob, subquery,
-							   root,
-							   false, tuple_fraction);
+	subroot = subquery_planner(root->glob, subquery, root, &context);
 
 	/* Isolate the params needed by this specific subplan */
 	plan_params = root->plan_params;
@@ -265,10 +268,14 @@ make_subplan(PlannerInfo *root, Query *orig_subquery,
 										 &newtestexpr, &paramIds);
 		if (subquery)
 		{
+			PlannerContext context;
+
+			context.hasRecursion = false;
+			context.tuple_fraction = 0.0;
+			context.setops = NULL;
+
 			/* Generate Paths for the ANY subquery; we'll need all rows */
-			subroot = subquery_planner(root->glob, subquery,
-									   root,
-									   false, 0.0);
+			subroot = subquery_planner(root->glob, subquery, root, &context);
 
 			/* Isolate the params needed by this specific subplan */
 			plan_params = root->plan_params;
@@ -891,6 +898,7 @@ SS_process_ctes(PlannerInfo *root)
 		CmdType		cmdType = ((Query *) cte->ctequery)->commandType;
 		Query	   *subquery;
 		PlannerInfo *subroot;
+		PlannerContext context;
 		RelOptInfo *final_rel;
 		Path	   *best_path;
 		Plan	   *plan;
@@ -963,13 +971,16 @@ SS_process_ctes(PlannerInfo *root)
 		/* plan_params should not be in use in current query level */
 		Assert(root->plan_params == NIL);
 
+		context.hasRecursion = cte->cterecursive;
 		/*
-		 * Generate Paths for the CTE query.  Always plan for full retrieval
-		 * --- we don't have enough info to predict otherwise.
+		 * Always plan for full retrieval --- we don't have enough info to
+		 * predict otherwise.
 		 */
-		subroot = subquery_planner(root->glob, subquery,
-								   root,
-								   cte->cterecursive, 0.0);
+		context.tuple_fraction = 0.0;
+		context.setops = NULL;
+
+		/* Generate Paths for the CTE query. */
+		subroot = subquery_planner(root->glob, subquery, root, &context);
 
 		/*
 		 * Since the current query level doesn't yet contain any RTEs, it
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 944afc7192..113c721602 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -242,6 +242,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
 
 	if (IsA(setOp, RangeTblRef))
 	{
+		PlannerContext context;
 		RangeTblRef *rtr = (RangeTblRef *) setOp;
 		RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
 		Query	   *subquery = rte->subquery;
@@ -257,11 +258,14 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
 		/* plan_params should not be in use in current query level */
 		Assert(root->plan_params == NIL);
 
+		context.hasRecursion = false;
+		context.tuple_fraction = root->tuple_fraction;
+		context.setops = castNode(SetOperationStmt,
+								  root->parse->setOperations);
+
 		/* Generate a subroot and Paths for the subquery */
-		subroot = rel->subroot = subquery_planner(root->glob, subquery,
-												  root,
-												  false,
-												  root->tuple_fraction);
+		subroot = rel->subroot = subquery_planner(root->glob, subquery, root,
+												  &context);
 
 		/*
 		 * It should not be possible for the primitive query to contain any
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 595eec2cbb..a3727ba2f1 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -551,6 +551,37 @@ struct PlannerInfo
 	bool		partColsUpdated;
 };
 
+/*----------
+ * PlannerContext
+ *		Per-query context to provide additional information to
+ *		subquery_planner() and grouping_planner().
+ */
+typedef struct PlannerContext
+{
+	/*
+	 * hasRecursion: must be given as true if planning recursive WITH query.
+	 */
+	bool hasRecursion;
+
+	/*--------------------
+	 * tuple_fraction is the fraction of tuples we expect will be retrieved.
+	 * tuple_fraction is interpreted as follows:
+	 *	  0: expect all tuples to be retrieved (normal case)
+	 *	  0 < tuple_fraction < 1: expect the given fraction of tuples available
+	 *		from the plan to be retrieved
+	 *	  tuple_fraction >= 1: tuple_fraction is the absolute number of tuples
+	 *		expected to be retrieved (ie, a LIMIT specification)
+	 *--------------------
+	 */
+	double tuple_fraction;
+
+	/*
+	 * Can be set for set operation child queries to provide information on
+	 * the parent-level operation to allow them to optimize for this context
+	 */
+	SetOperationStmt *setops;
+
+} PlannerContext;
 
 /*
  * In places where it's known that simple_rte_array[] must have been prepared
diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h
index e1d79ffdf3..e3c9a4e3ae 100644
--- a/src/include/optimizer/planner.h
+++ b/src/include/optimizer/planner.h
@@ -44,7 +44,7 @@ extern PlannedStmt *standard_planner(Query *parse, const char *query_string,
 
 extern PlannerInfo *subquery_planner(PlannerGlobal *glob, Query *parse,
 									 PlannerInfo *parent_root,
-									 bool hasRecursion, double tuple_fraction);
+									 PlannerContext *context);
 
 extern RowMarkType select_rowmark_type(RangeTblEntry *rte,
 									   LockClauseStrength strength);