diff options
Diffstat (limited to 'src/backend/optimizer/prep/prepjointree.c')
-rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 8e726ff7dad..755bed363b1 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -5,6 +5,7 @@ * * NOTE: the intended sequence for invoking these operations is * pull_up_IN_clauses + * inline_set_returning_functions * pull_up_subqueries * do expression preprocessing (including flattening JOIN alias vars) * reduce_outer_joins @@ -15,7 +16,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.49 2008/01/01 19:45:50 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.50 2008/03/18 22:04:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -125,6 +126,52 @@ pull_up_IN_clauses(PlannerInfo *root, Node *node) } /* + * inline_set_returning_functions + * Attempt to "inline" set-returning functions in the FROM clause. + * + * If an RTE_FUNCTION rtable entry invokes a set-returning function that + * contains just a simple SELECT, we can convert the rtable entry to an + * RTE_SUBQUERY entry exposing the SELECT directly. This is especially + * useful if the subquery can then be "pulled up" for further optimization, + * but we do it even if not, to reduce executor overhead. + * + * This has to be done before we have started to do any optimization of + * subqueries, else any such steps wouldn't get applied to subqueries + * obtained via inlining. However, we do it after pull_up_IN_clauses + * so that we can inline any functions used in IN subselects. + * + * Like most of the planner, this feels free to scribble on its input data + * structure. + */ +void +inline_set_returning_functions(PlannerInfo *root) +{ + ListCell *rt; + + foreach(rt, root->parse->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); + + if (rte->rtekind == RTE_FUNCTION) + { + Query *funcquery; + + /* Check safety of expansion, and expand if possible */ + funcquery = inline_set_returning_function(root, rte->funcexpr); + if (funcquery) + { + /* Successful expansion, replace the rtable entry */ + rte->rtekind = RTE_SUBQUERY; + rte->subquery = funcquery; + rte->funcexpr = NULL; + rte->funccoltypes = NIL; + rte->funccoltypmods = NIL; + } + } + } +} + +/* * pull_up_subqueries * Look for subqueries in the rangetable that can be pulled up into * the parent query. If the subquery has no special features like @@ -296,6 +343,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, subroot->query_level = root->query_level; subroot->planner_cxt = CurrentMemoryContext; subroot->init_plans = NIL; + subroot->eq_classes = NIL; subroot->in_info_list = NIL; subroot->append_rel_list = NIL; @@ -308,6 +356,11 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, subquery->jointree->quals); /* + * Similarly, inline any set-returning functions in its rangetable. + */ + inline_set_returning_functions(subroot); + + /* * Recursively pull up the subquery's subqueries, so that * pull_up_subqueries' processing is complete for its jointree and * rangetable. |