77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.64 1999/08/2220:14:48 tgl Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.65 1999/08/2223:56:45 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -39,7 +39,7 @@ static List *make_subplanTargetList(Query *parse, List *tlist,
3939AttrNumber * * groupColIdx );
4040static Plan * make_groupplan (List * group_tlist ,bool tuplePerGroup ,
4141List * groupClause ,AttrNumber * grpColIdx ,
42- bool is_sorted ,Plan * subplan );
42+ bool is_presorted ,Plan * subplan );
4343static Plan * make_sortplan (List * tlist ,List * sortcls ,Plan * plannode );
4444
4545/*****************************************************************************
@@ -91,7 +91,7 @@ union_planner(Query *parse)
9191List * rangetable = parse -> rtable ;
9292Plan * result_plan = (Plan * )NULL ;
9393AttrNumber * groupColIdx = NULL ;
94- bool is_sorted = false ;
94+ List * current_pathkeys = NIL ;
9595Index rt_index ;
9696
9797if (parse -> unionClause )
@@ -102,6 +102,11 @@ union_planner(Query *parse)
102102parse -> commandType ,
103103parse -> resultRelation ,
104104parse -> rtable );
105+ /*
106+ * We leave current_pathkeys NIL indicating we do not know sort order.
107+ * Actually, for a normal UNION we have done an explicit sort; ought
108+ * to change interface to plan_union_queries to pass that info back!
109+ */
105110}
106111else if ((rt_index = first_inherit_rt_entry (rangetable ))!= -1 )
107112{
@@ -135,6 +140,10 @@ union_planner(Query *parse)
135140
136141if (parse -> rowMark != NULL )
137142elog (ERROR ,"SELECT FOR UPDATE is not supported for inherit queries" );
143+ /*
144+ * We leave current_pathkeys NIL indicating we do not know sort order
145+ * of the Append-ed results.
146+ */
138147}
139148else
140149{
@@ -182,25 +191,25 @@ union_planner(Query *parse)
182191}
183192}
184193
194+ /*
195+ * Generate appropriate target list for subplan; may be different
196+ * from tlist if grouping or aggregation is needed.
197+ */
198+ sub_tlist = make_subplanTargetList (parse ,tlist ,& groupColIdx );
199+
185200/*
186201 * Figure out whether we need a sorted result from query_planner.
187202 *
188203 * If we have a GROUP BY clause, then we want a result sorted
189- * properly for grouping. Otherwise, if there is an ORDER BY clause
190- * and no need for an aggregate node, we want to sort by the ORDER BY
191- * clause. (XXX In some cases, we could presort even when there is
192- * an aggregate, but I'll leave that refinement for another day.)
193- *
194- * NOTE: the reason we put the target pathkeys into the Query node
195- * rather than passing them as an argument to query_planner is that
196- * the low-level routines in indxpath.c want to be able to see them.
204+ * properly for grouping. Otherwise, if there is an ORDER BY clause,
205+ * we want to sort by the ORDER BY clause.
197206 */
198207if (parse -> groupClause )
199208{
200209parse -> query_pathkeys =
201210make_pathkeys_for_sortclauses (parse -> groupClause ,tlist );
202211}
203- else if (parse -> sortClause && ! parse -> hasAggs )
212+ else if (parse -> sortClause )
204213{
205214parse -> query_pathkeys =
206215make_pathkeys_for_sortclauses (parse -> sortClause ,tlist );
@@ -210,23 +219,16 @@ union_planner(Query *parse)
210219parse -> query_pathkeys = NIL ;
211220}
212221
213- /*
214- * Generate appropriate target list for subplan; may be different
215- * from tlist if grouping or aggregation is needed.
216- */
217- sub_tlist = make_subplanTargetList (parse ,tlist ,& groupColIdx );
218-
219222/* Generate the (sub) plan */
220223result_plan = query_planner (parse ,
221224parse -> commandType ,
222225sub_tlist ,
223226(List * )parse -> qual );
224227
225- /* query_plannersets query_pathkeys to NIL if it didn't make
226- *a properly sorted plan
228+ /* query_plannerreturns actual sort order (which is not
229+ *necessarily what we requested) in query_pathkeys.
227230 */
228- if (parse -> query_pathkeys )
229- is_sorted = true;
231+ current_pathkeys = parse -> query_pathkeys ;
230232}
231233
232234/* query_planner returns NULL if it thinks plan is bogus */
@@ -241,6 +243,8 @@ union_planner(Query *parse)
241243{
242244bool tuplePerGroup ;
243245List * group_tlist ;
246+ List * group_pathkeys ;
247+ bool is_sorted ;
244248
245249/*
246250 * Decide whether how many tuples per group the Group node needs
@@ -261,18 +265,33 @@ union_planner(Query *parse)
261265else
262266group_tlist = tlist ;
263267
268+ /*
269+ * Figure out whether the path result is already ordered the way we
270+ * need it --- if so, no need for an explicit sort step.
271+ */
272+ group_pathkeys = make_pathkeys_for_sortclauses (parse -> groupClause ,
273+ tlist );
274+ if (pathkeys_contained_in (group_pathkeys ,current_pathkeys ))
275+ {
276+ is_sorted = true;/* no sort needed now */
277+ /* current_pathkeys remains unchanged */
278+ }
279+ else
280+ {
281+ /* We will need to do an explicit sort by the GROUP BY clause.
282+ * make_groupplan will do the work, but set current_pathkeys
283+ * to indicate the resulting order.
284+ */
285+ is_sorted = false;
286+ current_pathkeys = group_pathkeys ;
287+ }
288+
264289result_plan = make_groupplan (group_tlist ,
265290tuplePerGroup ,
266291parse -> groupClause ,
267292groupColIdx ,
268293is_sorted ,
269294result_plan );
270-
271- /*
272- * Assume the result of the group step is not ordered suitably
273- * for any ORDER BY that may exist. XXX it might be; improve this!
274- */
275- is_sorted = false;
276295}
277296
278297/*
@@ -325,20 +344,23 @@ union_planner(Query *parse)
325344/* HAVING clause, if any, becomes qual of the Agg node */
326345result_plan -> qual = (List * )parse -> havingQual ;
327346
328- /*
329- * Assume result is not ordered suitably for ORDER BY.
330- * XXX it might be; improve this!
331- */
332- is_sorted = false;
347+ /* Note: Agg does not affect any existing sort order of the tuples */
333348}
334349
335350/*
336351 * If we were not able to make the plan come out in the right order,
337352 * add an explicit sort step.
338353 */
339- if (parse -> sortClause && ! is_sorted )
354+ if (parse -> sortClause )
340355{
341- result_plan = make_sortplan (tlist ,parse -> sortClause ,result_plan );
356+ List * sort_pathkeys ;
357+
358+ sort_pathkeys = make_pathkeys_for_sortclauses (parse -> sortClause ,
359+ tlist );
360+ if (!pathkeys_contained_in (sort_pathkeys ,current_pathkeys ))
361+ {
362+ result_plan = make_sortplan (tlist ,parse -> sortClause ,result_plan );
363+ }
342364}
343365
344366/*
@@ -474,12 +496,12 @@ make_groupplan(List *group_tlist,
474496bool tuplePerGroup ,
475497List * groupClause ,
476498AttrNumber * grpColIdx ,
477- bool is_sorted ,
499+ bool is_presorted ,
478500Plan * subplan )
479501{
480502int numCols = length (groupClause );
481503
482- if (!is_sorted )
504+ if (!is_presorted )
483505{
484506/*
485507 * The Sort node always just takes a copy of the subplan's tlist