|
14 | 14 | * |
15 | 15 | * |
16 | 16 | * IDENTIFICATION |
17 | | - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.70 2002/03/01 06:01:20 tgl Exp $ |
| 17 | + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.71 2002/03/05 05:10:24 tgl Exp $ |
18 | 18 | * |
19 | 19 | *------------------------------------------------------------------------- |
20 | 20 | */ |
@@ -63,7 +63,9 @@ static List *generate_setop_tlist(List *colTypes, int flag, |
63 | 63 | boolhack_constants, |
64 | 64 | List*input_tlist, |
65 | 65 | List*refnames_tlist); |
66 | | -staticvoidmerge_tlist_typmods(List*tlist,List*planlist); |
| 66 | +staticList*generate_append_tlist(List*colTypes,boolflag, |
| 67 | +List*input_plans, |
| 68 | +List*refnames_tlist); |
67 | 69 | staticbooltlist_same_datatypes(List*tlist,List*colTypes,booljunkOK); |
68 | 70 | staticNode*adjust_inherited_attrs_mutator(Node*node, |
69 | 71 | adjust_inherited_attrs_context*context); |
@@ -169,13 +171,11 @@ recurse_set_operations(Node *setOp, Query *parse, |
169 | 171 | * |
170 | 172 | * XXX you don't really want to know about this: setrefs.c will apply |
171 | 173 | * replace_vars_with_subplan_refs() to the Result node's tlist. |
172 | | - * This would fail if the input plan's non-resjunk tlist entries |
173 | | - * were not all simple Vars equal() to the referencing Vars |
174 | | - * generated by generate_setop_tlist(). However, since the input |
175 | | - * plan was generated by generate_union_plan() or |
176 | | - * generate_nonunion_plan(), the referencing Vars will equal the |
177 | | - * tlist entries they reference. Ugly but I don't feel like making |
178 | | - * that code more general right now. |
| 174 | + * This would fail if the Vars generated by generate_setop_tlist() |
| 175 | + * were not exactly equal() to the corresponding tlist entries of |
| 176 | + * the subplan. However, since the subplan was generated by |
| 177 | + * generate_union_plan() or generate_nonunion_plan(), and hence its |
| 178 | + * tlist was generated by generate_append_tlist(), this will work. |
179 | 179 | */ |
180 | 180 | if (flag >=0|| |
181 | 181 | !tlist_same_datatypes(plan->targetlist,colTypes,junkOK)) |
@@ -226,10 +226,8 @@ generate_union_plan(SetOperationStmt *op, Query *parse, |
226 | 226 | * concerned, but we must make it look real anyway for the benefit of |
227 | 227 | * the next plan level up. |
228 | 228 | */ |
229 | | -tlist=generate_setop_tlist(op->colTypes,-1, false, |
230 | | - ((Plan*)lfirst(planlist))->targetlist, |
231 | | -refnames_tlist); |
232 | | -merge_tlist_typmods(tlist,planlist); |
| 229 | +tlist=generate_append_tlist(op->colTypes, false, |
| 230 | +planlist,refnames_tlist); |
233 | 231 |
|
234 | 232 | /* |
235 | 233 | * Append the child results together. |
@@ -285,10 +283,8 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse, |
285 | 283 | * flag column is shown as a variable not a constant, else setrefs.c |
286 | 284 | * will get confused. |
287 | 285 | */ |
288 | | -tlist=generate_setop_tlist(op->colTypes,2, false, |
289 | | -lplan->targetlist, |
290 | | -refnames_tlist); |
291 | | -merge_tlist_typmods(tlist,planlist); |
| 286 | +tlist=generate_append_tlist(op->colTypes, true, |
| 287 | +planlist,refnames_tlist); |
292 | 288 |
|
293 | 289 | /* |
294 | 290 | * Append the child results together. |
@@ -368,8 +364,7 @@ recurse_union_children(Node *setOp, Query *parse, |
368 | 364 | * Generate targetlist for a set-operation plan node |
369 | 365 | * |
370 | 366 | * colTypes: column datatypes for non-junk columns |
371 | | - * flag: -1 if no flag column needed, 0 or 1 to create a const flag column, |
372 | | - * 2 to create a variable flag column |
| 367 | + * flag: -1 if no flag column needed, 0 or 1 to create a const flag column |
373 | 368 | * hack_constants: true to copy up constants (see comments in code) |
374 | 369 | * input_tlist: targetlist of this node's input node |
375 | 370 | * refnames_tlist: targetlist to take column names from |
@@ -450,71 +445,132 @@ generate_setop_tlist(List *colTypes, int flag, |
450 | 445 | -1, |
451 | 446 | pstrdup("flag"), |
452 | 447 | true); |
453 | | -if (flag <=1) |
454 | | -{ |
455 | | -/* flag value is the given constant */ |
456 | | -expr= (Node*)makeConst(INT4OID, |
457 | | -sizeof(int4), |
458 | | -Int32GetDatum(flag), |
459 | | - false, |
460 | | - true, |
461 | | - false, |
462 | | - false); |
463 | | -} |
464 | | -else |
465 | | -{ |
466 | | -/* flag value is being copied up from subplan */ |
467 | | -expr= (Node*)makeVar(0, |
468 | | -resdom->resno, |
469 | | -INT4OID, |
470 | | --1, |
471 | | -0); |
472 | | -} |
| 448 | +/* flag value is the given constant */ |
| 449 | +expr= (Node*)makeConst(INT4OID, |
| 450 | +sizeof(int4), |
| 451 | +Int32GetDatum(flag), |
| 452 | + false, |
| 453 | + true, |
| 454 | + false, |
| 455 | + false); |
473 | 456 | tlist=lappend(tlist,makeTargetEntry(resdom,expr)); |
474 | 457 | } |
475 | 458 |
|
476 | 459 | returntlist; |
477 | 460 | } |
478 | 461 |
|
479 | 462 | /* |
480 | | - * Merge typmods of a list of set-operation subplans. |
| 463 | + * Generate targetlist for a set-operation Append node |
| 464 | + * |
| 465 | + * colTypes: column datatypes for non-junk columns |
| 466 | + * flag: true to create a flag column copied up from subplans |
| 467 | + * input_plans: list of sub-plans of the Append |
| 468 | + * refnames_tlist: targetlist to take column names from |
481 | 469 | * |
482 | | - * If the inputs all agree on type and typmod of a particular column, |
483 | | - * use that typmod; else use -1. We assume the result tlist has been |
484 | | - * initialized with the types and typmods of the first input subplan. |
| 470 | + * The entries in the Append's targetlist should always be simple Vars; |
| 471 | + * we just have to make sure they have the right datatypes and typmods. |
485 | 472 | */ |
486 | | -staticvoid |
487 | | -merge_tlist_typmods(List*tlist,List*planlist) |
| 473 | +staticList* |
| 474 | +generate_append_tlist(List*colTypes,boolflag, |
| 475 | +List*input_plans, |
| 476 | +List*refnames_tlist) |
488 | 477 | { |
| 478 | +List*tlist=NIL; |
| 479 | +intresno=1; |
| 480 | +List*curColType; |
| 481 | +intcolindex; |
| 482 | +Resdom*resdom; |
| 483 | +Node*expr; |
489 | 484 | List*planl; |
| 485 | +int32*colTypmods; |
| 486 | + |
| 487 | +/* |
| 488 | + * First extract typmods to use. |
| 489 | + * |
| 490 | + * If the inputs all agree on type and typmod of a particular column, |
| 491 | + * use that typmod; else use -1. |
| 492 | + */ |
| 493 | +colTypmods= (int32*)palloc(length(colTypes)*sizeof(int32)); |
490 | 494 |
|
491 | | -foreach(planl,planlist) |
| 495 | +foreach(planl,input_plans) |
492 | 496 | { |
493 | 497 | Plan*subplan= (Plan*)lfirst(planl); |
494 | | -List*subtlist=subplan->targetlist; |
495 | | -List*restlist; |
| 498 | +List*subtlist; |
496 | 499 |
|
497 | | -foreach(restlist,tlist) |
| 500 | +curColType=colTypes; |
| 501 | +colindex=0; |
| 502 | +foreach(subtlist,subplan->targetlist) |
498 | 503 | { |
499 | | -TargetEntry*restle= (TargetEntry*)lfirst(restlist); |
500 | | -TargetEntry*subtle; |
| 504 | +TargetEntry*subtle= (TargetEntry*)lfirst(subtlist); |
501 | 505 |
|
502 | | -if (restle->resdom->resjunk) |
| 506 | +if (subtle->resdom->resjunk) |
503 | 507 | continue; |
504 | | -Assert(subtlist!=NIL); |
505 | | -subtle= (TargetEntry*)lfirst(subtlist); |
506 | | -while (subtle->resdom->resjunk) |
| 508 | +Assert(curColType!=NIL); |
| 509 | +if (subtle->resdom->restype== (Oid)lfirsti(curColType)) |
507 | 510 | { |
508 | | -subtlist=lnext(subtlist); |
509 | | -Assert(subtlist!=NIL); |
510 | | -subtle= (TargetEntry*)lfirst(subtlist); |
| 511 | +/* If first subplan, copy the typmod; else compare */ |
| 512 | +if (planl==input_plans) |
| 513 | +colTypmods[colindex]=subtle->resdom->restypmod; |
| 514 | +elseif (subtle->resdom->restypmod!=colTypmods[colindex]) |
| 515 | +colTypmods[colindex]=-1; |
511 | 516 | } |
512 | | -if (restle->resdom->restype!=subtle->resdom->restype|| |
513 | | -restle->resdom->restypmod!=subtle->resdom->restypmod) |
514 | | -restle->resdom->restypmod=-1; |
515 | | -subtlist=lnext(subtlist); |
| 517 | +else |
| 518 | +{ |
| 519 | +/* types disagree, so force typmod to -1 */ |
| 520 | +colTypmods[colindex]=-1; |
| 521 | +} |
| 522 | +curColType=lnext(curColType); |
| 523 | +colindex++; |
516 | 524 | } |
| 525 | +Assert(curColType==NIL); |
517 | 526 | } |
| 527 | + |
| 528 | +/* |
| 529 | + * Now we can build the tlist for the Append. |
| 530 | + */ |
| 531 | +colindex=0; |
| 532 | +foreach(curColType,colTypes) |
| 533 | +{ |
| 534 | +OidcolType= (Oid)lfirsti(curColType); |
| 535 | +int32colTypmod=colTypmods[colindex++]; |
| 536 | +TargetEntry*reftle= (TargetEntry*)lfirst(refnames_tlist); |
| 537 | + |
| 538 | +Assert(reftle->resdom->resno==resno); |
| 539 | +Assert(!reftle->resdom->resjunk); |
| 540 | +expr= (Node*)makeVar(0, |
| 541 | +resno, |
| 542 | +colType, |
| 543 | +colTypmod, |
| 544 | +0); |
| 545 | +resdom=makeResdom((AttrNumber)resno++, |
| 546 | +colType, |
| 547 | +colTypmod, |
| 548 | +pstrdup(reftle->resdom->resname), |
| 549 | +false); |
| 550 | +tlist=lappend(tlist,makeTargetEntry(resdom,expr)); |
| 551 | +refnames_tlist=lnext(refnames_tlist); |
| 552 | +} |
| 553 | + |
| 554 | +if (flag) |
| 555 | +{ |
| 556 | +/* Add a resjunk flag column */ |
| 557 | +resdom=makeResdom((AttrNumber)resno++, |
| 558 | +INT4OID, |
| 559 | +-1, |
| 560 | +pstrdup("flag"), |
| 561 | +true); |
| 562 | +/* flag value is shown as copied up from subplan */ |
| 563 | +expr= (Node*)makeVar(0, |
| 564 | +resdom->resno, |
| 565 | +INT4OID, |
| 566 | +-1, |
| 567 | +0); |
| 568 | +tlist=lappend(tlist,makeTargetEntry(resdom,expr)); |
| 569 | +} |
| 570 | + |
| 571 | +pfree(colTypmods); |
| 572 | + |
| 573 | +returntlist; |
518 | 574 | } |
519 | 575 |
|
520 | 576 | /* |
|