diff options
Diffstat (limited to 'src/backend/optimizer/prep')
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 22 | ||||
-rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 72 |
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; |