Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4438b70

Browse files
committed
Repair some problems in planner's handling of HAVING clauses.
This fixes a few of the problems Hiroshi Inoue complained of, butI have not touched the rewrite-related issues.
1 parent2deef96 commit4438b70

File tree

4 files changed

+219
-380
lines changed

4 files changed

+219
-380
lines changed

‎src/backend/nodes/copyfuncs.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.76 1999/03/03 00:02:42 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.77 1999/04/19 01:43:11 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -470,7 +470,10 @@ _copyAgg(Agg *from)
470470

471471
CopyPlanFields((Plan*)from, (Plan*)newnode);
472472

473-
newnode->aggs=get_agg_tlist_references(newnode);
473+
/* Cannot copy agg list; it must be rebuilt to point to subnodes of
474+
* new node.
475+
*/
476+
set_agg_tlist_references(newnode);
474477

475478
returnnewnode;
476479
}

‎src/backend/optimizer/plan/planner.c

Lines changed: 63 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* 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 $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -138,32 +138,14 @@ union_planner(Query *parse)
138138
else
139139
{
140140
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+
167149
new_tlist=preprocess_targetlist(new_tlist,
168150
parse->commandType,
169151
parse->resultRelation,
@@ -208,10 +190,10 @@ union_planner(Query *parse)
208190
parse->rtable);
209191

210192
if (parse->rtable!=NULL)
211-
{
193+
{
212194
vpm= (List**)palloc(length(parse->rtable)*sizeof(List*));
213195
memset(vpm,0,length(parse->rtable)*sizeof(List*));
214-
}
196+
}
215197
PlannerVarParam=lcons(vpm,PlannerVarParam);
216198
result_plan=query_planner(parse,
217199
parse->commandType,
@@ -246,89 +228,67 @@ union_planner(Query *parse)
246228
result_plan);
247229
}
248230

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+
249272
/*
250273
* If aggregate is present, insert the agg node
251274
*/
252275
if (parse->hasAggs)
253276
{
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+
*/
259281
result_plan= (Plan*)make_agg(tlist,result_plan);
260282

283+
/* HAVING clause, if any, becomes qual of the Agg node */
284+
result_plan->qual= (List*)parse->havingQual;
285+
261286
/*
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.
264289
*/
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");
332292
}
333293

334294
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp