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

Commita1d1339

Browse files
committed
Repair some bugs in new union/intersect/except code.
Thanks to Kevin O'Gorman for finding these...
1 parent26adbc7 commita1d1339

File tree

2 files changed

+95
-27
lines changed

2 files changed

+95
-27
lines changed

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

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.94 2000/11/05 00:15:53 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.95 2000/11/09 02:46:16 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -48,6 +48,8 @@ static List *make_subplanTargetList(Query *parse, List *tlist,
4848
staticPlan*make_groupplan(List*group_tlist,booltuplePerGroup,
4949
List*groupClause,AttrNumber*grpColIdx,
5050
boolis_presorted,Plan*subplan);
51+
staticList*postprocess_setop_tlist(List*new_tlist,List*orig_tlist);
52+
5153

5254
/*****************************************************************************
5355
*
@@ -635,17 +637,22 @@ union_planner(Query *parse,
635637
if (parse->setOperations)
636638
{
637639
/*
638-
* Construct the plan for set operations. The result will
639-
*notneed any work except perhaps a top-level sort.
640+
* Construct the plan for set operations. The result will not
641+
* need any work except perhaps a top-level sort and/or LIMIT.
640642
*/
641643
result_plan=plan_set_operations(parse);
642644

643645
/*
644646
* We should not need to call preprocess_targetlist, since we must
645-
* be in a SELECT query node.
647+
* be in a SELECT query node. Instead, use the targetlist
648+
* returned by plan_set_operations (since this tells whether it
649+
* returned any resjunk columns!), and transfer any sort key
650+
* information from the original tlist.
646651
*/
647652
Assert(parse->commandType==CMD_SELECT);
648653

654+
tlist=postprocess_setop_tlist(result_plan->targetlist,tlist);
655+
649656
/*
650657
* We leave current_pathkeys NIL indicating we do not know sort
651658
* order. This is correct when the top set operation is UNION ALL,
@@ -1255,3 +1262,41 @@ make_sortplan(List *tlist, Plan *plannode, List *sortcls)
12551262

12561263
return (Plan*)make_sort(sort_tlist,plannode,keyno);
12571264
}
1265+
1266+
/*
1267+
* postprocess_setop_tlist
1268+
* Fix up targetlist returned by plan_set_operations().
1269+
*
1270+
* We need to transpose sort key info from the orig_tlist into new_tlist.
1271+
* NOTE: this would not be good enough if we supported resjunk sort keys
1272+
* for results of set operations --- then, we'd need to project a whole
1273+
* new tlist to evaluate the resjunk columns. For now, just elog if we
1274+
* find any resjunk columns in orig_tlist.
1275+
*/
1276+
staticList*
1277+
postprocess_setop_tlist(List*new_tlist,List*orig_tlist)
1278+
{
1279+
List*l;
1280+
1281+
foreach(l,new_tlist)
1282+
{
1283+
TargetEntry*new_tle= (TargetEntry*)lfirst(l);
1284+
TargetEntry*orig_tle;
1285+
1286+
/* ignore resjunk columns in setop result */
1287+
if (new_tle->resdom->resjunk)
1288+
continue;
1289+
1290+
Assert(orig_tlist!=NIL);
1291+
orig_tle= (TargetEntry*)lfirst(orig_tlist);
1292+
orig_tlist=lnext(orig_tlist);
1293+
if (orig_tle->resdom->resjunk)
1294+
elog(ERROR,"postprocess_setop_tlist: resjunk output columns not implemented");
1295+
Assert(new_tle->resdom->resno==orig_tle->resdom->resno);
1296+
Assert(new_tle->resdom->restype==orig_tle->resdom->restype);
1297+
new_tle->resdom->ressortgroupref=orig_tle->resdom->ressortgroupref;
1298+
}
1299+
if (orig_tlist!=NIL)
1300+
elog(ERROR,"postprocess_setop_tlist: resjunk output columns not implemented");
1301+
returnnew_tlist;
1302+
}

‎src/backend/optimizer/prep/prepunion.c

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.54 2000/10/05 19:11:30 tgl Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.55 2000/11/09 02:46:17 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -39,8 +39,8 @@ typedef struct
3939
}fix_parsetree_attnums_context;
4040

4141
staticPlan*recurse_set_operations(Node*setOp,Query*parse,
42-
List*colTypes,intflag,
43-
List*refnames_tlist);
42+
List*colTypes,booljunkOK,
43+
intflag,List*refnames_tlist);
4444
staticPlan*generate_union_plan(SetOperationStmt*op,Query*parse,
4545
List*refnames_tlist);
4646
staticPlan*generate_nonunion_plan(SetOperationStmt*op,Query*parse,
@@ -49,9 +49,10 @@ static List *recurse_union_children(Node *setOp, Query *parse,
4949
SetOperationStmt*top_union,
5050
List*refnames_tlist);
5151
staticList*generate_setop_tlist(List*colTypes,intflag,
52+
boolhack_constants,
5253
List*input_tlist,
5354
List*refnames_tlist);
54-
staticbooltlist_same_datatypes(List*tlist,List*colTypes);
55+
staticbooltlist_same_datatypes(List*tlist,List*colTypes,booljunkOK);
5556
staticvoidfix_parsetree_attnums(Indexrt_index,Oidold_relid,
5657
Oidnew_relid,Query*parsetree);
5758
staticboolfix_parsetree_attnums_walker(Node*node,
@@ -95,10 +96,11 @@ plan_set_operations(Query *parse)
9596
/*
9697
* Recurse on setOperations tree to generate plans for set ops.
9798
* The final output plan should have just the column types shown
98-
* as the output from the top-level node.
99+
* as the output from the top-level node, plus possibly a resjunk
100+
* working column (we can rely on upper-level nodes to deal with that).
99101
*/
100102
returnrecurse_set_operations((Node*)topop,parse,
101-
topop->colTypes,-1,
103+
topop->colTypes,true,-1,
102104
leftmostQuery->targetList);
103105
}
104106

@@ -107,13 +109,14 @@ plan_set_operations(Query *parse)
107109
* Recursively handle one step in a tree of set operations
108110
*
109111
* colTypes: integer list of type OIDs of expected output columns
112+
* junkOK: if true, child resjunk columns may be left in the result
110113
* flag: if >= 0, add a resjunk output column indicating value of flag
111114
* refnames_tlist: targetlist to take column names from
112115
*/
113116
staticPlan*
114117
recurse_set_operations(Node*setOp,Query*parse,
115-
List*colTypes,intflag,
116-
List*refnames_tlist)
118+
List*colTypes,booljunkOK,
119+
intflag,List*refnames_tlist)
117120
{
118121
if (IsA(setOp,RangeTblRef))
119122
{
@@ -133,7 +136,7 @@ recurse_set_operations(Node *setOp, Query *parse,
133136
* Add a SubqueryScan with the caller-requested targetlist
134137
*/
135138
plan= (Plan*)
136-
make_subqueryscan(generate_setop_tlist(colTypes,flag,
139+
make_subqueryscan(generate_setop_tlist(colTypes,flag, true,
137140
subplan->targetlist,
138141
refnames_tlist),
139142
NIL,
@@ -165,10 +168,11 @@ recurse_set_operations(Node *setOp, Query *parse,
165168
* the referencing Vars will equal the tlist entries they reference.
166169
* Ugly but I don't feel like making that code more general right now.
167170
*/
168-
if (flag >=0|| !tlist_same_datatypes(plan->targetlist,colTypes))
171+
if (flag >=0||
172+
!tlist_same_datatypes(plan->targetlist,colTypes,junkOK))
169173
{
170174
plan= (Plan*)
171-
make_result(generate_setop_tlist(colTypes,flag,
175+
make_result(generate_setop_tlist(colTypes,flag, false,
172176
plan->targetlist,
173177
refnames_tlist),
174178
NULL,
@@ -215,7 +219,7 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
215219
make_append(planlist,
216220
0,
217221
NIL,
218-
generate_setop_tlist(op->colTypes,-1,
222+
generate_setop_tlist(op->colTypes,-1, false,
219223
((Plan*)lfirst(planlist))->targetlist,
220224
refnames_tlist));
221225
/*
@@ -251,10 +255,10 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
251255

252256
/* Recurse on children, ensuring their outputs are marked */
253257
lplan=recurse_set_operations(op->larg,parse,
254-
op->colTypes,0,
258+
op->colTypes,false,0,
255259
refnames_tlist);
256260
rplan=recurse_set_operations(op->rarg,parse,
257-
op->colTypes,1,
261+
op->colTypes,false,1,
258262
refnames_tlist);
259263
/*
260264
* Append the child results together.
@@ -267,7 +271,7 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
267271
make_append(makeList2(lplan,rplan),
268272
0,
269273
NIL,
270-
generate_setop_tlist(op->colTypes,0,
274+
generate_setop_tlist(op->colTypes,0, false,
271275
lplan->targetlist,
272276
refnames_tlist));
273277
/*
@@ -321,17 +325,27 @@ recurse_union_children(Node *setOp, Query *parse,
321325
top_union,refnames_tlist));
322326
}
323327
}
324-
/* Not same, so plan this child separately */
328+
/*
329+
* Not same, so plan this child separately.
330+
*
331+
* Note we disallow any resjunk columns in child results. This
332+
* is necessary since the Append node that implements the union
333+
* won't do any projection, and upper levels will get confused if
334+
* some of our output tuples have junk and some don't. This case
335+
* only arises when we have an EXCEPT or INTERSECT as child, else
336+
* there won't be resjunk anyway.
337+
*/
325338
returnmakeList1(recurse_set_operations(setOp,parse,
326-
top_union->colTypes,-1,
327-
refnames_tlist));
339+
top_union->colTypes,false,
340+
-1,refnames_tlist));
328341
}
329342

330343
/*
331344
* Generate targetlist for a set-operation plan node
332345
*/
333346
staticList*
334347
generate_setop_tlist(List*colTypes,intflag,
348+
boolhack_constants,
335349
List*input_tlist,
336350
List*refnames_tlist)
337351
{
@@ -359,14 +373,17 @@ generate_setop_tlist(List *colTypes, int flag,
359373
* HACK: constants in the input's targetlist are copied up as-is
360374
* rather than being referenced as subquery outputs. This is mainly
361375
* to ensure that when we try to coerce them to the output column's
362-
* datatype, the right things happen for UNKNOWN constants.
376+
* datatype, the right things happen for UNKNOWN constants. But do
377+
* this only at the first level of subquery-scan plans; we don't
378+
* want phony constants appearing in the output tlists of upper-level
379+
* nodes!
363380
*/
364381
resdom=makeResdom((AttrNumber)resno++,
365382
colType,
366383
-1,
367384
pstrdup(reftle->resdom->resname),
368385
false);
369-
if (inputtle->expr&&IsA(inputtle->expr,Const))
386+
if (hack_constants&&inputtle->expr&&IsA(inputtle->expr,Const))
370387
expr=inputtle->expr;
371388
else
372389
expr= (Node*)makeVar(0,
@@ -407,18 +424,24 @@ generate_setop_tlist(List *colTypes, int flag,
407424
/*
408425
* Does tlist have same datatypes as requested colTypes?
409426
*
410-
* Resjunk columns are ignored.
427+
* Resjunk columns are ignored if junkOK is true; otherwise presence of
428+
* a resjunk column will always cause a 'false' result.
411429
*/
412430
staticbool
413-
tlist_same_datatypes(List*tlist,List*colTypes)
431+
tlist_same_datatypes(List*tlist,List*colTypes,booljunkOK)
414432
{
415433
List*i;
416434

417435
foreach(i,tlist)
418436
{
419437
TargetEntry*tle= (TargetEntry*)lfirst(i);
420438

421-
if (!tle->resdom->resjunk)
439+
if (tle->resdom->resjunk)
440+
{
441+
if (!junkOK)
442+
return false;
443+
}
444+
else
422445
{
423446
if (colTypes==NIL)
424447
return false;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp