aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/prep
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/prep')
-rw-r--r--src/backend/optimizer/prep/prepjointree.c22
-rw-r--r--src/backend/optimizer/prep/prepunion.c72
2 files changed, 84 insertions, 10 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 965856385d7..21bd8332f4a 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.54 2008/08/25 22:42:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.55 2008/10/04 21:56:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -567,10 +567,18 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
subroot->parse = subquery;
subroot->glob = root->glob;
subroot->query_level = root->query_level;
+ subroot->parent_root = root->parent_root;
subroot->planner_cxt = CurrentMemoryContext;
subroot->init_plans = NIL;
+ subroot->cte_plan_ids = NIL;
subroot->eq_classes = NIL;
subroot->append_rel_list = NIL;
+ subroot->hasRecursion = false;
+ subroot->wt_param_id = -1;
+ subroot->non_recursive_plan = NULL;
+
+ /* No CTEs to worry about */
+ Assert(subquery->cteList == NIL);
/*
* Pull up any SubLinks within the subquery's quals, so that we don't
@@ -916,8 +924,8 @@ is_simple_subquery(Query *subquery)
return false;
/*
- * Can't pull up a subquery involving grouping, aggregation, sorting, or
- * limiting.
+ * Can't pull up a subquery involving grouping, aggregation, sorting,
+ * limiting, or WITH. (XXX WITH could possibly be allowed later)
*/
if (subquery->hasAggs ||
subquery->groupClause ||
@@ -925,7 +933,8 @@ is_simple_subquery(Query *subquery)
subquery->sortClause ||
subquery->distinctClause ||
subquery->limitOffset ||
- subquery->limitCount)
+ subquery->limitCount ||
+ subquery->cteList)
return false;
/*
@@ -985,11 +994,12 @@ is_simple_union_all(Query *subquery)
return false;
Assert(IsA(topop, SetOperationStmt));
- /* Can't handle ORDER BY, LIMIT/OFFSET, or locking */
+ /* Can't handle ORDER BY, LIMIT/OFFSET, locking, or WITH */
if (subquery->sortClause ||
subquery->limitOffset ||
subquery->limitCount ||
- subquery->rowMarks)
+ subquery->rowMarks ||
+ subquery->cteList)
return false;
/* Recursively check the tree of set operations */
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 7dc274797e5..0836fde517b 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.155 2008/08/28 23:09:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.156 2008/10/04 21:56:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -56,6 +56,10 @@ static Plan *recurse_set_operations(Node *setOp, PlannerInfo *root,
List *colTypes, bool junkOK,
int flag, List *refnames_tlist,
List **sortClauses, double *pNumGroups);
+static Plan *generate_recursion_plan(SetOperationStmt *setOp,
+ PlannerInfo *root, double tuple_fraction,
+ List *refnames_tlist,
+ List **sortClauses);
static Plan *generate_union_plan(SetOperationStmt *op, PlannerInfo *root,
double tuple_fraction,
List *refnames_tlist,
@@ -148,6 +152,14 @@ plan_set_operations(PlannerInfo *root, double tuple_fraction,
Assert(leftmostQuery != NULL);
/*
+ * If the topmost node is a recursive union, it needs special processing.
+ */
+ if (root->hasRecursion)
+ return generate_recursion_plan(topop, root, tuple_fraction,
+ leftmostQuery->targetList,
+ sortClauses);
+
+ /*
* Recurse on setOperations tree to generate plans for set ops. The final
* output plan should have just the column types shown as the output from
* the top-level node, plus possibly resjunk working columns (we can rely
@@ -200,8 +212,8 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
* Generate plan for primitive subquery
*/
subplan = subquery_planner(root->glob, subquery,
- root->query_level + 1,
- tuple_fraction,
+ root,
+ false, tuple_fraction,
&subroot);
/*
@@ -294,6 +306,58 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
}
/*
+ * Generate plan for a recursive UNION node
+ */
+static Plan *
+generate_recursion_plan(SetOperationStmt *setOp, PlannerInfo *root,
+ double tuple_fraction,
+ List *refnames_tlist,
+ List **sortClauses)
+{
+ Plan *plan;
+ Plan *lplan;
+ Plan *rplan;
+ List *tlist;
+
+ /* Parser should have rejected other cases */
+ if (setOp->op != SETOP_UNION || !setOp->all)
+ elog(ERROR, "only UNION ALL queries can be recursive");
+ /* Worktable ID should be assigned */
+ Assert(root->wt_param_id >= 0);
+
+ /*
+ * Unlike a regular UNION node, process the left and right inputs
+ * separately without any intention of combining them into one Append.
+ */
+ lplan = recurse_set_operations(setOp->larg, root, tuple_fraction,
+ setOp->colTypes, false, -1,
+ refnames_tlist, sortClauses, NULL);
+ /* The right plan will want to look at the left one ... */
+ root->non_recursive_plan = lplan;
+ rplan = recurse_set_operations(setOp->rarg, root, tuple_fraction,
+ setOp->colTypes, false, -1,
+ refnames_tlist, sortClauses, NULL);
+ root->non_recursive_plan = NULL;
+
+ /*
+ * Generate tlist for RecursiveUnion plan node --- same as in Append cases
+ */
+ tlist = generate_append_tlist(setOp->colTypes, false,
+ list_make2(lplan, rplan),
+ refnames_tlist);
+
+ /*
+ * And make the plan node.
+ */
+ plan = (Plan *) make_recursive_union(tlist, lplan, rplan,
+ root->wt_param_id);
+
+ *sortClauses = NIL; /* result of UNION ALL is always unsorted */
+
+ return plan;
+}
+
+/*
* Generate plan for a UNION or UNION ALL node
*/
static Plan *
@@ -1346,7 +1410,7 @@ adjust_appendrel_attrs(Node *node, AppendRelInfo *appinfo)
newnode = query_tree_mutator((Query *) node,
adjust_appendrel_attrs_mutator,
(void *) appinfo,
- QTW_IGNORE_RT_SUBQUERIES);
+ QTW_IGNORE_RC_SUBQUERIES);
if (newnode->resultRelation == appinfo->parent_relid)
{
newnode->resultRelation = appinfo->child_relid;