]> granicus.if.org Git - postgresql/commitdiff
Correctly set up aggregate FILTER expression in partial-aggregation plans.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 24 Jul 2016 00:16:48 +0000 (20:16 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 24 Jul 2016 00:16:48 +0000 (20:16 -0400)
The aggfilter expression should be removed from the parent (combining)
Aggref, since it's not supposed to apply the filter, and indeed cannot
because any Vars used in the filter would not be available after the
lower-level aggregation step.  Per report from Jeff Janes.

(This has been broken since the introduction of partial aggregation,
I think.  The error became obvious after commit 59a3795c2, when setrefs.c
began processing the parent Aggref's fields normally and thus would detect
such Vars.  The special-case coding previously used in setrefs.c skipped
over the parent's aggfilter field without processing it.  That was broken
in its own way because no other setrefs.c processing got applied either;
though since the executor would not execute the filter expression, only
initialize it, that oversight might not have had any visible symptoms at
present.)

Report: <CAMkU=1xfuPf2edAe4ZGXTmJpU7jxuKukKyvNtEXwu35B7dvejg@mail.gmail.com>

src/backend/optimizer/plan/setrefs.c

index 6ea46c46812d9f985bd09030af6d80543dfd886f..d10a98396c7f75566ed0064ba9fa392b2bc54d7a 100644 (file)
@@ -1752,6 +1752,10 @@ convert_combining_aggrefs(Node *node, void *context)
                Aggref     *child_agg;
                Aggref     *parent_agg;
 
+               /* Assert we've not chosen to partial-ize any unsupported cases */
+               Assert(orig_agg->aggorder == NIL);
+               Assert(orig_agg->aggdistinct == NIL);
+
                /*
                 * Since aggregate calls can't be nested, we needn't recurse into the
                 * arguments.  But for safety, flat-copy the Aggref node itself rather
@@ -1762,13 +1766,17 @@ convert_combining_aggrefs(Node *node, void *context)
 
                /*
                 * For the parent Aggref, we want to copy all the fields of the
-                * original aggregate *except* the args list.  Rather than explicitly
-                * knowing what they all are here, we can momentarily modify child_agg
-                * to provide a source for copyObject.
+                * original aggregate *except* the args list, which we'll replace
+                * below, and the aggfilter expression, which should be applied only
+                * by the child not the parent.  Rather than explicitly knowing about
+                * all the other fields here, we can momentarily modify child_agg to
+                * provide a suitable source for copyObject.
                 */
                child_agg->args = NIL;
+               child_agg->aggfilter = NULL;
                parent_agg = (Aggref *) copyObject(child_agg);
                child_agg->args = orig_agg->args;
+               child_agg->aggfilter = orig_agg->aggfilter;
 
                /*
                 * Now, set up child_agg to represent the first phase of partial