|
7 | 7 | *
|
8 | 8 | *
|
9 | 9 | * IDENTIFICATION
|
10 |
| - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.46 1999/03/1918:56:37 momjian Exp $ |
| 10 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.47 1999/04/1901:43:11 tgl Exp $ |
11 | 11 | *
|
12 | 12 | *-------------------------------------------------------------------------
|
13 | 13 | */
|
@@ -138,32 +138,14 @@ union_planner(Query *parse)
|
138 | 138 | else
|
139 | 139 | {
|
140 | 140 | List**vpm=NULL;
|
141 |
| - |
142 |
| -/***S*H***/ |
143 |
| -/* This is only necessary if aggregates are in use in queries like: |
144 |
| - * SELECT sid |
145 |
| - * FROM part |
146 |
| - * GROUP BY sid |
147 |
| - * HAVING MIN(pid) > 1; (pid is used but never selected for!!!) |
148 |
| - * because the function 'query_planner' creates the plan for the lefttree |
149 |
| - * of the 'GROUP' node and returns only those attributes contained in 'tlist'. |
150 |
| - * The original 'tlist' contains only 'sid' here and that's why we have to |
151 |
| - * to extend it to attributes which are not selected but are used in the |
152 |
| - * havingQual. */ |
153 |
| - |
154 |
| -/* 'check_having_qual_for_vars' takes the havingQual and the actual 'tlist' |
155 |
| - * as arguments and recursively scans the havingQual for attributes |
156 |
| - * (VAR nodes) that are not contained in 'tlist' yet. If so, it creates |
157 |
| - * a new entry and attaches it to the list 'new_tlist' (consisting of the |
158 |
| - * VAR node and the RESDOM node as usual with tlists :-) ) */ |
159 |
| -if (parse->hasAggs) |
160 |
| - { |
161 |
| -if (parse->havingQual!=NULL) |
162 |
| - { |
163 |
| -new_tlist=check_having_qual_for_vars(parse->havingQual,new_tlist); |
164 |
| - } |
165 |
| - } |
166 |
| - |
| 141 | + |
| 142 | +/* |
| 143 | + * If there is a HAVING clause, make sure all vars referenced in it |
| 144 | + * are included in the target list for query_planner(). |
| 145 | + */ |
| 146 | +if (parse->havingQual) |
| 147 | +new_tlist=check_having_qual_for_vars(parse->havingQual,new_tlist); |
| 148 | + |
167 | 149 | new_tlist=preprocess_targetlist(new_tlist,
|
168 | 150 | parse->commandType,
|
169 | 151 | parse->resultRelation,
|
@@ -208,10 +190,10 @@ union_planner(Query *parse)
|
208 | 190 | parse->rtable);
|
209 | 191 |
|
210 | 192 | if (parse->rtable!=NULL)
|
211 |
| -{ |
| 193 | + { |
212 | 194 | vpm= (List**)palloc(length(parse->rtable)*sizeof(List*));
|
213 | 195 | memset(vpm,0,length(parse->rtable)*sizeof(List*));
|
214 |
| -} |
| 196 | + } |
215 | 197 | PlannerVarParam=lcons(vpm,PlannerVarParam);
|
216 | 198 | result_plan=query_planner(parse,
|
217 | 199 | parse->commandType,
|
@@ -246,89 +228,67 @@ union_planner(Query *parse)
|
246 | 228 | result_plan);
|
247 | 229 | }
|
248 | 230 |
|
| 231 | +/* |
| 232 | + * If we have a HAVING clause, do the necessary things with it. |
| 233 | + */ |
| 234 | +if (parse->havingQual) |
| 235 | +{ |
| 236 | +List**vpm=NULL; |
| 237 | + |
| 238 | +if (parse->rtable!=NULL) |
| 239 | +{ |
| 240 | +vpm= (List**)palloc(length(parse->rtable)*sizeof(List*)); |
| 241 | +memset(vpm,0,length(parse->rtable)*sizeof(List*)); |
| 242 | +} |
| 243 | +PlannerVarParam=lcons(vpm,PlannerVarParam); |
| 244 | + |
| 245 | +/* convert the havingQual to conjunctive normal form (cnf) */ |
| 246 | +parse->havingQual= (Node*)cnfify((Expr*)parse->havingQual, true); |
| 247 | + |
| 248 | +if (parse->hasSubLinks) |
| 249 | +{ |
| 250 | +/* There is a subselect in the havingQual, so we have to process it |
| 251 | + * using the same function as for a subselect in 'where' |
| 252 | + */ |
| 253 | +parse->havingQual= |
| 254 | +(Node*)SS_process_sublinks(parse->havingQual); |
| 255 | +/* Check for ungrouped variables passed to subplans. |
| 256 | + * (Probably this should be done by the parser, but right now |
| 257 | + * the parser is not smart enough to tell which level the vars |
| 258 | + * belong to?) |
| 259 | + */ |
| 260 | +check_having_for_ungrouped_vars(parse->havingQual, |
| 261 | +parse->groupClause); |
| 262 | +} |
| 263 | + |
| 264 | +/* Calculate the opfids from the opnos */ |
| 265 | +parse->havingQual= (Node*)fix_opids((List*)parse->havingQual); |
| 266 | + |
| 267 | +PlannerVarParam=lnext(PlannerVarParam); |
| 268 | +if (vpm!=NULL) |
| 269 | +pfree(vpm); |
| 270 | +} |
| 271 | + |
249 | 272 | /*
|
250 | 273 | * If aggregate is present, insert the agg node
|
251 | 274 | */
|
252 | 275 | if (parse->hasAggs)
|
253 | 276 | {
|
254 |
| -intold_length=0,new_length=0; |
255 |
| - |
256 |
| -/* Create the Agg node but use 'tlist' not 'new_tlist' as target list because we |
257 |
| - * don't want the additional attributes (only used for the havingQual, see above) |
258 |
| - * to show up in the result */ |
| 277 | +/* Use 'tlist' not 'new_tlist' as target list because we |
| 278 | + * don't want the additional attributes used for the havingQual |
| 279 | + * (see above) to show up in the result |
| 280 | + */ |
259 | 281 | result_plan= (Plan*)make_agg(tlist,result_plan);
|
260 | 282 |
|
| 283 | +/* HAVING clause, if any, becomes qual of the Agg node */ |
| 284 | +result_plan->qual= (List*)parse->havingQual; |
| 285 | + |
261 | 286 | /*
|
262 |
| - *get the varno/attno entries tothe appropriate references to |
263 |
| - *the result tuple of the subplans. |
| 287 | + *Update vars to refer tosubplan result tuples, |
| 288 | + *find Aggrefs, make sure there is an Aggref in every HAVING clause. |
264 | 289 | */
|
265 |
| -((Agg*)result_plan)->aggs=get_agg_tlist_references((Agg*)result_plan); |
266 |
| - |
267 |
| -/***S*H***/ |
268 |
| -if(parse->havingQual!=NULL) |
269 |
| - { |
270 |
| -List*clause; |
271 |
| -List**vpm=NULL; |
272 |
| - |
273 |
| - |
274 |
| -/* stuff copied from above to handle the use of attributes from outside |
275 |
| - * in subselects */ |
276 |
| - |
277 |
| -if (parse->rtable!=NULL) |
278 |
| - { |
279 |
| -vpm= (List**)palloc(length(parse->rtable)*sizeof(List*)); |
280 |
| -memset(vpm,0,length(parse->rtable)*sizeof(List*)); |
281 |
| - } |
282 |
| -PlannerVarParam=lcons(vpm,PlannerVarParam); |
283 |
| - |
284 |
| - |
285 |
| -/* convert the havingQual to conjunctive normal form (cnf) */ |
286 |
| -parse->havingQual= (Node*)cnfify((Expr*)(Node*)parse->havingQual,true); |
287 |
| - |
288 |
| -/* There is a subselect in the havingQual, so we have to process it |
289 |
| - * using the same function as for a subselect in 'where' */ |
290 |
| -if (parse->hasSubLinks) |
291 |
| - { |
292 |
| -parse->havingQual= |
293 |
| - (Node*)SS_process_sublinks((Node*)parse->havingQual); |
294 |
| - } |
295 |
| - |
296 |
| - |
297 |
| -/* Calculate the opfids from the opnos (=select the correct functions for |
298 |
| - * the used VAR datatypes) */ |
299 |
| -parse->havingQual= (Node*)fix_opids((List*)parse->havingQual); |
300 |
| - |
301 |
| - ((Agg*)result_plan)->plan.qual=(List*)parse->havingQual; |
302 |
| - |
303 |
| -/* Check every clause of the havingQual for aggregates used and append |
304 |
| - * them to result_plan->aggs |
305 |
| - */ |
306 |
| -foreach(clause, ((Agg*)result_plan)->plan.qual) |
307 |
| - { |
308 |
| -/* Make sure there are aggregates in the havingQual |
309 |
| - * if so, the list must be longer after check_having_qual_for_aggs |
310 |
| - */ |
311 |
| -old_length=length(((Agg*)result_plan)->aggs); |
312 |
| - |
313 |
| -((Agg*)result_plan)->aggs=nconc(((Agg*)result_plan)->aggs, |
314 |
| -check_having_qual_for_aggs((Node*)lfirst(clause), |
315 |
| - ((Agg*)result_plan)->plan.lefttree->targetlist, |
316 |
| - ((List*)parse->groupClause))); |
317 |
| - |
318 |
| -/* Have a look at the length of the returned list. If there is no |
319 |
| - * difference, no aggregates have been found and that means, that |
320 |
| - * the Qual belongs to the where clause */ |
321 |
| -if (((new_length=length(((Agg*)result_plan)->aggs))==old_length)|| |
322 |
| - (new_length==0)) |
323 |
| - { |
324 |
| -elog(ERROR,"This could have been done in a where clause!!"); |
325 |
| -return (Plan*)NIL; |
326 |
| - } |
327 |
| - } |
328 |
| -PlannerVarParam=lnext(PlannerVarParam); |
329 |
| -if (vpm!=NULL) |
330 |
| -pfree(vpm); |
331 |
| - } |
| 290 | +if (!set_agg_tlist_references((Agg*)result_plan)) |
| 291 | +elog(ERROR,"SELECT/HAVING requires aggregates to be valid"); |
332 | 292 | }
|
333 | 293 |
|
334 | 294 | /*
|
|