*** pgsql/src/backend/optimizer/plan/planner.c 2009/03/24 21:12:56 1.252 --- pgsql/src/backend/optimizer/plan/planner.c 2009/03/30 17:30:44 1.253 *************** *** 8,14 **** * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.251 2009/01/09 15:46:10 tgl Exp $ * *------------------------------------------------------------------------- */ --- 8,14 ---- * * * IDENTIFICATION ! * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.252 2009/03/24 21:12:56 tgl Exp $ * *------------------------------------------------------------------------- */ *************** static void locate_grouping_columns(Plan *** 83,88 **** --- 83,90 ---- AttrNumber *groupColIdx); static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist); static List *select_active_windows(PlannerInfo *root, WindowFuncLists *wflists); + static List *add_volatile_sort_exprs(List *window_tlist, List *tlist, + List *activeWindows); static List *make_pathkeys_for_window(PlannerInfo *root, WindowClause *wc, List *tlist, bool canonicalize); static void get_column_info_for_window(PlannerInfo *root, WindowClause *wc, *************** grouping_planner(PlannerInfo *root, doub *** 1305,1311 **** * (In some cases we wouldn't need to propagate all of these * all the way to the top, since they might only be needed as * inputs to WindowFuncs. It's probably not worth trying to ! * optimize that though.) As we climb up the stack, we add * outputs for the WindowFuncs computed at each level. Also, * each input tlist has to present all the columns needed to * sort the data for the next WindowAgg step. That's handled --- 1307,1316 ---- * (In some cases we wouldn't need to propagate all of these * all the way to the top, since they might only be needed as * inputs to WindowFuncs. It's probably not worth trying to ! * optimize that though.) We also need any volatile sort ! * expressions, because make_sort_from_pathkeys won't add those ! * on its own, and anyway we want them evaluated only once at ! * the bottom of the stack. As we climb up the stack, we add * outputs for the WindowFuncs computed at each level. Also, * each input tlist has to present all the columns needed to * sort the data for the next WindowAgg step. That's handled *************** grouping_planner(PlannerInfo *root, doub *** 1317,1322 **** --- 1322,1329 ---- if (parse->hasAggs) window_tlist = add_to_flat_tlist(window_tlist, pull_agg_clause((Node *) tlist)); + window_tlist = add_volatile_sort_exprs(window_tlist, tlist, + activeWindows); result_plan->targetlist = (List *) copyObject(window_tlist); foreach(l, activeWindows) *************** select_active_windows(PlannerInfo *root, *** 2430,2435 **** --- 2437,2504 ---- } /* + * add_volatile_sort_exprs + * Identify any volatile sort/group expressions used by the active + * windows, and add them to window_tlist if not already present. + * Return the modified window_tlist. + */ + static List * + add_volatile_sort_exprs(List *window_tlist, List *tlist, List *activeWindows) + { + Bitmapset *sgrefs = NULL; + ListCell *lc; + + /* First, collect the sortgrouprefs of the windows into a bitmapset */ + foreach(lc, activeWindows) + { + WindowClause *wc = (WindowClause *) lfirst(lc); + ListCell *lc2; + + foreach(lc2, wc->partitionClause) + { + SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc2); + + sgrefs = bms_add_member(sgrefs, sortcl->tleSortGroupRef); + } + foreach(lc2, wc->orderClause) + { + SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc2); + + sgrefs = bms_add_member(sgrefs, sortcl->tleSortGroupRef); + } + } + + /* + * Now scan the original tlist to find the referenced expressions. + * Any that are volatile must be added to window_tlist. + * + * Note: we know that the input window_tlist contains no items marked + * with ressortgrouprefs, so we don't have to worry about collisions + * of the reference numbers. + */ + foreach(lc, tlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(lc); + + if (tle->ressortgroupref != 0 && + bms_is_member(tle->ressortgroupref, sgrefs) && + contain_volatile_functions((Node *) tle->expr)) + { + TargetEntry *newtle; + + newtle = makeTargetEntry(tle->expr, + list_length(window_tlist) + 1, + NULL, + false); + newtle->ressortgroupref = tle->ressortgroupref; + window_tlist = lappend(window_tlist, newtle); + } + } + + return window_tlist; + } + + /* * make_pathkeys_for_window * Create a pathkeys list describing the required input ordering * for the given WindowClause.