summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c59
1 files changed, 38 insertions, 21 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 5d845e9842a..d2ec1b8a750 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.98 2000/12/14 22:30:43 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.99 2001/01/18 07:12:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -132,6 +132,7 @@ subquery_planner(Query *parse, double tuple_fraction)
List *saved_initplan = PlannerInitPlan;
int saved_planid = PlannerPlanId;
Plan *plan;
+ List *newHaving;
List *lst;
/* Set up for a new level of subquery */
@@ -156,20 +157,6 @@ subquery_planner(Query *parse, double tuple_fraction)
preprocess_jointree(parse, (Node *) parse->jointree);
/*
- * A HAVING clause without aggregates is equivalent to a WHERE clause
- * (except it can only refer to grouped fields). If there are no aggs
- * anywhere in the query, then we don't want to create an Agg plan
- * node, so merge the HAVING condition into WHERE. (We used to
- * consider this an error condition, but it seems to be legal SQL.)
- */
- if (parse->havingQual != NULL && !parse->hasAggs)
- {
- parse->jointree->quals = make_and_qual(parse->jointree->quals,
- parse->havingQual);
- parse->havingQual = NULL;
- }
-
- /*
* Do expression preprocessing on targetlist and quals.
*/
parse->targetList = (List *)
@@ -182,6 +169,37 @@ subquery_planner(Query *parse, double tuple_fraction)
EXPRKIND_HAVING);
/*
+ * A HAVING clause without aggregates is equivalent to a WHERE clause
+ * (except it can only refer to grouped fields). Transfer any agg-free
+ * clauses of the HAVING qual into WHERE. This may seem like wasting
+ * cycles to cater to stupidly-written queries, but there are other
+ * reasons for doing it. Firstly, if the query contains no aggs at all,
+ * then we aren't going to generate an Agg plan node, and so there'll be
+ * no place to execute HAVING conditions; without this transfer, we'd
+ * lose the HAVING condition entirely, which is wrong. Secondly, when
+ * we push down a qual condition into a sub-query, it's easiest to push
+ * the qual into HAVING always, in case it contains aggs, and then let
+ * this code sort it out.
+ *
+ * Note that both havingQual and parse->jointree->quals are in
+ * implicitly-ANDed-list form at this point, even though they are
+ * declared as Node *. Also note that contain_agg_clause does not
+ * recurse into sub-selects, which is exactly what we need here.
+ */
+ newHaving = NIL;
+ foreach(lst, (List *) parse->havingQual)
+ {
+ Node *havingclause = (Node *) lfirst(lst);
+
+ if (contain_agg_clause(havingclause))
+ newHaving = lappend(newHaving, havingclause);
+ else
+ parse->jointree->quals = (Node *)
+ lappend((List *) parse->jointree->quals, havingclause);
+ }
+ parse->havingQual = (Node *) newHaving;
+
+ /*
* Do the main planning. If we have an inherited target relation,
* that needs special processing, else go straight to grouping_planner.
*/
@@ -554,12 +572,6 @@ preprocess_expression(Query *parse, Node *expr, int kind)
* Check for ungrouped variables passed to subplans. Note we
* do NOT do this for subplans in WHERE (or JOIN/ON); it's legal
* there because WHERE is evaluated pre-GROUP.
- *
- * An interesting fine point: if subquery_planner reassigned a
- * HAVING qual into WHERE, then we will accept references to
- * ungrouped vars from subplans in the HAVING qual. This is not
- * entirely consistent, but it doesn't seem particularly
- * harmful...
*/
check_subplans_for_ungrouped_vars(expr, parse);
}
@@ -1049,6 +1061,11 @@ grouping_planner(Query *parse, double tuple_fraction)
result_plan);
/* Note: Agg does not affect any existing sort order of the tuples */
}
+ else
+ {
+ /* If there are no Aggs, we shouldn't have any HAVING qual anymore */
+ Assert(parse->havingQual == NULL);
+ }
/*
* If we were not able to make the plan come out in the right order,