diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 169 |
1 files changed, 86 insertions, 83 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 67089e68d29..7a1151f0c9a 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.95 2000/11/09 02:46:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.96 2000/11/12 00:36:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -43,6 +43,8 @@ static void resolvenew_in_jointree(Node *jtnode, int varno, List *subtlist); static Node *preprocess_jointree(Query *parse, Node *jtnode); static Node *preprocess_expression(Query *parse, Node *expr, int kind); static void preprocess_qual_conditions(Query *parse, Node *jtnode); +static Plan *inheritance_planner(Query *parse, List *inheritlist); +static Plan *grouping_planner(Query *parse, double tuple_fraction); static List *make_subplanTargetList(Query *parse, List *tlist, AttrNumber **groupColIdx); static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup, @@ -65,7 +67,7 @@ planner(Query *parse) /* * The planner can be called recursively (an example is when - * eval_const_expressions tries to simplify an SQL function). + * eval_const_expressions tries to pre-evaluate an SQL function). * So, these global state variables must be saved and restored. * * These vars cannot be moved into the Query structure since their @@ -109,11 +111,14 @@ planner(Query *parse) * * parse is the querytree produced by the parser & rewriter. * tuple_fraction is the fraction of tuples we expect will be retrieved. - * tuple_fraction is interpreted as explained for union_planner, below. + * 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 union_planner, which may be called - * recursively on the same Query node in order to handle inheritance. + * per Query object. It then calls grouping_planner. At one time, + * grouping_planner could be invoked recursively on the same Query object; + * that's not currently true, but we keep the separation between the two + * routines anyway, in case we need it again someday. + * * subquery_planner will be called recursively to handle sub-Query nodes * found within the query's expressions and rangetable. * @@ -164,7 +169,7 @@ subquery_planner(Query *parse, double tuple_fraction) } /* - * Do preprocessing on targetlist and quals. + * Do expression preprocessing on targetlist and quals. */ parse->targetList = (List *) preprocess_expression(parse, (Node *) parse->targetList, @@ -176,17 +181,14 @@ subquery_planner(Query *parse, double tuple_fraction) EXPRKIND_HAVING); /* - * Do the main planning (potentially recursive for inheritance) - */ - plan = union_planner(parse, tuple_fraction); - - /* - * XXX should any more of union_planner's activity be moved here? - * - * That would take careful study of the interactions with prepunion.c, - * but I suspect it would pay off in simplicity and avoidance of - * wasted cycles. + * Do the main planning. If we have an inherited target relation, + * that needs special processing, else go straight to grouping_planner. */ + if (parse->resultRelation && + (lst = expand_inherted_rtentry(parse, parse->resultRelation)) != NIL) + plan = inheritance_planner(parse, lst); + else + plan = grouping_planner(parse, tuple_fraction); /* * If any subplans were generated, or if we're inside a subplan, @@ -600,10 +602,65 @@ preprocess_qual_conditions(Query *parse, Node *jtnode) } /*-------------------- - * union_planner - * Invokes the planner on union-type queries (both set operations and - * appends produced by inheritance), recursing if necessary to get them - * all, then processes normal plans. + * inheritance_planner + * Generate a plan in the case where the result relation is an + * inheritance set. + * + * We have to handle this case differently from cases where a source + * relation is an inheritance set. Source inheritance is expanded at + * the bottom of the plan tree (see allpaths.c), but target inheritance + * has to be expanded at the top. The reason is that for UPDATE, each + * target relation needs a different targetlist matching its own column + * set. (This is not so critical for DELETE, but for simplicity we treat + * inherited DELETE the same way.) Fortunately, the UPDATE/DELETE target + * can never be the nullable side of an outer join, so it's OK to generate + * the plan this way. + * + * parse is the querytree produced by the parser & rewriter. + * inheritlist is an integer list of RT indexes for the result relation set. + * + * Returns a query plan. + *-------------------- + */ +static Plan * +inheritance_planner(Query *parse, List *inheritlist) +{ + int parentRTindex = parse->resultRelation; + Oid parentOID = getrelid(parentRTindex, parse->rtable); + List *subplans = NIL; + List *tlist = NIL; + List *l; + + foreach(l, inheritlist) + { + int childRTindex = lfirsti(l); + Oid childOID = getrelid(childRTindex, parse->rtable); + Query *subquery; + Plan *subplan; + + /* Generate modified query with this rel as target */ + subquery = (Query *) adjust_inherited_attrs((Node *) parse, + parentRTindex, parentOID, + childRTindex, childOID); + /* Generate plan */ + subplan = grouping_planner(subquery, 0.0 /* retrieve all tuples */); + subplans = lappend(subplans, subplan); + /* Save preprocessed tlist from first rel for use in Append */ + if (tlist == NIL) + tlist = subplan->targetlist; + } + + /* Save the target-relations list for the executor, too */ + parse->resultRelations = inheritlist; + + return (Plan *) make_append(subplans, true, tlist); +} + +/*-------------------- + * grouping_planner + * Perform planning steps related to grouping, aggregation, etc. + * This primarily means adding top-level processing to the basic + * query plan produced by query_planner. * * parse is the querytree produced by the parser & rewriter. * tuple_fraction is the fraction of tuples we expect will be retrieved @@ -621,18 +678,15 @@ preprocess_qual_conditions(Query *parse, Node *jtnode) * Returns a query plan. *-------------------- */ -Plan * -union_planner(Query *parse, - double tuple_fraction) +static Plan * +grouping_planner(Query *parse, double tuple_fraction) { List *tlist = parse->targetList; - Plan *result_plan = (Plan *) NULL; - AttrNumber *groupColIdx = NULL; - List *current_pathkeys = NIL; + Plan *result_plan; + List *current_pathkeys; List *group_pathkeys; List *sort_pathkeys; - Index rt_index; - List *inheritors; + AttrNumber *groupColIdx = NULL; if (parse->setOperations) { @@ -654,12 +708,13 @@ union_planner(Query *parse, tlist = postprocess_setop_tlist(result_plan->targetlist, tlist); /* - * We leave current_pathkeys NIL indicating we do not know sort + * We set current_pathkeys NIL indicating we do not know sort * order. This is correct when the top set operation is UNION ALL, * since the appended-together results are unsorted even if the * subplans were sorted. For other set operations we could be - * smarter --- future improvement! + * smarter --- room for future improvement! */ + current_pathkeys = NIL; /* * Calculate pathkeys that represent grouping/ordering @@ -670,54 +725,6 @@ union_planner(Query *parse, sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause, tlist); } - else if (find_inheritable_rt_entry(parse->rtable, - &rt_index, &inheritors)) - { - List *sub_tlist; - - /* - * Generate appropriate target list for subplan; may be different - * from tlist if grouping or aggregation is needed. - */ - sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx); - - /* - * Recursively plan the subqueries needed for inheritance - */ - result_plan = plan_inherit_queries(parse, sub_tlist, - rt_index, inheritors); - - /* - * Fix up outer target list. NOTE: unlike the case for - * non-inherited query, we pass the unfixed tlist to subplans, - * which do their own fixing. But we still want to fix the outer - * target list afterwards. I *think* this is correct --- doing the - * fix before recursing is definitely wrong, because - * preprocess_targetlist() will do the wrong thing if invoked - * twice on the same list. Maybe that is a bug? tgl 6/6/99 - */ - tlist = preprocess_targetlist(tlist, - parse->commandType, - parse->resultRelation, - parse->rtable); - - if (parse->rowMarks) - elog(ERROR, "SELECT FOR UPDATE is not supported for inherit queries"); - - /* - * We leave current_pathkeys NIL indicating we do not know sort - * order of the Append-ed results. - */ - - /* - * Calculate pathkeys that represent grouping/ordering - * requirements - */ - group_pathkeys = make_pathkeys_for_sortclauses(parse->groupClause, - tlist); - sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause, - tlist); - } else { List *sub_tlist; @@ -938,10 +945,6 @@ union_planner(Query *parse, current_pathkeys = parse->query_pathkeys; } - /* query_planner returns NULL if it thinks plan is bogus */ - if (!result_plan) - elog(ERROR, "union_planner: failed to create plan"); - /* * We couldn't canonicalize group_pathkeys and sort_pathkeys before * running query_planner(), so do it now. @@ -1057,7 +1060,7 @@ union_planner(Query *parse, * make_subplanTargetList * Generate appropriate target list when grouping is required. * - * When union_planner inserts Aggregate and/or Group plan nodes above + * When grouping_planner inserts Aggregate and/or Group plan nodes above * the result of query_planner, we typically want to pass a different * target list to query_planner than the outer plan nodes should have. * This routine generates the correct target list for the subplan. |