diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 207 |
1 files changed, 120 insertions, 87 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index b8871d5801e..a92d439ee52 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.78 2000/03/21 05:12:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.79 2000/04/12 17:15:22 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -38,10 +38,10 @@ static List *make_subplanTargetList(Query *parse, List *tlist, - AttrNumber **groupColIdx); + AttrNumber **groupColIdx); static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup, - List *groupClause, AttrNumber *grpColIdx, - bool is_presorted, Plan *subplan); + List *groupClause, AttrNumber *grpColIdx, + bool is_presorted, Plan *subplan); static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode); /***************************************************************************** @@ -64,7 +64,7 @@ planner(Query *parse) transformKeySetQuery(parse); /* primary planning entry point (may recurse for subplans) */ - result_plan = subquery_planner(parse, -1.0 /* default case */); + result_plan = subquery_planner(parse, -1.0 /* default case */ ); Assert(PlannerQueryLevel == 1); @@ -110,21 +110,22 @@ planner(Query *parse) Plan * subquery_planner(Query *parse, double tuple_fraction) { + /* * A HAVING clause without aggregates is equivalent to a WHERE clause - * (except it can only refer to grouped fields). If there are no - * aggs anywhere in the query, then we don't want to create an Agg - * plan node, so merge the HAVING condition into WHERE. (We used to + * (except it can only refer to grouped fields). If there are no aggs + * anywhere in the query, then we don't want to create an Agg plan + * node, so merge the HAVING condition into WHERE. (We used to * consider this an error condition, but it seems to be legal SQL.) */ - if (parse->havingQual != NULL && ! parse->hasAggs) + if (parse->havingQual != NULL && !parse->hasAggs) { if (parse->qual == NULL) parse->qual = parse->havingQual; else parse->qual = (Node *) make_andclause(lappend(lcons(parse->qual, NIL), - parse->havingQual)); + parse->havingQual)); parse->havingQual = NULL; } @@ -144,8 +145,8 @@ subquery_planner(Query *parse, double tuple_fraction) /* * Canonicalize the qual, and convert it to implicit-AND format. * - * XXX Is there any value in re-applying eval_const_expressions - * after canonicalize_qual? + * XXX Is there any value in re-applying eval_const_expressions after + * canonicalize_qual? */ parse->qual = (Node *) canonicalize_qual((Expr *) parse->qual, true); #ifdef OPTIMIZER_DEBUG @@ -169,15 +170,17 @@ subquery_planner(Query *parse, double tuple_fraction) if (parse->groupClause != NIL) { + /* - * Check for ungrouped variables passed to subplans. - * Note we do NOT do this for subplans in WHERE; it's legal - * there because WHERE is evaluated pre-GROUP. + * Check for ungrouped variables passed to subplans. Note we + * do NOT do this for subplans in WHERE; it's legal there + * because WHERE is evaluated pre-GROUP. * - * An interesting fine point: if we reassigned a HAVING qual - * into WHERE above, then we will accept references to ungrouped - * vars from subplans in the HAVING qual. This is not entirely - * consistent, but it doesn't seem particularly harmful... + * An interesting fine point: if we reassigned a HAVING qual into + * WHERE above, then we will accept references to ungrouped + * vars from subplans in the HAVING qual. This is not + * entirely consistent, but it doesn't seem particularly + * harmful... */ check_subplans_for_ungrouped_vars((Node *) parse->targetList, parse); @@ -218,8 +221,8 @@ subquery_planner(Query *parse, double tuple_fraction) * tuple_fraction is the fraction of tuples we expect will be retrieved * * tuple_fraction is interpreted as follows: - * < 0: determine fraction by inspection of query (normal case) - * 0: expect all tuples to be retrieved + * < 0: determine fraction by inspection of query (normal case) + * 0: expect all tuples to be retrieved * 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 @@ -251,13 +254,18 @@ union_planner(Query *parse, parse->commandType, parse->resultRelation, parse->rtable); + /* - * We leave current_pathkeys NIL indicating we do not know sort order. - * Actually, for a normal UNION we have done an explicit sort; ought - * to change interface to plan_union_queries to pass that info back! + * We leave current_pathkeys NIL indicating we do not know sort + * order. Actually, for a normal UNION we have done an explicit + * sort; ought to change interface to plan_union_queries to pass + * that info back! */ - /* Calculate pathkeys that represent grouping/ordering requirements */ + /* + * Calculate pathkeys that represent grouping/ordering + * requirements + */ group_pathkeys = make_pathkeys_for_sortclauses(parse->groupClause, tlist); sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause, @@ -280,13 +288,13 @@ union_planner(Query *parse, rt_index); /* - * 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 + * 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, @@ -295,12 +303,16 @@ union_planner(Query *parse, if (parse->rowMark != NULL) 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. + * We leave current_pathkeys NIL indicating we do not know sort + * order of the Append-ed results. */ - /* Calculate pathkeys that represent grouping/ordering requirements */ + /* + * Calculate pathkeys that represent grouping/ordering + * requirements + */ group_pathkeys = make_pathkeys_for_sortclauses(parse->groupClause, tlist); sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause, @@ -358,7 +370,10 @@ union_planner(Query *parse, */ sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx); - /* Calculate pathkeys that represent grouping/ordering requirements */ + /* + * Calculate pathkeys that represent grouping/ordering + * requirements + */ group_pathkeys = make_pathkeys_for_sortclauses(parse->groupClause, tlist); sort_pathkeys = make_pathkeys_for_sortclauses(parse->sortClause, @@ -368,11 +383,12 @@ union_planner(Query *parse, * Figure out whether we need a sorted result from query_planner. * * If we have a GROUP BY clause, then we want a result sorted - * properly for grouping. Otherwise, if there is an ORDER BY clause, - * we want to sort by the ORDER BY clause. (Note: if we have both, - * and ORDER BY is a superset of GROUP BY, it would be tempting to - * request sort by ORDER BY --- but that might just leave us failing - * to exploit an available sort order at all. Needs more thought...) + * properly for grouping. Otherwise, if there is an ORDER BY + * clause, we want to sort by the ORDER BY clause. (Note: if we + * have both, and ORDER BY is a superset of GROUP BY, it would be + * tempting to request sort by ORDER BY --- but that might just + * leave us failing to exploit an available sort order at all. + * Needs more thought...) */ if (parse->groupClause) parse->query_pathkeys = group_pathkeys; @@ -382,15 +398,16 @@ union_planner(Query *parse, parse->query_pathkeys = NIL; /* - * Figure out whether we expect to retrieve all the tuples that the - * plan can generate, or to stop early due to a LIMIT or other - * factors. If the caller passed a value >= 0, believe that value, - * else do our own examination of the query context. + * Figure out whether we expect to retrieve all the tuples that + * the plan can generate, or to stop early due to a LIMIT or other + * factors. If the caller passed a value >= 0, believe that + * value, else do our own examination of the query context. */ if (tuple_fraction < 0.0) { /* Initial assumption is we need all the tuples */ tuple_fraction = 0.0; + /* * Check for a LIMIT clause. */ @@ -430,33 +447,37 @@ union_planner(Query *parse, } else { + /* - * COUNT is a PARAM ... don't know exactly what the limit - * will be, but for lack of a better idea assume 10% - * of the plan's result is wanted. + * COUNT is a PARAM ... don't know exactly what the + * limit will be, but for lack of a better idea assume + * 10% of the plan's result is wanted. */ tuple_fraction = 0.10; } } + /* * Check for a retrieve-into-portal, ie DECLARE CURSOR. * * We have no real idea how many tuples the user will ultimately - * FETCH from a cursor, but it seems a good bet that he doesn't - * want 'em all. Optimize for 10% retrieval (you gotta better - * number?) + * FETCH from a cursor, but it seems a good bet that he + * doesn't want 'em all. Optimize for 10% retrieval (you + * gotta better number?) */ if (parse->isPortal) tuple_fraction = 0.10; } + /* * Adjust tuple_fraction if we see that we are going to apply * grouping/aggregation/etc. This is not overridable by the - * caller, since it reflects plan actions that this routine - * will certainly take, not assumptions about context. + * caller, since it reflects plan actions that this routine will + * certainly take, not assumptions about context. */ if (parse->groupClause) { + /* * In GROUP BY mode, we have the little problem that we don't * really know how many input tuples will be needed to make a @@ -464,33 +485,42 @@ union_planner(Query *parse, * input count. For lack of a better idea, assume 25% of the * input data will be processed if there is any output limit. * However, if the caller gave us a fraction rather than an - * absolute count, we can keep using that fraction (which amounts - * to assuming that all the groups are about the same size). + * absolute count, we can keep using that fraction (which + * amounts to assuming that all the groups are about the same + * size). */ if (tuple_fraction >= 1.0) tuple_fraction = 0.25; + /* * If both GROUP BY and ORDER BY are specified, we will need * two levels of sort --- and, therefore, certainly need to * read all the input tuples --- unless ORDER BY is a subset * of GROUP BY. (Although we are comparing non-canonicalized * pathkeys here, it should be OK since they will both contain - * only single-element sublists at this point. See pathkeys.c.) + * only single-element sublists at this point. See + * pathkeys.c.) */ if (parse->groupClause && parse->sortClause && - ! pathkeys_contained_in(sort_pathkeys, group_pathkeys)) + !pathkeys_contained_in(sort_pathkeys, group_pathkeys)) tuple_fraction = 0.0; } else if (parse->hasAggs) { - /* Ungrouped aggregate will certainly want all the input tuples. */ + + /* + * Ungrouped aggregate will certainly want all the input + * tuples. + */ tuple_fraction = 0.0; } else if (parse->distinctClause) { + /* * SELECT DISTINCT, like GROUP, will absorb an unpredictable - * number of input tuples per output tuple. Handle the same way. + * number of input tuples per output tuple. Handle the same + * way. */ if (tuple_fraction >= 1.0) tuple_fraction = 0.25; @@ -502,14 +532,15 @@ union_planner(Query *parse, (List *) parse->qual, tuple_fraction); - /* query_planner returns actual sort order (which is not + /* + * query_planner returns actual sort order (which is not * necessarily what we requested) in query_pathkeys. */ current_pathkeys = parse->query_pathkeys; } /* query_planner returns NULL if it thinks plan is bogus */ - if (! result_plan) + if (!result_plan) elog(ERROR, "union_planner: failed to create plan"); /* @@ -539,9 +570,9 @@ union_planner(Query *parse, /* * If there are aggregates then the Group node should just return - * the same set of vars as the subplan did (but we can exclude - * any GROUP BY expressions). If there are no aggregates - * then the Group node had better compute the final tlist. + * the same set of vars as the subplan did (but we can exclude any + * GROUP BY expressions). If there are no aggregates then the + * Group node had better compute the final tlist. */ if (parse->hasAggs) group_tlist = flatten_tlist(result_plan->targetlist); @@ -549,8 +580,8 @@ union_planner(Query *parse, group_tlist = tlist; /* - * Figure out whether the path result is already ordered the way we - * need it --- if so, no need for an explicit sort step. + * Figure out whether the path result is already ordered the way + * we need it --- if so, no need for an explicit sort step. */ if (pathkeys_contained_in(group_pathkeys, current_pathkeys)) { @@ -559,7 +590,9 @@ union_planner(Query *parse, } else { - /* We will need to do an explicit sort by the GROUP BY clause. + + /* + * We will need to do an explicit sort by the GROUP BY clause. * make_groupplan will do the work, but set current_pathkeys * to indicate the resulting order. */ @@ -594,10 +627,8 @@ union_planner(Query *parse, */ if (parse->sortClause) { - if (! pathkeys_contained_in(sort_pathkeys, current_pathkeys)) - { + if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys)) result_plan = make_sortplan(tlist, parse->sortClause, result_plan); - } } /* @@ -633,7 +664,7 @@ union_planner(Query *parse, * we want to pass this targetlist to the subplan: * a,b,c,d,a+b * where the a+b target will be used by the Sort/Group steps, and the - * other targets will be used for computing the final results. (In the + * other targets will be used for computing the final results. (In the * above example we could theoretically suppress the a and b targets and * use only a+b, but it's not really worth the trouble.) * @@ -675,8 +706,9 @@ make_subplanTargetList(Query *parse, /* * If grouping, create sub_tlist entries for all GROUP BY expressions - * (GROUP BY items that are simple Vars should be in the list already), - * and make an array showing where the group columns are in the sub_tlist. + * (GROUP BY items that are simple Vars should be in the list + * already), and make an array showing where the group columns are in + * the sub_tlist. */ numCols = length(parse->groupClause); if (numCols > 0) @@ -690,10 +722,10 @@ make_subplanTargetList(Query *parse, foreach(gl, parse->groupClause) { - GroupClause *grpcl = (GroupClause *) lfirst(gl); - Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist); - TargetEntry *te = NULL; - List *sl; + GroupClause *grpcl = (GroupClause *) lfirst(gl); + Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist); + TargetEntry *te = NULL; + List *sl; /* Find or make a matching sub_tlist entry */ foreach(sl, sub_tlist) @@ -702,7 +734,7 @@ make_subplanTargetList(Query *parse, if (equal(groupexpr, te->expr)) break; } - if (! sl) + if (!sl) { te = makeTargetEntry(makeResdom(length(sub_tlist) + 1, exprType(groupexpr), @@ -739,8 +771,9 @@ make_groupplan(List *group_tlist, { int numCols = length(groupClause); - if (! is_presorted) + if (!is_presorted) { + /* * The Sort node always just takes a copy of the subplan's tlist * plus ordering information. (This might seem inefficient if the @@ -755,14 +788,14 @@ make_groupplan(List *group_tlist, foreach(gl, groupClause) { - GroupClause *grpcl = (GroupClause *) lfirst(gl); - TargetEntry *te = nth(grpColIdx[keyno]-1, sort_tlist); - Resdom *resdom = te->resdom; + GroupClause *grpcl = (GroupClause *) lfirst(gl); + TargetEntry *te = nth(grpColIdx[keyno] - 1, sort_tlist); + Resdom *resdom = te->resdom; /* - * Check for the possibility of duplicate group-by clauses --- the - * parser should have removed 'em, but the Sort executor will get - * terribly confused if any get through! + * Check for the possibility of duplicate group-by clauses --- + * the parser should have removed 'em, but the Sort executor + * will get terribly confused if any get through! */ if (resdom->reskey == 0) { @@ -808,8 +841,8 @@ make_sortplan(List *tlist, List *sortcls, Plan *plannode) /* * Check for the possibility of duplicate order-by clauses --- the - * parser should have removed 'em, but the executor will get terribly - * confused if any get through! + * parser should have removed 'em, but the executor will get + * terribly confused if any get through! */ if (resdom->reskey == 0) { |