|
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 | /*
|
|