Skip to content

Commit fd8e580

Browse files
committed
Clean up problems with sublinks + grouping in planner. Not
sure if they are all fixed, because rewriter is now the stumbling block, but at least some cases work that did not work before.
1 parent 974bdd9 commit fd8e580

File tree

3 files changed

+85
-76
lines changed

3 files changed

+85
-76
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 10 additions & 37 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.56 1999/06/12 19:27:41 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.57 1999/06/21 01:20:57 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -73,10 +73,10 @@ planner(Query *parse)
7373
{
7474
Plan *result_plan;
7575

76+
/* Initialize state for subselects */
7677
PlannerQueryLevel = 1;
77-
PlannerVarParam = NULL;
78-
PlannerParamVar = NULL;
7978
PlannerInitPlan = NULL;
79+
PlannerParamVar = NULL;
8080
PlannerPlanId = 0;
8181

8282
transformKeySetQuery(parse);
@@ -155,7 +155,6 @@ union_planner(Query *parse)
155155
}
156156
else
157157
{
158-
List **vpm = NULL;
159158
List *sub_tlist;
160159

161160
/* Preprocess targetlist in case we are inside an INSERT/UPDATE. */
@@ -208,19 +207,10 @@ union_planner(Query *parse)
208207
sub_tlist = make_subplanTargetList(parse, tlist, &groupColIdx);
209208

210209
/* Generate the (sub) plan */
211-
if (parse->rtable != NULL)
212-
{
213-
vpm = (List **) palloc(length(parse->rtable) * sizeof(List *));
214-
memset(vpm, 0, length(parse->rtable) * sizeof(List *));
215-
}
216-
PlannerVarParam = lcons(vpm, PlannerVarParam);
217210
result_plan = query_planner(parse,
218211
parse->commandType,
219212
sub_tlist,
220213
(List *) parse->qual);
221-
PlannerVarParam = lnext(PlannerVarParam);
222-
if (vpm != NULL)
223-
pfree(vpm);
224214
}
225215

226216
/* query_planner returns NULL if it thinks plan is bogus */
@@ -264,34 +254,21 @@ union_planner(Query *parse)
264254
*/
265255
if (parse->havingQual)
266256
{
267-
List **vpm = NULL;
268-
269-
if (parse->rtable != NULL)
270-
{
271-
vpm = (List **) palloc(length(parse->rtable) * sizeof(List *));
272-
memset(vpm, 0, length(parse->rtable) * sizeof(List *));
273-
}
274-
PlannerVarParam = lcons(vpm, PlannerVarParam);
275-
276257
/* convert the havingQual to conjunctive normal form (cnf) */
277258
parse->havingQual = (Node *) cnfify((Expr *) parse->havingQual, true);
278259

279260
if (parse->hasSubLinks)
280261
{
281-
282262
/*
283-
* There is a subselect in the havingQual, so we have to
263+
* There may be a subselect in the havingQual, so we have to
284264
* process it using the same function as for a subselect in
285265
* 'where'
286266
*/
287-
parse->havingQual =
288-
(Node *) SS_process_sublinks(parse->havingQual);
267+
parse->havingQual = SS_process_sublinks(parse->havingQual);
289268

290269
/*
291270
* Check for ungrouped variables passed to subplans. (Probably
292-
* this should be done by the parser, but right now the parser
293-
* is not smart enough to tell which level the vars belong
294-
* to?)
271+
* this should be done for the targetlist as well???)
295272
*/
296273
check_having_for_ungrouped_vars(parse->havingQual,
297274
parse->groupClause,
@@ -300,10 +277,6 @@ union_planner(Query *parse)
300277

301278
/* Calculate the opfids from the opnos */
302279
parse->havingQual = (Node *) fix_opids((List *) parse->havingQual);
303-
304-
PlannerVarParam = lnext(PlannerVarParam);
305-
if (vpm != NULL)
306-
pfree(vpm);
307280
}
308281

309282
/*
@@ -325,10 +298,10 @@ union_planner(Query *parse)
325298

326299
/*
327300
* Check that we actually found some aggregates, else executor
328-
* will die unpleasantly. (The rewrite module currently has bugs
329-
* that allow hasAggs to be incorrectly set 'true' sometimes. It's
330-
* not easy to recover here, since we've already made decisions
331-
* assuming there will be an Agg node.)
301+
* will die unpleasantly. (This defends against possible bugs in
302+
* parser or rewrite that might cause hasAggs to be incorrectly
303+
* set 'true'. It's not easy to recover here, since we've already
304+
* made decisions assuming there will be an Agg node.)
332305
*/
333306
if (((Agg *) result_plan)->aggs == NIL)
334307
elog(ERROR, "union_planner: query is marked hasAggs, but I don't see any");

src/backend/optimizer/plan/subselect.c

Lines changed: 73 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
11
/*-------------------------------------------------------------------------
22
*
33
* subselect.c
4+
* Planning routines for subselects and parameters.
5+
*
6+
* Copyright (c) 1994, Regents of the University of California
7+
*
8+
* IDENTIFICATION
9+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.18 1999/06/21 01:20:57 tgl Exp $
410
*
511
*-------------------------------------------------------------------------
612
*/
713
#include "postgres.h"
814

915
#include "catalog/pg_type.h"
10-
1116
#include "nodes/pg_list.h"
1217
#include "nodes/plannodes.h"
1318
#include "nodes/parsenodes.h"
1419
#include "nodes/relation.h"
1520
#include "nodes/makefuncs.h"
1621
#include "nodes/nodeFuncs.h"
17-
1822
#include "optimizer/subselect.h"
1923
#include "optimizer/planner.h"
2024
#include "optimizer/planmain.h"
@@ -27,12 +31,31 @@
2731
#include "optimizer/cost.h"
2832

2933
int PlannerQueryLevel; /* level of current query */
30-
List *PlannerVarParam; /* correlation Vars to Param mapper */
31-
List *PlannerParamVar; /* to get Var from Param->paramid */
3234
List *PlannerInitPlan; /* init subplans for current query */
33-
int PlannerPlanId;
35+
List *PlannerParamVar; /* to get Var from Param->paramid */
36+
int PlannerPlanId; /* to assign unique ID to subquery plans */
37+
38+
/*--------------------
39+
* PlannerParamVar is a list of Var nodes, wherein the n'th entry
40+
* (n counts from 0) corresponds to Param->paramid = n. The Var nodes
41+
* are ordinary except for one thing: their varlevelsup field does NOT
42+
* have the usual interpretation of "subplan levels out from current".
43+
* Instead, it contains the absolute plan level, with the outermost
44+
* plan being level 1 and nested plans having higher level numbers.
45+
* This nonstandardness is useful because we don't have to run around
46+
* and update the list elements when we enter or exit a subplan
47+
* recursion level. But we must pay attention not to confuse this
48+
* meaning with the normal meaning of varlevelsup.
49+
*--------------------
50+
*/
3451

3552

53+
/*
54+
* Create a new entry in the PlannerParamVar list, and return its index.
55+
*
56+
* var contains the data to be copied, except for varlevelsup which
57+
* is set from the absolute level value given by varlevel.
58+
*/
3659
static int
3760
_new_param(Var *var, int varlevel)
3861
{
@@ -61,38 +84,49 @@ _new_param(Var *var, int varlevel)
6184
return i;
6285
}
6386

87+
/*
88+
* Generate a Param node to replace the given Var,
89+
* which is expected to have varlevelsup > 0 (ie, it is not local).
90+
*/
6491
static Param *
6592
_replace_var(Var *var)
6693
{
67-
List **rt = (List **) nth(var->varlevelsup, PlannerVarParam);
68-
List *vpe = rt[var->varno - 1];
94+
List *ppv;
6995
Param *retval;
96+
int varlevel;
7097
int i;
7198

72-
if (vpe == NULL)
73-
{
74-
vpe = rt[var->varno - 1] = makeNode(List);
75-
lfirsti(vpe) = -1;
76-
lnext(vpe) = NULL;
77-
}
99+
Assert(var->varlevelsup > 0 && var->varlevelsup < PlannerQueryLevel);
100+
varlevel = PlannerQueryLevel - var->varlevelsup;
78101

79-
for (i = ObjectIdAttributeNumber;; i++)
102+
/*
103+
* If there's already a PlannerParamVar entry for this same Var,
104+
* just use it. NOTE: in situations involving UNION or inheritance,
105+
* it is possible for the same varno/varlevel to refer to different RTEs
106+
* in different parts of the parsetree, so that different fields might
107+
* end up sharing the same Param number. As long as we check the vartype
108+
* as well, I believe that this sort of aliasing will cause no trouble.
109+
* The correct field should get stored into the Param slot at execution
110+
* in each part of the tree.
111+
*/
112+
i = 0;
113+
foreach(ppv, PlannerParamVar)
80114
{
81-
if (i == var->varattno)
115+
Var *pvar = lfirst(ppv);
116+
117+
if (pvar->varno == var->varno &&
118+
pvar->varattno == var->varattno &&
119+
pvar->varlevelsup == varlevel &&
120+
pvar->vartype == var->vartype)
82121
break;
83-
if (lnext(vpe) == NULL)
84-
{
85-
lnext(vpe) = makeNode(List);
86-
vpe = lnext(vpe);
87-
lfirsti(vpe) = -1;
88-
lnext(vpe) = NULL;
89-
}
90-
else
91-
vpe = lnext(vpe);
122+
i++;
92123
}
93124

94-
if ((i = lfirsti(vpe)) < 0) /* parameter is not assigned */
95-
i = _new_param(var, PlannerQueryLevel - var->varlevelsup);
125+
if (! ppv)
126+
{
127+
/* Nope, so make a new one */
128+
i = _new_param(var, varlevel);
129+
}
96130

97131
retval = makeNode(Param);
98132
retval->paramkind = PARAM_EXEC;
@@ -125,7 +159,7 @@ _make_subplan(SubLink *slink)
125159
(void) SS_finalize_plan(plan);
126160
plan->initPlan = PlannerInitPlan;
127161

128-
/* Get extParam from InitPlan-s */
162+
/* Create extParam list as union of InitPlan-s' lists */
129163
foreach(lst, PlannerInitPlan)
130164
{
131165
List *lp;
@@ -146,11 +180,12 @@ _make_subplan(SubLink *slink)
146180
node->sublink = slink;
147181
slink->subselect = NULL; /* cool ?! */
148182

149-
/* make parParam list */
183+
/* make parParam list of params coming from current query level */
150184
foreach(lst, plan->extParam)
151185
{
152186
Var *var = nth(lfirsti(lst), PlannerParamVar);
153187

188+
/* note varlevelsup is absolute level number */
154189
if (var->varlevelsup == PlannerQueryLevel)
155190
node->parParam = lappendi(node->parParam, lfirsti(lst));
156191
}
@@ -170,7 +205,7 @@ _make_subplan(SubLink *slink)
170205
TargetEntry *te = nth(i, plan->targetlist);
171206
Var *var = makeVar(0, 0, te->resdom->restype,
172207
te->resdom->restypmod,
173-
PlannerQueryLevel, 0, 0);
208+
0, 0, 0);
174209
Param *prm = makeNode(Param);
175210

176211
prm->paramkind = PARAM_EXEC;
@@ -190,7 +225,7 @@ _make_subplan(SubLink *slink)
190225
}
191226
else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)
192227
{
193-
Var *var = makeVar(0, 0, BOOLOID, -1, PlannerQueryLevel, 0, 0);
228+
Var *var = makeVar(0, 0, BOOLOID, -1, 0, 0, 0);
194229
Param *prm = makeNode(Param);
195230

196231
prm->paramkind = PARAM_EXEC;
@@ -202,10 +237,10 @@ _make_subplan(SubLink *slink)
202237
result = (Node *) prm;
203238
}
204239
else
205-
/* make expression of SUBPLAN type */
206240
{
241+
/* make expression of SUBPLAN type */
207242
Expr *expr = makeNode(Expr);
208-
List *args = NULL;
243+
List *args = NIL;
209244
int i = 0;
210245

211246
expr->typeOid = BOOLOID;
@@ -222,6 +257,10 @@ _make_subplan(SubLink *slink)
222257
Var *var = nth(lfirsti(lst), PlannerParamVar);
223258

224259
var = (Var *) copyObject(var);
260+
/* Must fix absolute-level varlevelsup from the
261+
* PlannerParamVar entry. But since var is at current
262+
* subplan level, this is easy:
263+
*/
225264
var->varlevelsup = 0;
226265
args = lappend(args, var);
227266
}
@@ -240,7 +279,6 @@ _make_subplan(SubLink *slink)
240279
}
241280

242281
return result;
243-
244282
}
245283

246284
static List *
@@ -305,6 +343,7 @@ _finalize_primnode(void *expr, List **subplan)
305343
{
306344
Var *var = nth(lfirsti(lst), PlannerParamVar);
307345

346+
/* note varlevelsup is absolute level number */
308347
if (var->varlevelsup < PlannerQueryLevel &&
309348
!intMember(lfirsti(lst), result))
310349
result = lappendi(result, lfirsti(lst));
@@ -332,10 +371,7 @@ SS_replace_correlation_vars(Node *expr)
332371
else if (IsA(expr, Var))
333372
{
334373
if (((Var *) expr)->varlevelsup > 0)
335-
{
336-
Assert(((Var *) expr)->varlevelsup < PlannerQueryLevel);
337374
expr = (Node *) _replace_var((Var *) expr);
338-
}
339375
}
340376
else if (IsA(expr, Iter))
341377
((Iter *) expr)->iterexpr = SS_replace_correlation_vars(((Iter *) expr)->iterexpr);
@@ -480,6 +516,7 @@ SS_finalize_plan(Plan *plan)
480516
{
481517
Var *var = nth(lfirsti(lst), PlannerParamVar);
482518

519+
/* note varlevelsup is absolute level number */
483520
if (var->varlevelsup < PlannerQueryLevel)
484521
extParam = lappendi(extParam, lfirsti(lst));
485522
else if (var->varlevelsup > PlannerQueryLevel)

src/include/optimizer/subselect.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@
88
#define SUBSELECT_H
99

1010
extern int PlannerQueryLevel; /* level of current query */
11-
extern List *PlannerVarParam; /* correlation Vars to Param mapper */
12-
extern List *PlannerParamVar; /* to get Var from Param->paramid */
1311
extern List *PlannerInitPlan; /* init subplans for current query */
14-
extern int PlannerPlanId; /* to assigne unique ID to subquery plans */
12+
extern List *PlannerParamVar; /* to get Var from Param->paramid */
13+
extern int PlannerPlanId; /* to assign unique ID to subquery plans */
1514

1615
extern List *SS_finalize_plan(Plan *plan);
1716
extern Node *SS_replace_correlation_vars(Node *expr);

0 commit comments

Comments
 (0)