aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-03-30 17:30:44 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-03-30 17:30:44 +0000
commit943337ee5e37a15caef942eb9bfca91c9ba709d7 (patch)
tree4d22df8d825a43157691b4be30943c365bcdb031
parent3fe3b811837c635201521c7e1889546e8f176b4f (diff)
downloadpostgresql-943337ee5e37a15caef942eb9bfca91c9ba709d7.tar.gz
postgresql-943337ee5e37a15caef942eb9bfca91c9ba709d7.zip
Fix window function plan generation to cope with volatile sort expressions.
(Not clear how useful these really are, but failing is no good...) Per report from David Fetter and Robert Treat.
-rw-r--r--src/backend/optimizer/plan/planner.c73
1 files changed, 71 insertions, 2 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 40ed1ac38cd..d7a793ba769 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.252 2009/03/24 21:12:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.253 2009/03/30 17:30:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -83,6 +83,8 @@ static void locate_grouping_columns(PlannerInfo *root,
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,
@@ -1305,7 +1307,10 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
* (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
+ * 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
@@ -1317,6 +1322,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
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)
@@ -2430,6 +2437,68 @@ select_active_windows(PlannerInfo *root, WindowFuncLists *wflists)
}
/*
+ * 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.