Skip to content

Commit 6bdfde9

Browse files
committed
When testing whether a sub-plan can do projection, use a general-purpose
check instead of hardwiring assumptions that only certain plan node types can appear at the places where we are testing. This was always a pretty fragile assumption, and it turns out to be broken in 7.4 for certain cases involving IN-subselect tests that need type coercion. Also, modify code that builds finished Plan tree so that node types that don't do projection always copy their input node's targetlist, rather than having the tlist passed in from the caller. The old method makes it too easy to write broken code that thinks it can modify the tlist when it cannot.
1 parent de816a0 commit 6bdfde9

File tree

4 files changed

+81
-91
lines changed

4 files changed

+81
-91
lines changed

src/backend/optimizer/plan/createplan.c

+61-64
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.166 2004/01/07 18:56:26 neilc Exp $
13+
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.167 2004/01/18 00:50:02 tgl Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -97,13 +97,13 @@ static HashJoin *make_hashjoin(List *tlist,
9797
List *hashclauses,
9898
Plan *lefttree, Plan *righttree,
9999
JoinType jointype);
100-
static Hash *make_hash(List *tlist, Plan *lefttree);
100+
static Hash *make_hash(Plan *lefttree);
101101
static MergeJoin *make_mergejoin(List *tlist,
102102
List *joinclauses, List *otherclauses,
103103
List *mergeclauses,
104104
Plan *lefttree, Plan *righttree,
105105
JoinType jointype);
106-
static Sort *make_sort(Query *root, List *tlist, Plan *lefttree, int numCols,
106+
static Sort *make_sort(Query *root, Plan *lefttree, int numCols,
107107
AttrNumber *sortColIdx, Oid *sortOperators);
108108
static Sort *make_sort_from_pathkeys(Query *root, Plan *lefttree,
109109
Relids relids, List *pathkeys);
@@ -492,7 +492,7 @@ create_material_plan(Query *root, MaterialPath *best_path)
492492
/* We don't want any excess columns in the materialized tuples */
493493
disuse_physical_tlist(subplan, best_path->subpath);
494494

495-
plan = make_material(subplan->targetlist, subplan);
495+
plan = make_material(subplan);
496496

497497
copy_path_costsize(&plan->plan, (Path *) best_path);
498498

@@ -518,7 +518,6 @@ create_unique_plan(Query *root, UniquePath *best_path)
518518
List *newtlist;
519519
int nextresno;
520520
bool newitems;
521-
List *my_tlist;
522521
List *l;
523522

524523
subplan = create_plan(root, best_path->subpath);
@@ -596,11 +595,8 @@ create_unique_plan(Query *root, UniquePath *best_path)
596595
/*
597596
* If the top plan node can't do projections, we need to add a
598597
* Result node to help it along.
599-
*
600-
* Currently, the only non-projection-capable plan type we can see
601-
* here is Append.
602598
*/
603-
if (IsA(subplan, Append))
599+
if (!is_projection_capable_plan(subplan))
604600
subplan = (Plan *) make_result(newtlist, NULL, subplan);
605601
else
606602
subplan->targetlist = newtlist;
@@ -610,17 +606,14 @@ create_unique_plan(Query *root, UniquePath *best_path)
610606
if (best_path->umethod == UNIQUE_PATH_NOOP)
611607
return subplan;
612608

613-
/* Copy tlist again to make one we can put sorting labels on */
614-
my_tlist = copyObject(subplan->targetlist);
615-
616609
if (best_path->umethod == UNIQUE_PATH_HASH)
617610
{
618611
long numGroups;
619612

620613
numGroups = (long) Min(best_path->rows, (double) LONG_MAX);
621614

622615
plan = (Plan *) make_agg(root,
623-
my_tlist,
616+
copyObject(subplan->targetlist),
624617
NIL,
625618
AGG_HASHED,
626619
numGroupCols,
@@ -637,15 +630,15 @@ create_unique_plan(Query *root, UniquePath *best_path)
637630
{
638631
TargetEntry *tle;
639632

640-
tle = get_tle_by_resno(my_tlist, groupColIdx[groupColPos]);
633+
tle = get_tle_by_resno(subplan->targetlist,
634+
groupColIdx[groupColPos]);
641635
Assert(tle != NULL);
642636
sortList = addTargetToSortList(NULL, tle,
643-
sortList, my_tlist,
637+
sortList, subplan->targetlist,
644638
SORTBY_ASC, NIL, false);
645639
}
646-
plan = (Plan *) make_sort_from_sortclauses(root, my_tlist,
647-
subplan, sortList);
648-
plan = (Plan *) make_unique(my_tlist, plan, sortList);
640+
plan = (Plan *) make_sort_from_sortclauses(root, sortList, subplan);
641+
plan = (Plan *) make_unique(plan, sortList);
649642
}
650643

651644
/* Adjust output size estimate (other fields should be OK already) */
@@ -1145,8 +1138,7 @@ create_hashjoin_plan(Query *root,
11451138
/*
11461139
* Build the hash node and hash join node.
11471140
*/
1148-
hash_plan = make_hash(inner_plan->targetlist,
1149-
inner_plan);
1141+
hash_plan = make_hash(inner_plan);
11501142
join_plan = make_hashjoin(tlist,
11511143
joinclauses,
11521144
otherclauses,
@@ -1735,7 +1727,7 @@ make_hashjoin(List *tlist,
17351727
}
17361728

17371729
static Hash *
1738-
make_hash(List *tlist, Plan *lefttree)
1730+
make_hash(Plan *lefttree)
17391731
{
17401732
Hash *node = makeNode(Hash);
17411733
Plan *plan = &node->plan;
@@ -1747,7 +1739,7 @@ make_hash(List *tlist, Plan *lefttree)
17471739
* input plan; this only affects EXPLAIN display not decisions.
17481740
*/
17491741
plan->startup_cost = plan->total_cost;
1750-
plan->targetlist = tlist;
1742+
plan->targetlist = copyObject(lefttree->targetlist);
17511743
plan->qual = NIL;
17521744
plan->lefttree = lefttree;
17531745
plan->righttree = NULL;
@@ -1785,7 +1777,7 @@ make_mergejoin(List *tlist,
17851777
* Caller must have built the sortColIdx and sortOperators arrays already.
17861778
*/
17871779
static Sort *
1788-
make_sort(Query *root, List *tlist, Plan *lefttree, int numCols,
1780+
make_sort(Query *root, Plan *lefttree, int numCols,
17891781
AttrNumber *sortColIdx, Oid *sortOperators)
17901782
{
17911783
Sort *node = makeNode(Sort);
@@ -1799,7 +1791,7 @@ make_sort(Query *root, List *tlist, Plan *lefttree, int numCols,
17991791
lefttree->plan_width);
18001792
plan->startup_cost = sort_path.startup_cost;
18011793
plan->total_cost = sort_path.total_cost;
1802-
plan->targetlist = tlist;
1794+
plan->targetlist = copyObject(lefttree->targetlist);
18031795
plan->qual = NIL;
18041796
plan->lefttree = lefttree;
18051797
plan->righttree = NULL;
@@ -1862,7 +1854,6 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
18621854
Relids relids, List *pathkeys)
18631855
{
18641856
List *tlist = lefttree->targetlist;
1865-
List *sort_tlist;
18661857
List *i;
18671858
int numsortkeys;
18681859
AttrNumber *sortColIdx;
@@ -1916,11 +1907,8 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
19161907

19171908
/*
19181909
* Do we need to insert a Result node?
1919-
*
1920-
* Currently, the only non-projection-capable plan type we can
1921-
* see here is Append.
19221910
*/
1923-
if (IsA(lefttree, Append))
1911+
if (!is_projection_capable_plan(lefttree))
19241912
{
19251913
tlist = copyObject(tlist);
19261914
lefttree = (Plan *) make_result(tlist, NULL, lefttree);
@@ -1952,26 +1940,21 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
19521940

19531941
Assert(numsortkeys > 0);
19541942

1955-
/* Give Sort node its own copy of the tlist (still necessary?) */
1956-
sort_tlist = copyObject(tlist);
1957-
1958-
return make_sort(root, sort_tlist, lefttree, numsortkeys,
1943+
return make_sort(root, lefttree, numsortkeys,
19591944
sortColIdx, sortOperators);
19601945
}
19611946

19621947
/*
19631948
* make_sort_from_sortclauses
19641949
* Create sort plan to sort according to given sortclauses
19651950
*
1966-
* 'tlist' is the targetlist
1967-
* 'lefttree' is the node which yields input tuples
19681951
* 'sortcls' is a list of SortClauses
1952+
* 'lefttree' is the node which yields input tuples
19691953
*/
19701954
Sort *
1971-
make_sort_from_sortclauses(Query *root, List *tlist,
1972-
Plan *lefttree, List *sortcls)
1955+
make_sort_from_sortclauses(Query *root, List *sortcls, Plan *lefttree)
19731956
{
1974-
List *sort_tlist;
1957+
List *sub_tlist = lefttree->targetlist;
19751958
List *i;
19761959
int numsortkeys;
19771960
AttrNumber *sortColIdx;
@@ -1987,24 +1970,20 @@ make_sort_from_sortclauses(Query *root, List *tlist,
19871970
foreach(i, sortcls)
19881971
{
19891972
SortClause *sortcl = (SortClause *) lfirst(i);
1990-
TargetEntry *tle = get_sortgroupclause_tle(sortcl, tlist);
1991-
Resdom *resdom = tle->resdom;
1973+
TargetEntry *tle = get_sortgroupclause_tle(sortcl, sub_tlist);
19921974

19931975
/*
19941976
* Check for the possibility of duplicate order-by clauses --- the
19951977
* parser should have removed 'em, but no point in sorting
19961978
* redundantly.
19971979
*/
1998-
numsortkeys = add_sort_column(resdom->resno, sortcl->sortop,
1980+
numsortkeys = add_sort_column(tle->resdom->resno, sortcl->sortop,
19991981
numsortkeys, sortColIdx, sortOperators);
20001982
}
20011983

20021984
Assert(numsortkeys > 0);
20031985

2004-
/* Give Sort node its own copy of the tlist (still necessary?) */
2005-
sort_tlist = copyObject(tlist);
2006-
2007-
return make_sort(root, sort_tlist, lefttree, numsortkeys,
1986+
return make_sort(root, lefttree, numsortkeys,
20081987
sortColIdx, sortOperators);
20091988
}
20101989

@@ -2028,7 +2007,6 @@ make_sort_from_groupcols(Query *root,
20282007
Plan *lefttree)
20292008
{
20302009
List *sub_tlist = lefttree->targetlist;
2031-
List *sort_tlist;
20322010
int grpno = 0;
20332011
List *i;
20342012
int numsortkeys;
@@ -2046,35 +2024,31 @@ make_sort_from_groupcols(Query *root,
20462024
{
20472025
GroupClause *grpcl = (GroupClause *) lfirst(i);
20482026
TargetEntry *tle = get_tle_by_resno(sub_tlist, grpColIdx[grpno]);
2049-
Resdom *resdom = tle->resdom;
20502027

20512028
/*
20522029
* Check for the possibility of duplicate group-by clauses --- the
20532030
* parser should have removed 'em, but no point in sorting
20542031
* redundantly.
20552032
*/
2056-
numsortkeys = add_sort_column(resdom->resno, grpcl->sortop,
2033+
numsortkeys = add_sort_column(tle->resdom->resno, grpcl->sortop,
20572034
numsortkeys, sortColIdx, sortOperators);
20582035
grpno++;
20592036
}
20602037

20612038
Assert(numsortkeys > 0);
20622039

2063-
/* Give Sort node its own copy of the tlist (still necessary?) */
2064-
sort_tlist = copyObject(sub_tlist);
2065-
2066-
return make_sort(root, sort_tlist, lefttree, numsortkeys,
2040+
return make_sort(root, lefttree, numsortkeys,
20672041
sortColIdx, sortOperators);
20682042
}
20692043

20702044
Material *
2071-
make_material(List *tlist, Plan *lefttree)
2045+
make_material(Plan *lefttree)
20722046
{
20732047
Material *node = makeNode(Material);
20742048
Plan *plan = &node->plan;
20752049

20762050
/* cost should be inserted by caller */
2077-
plan->targetlist = tlist;
2051+
plan->targetlist = copyObject(lefttree->targetlist);
20782052
plan->qual = NIL;
20792053
plan->lefttree = lefttree;
20802054
plan->righttree = NULL;
@@ -2098,7 +2072,7 @@ materialize_finished_plan(Plan *subplan)
20982072
Plan *matplan;
20992073
Path matpath; /* dummy for result of cost_material */
21002074

2101-
matplan = (Plan *) make_material(subplan->targetlist, subplan);
2075+
matplan = (Plan *) make_material(subplan);
21022076

21032077
/* Set cost data */
21042078
cost_material(&matpath,
@@ -2239,7 +2213,7 @@ make_group(Query *root,
22392213
* that should be considered by the Unique filter.
22402214
*/
22412215
Unique *
2242-
make_unique(List *tlist, Plan *lefttree, List *distinctList)
2216+
make_unique(Plan *lefttree, List *distinctList)
22432217
{
22442218
Unique *node = makeNode(Unique);
22452219
Plan *plan = &node->plan;
@@ -2263,7 +2237,7 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
22632237
* this if he has a better idea.
22642238
*/
22652239

2266-
plan->targetlist = tlist;
2240+
plan->targetlist = copyObject(lefttree->targetlist);
22672241
plan->qual = NIL;
22682242
plan->lefttree = lefttree;
22692243
plan->righttree = NULL;
@@ -2278,7 +2252,7 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
22782252
foreach(slitem, distinctList)
22792253
{
22802254
SortClause *sortcl = (SortClause *) lfirst(slitem);
2281-
TargetEntry *tle = get_sortgroupclause_tle(sortcl, tlist);
2255+
TargetEntry *tle = get_sortgroupclause_tle(sortcl, plan->targetlist);
22822256

22832257
uniqColIdx[keyno++] = tle->resdom->resno;
22842258
}
@@ -2295,7 +2269,7 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
22952269
*/
22962270

22972271
SetOp *
2298-
make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
2272+
make_setop(SetOpCmd cmd, Plan *lefttree,
22992273
List *distinctList, AttrNumber flagColIdx)
23002274
{
23012275
SetOp *node = makeNode(SetOp);
@@ -2321,7 +2295,7 @@ make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
23212295
if (plan->plan_rows < 1)
23222296
plan->plan_rows = 1;
23232297

2324-
plan->targetlist = tlist;
2298+
plan->targetlist = copyObject(lefttree->targetlist);
23252299
plan->qual = NIL;
23262300
plan->lefttree = lefttree;
23272301
plan->righttree = NULL;
@@ -2336,7 +2310,7 @@ make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
23362310
foreach(slitem, distinctList)
23372311
{
23382312
SortClause *sortcl = (SortClause *) lfirst(slitem);
2339-
TargetEntry *tle = get_sortgroupclause_tle(sortcl, tlist);
2313+
TargetEntry *tle = get_sortgroupclause_tle(sortcl, plan->targetlist);
23402314

23412315
dupColIdx[keyno++] = tle->resdom->resno;
23422316
}
@@ -2350,8 +2324,7 @@ make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
23502324
}
23512325

23522326
Limit *
2353-
make_limit(List *tlist, Plan *lefttree,
2354-
Node *limitOffset, Node *limitCount)
2327+
make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount)
23552328
{
23562329
Limit *node = makeNode(Limit);
23572330
Plan *plan = &node->plan;
@@ -2401,7 +2374,7 @@ make_limit(List *tlist, Plan *lefttree,
24012374
}
24022375
}
24032376

2404-
plan->targetlist = tlist;
2377+
plan->targetlist = copyObject(lefttree->targetlist);
24052378
plan->qual = NIL;
24062379
plan->lefttree = lefttree;
24072380
plan->righttree = NULL;
@@ -2448,3 +2421,27 @@ make_result(List *tlist,
24482421

24492422
return node;
24502423
}
2424+
2425+
/*
2426+
* is_projection_capable_plan
2427+
* Check whether a given Plan node is able to do projection.
2428+
*/
2429+
bool
2430+
is_projection_capable_plan(Plan *plan)
2431+
{
2432+
/* Most plan types can project, so just list the ones that can't */
2433+
switch (nodeTag(plan))
2434+
{
2435+
case T_Hash:
2436+
case T_Material:
2437+
case T_Sort:
2438+
case T_Unique:
2439+
case T_SetOp:
2440+
case T_Limit:
2441+
case T_Append:
2442+
return false;
2443+
default:
2444+
break;
2445+
}
2446+
return true;
2447+
}

0 commit comments

Comments
 (0)