summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/optimizer/plan/planner.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 6eeeb0e1d03..72a26695f06 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -3280,10 +3280,53 @@ adjust_group_pathkeys_for_groupagg(PlannerInfo *root)
if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
continue;
- /* only add aggregates with a DISTINCT or ORDER BY */
- if (aggref->aggdistinct != NIL || aggref->aggorder != NIL)
- unprocessed_aggs = bms_add_member(unprocessed_aggs,
- foreach_current_index(lc));
+ /* Skip unless there's a DISTINCT or ORDER BY clause */
+ if (aggref->aggdistinct == NIL && aggref->aggorder == NIL)
+ continue;
+
+ /* Additional safety checks are needed if there's a FILTER clause */
+ if (aggref->aggfilter != NULL)
+ {
+ ListCell *lc2;
+ bool allow_presort = true;
+
+ /*
+ * When the Aggref has a FILTER clause, it's possible that the
+ * filter removes rows that cannot be sorted because the
+ * expression to sort by results in an error during its
+ * evaluation. This is a problem for presorting as that happens
+ * before the FILTER, whereas without presorting, the Aggregate
+ * node will apply the FILTER *before* sorting. So that we never
+ * try to sort anything that might error, here we aim to skip over
+ * any Aggrefs with arguments with expressions which, when
+ * evaluated, could cause an ERROR. Vars and Consts are ok. There
+ * may be more cases that should be allowed, but more thought
+ * needs to be given. Err on the side of caution.
+ */
+ foreach(lc2, aggref->args)
+ {
+ TargetEntry *tle = (TargetEntry *) lfirst(lc2);
+ Expr *expr = tle->expr;
+
+ while (IsA(expr, RelabelType))
+ expr = (Expr *) (castNode(RelabelType, expr))->arg;
+
+ /* Common case, Vars and Consts are ok */
+ if (IsA(expr, Var) || IsA(expr, Const))
+ continue;
+
+ /* Unsupported. Don't try to presort for this Aggref */
+ allow_presort = false;
+ break;
+ }
+
+ /* Skip unsupported Aggrefs */
+ if (!allow_presort)
+ continue;
+ }
+
+ unprocessed_aggs = bms_add_member(unprocessed_aggs,
+ foreach_current_index(lc));
}
/*