8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.98 2000/12/14 22:30:43 tgl Exp $
11
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.99 2001/01/18 07:12:37 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -132,6 +132,7 @@ subquery_planner(Query *parse, double tuple_fraction)
132
132
List * saved_initplan = PlannerInitPlan ;
133
133
int saved_planid = PlannerPlanId ;
134
134
Plan * plan ;
135
+ List * newHaving ;
135
136
List * lst ;
136
137
137
138
/* Set up for a new level of subquery */
@@ -155,20 +156,6 @@ subquery_planner(Query *parse, double tuple_fraction)
155
156
parse -> jointree = (FromExpr * )
156
157
preprocess_jointree (parse , (Node * ) parse -> jointree );
157
158
158
- /*
159
- * A HAVING clause without aggregates is equivalent to a WHERE clause
160
- * (except it can only refer to grouped fields). If there are no aggs
161
- * anywhere in the query, then we don't want to create an Agg plan
162
- * node, so merge the HAVING condition into WHERE. (We used to
163
- * consider this an error condition, but it seems to be legal SQL.)
164
- */
165
- if (parse -> havingQual != NULL && !parse -> hasAggs )
166
- {
167
- parse -> jointree -> quals = make_and_qual (parse -> jointree -> quals ,
168
- parse -> havingQual );
169
- parse -> havingQual = NULL ;
170
- }
171
-
172
159
/*
173
160
* Do expression preprocessing on targetlist and quals.
174
161
*/
@@ -181,6 +168,37 @@ subquery_planner(Query *parse, double tuple_fraction)
181
168
parse -> havingQual = preprocess_expression (parse , parse -> havingQual ,
182
169
EXPRKIND_HAVING );
183
170
171
+ /*
172
+ * A HAVING clause without aggregates is equivalent to a WHERE clause
173
+ * (except it can only refer to grouped fields). Transfer any agg-free
174
+ * clauses of the HAVING qual into WHERE. This may seem like wasting
175
+ * cycles to cater to stupidly-written queries, but there are other
176
+ * reasons for doing it. Firstly, if the query contains no aggs at all,
177
+ * then we aren't going to generate an Agg plan node, and so there'll be
178
+ * no place to execute HAVING conditions; without this transfer, we'd
179
+ * lose the HAVING condition entirely, which is wrong. Secondly, when
180
+ * we push down a qual condition into a sub-query, it's easiest to push
181
+ * the qual into HAVING always, in case it contains aggs, and then let
182
+ * this code sort it out.
183
+ *
184
+ * Note that both havingQual and parse->jointree->quals are in
185
+ * implicitly-ANDed-list form at this point, even though they are
186
+ * declared as Node *. Also note that contain_agg_clause does not
187
+ * recurse into sub-selects, which is exactly what we need here.
188
+ */
189
+ newHaving = NIL ;
190
+ foreach (lst , (List * ) parse -> havingQual )
191
+ {
192
+ Node * havingclause = (Node * ) lfirst (lst );
193
+
194
+ if (contain_agg_clause (havingclause ))
195
+ newHaving = lappend (newHaving , havingclause );
196
+ else
197
+ parse -> jointree -> quals = (Node * )
198
+ lappend ((List * ) parse -> jointree -> quals , havingclause );
199
+ }
200
+ parse -> havingQual = (Node * ) newHaving ;
201
+
184
202
/*
185
203
* Do the main planning. If we have an inherited target relation,
186
204
* that needs special processing, else go straight to grouping_planner.
@@ -554,12 +572,6 @@ preprocess_expression(Query *parse, Node *expr, int kind)
554
572
* Check for ungrouped variables passed to subplans. Note we
555
573
* do NOT do this for subplans in WHERE (or JOIN/ON); it's legal
556
574
* there because WHERE is evaluated pre-GROUP.
557
- *
558
- * An interesting fine point: if subquery_planner reassigned a
559
- * HAVING qual into WHERE, then we will accept references to
560
- * ungrouped vars from subplans in the HAVING qual. This is not
561
- * entirely consistent, but it doesn't seem particularly
562
- * harmful...
563
575
*/
564
576
check_subplans_for_ungrouped_vars (expr , parse );
565
577
}
@@ -1049,6 +1061,11 @@ grouping_planner(Query *parse, double tuple_fraction)
1049
1061
result_plan );
1050
1062
/* Note: Agg does not affect any existing sort order of the tuples */
1051
1063
}
1064
+ else
1065
+ {
1066
+ /* If there are no Aggs, we shouldn't have any HAVING qual anymore */
1067
+ Assert (parse -> havingQual == NULL );
1068
+ }
1052
1069
1053
1070
/*
1054
1071
* If we were not able to make the plan come out in the right order,
0 commit comments