From b560ec1b0d7b910ce13edc51ffaafaca72136e3b Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Tue, 16 Jul 2013 20:15:36 -0400 Subject: Implement the FILTER clause for aggregate function calls. This is SQL-standard with a few extensions, namely support for subqueries and outer references in clause expressions. catversion bump due to change in Aggref and WindowFunc. David Fetter, reviewed by Dean Rasheed. --- src/backend/executor/execQual.c | 4 ++++ src/backend/executor/execUtils.c | 6 +++--- src/backend/executor/functions.c | 2 +- src/backend/executor/nodeAgg.c | 13 +++++++++++++ src/backend/executor/nodeWindowAgg.c | 14 ++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) (limited to 'src/backend/executor') diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 138818313b..90c27530e9 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -4410,6 +4410,8 @@ ExecInitExpr(Expr *node, PlanState *parent) astate->args = (List *) ExecInitExpr((Expr *) aggref->args, parent); + astate->aggfilter = ExecInitExpr(aggref->aggfilter, + parent); /* * Complain if the aggregate's arguments contain any @@ -4448,6 +4450,8 @@ ExecInitExpr(Expr *node, PlanState *parent) wfstate->args = (List *) ExecInitExpr((Expr *) wfunc->args, parent); + wfstate->aggfilter = ExecInitExpr(wfunc->aggfilter, + parent); /* * Complain if the windowfunc's arguments contain any diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index cf7fb72ffc..b449e0a553 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -649,9 +649,9 @@ get_last_attnums(Node *node, ProjectionInfo *projInfo) } /* - * Don't examine the arguments of Aggrefs or WindowFuncs, because those do - * not represent expressions to be evaluated within the overall - * targetlist's econtext. + * Don't examine the arguments or filters of Aggrefs or WindowFuncs, + * because those do not represent expressions to be evaluated within the + * overall targetlist's econtext. */ if (IsA(node, Aggref)) return false; diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 12e1b8ef59..ff6a123bc4 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -380,7 +380,7 @@ sql_fn_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var) param = ParseFuncOrColumn(pstate, list_make1(subfield), list_make1(param), - NIL, false, false, false, + NIL, NULL, false, false, false, NULL, true, cref->location); } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index c741131b25..7a0c2541cb 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -484,10 +484,23 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup) { AggStatePerAgg peraggstate = &aggstate->peragg[aggno]; AggStatePerGroup pergroupstate = &pergroup[aggno]; + ExprState *filter = peraggstate->aggrefstate->aggfilter; int nargs = peraggstate->numArguments; int i; TupleTableSlot *slot; + /* Skip anything FILTERed out */ + if (filter) + { + bool isnull; + Datum res; + + res = ExecEvalExprSwitchContext(filter, aggstate->tmpcontext, + &isnull, NULL); + if (isnull || !DatumGetBool(res)) + continue; + } + /* Evaluate the current input expressions for this aggregate */ slot = ExecProject(peraggstate->evalproj, NULL); diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index d9f0e79d10..bbc53361d6 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -227,9 +227,23 @@ advance_windowaggregate(WindowAggState *winstate, int i; MemoryContext oldContext; ExprContext *econtext = winstate->tmpcontext; + ExprState *filter = wfuncstate->aggfilter; oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); + /* Skip anything FILTERed out */ + if (filter) + { + bool isnull; + Datum res = ExecEvalExpr(filter, econtext, &isnull, NULL); + + if (isnull || !DatumGetBool(res)) + { + MemoryContextSwitchTo(oldContext); + return; + } + } + /* We start from 1, since the 0th arg will be the transition value */ i = 1; foreach(arg, wfuncstate->args) -- cgit v1.2.1